diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/CREDITS linux-2.5/CREDITS --- linux-2.5.1/CREDITS Wed Dec 5 21:02:14 2001 +++ linux-2.5/CREDITS Mon Jan 14 22:39:44 2002 @@ -527,6 +527,16 @@ S: Bellevue, Washington 98007 S: USA +N: Christopher L. Cheney +E: ccheney@debian.org +E: ccheney@cheney.cx +W: http://www.cheney.cx +P: 1024D/8E384AF2 2D31 1927 87D7 1F24 9FF9 1BC5 D106 5AB3 8E38 4AF2 +D: Vista Imaging usb webcam driver +S: 314 Prince of Wales +S: Conroe, TX 77304 +S: USA + N: Stuart Cheshire E: cheshire@cs.stanford.edu D: Author of Starmode Radio IP (STRIP) driver @@ -578,6 +588,13 @@ S: University of Michigan S: Ann Arbor, MI +N: Michael Cornwell +E: cornwell@acm.org +D: Original designer and co-author of ATA Taskfile +D: Kernel module SMART utilities +S: Santa Cruz, California +S: USA + N: Kees Cook E: cook@cpoint.net W: http://outflux.net/ @@ -1267,6 +1284,13 @@ D: bug toaster (A1 sauce makes all the difference) D: Random linux hacker +N: Tim Hockin +E: thockin@hockin.org +W: http://www.hockin.org/~thockin +D: Natsemi ethernet +D: Cobalt Networks (x86) support +D: This-and-That + N: Dirk Hohndel E: hohndel@suse.de D: The XFree86[tm] Project @@ -1437,11 +1461,10 @@ N: Dave Jones E: davej@suse.de -W: http://www.suse.de/~davej -D: Moved PCI bridge tuning to userspace (Powertweak). -D: Various x86 (& clones) setup code hacking. -D: AFFS fixes for 2.3.x -D: Various Janitorial hacks. (kernel-janitor.sourceforge.net) +W: http://www.codemonkey.org.uk +D: x86 errata/setup maintenance. +D: Backport/Forwardport merge monkey. +D: Various Janitor work. S: c/o SuSE Linux UK Ltd S: The Kinetic Centre S: Theobald Street @@ -1646,6 +1669,13 @@ S: 80-283 Gdansk S: Poland +N: Jakob Kemi +E: jakob.kemi@telia.com +D: V4L W9966 Webcam driver +S: Forsbyvägen 33 +S: 74143 Knivsta +S: Sweden + N: Gero Kuhlmann E: gero@gkminix.han.de D: mounting root via NFS @@ -1946,9 +1976,10 @@ S: Germany N: Mark W. McClelland -E: mwm@i.am +E: mmcclell@bigfoot.com E: mark@alpha.dyndns.org W: http://alpha.dyndns.org/ov511/ +P: 1024D/357375CC 317C 58AC 1B39 2AB0 AB96 EB38 0B6F 731F 3573 75CC D: OV511 driver S: (address available on request) S: USA @@ -2107,6 +2138,10 @@ S: Fullarton 5063 S: South Australia +N. Wolfgang Muees +E: wmues@nexgo.de +D: Auerswald USB driver + N: Ian A. Murdock E: imurdock@gnu.ai.mit.edu D: Creator of Debian distribution @@ -2507,7 +2542,7 @@ S: Australia N: Gerard Roudier -E: groudier@iplus.fr +E: groudier@free.fr D: Contributed to asynchronous read-ahead improvement S: 21 Rue Carnot S: 95170 Deuil La Barre diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/Changes linux-2.5/Documentation/Changes --- linux-2.5.1/Documentation/Changes Fri Nov 30 16:53:20 2001 +++ linux-2.5/Documentation/Changes Thu Dec 13 16:32:35 2001 @@ -53,7 +53,7 @@ o binutils 2.9.5.0.24 # ld -v o util-linux 2.10o # fdformat --version o modutils 2.4.2 # insmod -V -o e2fsprogs 1.19 # tune2fs +o e2fsprogs 1.25 # tune2fs 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 @@ -304,8 +304,7 @@ E2fsprogs --------- -o -o +o Reiserfsprogs ------------- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/Configure.help linux-2.5/Documentation/Configure.help --- linux-2.5.1/Documentation/Configure.help Fri Nov 30 21:25:10 2001 +++ linux-2.5/Documentation/Configure.help Mon Jan 14 22:39:44 2002 @@ -2,7 +2,7 @@ # Eric S. Raymond # Steven Cole # -# Merged version 2.61: current with 2.4.16/2.5.1-pre1. +# Merged version 2.73: current with 2.4.17-rc1/2.5.1-pre11. # # This version of the Linux kernel configuration help texts # corresponds to kernel versions 2.4.x and 2.5.x. @@ -69,7 +69,7 @@ # Explain why someone configuring a kernel might want to select your # option. # -# All this was shamelessly stolen from several different sources. Many +# All this was shamelessly stolen from numerous different sources. Many # thanks to all the contributors. Feel free to use these help texts in # your own kernel configuration tools. The texts are copyrighted (c) # 1995-2000 by Axel Boldt and many others and are governed by the GNU @@ -235,13 +235,13 @@ Multiquad support for NUMA systems CONFIG_MULTIQUAD - This option is used for getting Linux to run on a (IBM/Sequent) NUMA + This option is used for getting Linux to run on a (IBM/Sequent) NUMA multiquad box. This changes the way that processors are bootstrapped, - and uses Clustered Logical APIC addressing mode instead of Flat Logical. - You will need a new lynxer.elf file to flash your firmware with - send - email to Martin.Bligh@us.ibm.com + and uses Clustered Logical APIC addressing mode instead of Flat + Logical. You will need a new lynxer.elf file to flash your firmware + with - send email to . -IO-APIC Support on Uniprocessors +IO-APIC support on uniprocessors CONFIG_X86_UP_IOAPIC An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an SMP-capable replacement for PC-style interrupt controllers. Most @@ -257,11 +257,12 @@ CONFIG_X86_UP_APIC A local APIC (Advanced Programmable Interrupt Controller) is an integrated interrupt controller in the CPU. If you have a single-CPU - system which has a processor with a local APIC, you can say Y here to - enable and use it. If you say Y here even though your machine doesn't - have a local APIC, then the kernel will still run with no slowdown at - all. The local APIC supports CPU-generated self-interrupts (timer, - performance counters), and the NMI watchdog which detects hard lockups. + system which has a processor with a local APIC, you can say Y here + to enable and use it. If you say Y here even though your machine + doesn't have a local APIC, then the kernel will still run with no + slowdown at all. The local APIC supports CPU-generated + self-interrupts (timer, performance counters), and the NMI watchdog + which detects hard lockups. If you have a system with several CPUs, you do not need to say Y here: the local APIC will be used automatically. @@ -280,9 +281,9 @@ be used nevertheless. (This behavior can be changed with the kernel command line option "no387", which comes handy if your coprocessor is broken. Try "man bootparam" or see the documentation of your boot - loader (lilo or loadlin) about how to pass options to the kernel at - boot time.) This means that it is a good idea to say Y here if you - intend to use this kernel on different machines. + loader (grub, lilo or loadlin) about how to pass options to the + kernel at boot time.) This means that it is a good idea to say Y + here if you intend to use this kernel on different machines. More information about the internals of the Linux math coprocessor emulation can be found in . @@ -341,12 +342,12 @@ "high memory". If you are compiling a kernel which will never run on a machine with - more than 1 Gigabyte total physical RAM, answer "off" here (default - choice and suitable for most users). This will result in a "3GB/1GB" - split: 3GB are mapped so that each process sees a 3GB virtual memory - space and the remaining part of the 4GB virtual memory space is used - by the kernel to permanently map as much physical memory as - possible. + more than 960 megabytes of total physical RAM, answer "off" here + (default choice and suitable for most users). This will result in a + "3GB/1GB" split: 3GB are mapped so that each process sees a 3GB + virtual memory space and the remaining part of the 4GB virtual memory + space is used by the kernel to permanently map as much physical memory + as possible. If the machine has between 1 and 4 Gigabytes physical RAM, then answer "4GB" here. @@ -358,10 +359,10 @@ processors (Pentium Pro and better). NOTE: If you say "64GB" here, then the kernel will not boot on CPUs that don't support PAE! - The actual amount of total physical memory will either be - auto detected or can be forced by using a kernel command line option - such as "mem=256M". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the + The actual amount of total physical memory will either be auto + detected or can be forced by using a kernel command line option such + as "mem=256M". (Try "man bootparam" or see the documentation of your + boot loader (grub, lilo or loadlin) about how to pass options to the kernel at boot time.) If unsure, say "off". @@ -376,7 +377,7 @@ Select this if you have a 32-bit processor and more than 4 gigabytes of physical RAM. -Normal PC floppy disk support +Normal floppy disk support CONFIG_BLK_DEV_FD If you want to use the floppy disk drive(s) of your PC under Linux, say Y. Information about this driver, especially important for IBM @@ -390,18 +391,6 @@ The module will be called floppy.o. If you want to compile it as a module, say M here and read . -iSeries Virtual I/O Disk Support -CONFIG_VIODASD - If you are running on an iSeries system and you want to use - virtual disks created and managed by OS/400, say Y. - -iSeries Virtual I/O Disk IDE Emulation -CONFIG_VIODASD_IDE - This causes the iSeries virtual disks to look like IDE disks. - If you have programs or utilities that only support certain - kinds of disks, this option will cause iSeries virtual disks - to pretend to be IDE disks, which may satisfy the program. - Support for PowerMac floppy CONFIG_MAC_FLOPPY If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple) @@ -747,6 +736,14 @@ If both this SCSI emulation and native ATAPI support are compiled into the kernel, the native support will be used. +Use the NOOP Elevator (WARNING) +CONFIG_BLK_DEV_ELEVATOR_NOOP + If you are using a raid class top-level driver above the ATA/IDE core, + one may find a performance boost by preventing a merging and re-sorting + of the new requests. + + If unsure, say N. + ISA-PNP EIDE support CONFIG_BLK_DEV_ISAPNP If you have an ISA EIDE card that is PnP (Plug and Play) and @@ -839,6 +836,7 @@ If in doubt, say N. +# Currently commented out Attempt to HACK around Chipsets that TIMEOUT (WIP) CONFIG_BLK_DEV_IDEDMA_TIMEOUT If you say Y here, this is a NASTY UGLY HACK! @@ -911,10 +909,6 @@ Please read the comments at the top of . -Pacific Digital A-DMA support (EXPERIMENTAL) -CONFIG_BLK_DEV_PDC_ADMA - Please read the comments at the top of . - 3ware Hardware ATA-RAID support CONFIG_BLK_DEV_3W_XXXX_RAID 3ware is the only hardware ATA-Raid product in Linux to date. @@ -972,7 +966,7 @@ SAY N! -AMD Viper support +AMD Viper (7401/7409/7411) chipset support CONFIG_BLK_DEV_AMD74XX This driver ensures (U)DMA support for the AMD756/760 Viper chipsets. @@ -983,7 +977,7 @@ If unsure, say N. -AMD Viper ATA-66 Override (WIP) +AMD Viper ATA-66 Override support (WIP) CONFIG_AMD74XX_OVERRIDE This option auto-forces the ata66 flag. This effect can be also invoked by calling "idex=ata66" @@ -1092,6 +1086,18 @@ If unsure, say N. +IT8172 IDE support +CONFIG_BLK_DEV_IT8172 + Say Y here to support the on-board IDE controller on the Integrated + Technology Express, Inc. ITE8172 SBC. Vendor page at + ; picture of the + board at . + +IT8172 IDE Tuning support +CONFIG_IT8172_TUNING + Say Y here to support tuning the ITE8172's IDE interface. This makes + it possible to set DMA channel or PIO opration and the transfer rate. + PROMISE PDC20246/PDC20262/PDC20265/PDC20267/PDC20268 support CONFIG_BLK_DEV_PDC202XX Promise Ultra33 or PDC20246 @@ -1285,9 +1291,10 @@ Amiga Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL) CONFIG_BLK_DEV_BUDDHA - This is the IDE driver for the IDE interfaces on the Buddha, - Catweasel and X-Surf expansion boards. It supports up to two interfaces - on the Buddha, three on the Catweasel and two on the X-Surf. + This is the IDE driver for the IDE interfaces on the Buddha, + Catweasel and X-Surf expansion boards. It supports up to two + interfaces on the Buddha, three on the Catweasel and two on the + X-Surf. Say Y if you have a Buddha or Catweasel expansion board and want to use IDE devices (hard disks, CD-ROM drives, etc.) that are connected @@ -1595,7 +1602,7 @@ (low speed) adapter that is used in some portable hard drives. 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 ktti.o. + to build it as a loadable module. The module will be called fit2.o. You must also have a high-level driver for the type of device that you want to support. @@ -1876,20 +1883,6 @@ otherwise choose R3000. -Support for Cobalt Micro Server -CONFIG_COBALT_MICRO_SERVER - Support for MIPS-based Cobalt boxes (they have been bought by Sun - and are now the "Server Appliance Business Unit") including the 2700 - series -- versions 1 of the Qube and Raq. To compile a Linux kernel - for this hardware, say Y here. - -Support for Cobalt 2800 -CONFIG_COBALT_28 - Support for the second generation of MIPS-based Cobalt boxes (they - have been bought by Sun and are now the "Server Appliance Business - Unit") including the 2800 series -- versions 2 of the Qube and Raq. - To compile a Linux kernel for this hardware, say Y here. - Support for the Momentum Computer Ocelot SBC CONFIG_MOMENCO_OCELOT The Ocelot is a MIPS-based Single Board Computer (SBC) made by @@ -1929,14 +1922,6 @@ This enables support for the VR5000-based MIPS Malta evaluation board. -Support for Galileo Evaluation board or CoSine Orion -CONFIG_ORION - Say Y if configuring for the Galileo evaluation board - or CoSine Orion. More information is available at - . - - Otherwise, say N. - Support for Mips Magnum 4000 CONFIG_MIPS_MAGNUM_4000 This is a machine with a R4000 100 MHz CPU. To compile a Linux @@ -1949,6 +1934,27 @@ Images of Qtronix keyboards are at . +Support for older IT8172 (Rev C) +CONFIG_IT8172_REVC + Say Y here to support the older, Revision C version of the Integrated + Technology Express, Inc. ITE8172 SBC. Vendor page at + ; picture of the + board at . + +Enable Smart Card Reader 0 Support +CONFIG_IT8172_SCR0 + Say Y here to support smart-card reader 0 (SCR0) on the Integrated + Technology Express, Inc. ITE8172 SBC. Vendor page at + ; picture of the + board at . + +Enable Smart Card Reader 1 Support +CONFIG_IT8172_SCR1 + Say Y here to support smart-card reader 1 (SCR1) on the Integrated + Technology Express, Inc. ITE8172 SBC. Vendor page at + ; picture of the + board at . + Support for Olivetti M700 CONFIG_OLIVETTI_M700 This is a machine with a R4000 100 MHz CPU. To compile a Linux @@ -1963,13 +1969,13 @@ Technology and now in turn merged with Fujitsu. Say Y here to support this machine type. -Support for SGI IP22 +Support for SGI-IP22 (Indy/Indigo2) CONFIG_SGI_IP22 This are the SGI Indy, Challenge S and Indigo2, as well as certain OEM variants like the Tandem CMN B006S. To compile a Linux kernel that runs on these, say Y here. -Support for SGI IP27 +Support for SGI IP27 (Origin200/2000) CONFIG_SGI_IP27 This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics workstations. To compile a Linux kernel that runs on these, say Y @@ -2016,6 +2022,13 @@ the way floating point works you should always enable this option unless you exactly know what you're doing. +ARC console support +CONFIG_ARC_CONSOLE + Support for the PROM-based console on MIPS machines built according + to the Advanced Risc Computing specification, which is now (2001) + dead. These included boxes from Deskstation, Acer, Olivetti and + NEC. There is a history at . + SGI PROM Console Support CONFIG_SGI_PROM_CONSOLE Say Y here to set up the boot console on serial port 0. @@ -2025,13 +2038,27 @@ DZ11-family serial controllers for VAXstations, including the DC7085, M7814, and M7819. - TURBOchannel support CONFIG_TC - TurboChannel is a DEC (now Compaq) bus for Alpha and MIPS processors. - Documentation on writing device drivers for TurboChannel is available at: + TurboChannel is a DEC (now Compaq) bus for Alpha and MIPS + processors. Documentation on writing device drivers for + TurboChannel is available at: . +# Choice: galileo_clock +75 +CONFIG_SYSCLK_75 + Configure the kernel for clock speed of your Galileo board. + The choices are 75MHz, 83.3MHz, and 100MHz. + +83.3 +CONFIG_SYSCLK_83 + Configure the Galileo kernel for a clock speed of 83.3 MHz. + +100 +CONFIG_SYSCLK_100 + Configure the Galileo kernel for a clock speed of 100 MHz. + Z85C30 Serial Support CONFIG_ZS Documentation on the Zilog 85C350 serial communications controller @@ -2047,16 +2074,6 @@ kernel: saying N will just cause the configurator to skip all the questions PCMCIA SCSI host adapters. -Adaptec APA1480 CardBus support -CONFIG_PCMCIA_APA1480 - Say Y here if you intend to attach this type of CardBus SCSI host - adapter to your computer. - - This driver is also available as a module called apa1480_cb.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 . - NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support CONFIG_PCMCIA_NINJA_SCSI If you intend to attach this type of PCMCIA SCSI host adapter to @@ -2186,7 +2203,7 @@ Access). This option is for configuring high-end multiprocessor server machines. If in doubt, say N. -CPU type +R41xx CONFIG_CPU_VR41XX The options selects support for the NEC VR41xx series of processors. Only choose this option if you have one of these processors as a @@ -2198,7 +2215,7 @@ Saying yes here allows you to select support for various features your CPU may or may not have. Most people should say N here. -ll/sc Instructions available +ll and sc instructions available CONFIG_CPU_HAS_LLSC MIPS R4000 series and later provide the Load Linked (ll) and Store Conditional (sc) instructions. More information is @@ -2208,7 +2225,7 @@ for better performance, N if you don't know. You must say Y here for multiprocessor machines. -lld and scd instructions +lld and scd instructions available CONFIG_CPU_HAS_LLDSCD Say Y here if your CPU has the lld and scd instructions, the 64-bit equivalents of ll and sc. Say Y here for better performance, N if @@ -2341,7 +2358,7 @@ If you want to compile it as a module, say M here and read . If unsure, say `N'. -IRC Send/Chat support +IRC Send/Chat protocol support CONFIG_IP_NF_IRC There is a commonly-used extension to IRC called Direct Client-to-Client Protocol (DCC). This enables users to send @@ -2425,7 +2442,7 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. -length match support +LENGTH match support CONFIG_IP_NF_MATCH_LENGTH This option allows you to match the length of a packet against a specific value or range of values. @@ -2773,14 +2790,6 @@ If unsure, say N. -HCI EMU (virtual device) driver -CONFIG_BLUEZ_HCIEMU - Bluetooth Virtual HCI device driver. - This driver is required if you want to use HCI Emulation software. - - Say Y here to compile support for Virtual HCI devices into the - kernel or say M to compile it as module (hci_usb.o). - # Choice: alphatype Alpha system type CONFIG_ALPHA_GENERIC @@ -2811,8 +2820,10 @@ Noname AXPpci33, UDB (Multia) Noritake AS 1000A, AS 600A, AS 800 PC164 AlphaPC164 + P2K Platform2000 Rawhide AS 1200, AS 4000, AS 4100 Ruffian RPX164-2, AlphaPC164-UX, AlphaPC164-BX + RX164 An obscure EV5-based motherboard SX164 AlphaPC164-SX Sable AS 2000, AS 2100 Shark DS 20L @@ -2938,6 +2949,13 @@ AlphaServer 1000A, AlphaServer 600A, and AlphaServer 800-based systems. +Platform2000 +CONFIG_ALPHA_P2K + The Platform2000 is a modular motherboard that can accept `engine + cards' featuring various processors, including the Alpha. Info + page, with link to picture, at + . + Rawhide CONFIG_ALPHA_RAWHIDE AlphaServer 1200, AlphaServer 4000 and AlphaServer 4100 machines. @@ -2949,6 +2967,11 @@ Samsung APC164UX. There is a page on known problems and workarounds at . +PC164 +CONFIG_ALPHA_PC164 + Digital Alpha PC164. Product brief page from a reseller ast: + + Sable CONFIG_ALPHA_SABLE Digital AlphaServer 2000 and 2100-based systems. @@ -2969,6 +2992,11 @@ CONFIG_ALPHA_GAMMA Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx. +EV67 (or later) CPU (speed > 600MHz)? +CONFIG_ALPHA_EV67 + Is this a machine based on the EV67 core? If in doubt, select N here + and the machine will be treated as an EV6. + Use SRM as bootloader CONFIG_ALPHA_SRM There are two different types of booting firmware on Alphas: SRM, @@ -3056,9 +3084,9 @@ Support for serial ports defined by ACPI tables CONFIG_SERIAL_ACPI - Legacy free machines may not have serial ports at the legacy COM1, + Legacy free machines may not have serial ports at the legacy COM1, COM2 etc addresses. Serial ports on such machines are described by - the ACPI tables SPCR (Serial Port Console Redirection) table and + the ACPI tables SPCR (Serial Port Console Redirection) table and DBGP (Debug Port) table. Say Y here if you want to include support for these serial ports. @@ -3132,9 +3160,9 @@ ACP Modem (Mwave) support CONFIG_MWAVE The ACP modem (Mwave) for Linux is a WinModem. It is composed of a - kernel driver and a user level application. Together these components - support direct attachment to public switched telephone networks (PSTNs) - and support selected world wide countries. + kernel driver and a user level application. Together these + components support direct attachment to public switched telephone + networks (PSTNs) and support selected world wide countries. This version of the ACP Modem driver supports the IBM Thinkpad 600E, 600, and 770 that include on board ACP modem hardware. @@ -3182,16 +3210,17 @@ Intel 440LX/BX/GX/815/820/830/840/845/850/860 support CONFIG_AGP_INTEL This option gives you AGP support for the GLX component of the - XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850 and 860 chipsets. + XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850 and 860 + chipsets. You should say Y here if you use XFree86 3.3.6 or 4.x and want to use GLX or DRI. If unsure, say N. -Intel I810/I815 DC100/I810e support +Intel I810/I815/I830M (on board) support CONFIG_AGP_I810 This option gives you AGP support for the Xserver on the Intel 810 - 815 and 830m chipset boards for their on-board integrated graphics. This - is required to do any useful video modes with these boards. + 815 and 830m chipset boards for their on-board integrated graphics. + This is required to do any useful video modes with these boards. VIA chipset support CONFIG_AGP_VIA @@ -3222,7 +3251,7 @@ Serverworks LE/HE support CONFIG_AGP_SWORKS - Say Y here to support the Serverworks AGP card. See + Say Y here to support the Serverworks AGP card. See for product descriptions and images. ALI chipset support @@ -3261,18 +3290,6 @@ information about which PCI hardware does work under Linux and which doesn't. -PCI support -CONFIG_PCI_INTEGRATOR - Find out whether you have a PCI motherboard. PCI is the name of a - bus system, i.e. the way the CPU talks to the other stuff inside - your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or - VESA. If you have PCI, say Y, otherwise N. - - The PCI-HOWTO, available from - , contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - QSpan PCI CONFIG_PCI_QSPAN Find out whether you have a PCI motherboard. PCI is the name of a @@ -3314,7 +3331,7 @@ When in doubt, say Y. -PCI Hotplug support +Generic PCI hotplug support CONFIG_HOTPLUG_PCI Say Y here if you have a motherboard with a PCI Hotplug controller. This allows you to add and remove PCI cards while the machine is @@ -3328,7 +3345,7 @@ When in doubt, say N. -PCI Compaq Hotplug controller +Compaq PCI Hotplug driver CONFIG_HOTPLUG_PCI_COMPAQ Say Y here if you have a motherboard with a Compaq PCI Hotplug controller. @@ -3340,7 +3357,7 @@ When in doubt, say N. -PCI Compaq Hotplug controller NVRAM support +Save configuration into NVRAM on Compaq servers CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM Say Y here if you have a Compaq server that has a PCI Hotplug controller. This will allow the PCI Hotplug driver to store the PCI @@ -3563,9 +3580,9 @@ i82092 compatible bridge support CONFIG_I82092 - This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device, - found in some older laptops and more commonly in evaluation boards for the - chip. + This provides support for the Intel I82092AA PCI-to-PCMCIA bridge + device, found in some older laptops and more commonly in evaluation + boards for the chip. i82365 compatible host bridge support CONFIG_I82365 @@ -3645,8 +3662,7 @@ don't understand what this means or are not a kernel hacker, just leave it at its default value ELF. -# Choice: kcore -Select a.out format for /proc/kcore +a.out CONFIG_KCORE_AOUT Not necessary unless you're using a very out-of-date binutils version. You probably want KCORE_ELF. @@ -3692,13 +3708,13 @@ warrant removing support. However its removal is a good idea if you wish to ensure that absolutely none of your programs will use this older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout.o. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. + point then answer Y. If someone told you you will need a kernel with + support for the QMAGIC executable format, then you will have to say + Y here. You may answer M to compile a.out support as a module and + later load the module when you want to use a program or library in + a.out format. The module will be called binfmt_aout.o. Saying M or N + here is dangerous though, because some crucial programs on your + system might still be in A.OUT format. Kernel support for Linux/Intel ELF binaries CONFIG_BINFMT_EM86 @@ -3768,7 +3784,7 @@ The module will be called envctrl.o. If you want to compile it as a module, say M here and read . -# Choice: x86 +# Choice: x86type Processor family CONFIG_M386 This is the processor type of your CPU. This information is used for @@ -3786,7 +3802,7 @@ will run on a 386 class machine. - "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S. - - "586" for generic Pentium CPUs, possibly lacking the TSC + - "586" for generic Pentium CPUs lacking the TSC (time stamp counter) register. - "Pentium-Classic" for the Intel Pentium. - "Pentium-MMX" for the Intel Pentium MMX. @@ -3815,23 +3831,80 @@ CONFIG_M586 Select this for an x586 or x686 processor such as the AMD K5, the Intel 5x86 or 6x86, or the Intel 6x86MX. This choice does not - assume the RDTSC instruction. + assume the RDTSC (Read Time Stamp Counter) instruction. Pentium Classic CONFIG_M586TSC Select this for a Pentium Classic processor with the RDTSC (Read Time Stamp Counter) instruction for benchmarking. -32-bit PDC -CONFIG_PDC_NARROW - Saying Y here will allow developers with a C180, C200, C240, C360, - J200, J210, and/or a J2240 to test 64-bit kernels by providing a - wrapper for the 32-bit PDC calls. Since the machines which require - this option do not support over 4G of RAM, this option is targeted - for developers of these machines wishing to test changes on both - 32-bit and 64-bit configurations. - - If unsure, say N. +Pentium MMX +CONFIG_M586MMX + Select this for a Pentium with the MMX graphics/multimedia + extended instructions. + +Pentium Pro/Celeron/Pentium II +CONFIG_M686 + Select this for a Pro/Celeron/Pentium II. This enables the use of + Pentium Pro extended instructions, and disables the init-time guard + against the f00f bug found in earlier Pentiums. + +Pentium-III/Celeron-Coppermine +CONFIG_MPENTIUMIII + Select this for Intel chips based on the Pentium-III and + Celeron-Coppermine core. Enables use of some extended prefetch + instructions, in addition to the Pentium II extensions. + +Pentium-4 +CONFIG_MPENTIUM4 + Select this for Intel Pentium 4 chips. Presently these are + treated almost like Pentium IIIs, but with a different cache + shift. + +Crusoe +CONFIG_MCRUSOE + Select this for Transmeta Crusoe processor. Treats the processor + like a 586 with TSC, and sets some GCC optimization flags (like a + Pentium Pro with no alignment requirements). + +K6/K6-II/K6-III +CONFIG_MK6 + Select this for an AMD K6-family processor. Enables use of + some extended instructions, and passes appropriate optimization + flags to GCC. + +Athlon/Duron/K7 +CONFIG_MK7 + Select this for an AMD Athlon K7-family processor. Enables use of + some extended instructions, and passes appropriate optimization + flags to GCC. + +CyrixIII/C3 +CONFIG_MCYRIXIII + Select this for a Cyrix III or C3 chip. Presently Linux and GCC + treat this chip as a generic 586. Whilst the CPU is 686 class, + it lacks the cmov extension which gcc assumes is present when + generating 686 code. + +Winchip-C6 +CONFIG_MWINCHIPC6 + Select this for a IDT Winchip C6 chip. Linux and GCC + treat this chip as a 586TSC with some extended instructions + and alignment requirements. + +Winchip-2 +CONFIG_MWINCHIP2 + Select this for a IDT Winchip-2. Linux and GCC + treat this chip as a 586TSC with some extended instructions + and alignment requirements. + +Winchip-2A/Winchip-3 +CONFIG_MWINCHIP3D + Select this for a IDT Winchip-2A or 3. Linux and GCC + treat this chip as a 586TSC with some extended instructions + and alignment reqirements. Development kernels also enable + out of order memory stores for this CPU, which can increase + performance of some operations. VGA text console CONFIG_VGA_CONSOLE @@ -4077,7 +4150,8 @@ CONFIG_FB_MAXINE Say Y here to directly support the on-board framebuffer in the Maxine (5000/20, /25, /33) version of the DECstation. There is a - page dedicated to Linux on DECstations at . + page dedicated to Linux on DECstations at + . PMAG-BA TURBOchannel framebuffer support CONFIG_FB_PMAG_BA @@ -4098,8 +4172,9 @@ ANAKIN Vehicle Telematics Platform CONFIG_ARCH_ANAKIN - The Anakin is a StrongArm based SA110 - 2 DIN Vehicle Telematics Platform. - 64MB SDRAM - 4 Mb Flash - Compact Flash Interface - 1 MB VRAM + The Anakin is a StrongArm based SA110 - 2 DIN Vehicle Telematics + Platform. 64MB SDRAM - 4 Mb Flash - Compact Flash Interface - 1 MB + VRAM On board peripherals: * Front display: 400x234 16 bit TFT touchscreen @@ -4123,11 +4198,6 @@ If you would like to build your kernel to run on one of these boards then you must say 'Y' here. Otherwise say 'N' -Link-Up Systems LCD support -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 @@ -4461,10 +4531,10 @@ 3Dfx Voodoo Graphics / Voodoo2 frame buffer support CONFIG_FB_VOODOO1 - Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or + Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or Voodoo2 (cvg) based graphics card. - This driver is also available as a module ( = code which can be + This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The module will be called sstfb.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. @@ -4541,7 +4611,7 @@ This is the frame buffer device driver for the Hitachi HD64461 LCD frame buffer card. -SIS 630/540 display support +SIS acceleration CONFIG_FB_SIS This is the frame buffer device driver for the SiS 630 and 640 Super Socket 7 UMA cards. Specs available at . @@ -4587,16 +4657,6 @@ framebuffer device. The ATI product support page for these boards is at . -Sony Vaio Picturebook laptop LCD panel support -CONFIG_FB_ATY_CT_VAIO_LCD - Say Y here if you want to use the full width of the Sony Vaio - Picturebook laptops LCD panels (you will get a 128x30 console). - - Note that you need to activate this mode using the 'vga=0x301' - option from your boot loader (lilo or loadlin). See the - documentation of your boot loader about how to pass options to the - kernel. - Mach64 GX support CONFIG_FB_ATY_GX Say Y here to support use of the ATI Mach64 Graphics Expression @@ -4764,7 +4824,7 @@ If unsure, say Y. -Parallel+serial PCI card support +Parallel+serial PCI multi-IO card support CONFIG_PARPORT_SERIAL This adds support for multi-IO PCI cards that have parallel and serial ports. You should say Y or M here. If you say M, the module @@ -5189,6 +5249,7 @@ It is safe to say N here for now. +# 2.5 tree only IPv6: routing messages via old netlink CONFIG_IPV6_NETLINK You can say Y here to receive routing messages from the IPv6 code @@ -5459,8 +5520,9 @@ Amateur Radio support CONFIG_HAMRADIO If you want to connect your Linux box to an amateur radio, answer Y - here. You want to read and - the AX25-HOWTO, available from . + here. You want to read + and the AX25-HOWTO, available from + . Note that the answer to this question won't directly affect the kernel: saying N will just cause the configurator to skip all @@ -5505,6 +5567,7 @@ configuration. (Linux cannot yet act as a DAMA server.) If unsure, say N. +# Currently commented out AX.25 DAMA Master support CONFIG_AX25_DAMA_MASTER DAMA is a mechanism to prevent collisions when doing AX.25 @@ -5949,6 +6012,7 @@ If unsure, say N. +# 2.5 tree only Kernel/User network link driver CONFIG_NETLINK This driver allows for two-way communication between the kernel and @@ -5967,6 +6031,7 @@ If unsure, say Y. +# 2.5 tree only Routing messages CONFIG_RTNETLINK If you say Y here, user space programs can receive some network @@ -6280,6 +6345,13 @@ speed of the driver, and the size of your syslog files! When inactive, they will have only a modest impact on performance. +Efficient Networks Speedstream 3010 +CONFIG_ATM_LANAI + Supports ATM cards based on the Efficient Networks "Lanai" + chipset such as the Speedstream 3010 and the ENI-25p. The + Speedstream 3060 is currently not supported since we don't + have the code to drive the on-board Alcatel DSL chipset (yet). + Linux telephony support CONFIG_PHONE Say Y here if you have a telephony card, which for example allows @@ -6318,6 +6390,12 @@ If you do not have any Quicknet telephony cards, you can safely say N here. +QuickNet Internet LineJack/PhoneJack PCMCIA support +CONFIG_PHONE_IXJ_PCMCIA + Say Y here to configure in PCMCIA service support for the Quicknet + cards manufactured by Quicknet Technologies, Inc. This changes the + card initialization code to work with the card manager daemon. + FORE Systems 200E-series CONFIG_ATM_FORE200E_MAYBE This is a driver for the FORE Systems 200E-series ATM adapter @@ -6398,6 +6476,13 @@ the performances of the driver, and the size of your syslog files! Keep the debugging level to 0 during normal operations. +PPP over ATM +CONFIG_PPPOATM + Support PPP (Point to Point Protocol) encapsulated in ATM frames. + This implementation does not yet comply with section 8 of RFC2364, + which can lead to bad results idf the ATM peer loses state and + changes its encapsulation unilaterally. + Fusion MPT device support CONFIG_FUSION LSI Logic Fusion(TM) Message Passing Technology (MPT) device support @@ -6452,24 +6537,24 @@ 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 + 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" + 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. + 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. @@ -6668,8 +6753,8 @@ 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 and - . The module will be called sg.o. If unsure, - say N. + . The module will be called sg.o. If + unsure, say N. Probe all LUNs on each SCSI device CONFIG_SCSI_MULTI_LUN @@ -6784,9 +6869,9 @@ intended to replace the previous aic7xxx driver maintained by Doug Ledford since Doug is no longer maintaining that driver. -Adaptec I2O RAID controllers +Adaptec I2O RAID support CONFIG_SCSI_DPT_I2O - This driver supports all of Adaptec's I2O based RAID controllers as + This driver supports all of Adaptec's I2O based RAID controllers as well as the DPT SmartRaid V cards. This is an Adaptec maintained driver by Deanna Bonds. See . @@ -6944,7 +7029,7 @@ See for more information. If this driver does not work correctly without modification please contact the author by email at - ipslinux@us.ibm.com. + . You can build this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -6960,7 +7045,8 @@ and for more information. If this driver does not work correctly without modification, please contact - the author, Leonard N. Zubkoff, by email to lnz@dandelion.com. + the author, Leonard N. Zubkoff, by email to + . You can also build this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -7137,7 +7223,7 @@ Unless you have an NCR manufactured machine, the chances are that you do not have this SCSI card, so say N. -HP LASI SCSI support for 53c700 +HP LASI SCSI support for 53c700/710 CONFIG_SCSI_LASI700 This is a driver for the lasi baseboard in some parisc machines which is based on the 53c700 chip. Will also support LASI subsystems @@ -7193,10 +7279,10 @@ SYM53C8XX Version 2 SCSI support CONFIG_SCSI_SYM53C8XX_2 - This driver supports the whole NCR53C8XX/SYM53C8XX family of - PCI-SCSI controllers. It also supports the subset of LSI53C10XX - Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS - language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI + This driver supports the whole NCR53C8XX/SYM53C8XX family of + PCI-SCSI controllers. It also supports the subset of LSI53C10XX + Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS + language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI controllers. If your system has problems using this new major version of the @@ -7207,32 +7293,32 @@ PCI DMA addressing mode CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE - This option only applies to PCI-SCSI chip that are PCI DAC capable + This option only applies to PCI-SCSI chip that are PCI DAC capable (875A, 895A, 896, 1010-33, 1010-66, 1000). When set to 0, only PCI 32 bit DMA addressing (SAC) will be performed. - When set to 1, 40 bit DMA addressing (with upper 24 bits of address + When set to 1, 40 bit DMA addressing (with upper 24 bits of address set to zero) is supported. The addressable range is here 1 TB. When set to 2, full 64 bits of address for DMA are supported, but only - 16 segments of 4 GB can be addressed. The addressable range is so + 16 segments of 4 GB can be addressed. The addressable range is so limited to 64 GB. - The safest value is 0 (32 bit DMA addressing) that is guessed to still + The safest value is 0 (32 bit DMA addressing) that is guessed to still fit most of real machines. - The preferred value 1 (40 bit DMA addressing) should make happy + The preferred value 1 (40 bit DMA addressing) should make happy properly engineered PCI DAC capable host bridges. You may configure this option for Intel platforms with more than 4 GB of memory. - The still experimental value 2 (64 bit DMA addressing with 16 x 4GB - segments limitation) can be used on systems that require PCI address - bits past bit 39 to be set for the addressing of memory using PCI + The still experimental value 2 (64 bit DMA addressing with 16 x 4GB + segments limitation) can be used on systems that require PCI address + bits past bit 39 to be set for the addressing of memory using PCI DAC cycles. use normal IO CONFIG_SCSI_SYM53C8XX_IOMAPPED - If you say Y here, the driver will preferently use normal IO rather than - memory mapped IO. + If you say Y here, the driver will preferently use normal IO rather + than memory mapped IO. maximum number of queued commands CONFIG_SCSI_SYM53C8XX_MAX_TAGS @@ -7243,10 +7329,11 @@ default tagged command queue depth CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS - This is the default value of the command queue depth the driver will - announce to the generic SCSI layer for devices that support tagged - command queueing. This value can be changed from the boot command line. - This is a soft limit that cannot exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS. + This is the default value of the command queue depth the driver will + announce to the generic SCSI layer for devices that support tagged + command queueing. This value can be changed from the boot command + line. This is a soft limit that cannot exceed + CONFIG_SCSI_SYM53C8XX_MAX_TAGS. NCR53C8XX SCSI support CONFIG_SCSI_NCR53C8XX @@ -7629,6 +7716,12 @@ The module will be called qla1280.o. If you want to compile it as a module, say M here and read . +Include loadable firmware in driver +CONFIG_SCSI_QLOGIC_FC_FIRMWARE + Say Y to include ISP2100 Fabric Initiator/Target Firmware, with + expanded LUN addressing and FcTape (FCP-2) support, in the + Qlogic QLA 1280 driver. + Seagate ST-02 and Future Domain TMC-8xx SCSI support CONFIG_SCSI_SEAGATE These are 8-bit SCSI controllers; the ST-01 is also supported by @@ -7849,11 +7942,11 @@ say M here and read . The module will be called megaraid.o. -Intel/ICP (former GDT SCSI Disk Array) RAID Controller Support +Intel/ICP (former GDT SCSI Disk Array) RAID Controller support CONFIG_SCSI_GDTH Formerly called GDT SCSI Disk Array Controller Support. - - This is a driver for RAID/SCSI Disk Array Controllers (EISA/ISA/PCI) + + This is a driver for RAID/SCSI Disk Array Controllers (EISA/ISA/PCI) manufactured by Intel/ICP vortex (an Intel Company). It is documented in the kernel source in and @@ -8128,18 +8221,7 @@ If unsure, say N. -#Adaptec AIC-5800 IEEE 1394 support -#CONFIG_IEEE1394_AIC5800 -# Say Y here if you have a IEEE 1394 controller using the Adaptec -# AIC-5800 chip. All Adaptec host adapters (89xx series) use this -# chip, as well as miro's DV boards. -# -# If you want to compile this as a module ( = code which can be -# inserted in and removed from the running kernel whenever you want), -# say M here and read . The module -# will be called aic5800.o. -# -OHCI-1394 support +OHCI-1394 (Open Host Controller Interface) support CONFIG_IEEE1394_OHCI1394 Enable this driver if you have an IEEE 1394 controller based on the OHCI-1394 specification. The current driver is only tested with OHCI @@ -8523,7 +8605,7 @@ Aironet 4500/4800 series adapters CONFIG_AIRONET4500 www.aironet.com (recently bought by Cisco) makes these 802.11 DS - adapters. Driver by Elmer Joandi (elmer@ylenurme.ee). + adapters. Driver by Elmer Joandi (). Say Y here if you have such an adapter, and then say Y below to the option that applies to your particular type of card (PCI, ISA, @@ -8701,6 +8783,19 @@ a module, say M here and read . If unsure, say N. +Asix AX88190 PCMCIA support +CONFIG_PCMCIA_AXNET + Say Y here if you intend to attach an Asix AX88190-based PCMCIA + (PC-card) Fast Ethernet card to your computer. These cards are + nearly NE2000 compatible but need a separate driver due to a few + misfeatures. + + 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 axnet_cs.o. If you want to compile it as + a module, say M here and read . If + unsure, say N. + New Media PCMCIA support CONFIG_PCMCIA_NMCLAN Say Y here if you intend to attach a New Media Ethernet or LiveWire @@ -8756,7 +8851,7 @@ The module will be called ibmtr_cs.o. If you want to compile it as a module, say M here and read . -Xircom Tulip-like CardBus support +Xircom Tulip-like CardBus support (old driver) CONFIG_PCMCIA_XIRTULIP This driver is for the Digital "Tulip" Ethernet CardBus adapters. It should work with most DEC 21*4*-based chips/ethercards, as well @@ -8769,6 +8864,19 @@ it as a module, say M here and read . If unsure, say N. +Xircom CardBus support (new driver) +CONFIG_PCMCIA_XIRCOM + This driver is for the Digital "Tulip" Ethernet CardBus adapters. + It should work with most DEC 21*4*-based chips/ethercards, as well + as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and + ASIX. + + 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 xircom_tulip_cb.o. If you want to compile + it as a module, say M here and read + . If unsure, say N. + PCMCIA Wireless LAN CONFIG_NET_PCMCIA_RADIO Say Y here if you would like to use a PCMCIA (PC-card) device to @@ -8794,27 +8902,27 @@ This option includes the guts of the driver, but in order to actually use a card you will also need to enable support for PCMCIA - Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below. + Hermes cards, PLX9052 based PCI adapters or the Apple Airport below. You will also very likely also need the Wireless Tools in order to configure your card and that /etc/pcmcia/wireless.opts works : -Hermes 802.11b in PLX9052 based PCI adaptor support +Hermes in PLX9052 based PCI adapter support (Netgear MA301 etc.) CONFIG_PLX_HERMES Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco_cs) driver when used in PLX9052 based PCI adaptors. These - adaptors are not a full PCMCIA controller but act as a more limited - PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that + orinoco_cs) driver when used in PLX9052 based PCI adapters. These + adapters are not a full PCMCIA controller but act as a more limited + PCI <-> PCMCIA bridge. Several vendors sell such adapters so that 802.11b PCMCIA cards can be used in desktop machines. The Netgear - MA301 is such an adaptor. + MA301 is such an adapter. - Support for these adaptors is so far still incomplete and buggy. + Support for these adapters is so far still incomplete and buggy. You have been warned. Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards) CONFIG_PCMCIA_HERMES - A driver for "Hermes" chipset based PCMCIA wireless adaptors, such + A driver for "Hermes" chipset based PCMCIA wireless adapters, such as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). It should also be usable on various Prism II based cards @@ -8881,7 +8989,7 @@ CONFIG_APPLE_AIRPORT Say Y here to support the Airport 802.11b wireless Ethernet hardware built into the Macintosh iBook and other recent PowerPC-based - Macintosh machines. This is essentially a Lucent Orinoco card with + Macintosh machines. This is essentially a Lucent Orinoco card with a non-standard interface Xircom Netwave AirSurfer wireless support @@ -9027,7 +9135,7 @@ of the Cisco HDLC/PPP driver (syncppp.c). The SyncLink WAN driver (in character devices) must also be enabled. -FarSync T-Series support +FarSync T-Series X.21 (and V.35/V.24) cards CONFIG_FARSYNC This driver supports the FarSync T-Series X.21 (and V.35/V.24) cards from FarSite Communications Ltd. @@ -9174,6 +9282,13 @@ However, do not say Y here if you did not experience any serious problems. +802.1Q VLAN Support +CONFIG_VLAN_8021Q + Support Ben Greear's VLAN (Virtual LAN) option code, which multiplexes + any number of logical Ethernets over a single physical Ethernet link + according to the 902.1Q standard. There is a website on the Linux + implementation at . + QoS and/or fair queueing CONFIG_NET_SCHED When the kernel has several packets to send out over a network @@ -9512,8 +9627,8 @@ up. Look at the for more information about the cards (including the pointer to the user-space utilities). You can also read the comment at the top of the - for details about the cards and the driver - itself. + for details about the cards and the + driver itself. The driver will be compiled as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9565,13 +9680,13 @@ intended to replace SCSI. If you intend to use Fibre Channel, you need to have a Fibre channel - adaptor card in your computer; say Y here and to the driver for your - adaptor below. You also should have said Y to "SCSI support" and + adapter card in your computer; say Y here and to the driver for your + adapter below. You also should have said Y to "SCSI support" and "SCSI generic support". -Interphase 5526 Tachyon chipset based adaptor support +Interphase 5526 Tachyon chipset based adapter support CONFIG_IPHASE5526 - Say Y here if you have a Fibre Channel adaptor of this kind. + Say Y here if you have a Fibre Channel adapter of this kind. The driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9597,11 +9712,11 @@ You can find more information and last versions of drivers and utilities at . If you have any question you - can send email to sbni@granch.ru. + can send email to . Say N if unsure. -SBNI Adapters Multiline feature +SBNI multiple-line feature support CONFIG_SBNI_MULTILINE Schedule traffic for some parallel lines, via SBNI12 adapters. If you have two computers connected with two parallel lines it's @@ -9716,7 +9831,7 @@ Read for help on configuring and using COMX interfaces. Further info on these cards - can be found at or . + can be found at or . You must say Y to "/proc file system support" (CONFIG_PROC_FS) to use this driver. @@ -9826,9 +9941,10 @@ ). Feel free to contact me or the cycsyn-devel mailing list at - acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for - additional details, I hope to have documentation available as soon - as possible. (Cyclades Brazil is writing the Documentation). + and + for additional details, + I hope to have documentation available as soon as + possible. (Cyclades Brazil is writing the Documentation). The driver will be compiled as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9854,34 +9970,6 @@ If unsure, say N here. -Raw HDLC support -CONFIG_HDLC_RAW - Say Y to this option if you want generic HDLC driver to support - raw HDLC over WAN (Wide Area Network) connections. - - If unsure, say N here. - -Cisco HDLC support -CONFIG_HDLC_CISCO - Say Y to this option if you want generic HDLC driver to support - Cisco HDLC over WAN (Wide Area Network) connections. - - If unsure, say N here. - -Frame-Relay HDLC support -CONFIG_HDLC_FR - Say Y to this option if you want generic HDLC driver to support - Frame-Relay protocol over WAN (Wide Area Network) connections. - - If unsure, say N here. - -Frame-Relay bridging support -CONFIG_HDLC_FR_BRIDGE - Say Y to this option if you want generic HDLC driver to support - bridging LAN frames over Frame-Relay links. - - If unsure, say N here. - Synchronous Point-to-Point Protocol (PPP) support CONFIG_HDLC_PPP Say Y to this option if you want generic HDLC driver to support @@ -9914,7 +10002,7 @@ If unsure, say N here. -Ethernet (10 or 100Mbit) +Ethernet support CONFIG_NET_ETHERNET Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common type of Local Area Network (LAN) in universities and companies. @@ -10242,7 +10330,7 @@ for information about optional driver parameters. Questions concerning this driver may be addressed to: - linux@syskonnect.de + If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -10533,7 +10621,7 @@ This is yet another chipset driver for the COM90xx cards, but this time only using memory-mapped mode, and no IO ports at all. This driver is completely untested, so if you have one of these cards, - please mail dwmw2@infradead.org, especially if it works! + please mail , especially if it works! This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you @@ -10724,6 +10812,12 @@ . The module will be called hp100.o. +LP486E on board Ethernet +CONFIG_LP486E + Say Y here to support the 82596-based on-board Ethernet controller + for the Panther motherboard, which is one of the two shipped in the + Intel Professional Workstation. + NE2000/NE1000 support CONFIG_NE2000 If you have a network (Ethernet) card of this type, say Y and read @@ -10798,6 +10892,7 @@ boards with this driver should be possible, but has not been tested up to now due to lack of hardware. +# This symbol is a derived one in CML2 EISA, VLB, PCI and on board controllers CONFIG_NET_PCI This is another class of network cards which attach directly to the @@ -10887,17 +10982,36 @@ module, say M here and read as well as . -DECchip Tulip (dc21x4x) PCI support +Early DECchip Tulip (dc2104x) PCI support +CONFIG_DE2104X + This driver is developed for the SMC EtherPower series Ethernet + cards and also works with cards based on the DECchip + 21040 (Tulip series) chips. Some LinkSys PCI cards are + of this type. (If your card is NOT SMC EtherPower 10/100 PCI + (smc9332dst), you can also try the driver for "Generic DECchip" + cards, above. However, most people with a network card of this type + will say Y here.) Do read the Ethernet-HOWTO, available from + . More specific + information is contained in + . + + 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 tulip.o. If you want to compile it as a + module, say M here and read as well + as . + +DECchip Tulip (dc2114x) PCI support CONFIG_TULIP This driver is developed for the SMC EtherPower series Ethernet - cards and also works with cards based on the DECchip - 21040/21041/21140 (Tulip series) chips. Some LinkSys PCI cards are + cards and also works with cards based on the DECchip + 21041/21140 (Tulip series) chips. Some LinkSys PCI cards are of this type. (If your card is NOT SMC EtherPower 10/100 PCI (smc9332dst), you can also try the driver for "Generic DECchip" cards, above. However, most people with a network card of this type will say Y here.) Do read the Ethernet-HOWTO, available from . More specific - information is contained in + information is contained in . This driver is also available as a module ( = code which can be @@ -10907,7 +11021,7 @@ as . New Tulip bus configuration -CONFIG_TULIP_MWI +CONFIG_TULIP_MWI This configures your Tulip card specifically for the card and system cache line size type you are using. @@ -10915,6 +11029,13 @@ If unsure, say N. +Use PCI shared memory for NIC registers +CONFIG_TULIP_MMIO + Use PCI shared memory for the NIC registers, rather than going through + the Tulip's PIO (programmed I/O ports). Faster, but could produce + obscure bugs if your mainboard has memory controller timing issues. + If in doubt, say N. + Digi Intl. RightSwitch SE-X support CONFIG_DGRS This is support for the Digi International RightSwitch series of @@ -10942,18 +11063,6 @@ a module, say M here and read as well as . -Enable Power Management -CONFIG_EEPRO100_PM - Many Intel EtherExpress PRO/100 PCI network cards are capable - of providing power management capabilities. To make use of these - capabilities, say Y. - - WARNING: This option is intended for kernel developers and testers. - It is still very experimental, with some people reporting complete - lockups. - - It is recommended to say N here. - Myson MTD-8xx PCI Ethernet support CONFIG_FEALNX Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet @@ -10989,7 +11098,7 @@ module, say M here and read as well as . - Please email feedback to torben.mathiasen@compaq.com. + Please email feedback to . VIA Rhine support CONFIG_VIA_RHINE @@ -11002,6 +11111,17 @@ a module, say M here and read as well as . +VIA Rhine MMIO support (EXPERIMENTAL) +CONFIG_VIA_RHINE_MMIO + This instructs the driver to use PCI shared memory (MMIO) instead of + programmed I/O ports (PIO). Enabling this gives an improvement in + processing time in parts of the driver. + + It is not known if this works reliably on all "rhine" based cards, + but it has been tested successfully on some DFE-530TX adapters. + + If unsure, say N. + Davicom DM910x/DM980x support CONFIG_DM9102 This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from @@ -11404,7 +11524,7 @@ the driver. Questions concerning this driver can be addressed to: - linux@syskonnect.de + If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -11460,6 +11580,16 @@ If you wish to compile a kernel for the EBSA-110, then you should always answer Y to this. +Support CPU clock change +CONFIG_CPU_FREQ + CPU clock scaling allows you to change the clock speed of the + running CPU on the fly. This is a nice method to save battery power, + because the lower the clock speed, the less power the CPU + consumes. Note that this driver doesn't automatically change the CPU + clock speed, you need some userland tools (which still have to be + written) to implement the policy. If you don't understand what this + is all about, it's safe to say 'N'. + Support Thumb instructions CONFIG_ARM_THUMB Say Y if you want to have kernel support for ARM Thumb instructions, @@ -11742,11 +11872,6 @@ The module will be called isp16.o. If you want to compile it as a module, say M here and read . -iSeries Virtual I/O CD Support -CONFIG_VIOCD - If you are running Linux on an IBM iSeries system and you want to - read a CD drive owned by OS/400, say Y here. - Quota support CONFIG_QUOTA If you say Y here, you will be able to set per user limits for disk @@ -11763,8 +11888,10 @@ 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 devices. If unsure, say N. + them. It will also allow you to select individual drivers for + particular hardware and users of MTD devices; in many cases, + selecting this feature will be sufficient to ensure that MTD + support is configured into the kernel. If unsure, say N. MTD debugging support CONFIG_MTD_DEBUG @@ -11810,8 +11937,8 @@ this option. You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The - SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for + for your particular device. It won't happen automatically. The + SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for example. ARM Firmware Suite flash layout / partition parsing @@ -11825,8 +11952,7 @@ enable this option. You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The - 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. + for your particular device. It won't happen automatically. MTD debugging verbosity (0 = quiet, 3 = noisy) CONFIG_MTD_DEBUG_VERBOSE @@ -11900,10 +12026,10 @@ CONFIG_NFTL_RW If you're lucky, this will actually work. Don't whinge if it doesn't. Send mail to the MTD mailing list - if you want to help to make it more - reliable. + if you want to help to make + it more reliable. -Common Flash Interface (CFI) support +Detect flash chips by Common Flash Interface (CFI) probe CONFIG_MTD_CFI The Common Flash Interface specification was developed by Intel, AMD and other flash manufactures that provides a universal method @@ -11917,17 +12043,17 @@ If you need to specify a specific endianness for access to flash chips, or if you wish to reduce the size of the kernel by including support for only specific arrangements of flash chips, say 'Y'. This - option does not directly affect the code, but will enable other + option does not directly affect the code, but will enable other configuration options which allow you to do so. If unsure, say 'N'. Specific CFI Flash geometry selection CONFIG_MTD_CFI_GEOMETRY - This option does not affect the code directly, but will enable + This option does not affect the code directly, but will enable some other configuration options which would allow you to reduce - the size of the kernel by including support for only certain - arrangements of CFI chips. If unsure, say 'N' and all options + the size of the kernel by including support for only certain + arrangements of CFI chips. If unsure, say 'N' and all options which are supported by the current code will be enabled. Support 8-bit buswidth @@ -11960,14 +12086,14 @@ If your flash chips are interleaved in fours - i.e. you have four flash chips addressed by each bus cycle, then say 'Y'. -# Choice: mtd_swap_data +# Choice: mtd_data_swap Flash cmd/query data swapping CONFIG_MTD_CFI_NOSWAP This option defines the way in which the CPU attempts to arrange data bits when writing the 'magic' commands to the chips. Saying 'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't enabled, means that the CPU will not do any swapping; the chips - are expected to be wired to the CPU in 'host-endian' form. + are expected to be wired to the CPU in 'host-endian' form. Specific arrangements are possible with the BIG_ENDIAN_BYTE and LITTLE_ENDIAN_BYTE, if the bytes are reversed. @@ -11989,37 +12115,31 @@ CONFIG_MTD_CFI_AMDSTD The Common Flash Interface defines a number of different command sets which a CFI-compliant chip may claim to implement. This code - provides support for one of those command sets, used on chips + provides support for one of those command sets, used on chips chips including the AMD Am29LV320. -CFI support for Intel/Sharp Standard Commands -CONFIG_MTD_CFI_INTELSTD - The Common Flash Interface defines a number of different command - sets which a CFI-compliant chip may claim to implement. This code - provides support for one of those command sets. - pre-CFI Sharp chip support CONFIG_MTD_SHARP This option enables support for flash chips using Sharp-compatible - commands, including some which are not CFI-compatible and hence - cannot be used with the CONFIG_MTD_CFI_INTELxxx options. + commands, including some which are not CFI-compatible and hence + cannot be used with the MTD_CFI_* options. AMD compatible flash chip support (non-CFI) CONFIG_MTD_AMDSTD This option enables support for flash chips using AMD-compatible - commands, including some which are not CFI-compatible and hence + commands, including some which are not CFI-compatible and hence cannot be used with the CONFIG_MTD_CFI_AMDSTD option. It also works on AMD compatible chips that do conform to CFI. Support for RAM chips in bus mapping CONFIG_MTD_RAM - This option enables basic support for RAM chips accessed through + This option enables basic support for RAM chips accessed through a bus mapping driver. Support for ROM chips in bus mapping CONFIG_MTD_ROM - This option enables basic support for ROM chips accessed through + This option enables basic support for ROM chips accessed through a bus mapping driver. JEDEC device support @@ -12038,18 +12158,10 @@ If you have such a board, say 'Y'. Support for Compaq bootldr partition tables on SA11x0 -CONFIG_MTD_SA1100_REDBOOT_PARTITIONS - Enabling this option will cause the kernel to look for a RedBoot - FIS (Flash Image System) table in the last erase block of the flash - chips detected. If you are using RedBoot on your SA11x0-based board - and want Linux to present 'partitions' matching the images which - RedBoot has listed, say 'Y'. - -Support for Compaq bootldr partition tables on SA11x0 CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS Enabling this option will cause the kernel to look for a Compaq bootldr partition table on the flash chips detected. If you are - using the Compaq bootldr on your SA11x0-based board and want Linux + using the Compaq bootldr on your SA11x0-based board and want Linux to present 'partitions' matching the images which the bootldr has listed, say 'Y'. @@ -12086,9 +12198,9 @@ Flash chip mapping on Sun Microsystems boardsets CONFIG_MTD_SUN_UFLASH - This provides a 'mapping' driver which supports the way in - which user-programmable flash chips are connected on various - Sun Microsystems boardsets. This driver will require CFI support + This provides a 'mapping' driver which supports the way in + which user-programmable flash chips are connected on various + Sun Microsystems boardsets. This driver will require CFI support in the kernel, so if you did not enable CFI previously, do that now. Flash chip mapping on Nora @@ -12100,7 +12212,7 @@ PNC-2000 is the name of Network Camera product from PHOTRON Ltd. in Japan. It uses CFI-compliant flash. -Flash chip mapping on RPXlite PPC board +Flash chip mapping on RPXlite or CLLF PPC board CONFIG_MTD_RPXLITE The RPXLite PowerPC board has CFI-compliant chips mapped in a strange sparse mapping. This 'mapping' driver supports that @@ -12132,13 +12244,13 @@ CFI Flash device mapped on the XScale IQ80310 board CONFIG_MTD_IQ80310 This enables access routines for the flash chips on the Intel XScale - IQ80310 evaluation board. If you have one of these boards and would + IQ80310 evaluation board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. CFI Flash device mapped on AMD NetSc520 CONFIG_MTD_NETSC520 This enables access routines for the flash chips on the AMD NetSc520 - demonstration board. If you have one of these boards and would like + demonstration board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. Flash chip mapping on Arcom Control Systems ELAN-104NC @@ -12150,13 +12262,6 @@ . Flash chip mapping on Compaq iPAQ/Bitsy -CONFIG_MTD_BITSY - This provides a driver for the on-board flash found in Compaq's - iPAQ Palm PC and their research prototype the Itsy. iPAQ info at - and the - Itsy . - -Flash chip mapping on Compaq iPAQ/Bitsy CONFIG_MTD_DC21285 This provides a driver for the flash accessed using Intel's 21285 bridge used with Intel's StrongARM processors. More info at @@ -12176,26 +12281,26 @@ allow a window into the flash. Both CFI and JEDEC probes are called. -Physical start location of flash mapping +Physical start location of flash chip mapping CONFIG_MTD_CSTM_MIPS_IXX_START This is the physical memory location that the MTD driver will - use for the flash chips on your particular target board. - Refer to the memory map which should hopefully be in the + use for the flash chips on your particular target board. + Refer to the memory map which should hopefully be in the documentation for your board. -Physical length of flash mapping +Physical length of flash chip mapping CONFIG_MTD_CSTM_MIPS_IXX_LEN - This is the total length that the MTD driver will use for the + This is the total length that the MTD driver will use for the flash chips on your particular board. Refer to the memory map which should hopefully be in the documentation for your board. -Physical bus width of flash mapping +Physical bus width of flash mapping in bytes CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH This is the total bus width of the mapping of the flash chips on your particular board. -Flash chip mapping on Mixcom piggyback card +JEDEC Flash device mapped 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 @@ -12204,14 +12309,14 @@ you probably want to enable this mapping driver. More info is at . -Flash chip mapping on Octagon 5066 SBC +JEDEC Flash device mapped 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. More information on the board is available at . -Flash chip mapping on Tempustech VMAX SBC301 +JEDEC Flash device mapped 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 @@ -12265,7 +12370,7 @@ Alternative Disk-On-Chip Millennium support CONFIG_MTD_DOC2001 - This provides an alternative MTD device driver for the M-Systems + 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 @@ -12379,10 +12484,10 @@ If you have system RAM accessible by the CPU but not used by Linux in normal operation, you can give the physical address at which the available RAM starts, and the MTDRAM driver will use it instead of - allocating space from Linux's available memory. Otherwise, leave + allocating space from Linux's available memory. Otherwise, leave this set to zero. Most people will want to leave this as zero. -Flash chip mapping on the Flaga Digital Module +CFI Flash device mapping on the Flaga Digital Module CONFIG_MTD_CFI_FLAGADM Mapping for the Flaga digital module. If you don´t have one, ignore this setting. @@ -12402,7 +12507,7 @@ the system regardless of media presence. Device nodes created with this driver will return -ENODEV upon access. -MTD Emulation using block device +MTD emulation using block device CONFIG_MTD_BLKMTD This driver allows a block device to appear as an MTD. It would generally be used in the following cases: @@ -12415,7 +12520,9 @@ Cirrus CDB89712 evaluation board mappings CONFIG_MTD_CDB89712 This enables access to the flash or ROM chips on the CDB89712 board. - If you have such a board, say 'Y'. + (This board has 8 MB of Intel Strataflash, a 128 byte boot ROM, and + 48 KB of internal SRAM. This driver provides MTD devices for all + three components.) If you have such a board, say 'Y'. Detect non-CFI AMD/JEDEC-compatible flash chips CONFIG_MTD_JEDECPROBE @@ -12423,9 +12530,9 @@ compatible with the Common Flash Interface, but will use the common CFI-targetted flash drivers for any chips which are identified which are in fact compatible in all but the probe method. This actually - covers most AMD/Fujitsu-compatible chips, and will shortly cover also - non-CFI Intel chips (that code is in MTD CVS and should shortly be sent - for inclusion in Linus' tree) + covers most AMD/Fujitsu-compatible chips, and will shortly cover + also non-CFI Intel chips (that code is in MTD CVS and should shortly + be sent for inclusion in Linus' tree) BIOS flash chip on Intel L440GX boards CONFIG_MTD_L440GX @@ -12444,18 +12551,20 @@ CONFIG_MTD_OBSOLETE_CHIPS This option does not enable any code directly, but will allow you to select some other chip drivers which are now considered obsolete, - because the generic CONFIG_JEDEC_PROBE code above should now detect - the chips which are supported by these drivers, and allow the generic - CFI-compatible drivers to drive the chips. Say 'N' here unless you have - already tried the CONFIG_JEDEC_PROBE method and reported its failure - to the MTD mailing list at + because the generic CONFIG_MTD_JEDECPROBE code above should now + detect the chips which are supported by these drivers, and allow the + generic CFI-compatible drivers to drive the chips. Say 'N' here + unless you have already tried the CONFIG_MTD_JEDECPROBE method and + reported its failure to the MTD mailing list at + CFI Flash device mapped on Hitachi SolutionEngine CONFIG_MTD_SOLUTIONENGINE - This enables access to the flash chips on the Hitachi SolutionEngine and - similar boards. Say 'Y' if you are building a kernel for such a board. + This enables access to the flash chips on the Hitachi SolutionEngine + and similar boards. Say 'Y' if you are building a kernel for such a + board. -Flash chip mapping on TQM8xxL PPC board +CFI Flash device mapped on TQM8XXL PPC board CONFIG_MTD_TQM8XXL The TQM8xxL PowerPC board has up to two banks of CFI-compliant chips, currently uses AMD one. This 'mapping' driver supports @@ -12469,7 +12578,6 @@ Therefore, I conclude that you do not exist - go away. There is a grue here. - Physical memory size CONFIG_MEMORY_SIZE This sets the default memory size assumed by your SH kernel. It can @@ -12519,19 +12627,7 @@ of debug messages to the system log. Select this if you are having a problem with USB support and want to see more of what is going on. -USB fetch large config -CONFIG_USB_LARGE_CONFIG - This option changes the initial request for a config descriptor so - that some poorly designed devices will still work. Some APC UPSes - need it. Basically, the usb subsystem sends a request for a short - (8 byte) config, just to find out how large the real config is. - Incorrectly implemented devices may choke on this small config - request. This option make the initial request for a quite large - config (1009 bytes), and things just work. - - If you have an APC UPS, say Y; otherwise say N. - -USB long timeout +USB long timeout for slow-responding devices (some MGE Ellipse UPSes) CONFIG_USB_LONG_TIMEOUT This option makes the standard time out a bit longer. Basically, some devices are just slow to respond, so this makes usb more @@ -12541,6 +12637,30 @@ If you have an MGE Ellipse UPS, or you see timeouts in HID transactions, say Y; otherwise say N. +EHCI (USB 2.0) support +CONFIG_USB_EHCI_HCD + The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 + "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. + If your USB host controller supports USB 2.0, you will likely want to + configure this Host Controller Driver. At this writing, the primary + implementation of EHCI is a chip from NEC, widely available in add-on + PCI cards, but implementations are in the works from other vendors + including Intel and Philips. Motherboard support is appearing. + + EHCI controllers are packaged with "companion" host controllers (OHCI + or UHCI) to handle USB 1.1 devices connected to root hub ports. Ports + will connect to EHCI if it the device is high speed, otherwise they + connect to a companion controller. If you configure EHCI, you should + probably configure the OHCI (for NEC and some other vendors) USB Host + Controller Driver too. + + You may want to read . + + 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 ehci-hcd.o. If you want to compile it as a + module, say M here and read . + UHCI (Intel PIIX4, VIA, ...) support CONFIG_USB_UHCI The Universal Host Controller Interface is a standard by Intel for @@ -12663,17 +12783,6 @@ The module will be called wacom.o. If you want to compile it as a module, say M here and read . -Aiptek 8000U tablet support -CONFIG_USB_AIPTEK - Say Y here if you want to use the USB version of the Aiptek 8000U - tablet. Make sure to say Y to "Event interface support" - (CONFIG_INPUT_EVDEV) as well. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called aiptek.o. If you want to compile it as a - module, say M here and read . - Use input layer for ADB devices CONFIG_INPUT_ADBHID Say Y here if you want to have ADB (Apple Desktop Bus) HID devices @@ -12765,16 +12874,6 @@ The module will be called scanner.o. If you want to compile it as a module, say M here and read . -HP 5300C scanner support -CONFIG_USB_HP5300 - Say Y here if you want to connect a HP5300C scanner to your - computer's USB port. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called hp5300.o. If you want to compile it as - a module, say M here and read . - USB Audio support CONFIG_USB_AUDIO Say Y here if you want to connect USB audio equipment such as @@ -12841,15 +12940,26 @@ The module will be called visor.o. If you want to compile it as a module, say M here and read . -USB IR Dongle Serial Driver -CONFIG_USB_SERIAL_IR - Say Y here if you want to enable simple serial support for USB IrDA - devices. This is useful if you do not want to use the full IrDA - stack. - +USB Compaq iPAQ Driver +CONFIG_USB_SERIAL_IPAQ + Say Y here if you want to connect to your Compaq iPAQ running + Windows CE 3.0 using a USB autosync cable. For information on using + the driver, read . + 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 ir-usb.o. If you want to compile it as a + The module will be called ipaq.o. If you want to compile it as a + module, say M here and read . + +USB Compaq iPAQ Driver +CONFIG_USB_SERIAL_IPAQ + Say Y here if you want to connect to your Compaq iPAQ running + Windows CE 3.0 using a USB autosync cable. For information on using + the driver, read . + + 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 ipaq.o. If you want to compile it as a module, say M here and read . USB IR Dongle Serial Driver @@ -12857,7 +12967,7 @@ Say Y here if you want to enable simple serial support for USB IrDA devices. This is useful if you do not want to use the full IrDA stack. - + 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 ir-usb.o. If you want to compile it as a @@ -12866,7 +12976,7 @@ USB Belkin and Paracom Single Port Serial Driver CONFIG_USB_SERIAL_BELKIN Say Y here if you want to use a Belkin USB Serial single port - adaptor (F5U103 is one of the model numbers) or the Peracom single + adapter (F5U103 is one of the model numbers) or the Peracom single port USB to serial adapter. This code is also available as a module ( = code which can be @@ -13061,6 +13171,22 @@ The module will be called io_edgeport.o. If you want to compile it as a module, say M here and read . +USB PalmConnect (and other KL5KUSB105-based) Single Port Serial Driver +CONFIG_USB_SERIAL_KLSI + Say Y here if you want to use a KL5KUSB105 - based single port + serial adapter. The most widely known -- and currently the only + tested -- device in this category is the PalmConnect USB Serial + adapter sold by Palm Inc. for use with their Palm III and Palm V + series PDAs. + + Please read for more + information. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called kl5kusb105.o. If you want to compile it as + a module, say M here and read . + USB Serial Converter verbose debug CONFIG_USB_SERIAL_DEBUG Say Y here if you want verbose debug messages from the USB Serial @@ -13112,7 +13238,7 @@ The module will be called ov511.o. If you want to compile it as a module, say M here and read . -USB Communication Class Ethernet driver +USB Communication Class Ethernet device support CONFIG_USB_CDCETHER This driver supports devices conforming to the Communication Device Class Ethernet Control Model. This is used in some cable modems. @@ -13167,21 +13293,68 @@ The module will be called pwc.o. If you want to compile it as a module, say M here and read . -Pegasus/Pegasus II based USB-Ethernet device support +USB SE401 Camera support +CONFIG_USB_SE401 + Say Y here if you want to connect this type of camera to your + computer's USB port. See for more + information and for a list of supported cameras. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Multimedia Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at . + + 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 se401.o. If you want to compile it as a + module, say M here and read . + +USB STV680 (Pencam) Camera support +CONFIG_USB_STV680 + Say Y here if you want to connect this type of camera to your + computer's USB port. This includes the Pencam line of cameras. + See for more information and for + a list of supported cameras. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Multimedia Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at . + + 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 stv680.o. If you want to compile it as a + module, say M here and read . + +Vicam +CONFIG_USB_VICAM + Say Y here if you have 3com homeconnect camera (vicam). + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Multimedia Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at . + + 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 vicam.o. If you want to compile it as a + module, say M here and read . + + +USB ADMtek Pegasus-based USB-Ethernet device support CONFIG_USB_PEGASUS Say Y here if you know you have Pegasus or Pegasus II based adapter. - If in doubt then look at linux/drivers/usb/pegasus.h for the complete - list of supported devices. - If your particular adapter is not in the list and you are _sure_ it - is Pegasus or Pegasus II based then send me (pmanolov@lnxw.com) vendor - and device IDs. + If in doubt then look at linux/drivers/usb/pegasus.h for the + complete list of supported devices. If your particular adapter is + not in the list and you are _sure_ it is Pegasus or Pegasus II based + then send me () vendor and device IDs. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called pegasus.o. If you want to compile it as a module, say M here and read . -USB KLSI KL5USB101-based Ethernet device support ' +USB KLSI KL5USB101-based Ethernet device support 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: @@ -13279,7 +13452,7 @@ Say Y here in order to have the USB Mass Storage code generate verbose debugging messages. -ISD-200 USB/ATA driver +ISD-200 USB/ATA Bridge support CONFIG_USB_STORAGE_ISD200 Say Y here if you want to use USB Mass Store devices based on the In-Systems Design ISD-200 USB/ATA bridge. @@ -13390,7 +13563,7 @@ Freecom USB/ATAPI Bridge support CONFIG_USB_STORAGE_FREECOM - Support for the Freecom USB to IDE/ATAPI adaptor. + Support for the Freecom USB to IDE/ATAPI adapter. Freecom has a web page at . Microtech CompactFlash/SmartMedia reader @@ -13399,7 +13572,7 @@ reader, details at . This driver treats the flash card as a removable storage device. -Sandisk SDDR-09 SmartMedia reader support +SanDisk SDDR-09 (and other SmartMedia) support CONFIG_USB_STORAGE_SDDR09 Say Y here to include additional code to support the Sandisk SDDR-09 SmartMedia reader in the USB Mass Storage driver. @@ -13415,6 +13588,16 @@ The module will be called rio500.o. If you want to compile it as a module, say M here and read . +USB Auerswald ISDN device support +CONFIG_USB_AUERSWALD + Say Y here if you want to connect an Auerswald USB ISDN Device + to your computer's USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called auerswald.o. If you want to compile it as + a module, say M here and read . + D-Link DSB-R100 FM radio support CONFIG_USB_DSBR Say Y here if you want to connect this type of radio to your @@ -13453,12 +13636,6 @@ wise choice too. In all other cases (for example, if you're just playing around with User-Mode Linux) you can choose 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. - Management console CONFIG_MCONSOLE The user mode linux management console is a low-level interface to @@ -13523,7 +13700,7 @@ For more information, see . - If you'd like to be able to work with files stored on the host, + If you'd like to be able to work with files stored on the host, say Y or M here; otherwise say N. Example IO Memory driver @@ -13602,7 +13779,7 @@ link with the host. To use this, your host kernel must have support for Ethertap - devices. Also, if your host kernel is 2.4.x, it must have + devices. Also, if your host kernel is 2.4.x, it must have CONFIG_NETLINK_DEV configured as Y or M. For more information, see @@ -13611,7 +13788,7 @@ networking. If you'd like to set up an IP network with the host and/or the - outside world, say Y to this, the Daemon Transport and/or the + outside world, say Y to this, the Daemon Transport and/or the Slip Transport. You'll need at least one of them, but may choose more than one without conflict. If you don't need UML networking, say N. @@ -13665,7 +13842,7 @@ The Ethertap Transport is preferred over Slip because of its limitation. If you prefer Slip, however, say Y here. Otherwise - choose the Multicast transport (to network multiple UMLs on + choose the Multicast transport (to network multiple UMLs on multiple hosts), Ethertap (to network with the host and the outside world), and/or the Daemon transport (to network multiple UMLs on a single host). You may choose more than one without @@ -13682,7 +13859,7 @@ and work. SANE 1.0.4 or newer is needed to make use of your scanner. This driver can be compiled as a module. -HP 53xx and Minolta Dual Scanner support +HP53xx and Minolta Dual Scanner support CONFIG_USB_HPUSBSCSI Say Y here if you want support for the HP 53xx series of scanners and the Minolta Scan Dual. This driver is experimental. @@ -13721,7 +13898,7 @@ Reiserfs support CONFIG_REISERFS_FS Stores not just filenames but the files themselves in a balanced - tree. Uses journaling. + tree. Uses journalling. Balanced trees are more efficient than traditional file system architectural foundations. @@ -13810,13 +13987,13 @@ be compiled as a module, and so this could be dangerous. Most everyone wants to say Y here. -Ext3 journaling file system support (EXPERIMENTAL) +Ext3 journalling file system support (EXPERIMENTAL) CONFIG_EXT3_FS - This is the journaling version of the Second extended file system - (often called ext3), the de facto standard Linux file system + This is the journalling version of the Second extended file system + (often called ext2), the de facto standard Linux file system (method to organize files on a storage device) for hard disks. - The journaling code included in this driver means you do not have + The journalling code included in this driver means you do not have to run e2fsck (file system checker) on your file systems after a crash. The journal keeps track of any changes that were being made at the time the system crashed, and can ensure that your file system @@ -13844,7 +14021,7 @@ Journal Block Device support (JBD for ext3) (EXPERIMENTAL) CONFIG_JBD - This is a generic journaling layer for block devices. It is + This is a generic journalling layer for block devices. It is currently used by the ext3 file system, but it could also be used to add journal support to other file systems or block devices such as RAID or LVM. @@ -13872,7 +14049,7 @@ generated. To turn debugging off again, do "echo 0 > /proc/sys/fs/jbd-debug". -Buffer Head tracing (DEBUG) +Buffer Head tracing CONFIG_BUFFER_DEBUG If you are a kernel developer working with file systems or in the block device layer, this buffer head tracing may help you to track @@ -13924,15 +14101,14 @@ If unsure, say N. -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. - +# When the 2.5 version of configure.help goes away, the part of this that +# duplicates Documentation/filesystems/tmpfs.txt can drop out. Virtual memory file system support CONFIG_TMPFS Tmpfs is a file system which keeps all files in virtual memory. + Everything in tmpfs is temporary in the sense that no files will be + created on your hard drive. If you reboot, everything in tmpfs will + be lost. In contrast to RAM disks, which get allocated a fixed amount of physical RAM, tmpfs grows and shrinks to accommodate the files it @@ -13959,6 +14135,8 @@ The initial permissions of the root directory can be set with the mount option "mode". + See for details. + Simple RAM-based file system support CONFIG_RAMFS Ramfs is a file system which keeps all files in RAM. It allows @@ -14313,7 +14491,7 @@ If you would like to include the NFSv3 server as well as the NFSv2 server, say Y here. If unsure, say Y. -Provide NFS over TCP server support DEVELOPER ONLY +Provide NFS over TCP server support (DEVELOPER ONLY) CONFIG_NFSD_TCP If you are a developer and want to work on fixing problems with NFS server over TCP support, say Y here. If unsure, say N. @@ -14541,7 +14719,7 @@ Journalling Flash File System (JFFS) support CONFIG_JFFS_FS - JFFS is the Journaling Flash File System developed by Axis + JFFS is the Journalling Flash File System developed by Axis Communications in Sweden, aimed at providing a crash/powerdown-safe file system for disk-less embedded devices. Further information is available at (). @@ -14576,8 +14754,9 @@ JFFS stats available in /proc filesystem CONFIG_JFFS_PROC_FS - Enabling this option will cause statistics from mounted JFFS file systems - to be made available to the user in the /proc/fs/jffs/ directory. + Enabling this option will cause statistics from mounted JFFS file + systems to be made available to the user in the /proc/fs/jffs/ + directory. UFS file system support (read-only) CONFIG_UFS_FS @@ -14663,7 +14842,7 @@ Say Y here if you would like to use hard disks under Linux which were partitioned on a Macintosh. -Windows' Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL) +Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL) CONFIG_LDM_PARTITION Say Y here if you would like to use hard disks under Linux which were partitioned using Windows 2000's or XP's Logical Disk Manager. @@ -14683,7 +14862,7 @@ If unsure, say N. -Windows' LDM extra logging +Windows LDM extra logging CONFIG_LDM_DEBUG Say Y here if you would like LDM to log verbosely. This could be helpful if the driver doesn't work as expected and you'd like to @@ -14823,7 +15002,7 @@ inserted in and removed from the running kernel whenever you want). The module is called freevxfs.o. If you want to compile it as a module, say M here and read . If - unsure, say N. + unsure, say N. UnixWare slices support CONFIG_UNIXWARE_DISKLABEL @@ -14915,7 +15094,7 @@ whenever you want), say M here and read . The module will be called coda.o. -InterMezzo file system support (experimental, replicating fs) +InterMezzo file system support (replicating fs) CONFIG_INTERMEZZO_FS InterMezzo is a networked file system with disconnected operation and kernel level write back caching. It is most often used for @@ -15023,7 +15202,7 @@ Currently, the valid values are: big5, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861, cp862, cp863, cp864, cp865, cp866, cp869, cp874, cp932, cp936, - cp949, cp950, cp1251, cp1255, euc-jp, euc-kr, gb2312, iso8859-1, + cp949, cp950, cp1250, cp1251, cp1255, euc-jp, euc-kr, gb2312, iso8859-1, iso8859-2, iso8859-3, iso8859-4, iso8859-5, iso8859-6, iso8859-7, iso8859-8, iso8859-9, iso8859-13, iso8859-14, iso8859-15, koi8-r, koi8-ru, koi8-u, sjis, tis-620, utf8. @@ -15263,6 +15442,16 @@ say Y here if you want to include the DOS codepage for Traditional Chinese(Big5). +Central European (Codepage 1250) +CONFIG_NLS_CODEPAGE_1250 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Windows CP-1250 + character set, which works for most Latin-written Slavic and Central + European languages: Czech, German, Hungarian, Polish, Rumanian, Croatian, + Slovak, Slovene. + NLS ISO 8859-1 (Latin 1; Western European Languages) CONFIG_NLS_ISO8859_1 If you want to display filenames with native language characters @@ -15345,6 +15534,7 @@ set, and it replaces the rarely needed Icelandic letters in Latin 1 with the Turkish ones. Useful in Turkey. +# This is not actually used. NLS ISO 8859-10 (Latin 6; Nordic) CONFIG_NLS_ISO8859_10 If you want to display filenames with native language characters @@ -15495,6 +15685,7 @@ Enable Ethernet support via the Motorola MPC8xx serial commmunications controller. +# Choice: scc_ethernet Ethernet on SCC1 CONFIG_SCC1_ENET Use MPC8xx serial communications controller 1 to drive Ethernet @@ -15532,13 +15723,10 @@ Support for PMU-based PowerMacs CONFIG_ADB_PMU - On the PowerBook 3400 and 2400, the PMU is a 6805 microprocessor - core whose primary function is to control battery charging and - system power. The PMU also controls the ADB (Apple Desktop Bus) - which connects to the keyboard and mouse, as well as the - non-volatile RAM and the RTC (real time clock) chip. Say Y to - enable support for this device; you should do so if your machine - is one of these PowerBooks. + This provides support for PMU based Power Macintosh systems. This + includes all PowerBooks and all AGP-based machines. + + If unsure say Y. Include MacIO ADB driver CONFIG_ADB_MACIO @@ -15557,21 +15745,6 @@ If you use an ADB keyboard (4 pin connector), say Y here. If you use a PS/2 keyboard (6 pin connector), say N here. -HIL keyboard support -CONFIG_HIL - The "Human Interface Loop" is a older, 8-channel USB-like controller - used in Hewlette Packard PA-RISC based machines. There are a few - cases where it is seen on PC/MAC architectures as well, usually also - manufactured by HP. This driver is based off MACH and BSD drivers, - and implements support for a keyboard attached to the HIL port. - Full support for the USB-like functions and non-keyboard channels of - the HIL is not provided for in this driver. There are vestiges of - mouse support in the driver, but it is probably not working. The - necessary hardware documentation to fully support the HIL controller - and interface it to the linux-input API is lacking. - - Enable this option if you intend to use a HIL keyboard. - Include IOP (IIfx/Quadra 9x0) ADB driver CONFIG_ADB_IOP The I/O Processor (IOP) is an Apple custom IC designed to provide @@ -15716,6 +15889,23 @@ If unsure, say N. +Enable protocol mode for the L1 console +CONFIG_SERIAL_SGI_L1_PROTOCOL + Saying Y here will build support for SGI L1 system controllers. + + The L1 system controller is used as a console device as well as + for various system management tasks (e.g. power on/off, reset, + fan control, etc.). You'll want to say Y here unless you have + special needs. + +Enable autotest (llsc). Option to run cache test instead of booting +CONFIG_IA64_SGI_AUTOTEST + Build a kernel used for hardware validation. If you include the + keyword "autotest" on the boot command line, the kernel does NOT boot. + Instead, it starts all cpus and runs cache coherency tests instead. + + If unsure, say N. + Support for PowerMac serial ports CONFIG_MAC_SERIAL If you have Macintosh style serial ports (8 pin mini-DIN), say Y @@ -16044,123 +16234,6 @@ If unsure, say N. -Cobalt Networks support -CONFIG_COBALT - Support for Cobalt Networks x86-based servers. - -Gen III (3000 series) system support -CONFIG_COBALT_GEN_III - This option enables support for the 3000 series of Cobalt Networks - systems. This includes the RaQ 3, RaQ 4, and Qube 3 product lines. - - This platform uses an AMD K6-2 processor, an ALI M1541/1533 chipset, - an optional NCR 53c875 SCSI controller, and two Intel 82559ER or - National Semiconductor DP83815 NICs. - - Getting this option wrong will likely result in a kernel that does - not boot. Selecting support for more than 1 system series will add - bloat to your kernel, but will not cause anything bad to happen. - - If you have a Cobalt Networks System, but aren't sure what kind, - say Y here. - -Gen V (5000 series) system support -CONFIG_COBALT_GEN_V - This option enables support for the 5000 series of Cobalt Networks - systems. This includes the RaQ XTR product line. - - This platform uses Intel Pentium III Coppermine FCPGA CPUs, the - ServerWorks LE chipset (with registered ECC DIMMs only!), two - HighPoint HPT370 IDE controllers, and two National Semiconductor - DP83815 NICs. - - Getting this option wrong will likely result in a kernel that does - not boot. Selecting support for more than 1 system series will add - bloat to your kernel, but will not cause anything bad to happen. - - If you have a Cobalt Networks System, but aren't sure what kind, - say Y here. - -Create legacy /proc files -CONFIG_COBALT_OLDPROC - This option forces some Cobalt Networks drivers to support legacy - files in /proc. Older versions of these drivers exported files - directly in /proc, as opposed to the newer /proc/cobalt. If you say - N to this option, the old filenames will no longer be exported. - Regardless of your selection here, files in /proc/cobalt will be - exported. Of course, you have to include support for /proc fs, too. - - It is safe to say Y here. - -Front panel LCD support -CONFIG_COBALT_LCD - This enables support for the Cobalt Networks front panel. This is - for the LCD panel and buttons. The primary method for connection is - via the parallel port (IO base 0x370), but newer systems use an - I2C bus. - - If you have a Cobalt Networks system, you should say Y here. - -Software controlled LED support -CONFIG_COBALT_LED - This enables support for the software-controlled LEDs on Cobalt - Networks systems. This includes the fault light and front panel - LEDs on the RaQ XTR, the lightbar on the Qube 3, and others. - - If you have a Cobalt Networks system, you should say Y here. - -Silicon serial number support -CONFIG_COBALT_SERNUM - This enables support for the on-board serial number on Cobalt - Networks systems. This is a universally-unique 64-bit serial - number. Some systems use a Dallas DS2401 chip, others have an I2C - based EEPROM. - - If you select Y here, the files /proc/cobalt/hostid and - /proc/cobalt/serialnumber will be created. The hostid file contains - a 32 bit integer generated from the serial number, in binary form. - The serialnumber file contains the hexadecimal representation of the - serial number, in ASCII. - - If you have a Cobalt Networks system, you should say Y here. - -Chipset watchdog timer support -CONFIG_COBALT_WDT - This enables support for the watchdog timer built into Cobalt - chipsets. The timer wakes up periodically, to make find out if - system has hung, or disabled interrupts too long. The result of - detecting a hang is a hard reboot. - - If you have a Cobalt Networks system, you should say Y here. - -Thermal sensor support -CONFIG_COBALT_THERMAL - This enables support for the thermal sensor(s) built into Cobalt - Networks systems. This driver exports /proc/cobalt/thermal_sensors. - - If you have a Cobalt Networks system, you should say Y here. - -Fan tachometer support -CONFIG_COBALT_FANS - This enables support for the fan tachometers built into some Cobalt - Networks systems. This driver exports /proc/cobalt/faninfo. Some - Cobalt software depends on this feature, and enabling it does not - cause any risks. - - If you have a Cobalt Networks system, you should say Y here, unless - you are absolutely sure. - -Disk drive ruler support -CONFIG_COBALT_RULER - This enables support for the cobalt hard drive ruler, found on some - Cobalt systems, including the RaQ XTR. This is the device that - enables swapping of drives. It is not needed for basic disk - operation. Enabling this on a system with no ruler will have no - adverse effects. - - If you have a Cobalt Networks system, you should say Y here, - unless you are absolutely sure. - I2C support CONFIG_I2C I2C (pronounce: I-square-C) is a slow serial bus protocol used in @@ -16185,7 +16258,7 @@ . The module will be called i2c-core.o. -UltraSPARC-III bootbus i2c controller driver +UltraSPARC-III bootbus I2C controller driver CONFIG_BBC_I2C The BBC devices on the UltraSPARC III have two I2C controllers. The first I2C controller connects mainly to configuration PROMs (NVRAM, @@ -16194,6 +16267,29 @@ temperature sensors. The second controller also connects to the smartcard reader, if present. Say Y to enable support for these. +# This should turn into a derivation from ITE8172 and I2C_ALGOBIT +MIPS ITE8172 I2C driver algorithm +CONFIG_ITE_I2C_ALGO + This supports the use the ITE8172 I2C interface found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C peripheral driver support below. + + This support is also available as a module. If you want to compile + it as a modules, say M here and read + . + The module will be called i2c-algo-ite.o. + +MIPS ITE8172 I2C peripheral driver +CONFIG_ITE_I2C_ADAP + This supports the ITE8172 I2C peripheral found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C driver algorithm support above. + + This support is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-adap-ite.o. + I2C bit-banging interfaces CONFIG_I2C_ALGOBIT This allows you to use a range of I2C adapters called bit-banging @@ -16271,7 +16367,7 @@ . The module will be called i2c-dev.o. -I2C /proc support +I2C /proc interface (required for hardware sensors) CONFIG_I2C_PROC This provides support for i2c device entries in the /proc filesystem. The entries will be found in /proc/sys/dev/sensors. @@ -16285,7 +16381,7 @@ Say Y here if your machine has a bus mouse as opposed to a serial mouse. Most people have a regular serial MouseSystem or Microsoft mouse (made by Logitech) that plugs into a COM port - (rectangular with 9 or 25 pins). These people say N here. + (rectangular with 9 or 25 pins). These people say N here. If you have a laptop, you either have to check the documentation or experiment a bit to find out whether the trackball is a serial mouse @@ -16424,11 +16520,6 @@ and read . The module will be called tpqic02.o. -iSeries Virtual Tape Support -CONFIG_VIOTAPE - If you are running Linux on an iSeries system and you want Linux - to read and/or write a tape drive owned by OS/400, say Y here. - Do you want runtime configuration for QIC-02 CONFIG_QIC02_DYNCONF You can either configure this driver once and for all by editing a @@ -16641,6 +16732,25 @@ PCI-bus based system, please read the file . +MACH-2 +CONFIG_FT_MACH2 + Choose "MACH-2" if you have a Mountain Mach-2 tape controller. + +FC-10/FC-20 +CONFIG_FT_PROBE_FC10 + Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20 + tape controller. + +Alt/82078 +CONFIG_FT_ALT_FDC + Choose "Alt/82078" if you have another controller that is located at + an IO base address different from the standard floppy drive + controller's base address of `0x3f0', or uses an IRQ (interrupt) + channel different from `6', or a DMA channel different from + `2'. This is necessary for any controller card that is based on + Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high + speed" controllers. + IO base for the floppy disk controller used with Ftape CONFIG_FT_FDC_BASE You don't need to specify a value if the following default @@ -16753,12 +16863,6 @@ details. You should also select and configure AGP (/dev/agpgart) support. -Build drivers for new (XFree 4.1) DRM -CONFIG_DRM_NEW - If you set this option, the new DRM version needed by XFree86 4.1 - will be used. Otherwise, the old DRM version will be used, - appropriate for XFree86 4.0. - 3dfx Banshee/Voodoo3+ CONFIG_DRM_TDFX Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), @@ -16795,42 +16899,6 @@ card. If M is selected, the module will be called mga.o. AGP support is required for this driver to work. -3dfx Banshee/Voodoo3+ -CONFIG_DRM40_TDFX - Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), - graphics card. If M is selected, the module will be called tdfx.o. - -3dlabs GMX 2000 -CONFIG_DRM40_GAMMA - Choose this option if you have a 3dlabs GMX 2000 graphics card. - If M is selected, the module will be called gamma.o. - -ATI Rage 128 -CONFIG_DRM40_R128 - Choose this option if you have an ATI Rage 128 graphics card. If M - 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_DRM40_RADEON - Choose this option if you have an ATI Radeon graphics card. There - are both PCI and AGP versions. You don't need to choose this to - run the Radeon in plain VGA mode. There is a product page at - . - If M is selected, the module will be called radeon.o. - -Intel I810 -CONFIG_DRM40_I810 - Choose this option if you have an Intel I810 graphics card. If M is - selected, the module will be called i810.o. AGP support is required - for this driver to work. - -Matrox G200/G400/G450 -CONFIG_DRM40_MGA - Choose this option if you have a Matrox G200, G400 or G450 graphics - card. If M is selected, the module will be called mga.o. AGP - support is required for this driver to work. - Creator/Creator3D/Elite3D CONFIG_DRM_FFB Choose this option if you have one of Sun's Creator3D-based graphics @@ -16904,7 +16972,7 @@ fieldbus cards made by Applicom International. More information about these cards can be found on the WWW at the address , or by email from David Woodhouse - . + . 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 @@ -16961,22 +17029,6 @@ will issue the hlt instruction if nothing is to be done, thereby sending the processor to sleep and saving power. -USB SE401 Camera support -CONFIG_USB_SE401 - Say Y here if you want to connect this type of camera to your - computer's USB port. See for more - information and for a list of supported cameras. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Multimedia Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - on the WWW at . - - 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 se401.o. If you want to compile it as a - module, say M here and read . - ACPI support CONFIG_ACPI ACPI/OSPM support for Linux is currently under development. As such, @@ -17007,11 +17059,6 @@ The ACPI Sourceforge project may also be of interest: -Enable ACPI 2.0 with errata 1.3 -CONFIG_ACPI20 - Enable support for the 2.0 version of the ACPI interpreter. See the - help for ACPI for caveats and discussion. - ACPI kernel configuration manager CONFIG_ACPI_KERNEL_CONFIG If you say `Y' here, Linux's ACPI support will use the @@ -17214,11 +17261,11 @@ your computer. For details, read in the kernel source. - The watchdog is usually used together with the watchdog daemon - which is available from - . This daemon can - also monitor NFS connections and can reboot the machine when the process - table is full. + The watchdog is usually used together with the watchdog daemon which + is available from + . This daemon + can also monitor NFS connections and can reboot the machine when the + process table is full. If unsure, say N. @@ -17282,7 +17329,7 @@ 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 . The module will be called - softdog.o. + softdog.o. Berkshire Products PC Watchdog CONFIG_PCWATCHDOG @@ -17337,11 +17384,13 @@ IB700 SBC Watchdog Timer CONFIG_IB700_WDT This is the driver for the hardware watchdog on the IB700 Single - Board Computer produced by TMC Technology (www.tmc-uk.com). 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. + Board Computer produced by TMC Technology (www.tmc-uk.com). 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 like the WDT501 driver but for slightly different hardware. + This driver is like the WDT501 driver but for slightly different + hardware. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -17375,7 +17424,7 @@ The module is called machzwd.o. If you want to compile it as a module, say M here and read . -SuperH 3/4 Watchdog +SuperH 3/4 on-chip Watchdog support CONFIG_SH_WDT This driver adds watchdog support for the integrated watchdog in the SuperH 3 and 4 processors. If you have one of these processors, say Y, @@ -17385,7 +17434,7 @@ inserted in and removed from the running kernel whenever you want). The module is called shwdt.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. - + Toshiba Laptop support CONFIG_TOSHIBA This adds a driver to safely access the System Management Mode of @@ -17400,23 +17449,24 @@ Say Y if you intend to run this kernel on a Toshiba portable. Say N otherwise. -Dell Inspiron 8000 support +Dell laptop support CONFIG_I8K This adds a driver to safely access the System Management Mode - of the CPU on the Dell Inspiron 8000. The System Management Mode - is used to read cpu temperature and cooling fan status and to - control the fans on the I8K portables. - - This driver has been tested only on the Inspiron 8000 but it may - also work with other Dell laptops. You can force loading on other - models by passing the parameter `force=1' to the module. Use at - your own risk. - - For information on utilities to make use of this driver see the - I8K Linux utilities web site at: - + of the CPU on the Dell Inspiron and Latitude laptops. The System + Management Mode is used to read cpu temperature, cooling fan + status and Fn-keys status on Dell laptops. It can also be used + to switch the fans on and off. + + The driver has been developed and tested on an Inspiron 8000 + but it should work on any Dell Inspiron or Latitude laptop. + You can force loading on unsupported models by passing the + parameter `force=1' to the module. Use at your own risk. + + For more information on this driver and for utilities that make + use of the module see the I8K Linux Utilities web site at: + . - Say Y if you intend to run this kernel on a Dell Inspiron 8000. + Say Y if you intend to run this kernel on a Dell laptop. Say N otherwise. /dev/cpu/microcode - Intel IA32 CPU microcode support @@ -17466,6 +17516,12 @@ You can compile this driver directly into the kernel, or use it as a module. The module will be called sbc60xxwdt.o. +Eurotech CPU-1220/1410 Watchdog Timer +CONFIG_EUROTECH_WDT + Enable support for the watchdog timer on the Eurotech CPU-1220 and + CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product + information are at . + Enhanced Real Time Clock Support CONFIG_RTC If you say Y here and create a character special file /dev/rtc with @@ -17575,8 +17631,8 @@ Crystal SoundFusion gameports CONFIG_INPUT_CS461X - Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion" - PCI audio accelerator. A product page for the CS4614 is at + Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion" PCI + audio accelerator. A product page for the CS4614 is at . This driver is also available as a module ( = code which can be @@ -17680,7 +17736,8 @@ CONFIG_INPUT_INTERACT Say Y hereif you have an InterAct gameport or joystick communicating digitally over the gameport. For more information on - how to use the driver please read . + how to use the driver please read + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -17748,7 +17805,8 @@ CONFIG_INPUT_MAGELLAN Say Y here if you have a Magellan or Space Mouse 6DOF controller connected to your computer's serial port. For more information on - how to use the driver please read . + how to use the driver please read + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -17771,7 +17829,8 @@ CONFIG_INPUT_SPACEBALL Say Y here if you have a SpaceTec SpaceBall 4000 FLX controller connected to your computer's serial port. For more information on - how to use the driver please read . + how to use the driver please read + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -18493,6 +18552,41 @@ chips is available at . +Enable legacy FM +CONFIG_SOUND_CMPCI_FM + Say Y here to enable the legacy FM (frequency-modulation) synthesis + support on a card using the CMI8338 or CMI8378 chipset. + +FM I/O (388, 3C8, 3E0, 3E8) +CONFIG_SOUND_CMPCI_FMIO + Set the base I/O address for FM synthesis control on a card using + the CMI8338 or CMI8378 chipset. + +Enable legacy MPU-401 +CONFIG_SOUND_CMPCI_MIDI + Say Y here to enable the legacy MP401 MIDI synthesis support on a + card using the CMI8338 or CMI8378 chipset. + +MPU-401 I/O (330, 320, 310, 300) +CONFIG_SOUND_CMPCI_MPUIO + Set the base I/O address for MP401 MIDI synthesis control on a card + using the CMI8338 or CMI8378 chipset. + +Inverse S/PDIF in for CMI8738 +CONFIG_SOUND_CMPCI_SPDIFINVERSE + Say Y here to have the driver invert the signal presented on SPDIF IN + of s card using the CMI8338 or CMI8378 chipset. + +Use Line-in as Rear-out +CONFIG_SOUND_CMPCI_LINE_REAR + Say Y here to enable using line-in jack as an output jack for a rear + speaker. + +Use Line-in as Bass +CONFIG_SOUND_CMPCI_LINE_BASS + Say Y here to enable using line-in jack as an output jack for a bass + speaker. + Support CMI8738 based audio cards CONFIG_SOUND_CMPCI_CM8738 Say Y or M if you have a PCI sound card using the CMI8338 @@ -18523,7 +18617,7 @@ A userspace utility to control even more internal registers of these chips is available at . - This package will among other things help you enable SPDIF + This package will among other things help you enable SPDIF out/in/loop/monitor. Creative SBLive! (EMU10K1) based PCI sound cards @@ -18541,7 +18635,7 @@ Userspace tools to create new patches and load/unload them can be found at . -Creative EMU10K1 MIDI +Creative SBLive! (EMU10K1) MIDI CONFIG_MIDI_EMU10K1 Say Y if you want to be able to use the OSS /dev/sequencer interface. This code is still experimental. @@ -18592,6 +18686,12 @@ differs slightly from OSS/Free, so PLEASE READ . +NEC Vrc5477 AC97 sound +CONFIG_SOUND_VRC5477 + Say Y here to enable sound support for the NEC Vrc5477 chip, an + integrated, multi-function controller chip for MIPS CPUs. Works + with the AC97 codec. + Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core CONFIG_SOUND_TRIDENT Say Y or M if you have a PCI sound card utilizing the Trident @@ -18708,6 +18808,13 @@ Support for audio mixer facilities on the BT848 TV frame-grabber card. +IT8172G Sound +CONFIG_SOUND_IT8172 + Say Y here to support the on-board sound generator on the Integrated + Technology Express, Inc. ITE8172 SBC. Vendor page at + ; picture of the + board at . + VIDC 16-bit sound CONFIG_SOUND_VIDC 16-bit support for the VIDC onboard sound hardware found on Acorn @@ -18794,20 +18901,21 @@ website at will have more information. -Model-500/510 -CONFIG_NINO_16MB - Say Y here to build a kernel specifically for Nino 500/501 color - Palm PCs from Philips (INCOMPLETE). +# Choice: nino_model +CONFIG_NINO_4MB + Say Y here to build a kernel specifically for Nino Palm PCs with + 4MB of memory. These include models 300/301/302/319. Model-200/210/312/320/325/350/390 CONFIG_NINO_8MB Say Y here to build a kernel specifically for Nino Palm PCs with 8MB of memory. These include models 200/210/312/320/325/350/390. +Model-500/510 +CONFIG_NINO_16MB + Say Y here to build a kernel specifically for Nino 500/501 color + Palm PCs from Philips (INCOMPLETE). Model-300/301/302/319 -CONFIG_NINO_4MB - Say Y here to build a kernel specifically for Nino Palm PCs with - 4MB of memory. These include models 300/301/302/319. Low-level debugging CONFIG_LL_DEBUG @@ -18831,6 +18939,44 @@ hardware debugging with a logic analyzer and need to see all traffic on the bus. +Enable AU1000 serial console +CONFIG_AU1000_SERIAL_CONSOLE + If you have an Alchemy AU1000 processor (MIPS based) and you want + to use a console on a serial port, say Y. Otherwise, say N. + +Enable AU1000 serial support +CONFIG_AU1000_UART + If you have an Alchemy AU1000 processor (MIPS based) and you want + to use serial ports, say Y. Otherwise, say N. + +AU1000 ethernet controller on SGI MIPS system +CONFIG_MIPS_AU1000_ENET + If you have an Alchemy Semi AU1000 ethernet controller + on an SGI MIPS system, say Y. Otherwise, say N. + +TMPTX3912/PR31700 serial port support +CONFIG_SERIAL_TX3912 + The TX3912 is a Toshiba RISC processor based o the MIPS 3900 core; + see . + Say Y here to enable kernel support for the on-board serial port. + +Console on TMPTX3912/PR31700 serial port +CONFIG_SERIAL_TX3912_CONSOLE + The TX3912 is a Toshiba RISC processor based o the MIPS 3900 core; + see . + Say Y here to direct console I/O to the on-board serial port. + +TMPTX3912/PR31700 frame buffer support +CONFIG_FB_TX3912 + The TX3912 is a Toshiba RISC processor based o the MIPS 3900 core; + see . + Say Y here to enable kernel support for the on-board framebebuffer. + +SGI WD93C93 SCSI Driver +CONFIG_SGIWD93_SCSI + If you have a Western Digital WD93 SCSI controller on + an SGI MIPS system, say Y. Otherwise, say N. + Magic System Request Key support CONFIG_MAGIC_SYSRQ If you say Y here, you will have some control over the system even @@ -18905,11 +19051,11 @@ CONFIG_ISDN_AUDIO If you say Y here, the modem-emulator will support a subset of the EIA Class 8 Voice commands. Using a getty with voice-support - (mgetty+sendfax by gert@greenie.muc.de with an extension, available - with the ISDN utility package for example), you will be able to use - your Linux box as an ISDN-answering machine. Of course, this must be - supported by the lowlevel driver also. Currently, the HiSax driver - is the only voice-supporting driver. See + (mgetty+sendfax by with an extension, + available with the ISDN utility package for example), you will be + able to use your Linux box as an ISDN-answering machine. Of course, + this must be supported by the lowlevel driver also. Currently, the + HiSax driver is the only voice-supporting driver. See for more information. X.25 PLP on top of ISDN @@ -19024,6 +19170,12 @@ Enable this if you like to use ISDN in US on a NI1 basic rate interface. +# 2.4 tree only +Maximum number of cards supported by HiSax +CONFIG_HISAX_MAX_CARDS + This is used to allocate a driver-internal structure array with one + entry for each HiSax card on your system. + Teles 16.0/8.0 CONFIG_HISAX_16_0 This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 @@ -19240,7 +19392,7 @@ HiSax debugging CONFIG_HISAX_DEBUG This enables debugging code in the new-style HiSax drivers, i.e. - the ST5481 USB driver currently. + the ST5481 USB driver currently. If in doubt, say yes. ELSA PCMCIA MicroLink cards @@ -19253,7 +19405,7 @@ This enables the PCMCIA client driver for the Sedlbauer Speed Star and Speed Star II cards. -ST5481 USB ISDN adapter +ST5481 USB ISDN modem CONFIG_HISAX_ST5481 This enables the driver for ST5481 based USB ISDN adapters, e.g. the BeWan Gazel 128 USB @@ -19423,7 +19575,8 @@ to be downloaded into the card using a utility which is distributed separately from the Auvertech's web site: . - Please redirect all support questions to support@auvertech.fr. + Please redirect all support questions to + . If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -19688,9 +19841,9 @@ # Choice: cf_area CompactFlash Connection Area CONFIG_CF_AREA5 - If your board has "Directly Connected" CompactFlash, You should + If your SuperH board has "Directly Connected" CompactFlash, you should select the area where your CF is connected to. - + - "Area5" if CompactFlash is connected to Area 5 (0x14000000) - "Area6" if it is connected to Area 6 (0x18000000) @@ -19767,6 +19920,12 @@ Q60. Select your CPU below. For 68LC060 don't forget to enable FPU emulation. +Q40/Q60 IDE interface support +CONFIG_BLK_DEV_Q40IDE + Enable the on-board IDE controller in the Q40/Q60. This should + normally be on; disable it only if you are running a custom hard + drive subsystem through an expansion card. + Sun 3 support CONFIG_SUN3 This option enables support for the Sun 3 series of workstations. @@ -19799,7 +19958,7 @@ CONFIG_SUN_KEYBOARD Say Y here to support the keyboard found on Sun 3 and 3x workstations. It can also be used support Sun Type-5 keyboards - through an adaptor. See + through an adapter. See and for details on the latter. @@ -19853,7 +20012,7 @@ correct rounding, the emulator can (often) do the same but this extra calculation can cost quite some time, so you can disable it here. The emulator will then "only" calculate with a 64 bit - mantissa and round slightly incorrect, what is more then enough + mantissa and round slightly incorrect, what is more than enough for normal usage. Advanced configuration options @@ -20131,6 +20290,11 @@ want). The module is called hydra.o. If you want to compile it as a module, say M here and read . +Lasi ethernet +CONFIG_LASI_82596 + Say Y here to support the on-board Intel 82596 ethernet controller + built into Hewlett-Packard PA-RISC machines. + Sun3 NCR5380 SCSI CONFIG_SUN3_SCSI This option will enable support for the OBIO (onboard io) NCR5380 @@ -20305,7 +20469,7 @@ . PowerMac DMA sound support -CONFIG_DMASOUND_AWACS +CONFIG_DMASOUND_PMAC If you want to use the internal audio of your PowerMac in Linux, answer Y to this question. This will provide a Sun-like /dev/audio, compatible with the Linux/i386 sound system. Otherwise, say N. @@ -20375,7 +20539,7 @@ If in doubt, say N. -# Choice: Machine type +# Choice: ppc4xxtype Oak CONFIG_OAK Select Oak if you have an IBM 403GCX "Oak" Evaluation Board. @@ -20420,13 +20584,14 @@ If in doubt, say N here. -MPC8xx IDE support +MPC8xx direct IDE support on PCMCIA port CONFIG_BLK_DEV_MPC8xx_IDE This option provides support for IDE on Motorola MPC8xx Systems. Please see 'Type of MPC8xx IDE interface' for details. If unsure, say N. +# Choice: mpc8xxtype Type of MPC8xx IDE interface CONFIG_IDE_8xx_PCCARD Select how the IDE devices are connected to the MPC8xx system: @@ -20501,7 +20666,7 @@ More information is available at: . -AltiVec Kernel Support +AltiVec kernel support CONFIG_ALTIVEC This option enables kernel support for the Altivec extensions to the PowerPC processor. The kernel currently supports saving and restoring @@ -20542,11 +20707,12 @@ Average high and low temp CONFIG_TAU_AVERAGE - The TAU hardware can compare the temperature to an upper and lower bound. - The default behavior is to show both the upper and lower bound in - /proc/cpuinfo. If the range is large, the temperature is either changing - a lot, or the TAU hardware is broken (likely on some G4's). If the range - is small (around 4 degrees), the temperature is relatively stable. + The TAU hardware can compare the temperature to an upper and lower + bound. The default behavior is to show both the upper and lower + bound in /proc/cpuinfo. If the range is large, the temperature is + either changing a lot, or the TAU hardware is broken (likely on some + G4's). If the range is small (around 4 degrees), the temperature is + relatively stable. Power management support for PowerBooks CONFIG_PMAC_PBOOK @@ -20564,6 +20730,14 @@ have it autoloaded. The act of removing the module shuts down the sound hardware for more power savings. +APM emulation +CONFIG_PMAC_APM_EMU + This driver provides an emulated /dev/apm_bios and /proc/apm. The + first one is mostly intended for XFree to sleep & wakeup properly, + the second ones provides some battery informations to allow existing + APM utilities to work. It provides less useful informations than + tools specifically designed for PowerBooks or /proc/pmu/battery_x + Backlight control for LCD screens CONFIG_PMAC_BACKLIGHT Say Y here to build in code to manage the LCD backlight on a @@ -20583,10 +20757,10 @@ Embedded Planet RPX Lite. PC104 form-factor SBC based on the MPC823. RPX-Classic: - Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on + Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on the MPC 860 - BSE-IP: + BSE-IP: Bright Star Engineering ip-Engine. TQM823L: @@ -20628,7 +20802,7 @@ URL: IVML24: - MPC860 based board used in the "Integrated Voice Mail System", + MPC860 based board used in the "Integrated Voice Mail System", Large Version (24 voice channels) Manufacturer: Speech Design, Date of Release: March 2001 (?) @@ -20637,12 +20811,13 @@ SM850: Service Module (based on TQM850L) - Manufacturer: Dependable Computer Systems, + Manufacturer: Dependable Computer Systems, + Date of Release: end 2000 (?) End of life: mid 2001 (?) URL: - HERMES: + HERMES_PRO: Hermes-Pro ISDN/LAN router with integrated 8 x hub Manufacturer: Multidata Gesellschaft für Datentechnik und Informatik @@ -20659,8 +20834,11 @@ PCU_E: PCU = Peripheral Controller Unit, Extended - Manufacturer: Siemens AG, ICN (Information and Communication Networks) - + + Manufacturer: Siemens AG, ICN (Information and Communication + Networks) + + Date of Release: April 2001 End of life: August 2001 URL: n. a. @@ -20680,6 +20858,11 @@ 26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video controller, and two RS232 ports. +FADS +CONFIG_FADS + Say Y here to support the PPC860-based FADS (Family Application + Development System) evaluation boards from Motorola. + TQM823L CONFIG_TQM823L Say Y here to support the TQM823L, one of an MPC8xx-based family of @@ -20716,8 +20899,8 @@ , and an image at . -FPS850 -CONFIG_FPS850 +FPS850L +CONFIG_FPS850L Say Y here to support the FingerPrint Sensor from AKENDI IG, based on the TQ Components TQM850L module, released November 1999 and discontinued a year later. @@ -20725,7 +20908,7 @@ TQM860 CONFIG_TQM860 Say Y here to support the TQM860, one of an MPC8xx-based family of - SBCs (credit-card size) from TQ Components first released in + SBCs (credit-card size) from TQ Components first released in mid-1999 and discontinued mid-2000. SM850 @@ -20767,7 +20950,7 @@ thin-client machines. Say Y to support it directly. # More systems that will be supported soon, according to -# Wolfgang Denk : +# Wolfgang Denk : # # TQM8260: # MPC8260 based module @@ -20857,11 +21040,11 @@ If unsure, say Y here. I2C/SPI Microcode Patch -UCODE_PATCH +CONFIG_UCODE_PATCH Motorola releases microcode updates for their 8xx CPM modules. The - microcode update file has updates for IIC, SMC and USB. Currently only - the USB update is available by default, if the MPC8xx USB option is - enabled. If in doubt, say 'N' here. + microcode update file has updates for IIC, SMC and USB. Currently + only the USB update is available by default, if the MPC8xx USB + option is enabled. If in doubt, say 'N' here. Mouse button 2+3 emulation support CONFIG_MAC_EMUMOUSEBTN @@ -20922,16 +21105,16 @@ MESH (Power Mac internal SCSI) support CONFIG_SCSI_MESH Many Power Macintoshes and clones have a MESH (Macintosh Enhanced - SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the + SCSI Hardware) SCSI bus adapter (the 7200 doesn't, but all of the other Power Macintoshes do). Say Y to include support for this SCSI - adaptor. This driver is also available as a module called mesh.o + adapter. This driver is also available as a module called mesh.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 . Maximum synchronous transfer rate (MB/s) (0 = async) CONFIG_SCSI_MESH_SYNC_RATE - On Power Macintoshes (and clones) where the MESH SCSI bus adaptor + On Power Macintoshes (and clones) where the MESH SCSI bus adapter drives a bus which is entirely internal to the machine (such as the 7500, 7600, 8500, etc.), the MESH is capable of synchronous operation at up to 10 MB/s. On machines where the SCSI bus @@ -20943,7 +21126,7 @@ 53C94 (Power Mac external SCSI) support CONFIG_SCSI_MAC53C94 On Power Macintoshes (and clones) with two SCSI buses, the external - SCSI bus is usually controlled by a 53C94 SCSI bus adaptor. Older + SCSI bus is usually controlled by a 53C94 SCSI bus adapter. Older machines which only have one SCSI bus, such as the 7200, also use the 53C94. Say Y to include support for the 53C94. @@ -21246,7 +21429,7 @@ 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. + 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 @@ -21277,15 +21460,15 @@ CONFIG_RADIO_GEMTEK_PORT Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is 0x34c, if you haven't changed the jumper setting on the card. On - Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O + Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM GemTek), the I/O port is 0x28c. -Gemtek PCI Radio +GemTek PCI Radio Card support CONFIG_RADIO_GEMTEK_PCI Choose Y here if you have this PCI FM radio card. In order to control your radio card, you will need to use programs - that are compatible with the Video for Linux API. Information on + 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 . @@ -21312,7 +21495,7 @@ frequency control and muting works at least for me, but unfortunately I have not found anybody who wants to use this card with Linux. So if it is this what YOU are trying to do right now, - PLEASE DROP ME A NOTE!! Rolf Offermanns (rolf@offermanns.de) + PLEASE DROP ME A NOTE!! Rolf Offermanns () In order to control your radio card, you will need to use programs that are compatible with the Video For Linux API. Information on @@ -21358,7 +21541,7 @@ whenever you want). If you want to compile it as a module, say M here and read . -BT878 Audio DMA +BT878 audio DMA CONFIG_SOUND_BT878 Audio DMA support for bt878 based grabber boards. As you might have already noticed, bt878 is listed with two functions in /proc/pci. @@ -21396,6 +21579,18 @@ Say Y here to include support for the Iomega Buz video card. There is a Buz/Linux homepage at . +Miro DC10(+) support +CONFIG_VIDEO_ZORAN_DC10 + Say Y to support the Pinnacle Systems Studio DC10 plus TV/Video + card. Linux page at + . Vendor + page at . + +Linux Media Labs LML33 support +CONFIG_VIDEO_ZORAN_LML33 + Say Y here to support the Linux Media Labs LML33 TV/Video card. + Resources page is at . + Zoran ZR36120/36125 Video For Linux CONFIG_VIDEO_ZR36120 Support for ZR36120/ZR36125 based frame grabber/overlay boards. @@ -21437,7 +21632,7 @@ as a module (c-qcam.o). Read for more information. -Winbond W9966CF Webcam Video For Linux +Winbond W9966CF Webcam (FlyCam Supra and others) Video For Linux CONFIG_VIDEO_W9966 Video4linux driver for Winbond's w9966 based Webcams. Currently tested with the LifeView FlyCam Supra. @@ -21445,8 +21640,8 @@ otherwise say N. This driver is also available as a module (w9966.o). - Check out for more - information. + Check out and + for more information. CPiA Video For Linux CONFIG_VIDEO_CPIA @@ -21485,7 +21680,7 @@ it as a module, say M here and read . -Sony Vaio Picturebook Motion Eye Video for Linux +Sony Vaio Picturebook Motion Eye Video For Linux CONFIG_VIDEO_MEYE This is the video4linux driver for the Motion Eye camera found in the Vaio Picturebook laptops. Please read the material in @@ -21505,6 +21700,25 @@ mainframes of the S/390 generation. You should have installed the s390-compiler released by IBM (based on gcc-2.95.1) before. +VM pseudo page fault handling support using PFAULT +CONFIG_PFAULT + Select this option, if you want to use PFAULT pseudo page fault + handling under VM. If running native or in LPAR, this option + has no effect. If your VM does not support PFAULT, PAGEEX + pseudo page fault handling will be used. + Note that VM 4.2 supports PFAULT but has a bug in its + implementation that causes some problems. + Everybody who wants to run Linux under VM != VM4.2 should select + this option. + +VM shared kernel support +CONFIG_SHARED_KERNEL + Select this option, if you want to share the text segment of the + Linux kernel between different VM guests. This reduces memory + usage with lots of guests but greatly increases kernel size. + You should only select this option if you know what you are + doing and want to exploit this feature. + Merge some code into the kernel to make the image IPLable CONFIG_IPL If you want to use the produced kernel to IPL directly from a @@ -21518,56 +21732,34 @@ 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 +CONFIG_IPL_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. - Support for DASD hard disks 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 +Support for ECKD hard disks 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. + ECKD devices are the most commonly used devices. You should enable + this option unless you are very sure you have no ECKD device. -CKD devices -CONFIG_DASD_CKD - CKD devices are currently unsupported. +Automatic activation of ECKD module on DASD driver startup +CONFIG_DASD_AUTO_ECKD + Enable this option if you want your ECKD discipline module loaded + on DASD driver startup. -FBA devices +Support for FBA hard disks CONFIG_DASD_FBA FBA devices are currently unsupported. -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. +Automatic activation of FBA module on DASD driver startup +CONFIG_DASD_AUTO_FBA + Enable this option if you want your FBA discipline module loaded + on DASD driver startup. Support for 3215 line mode terminal CONFIG_TN3215 @@ -21592,6 +21784,16 @@ CONFIG_HWC Include support for IBM HWC line-mode terminals. +HWC Control-Program Identification +CONFIG_HWC_CPI + This option enables the hardware console interface for system + identification This is commonly used for workload management and + gives you a nice name for the system on the service element. + Please select this option as a module since built-in operation is + completely untested. + You should only select this option if you know what you are doing, + need this feature and intend to run your kernel in LPAR. + Console on HWC line mode terminal CONFIG_HWC_CONSOLE Include support for using an IBM HWC line-mode terminal as the Linux @@ -21651,6 +21853,11 @@ with the Diagnose250 command. If you are not running under VM or unsure what it is, say "N". +Automatic activation of DIAG module on DASD driver startup +CONFIG_DASD_AUTO_DIAG + Enable this option if you want your DIAG discipline module loaded + on DASD driver startup. + XPRAM disk support CONFIG_BLK_DEV_XPRAM Select this option if you want to use your expanded storage on S/390 @@ -21801,6 +22008,12 @@ Saying N will reduce the size of the Footbridge kernel. +Integrator +CONFIG_ARCH_INTEGRATOR + The ARM Integrator family is a line of SBCs for embedded systems + designed by Bluewater Systems; home page, with board pictures, at + + LinkUp Systems L7200 SDB CONFIG_ARCH_L7200 Say Y here if you intend to run this kernel on a LinkUp Systems @@ -21810,7 +22023,7 @@ If you have any questions or comments about the Linux kernel port - to this board, send e-mail to sjhill@cotw.com. + to this board, send e-mail to . NetWinder CONFIG_ARCH_NETWINDER @@ -21840,7 +22053,26 @@ If you have any questions or comments about the Compaq Personal - Server, send e-mail to skiff@crl.dec.com. + Server, send e-mail to . + +Cirrus Logic EDB-7211 evaluation board +CONFIG_ARCH_EDB7211 + Say Y here if you intend to run this kernel on a Cirrus Logic EDB-7211 + evaluation board. + +EP7211 infrared support +CONFIG_EP7211_IR + Say Y here if you wish to use the infrared port on the EP7211. Note + that you can't use the first UART and the infrared port at the same + time, and that the EP7211 only supports SIR mode, at speeds up to + 115.2 kbps. To use the I/R port, you will need to get the source to + irda-utils and apply the patch at + . + +SA1100 Internal IR +CONFIG_SA1100_FIR + Say Y here to enable the on-board IRDA device on a Intel(R) + StrongARM(R) SA-1110 based microporocessor. Assabet CONFIG_SA1100_ASSABET @@ -21877,23 +22109,85 @@ CONFIG_SA1100_GRAPHICSCLIENT Say Y here if you are using an Applied Data Systems Intel(R) StrongARM(R) SA-1100 based Graphics Client SBC. See - for information on this system. + for information on this system. + +GraphicsMaster +CONFIG_SA1100_GRAPHICSMASTER + Say Y here if you are using an Applied Data Systems Intel(R) + StrongARM(R) SA-1100 based Graphics Master SBC with SA-1111 + StrongARM companion chip. See + for information + on this system. + +ADS Bitsy +CONFIG_SA1100_ADSBITSY + Say Y here if you are using Applied Data Systems Intel(R) + StrongARM(R) 1110 based Bitsy, 3 x 5 inches in size, Compaq - IPAQ - + like platform. See + for more + information. + +Itsy +CONFIG_SA1100_ITSY + Say Y here if you are using the Compaq Itsy experimental pocket + computer. See for + more information. + +HuW WebPanel +CONFIG_SA1100_HUW_WEBPANEL + Say Y here to support the HuW Webpanel produced by Hoeft & Wessel + AG. English-language website is at + ; credits and build instructions + at . + +PLEB +CONFIG_SA1100_PLEB + Say Y here if you are using a Portable Linux Embedded Board + (also known as PLEB). See + for more information. + +Sherman +CONFIG_SA1100_SHERMAN + Say Y here to support the Blazie Engineering `Sherman' StrongARM + 1110-based SBC, used primarily in assistance products for the + visually impaired. The company is now Freedom Scientific, with + a website at . The + Sherman product, however, appears to have been discontinued. + +Yopy +CONFIG_SA1100_YOPY + Say Y here to support the Yopy PDA. Product information at + . See + for more. CerfBoard CONFIG_SA1100_CERF The Intrinsyc CerfBoard is based on the StrongARM 1110. More information is available at: . + Build instructions at . Say Y if configuring for an Intrinsyc CerfBoard. Say N otherwise. +Cerf w/CPLD support (CerfPDA) +CONFIG_SA1100_CERF_CPLD + Say Y here to support the Linux CerfPDA development kit from + Intrinsyc. This is a StrongARM-1110-based reference platform for + designing custom PDAs. Product info is at + . + FlexaNet CONFIG_SA1100_FLEXANET Say Y here if you intend to run this kernel on the FlexaNet handheld instruments. Information about this machine can be found at: . +FreeBird-v1.1 +CONFIG_SA1100_FREEBIRD + Support the FreeBird board used in Coventive embedded products. See + . + nanoEngine CONFIG_SA1100_NANOENGINE The nanoEngine is a StrongARM 1110-based single board computer @@ -21920,6 +22214,38 @@ for information on this system. +# Choice: cerf_ram +Cerf on-board RAM size +CONFIG_SA1100_CERF_8MB + Declare the size of the CerfBoard's on-board RAM. + Alternatives are 8, 16, 32, and 64MB. + +16MB +CONFIG_SA1100_CERF_16MB + Declare that the CerfBoard has 16MB RAM. + +32MB +CONFIG_SA1100_CERF_32MB + Declare that the CerfBoard has 32MB RAM. + +64MB +CONFIG_SA1100_CERF_64MB + Declare that the CerfBoard has 64MB RAM. + +# Choice: cerf_flash +Cerf flash memory size +CONFIG_SA1100_CERF_FLASH_8MB + Tell the Cerf kernel the size of on-board memory. The choices + are 8MB, 16MB, or 32MB. + +16MB +CONFIG_SA1100_CERF_FLASH_16MB + Configure the Cerf kernel to expect 16MB of flash memory. + +32MB +CONFIG_SA1100_CERF_FLASH_32MB + Configure the Cerf kernel to expect 32MB of flash memory. + Support ARM610 processor CONFIG_CPU_ARM610 The ARM610 is the successor to the ARM3 processor @@ -21955,6 +22281,15 @@ Say Y if you want support for the ARM920T processor. Otherwise, say N. +Support ARM926T processor +CONFIG_CPU_ARM926T + This is a variant of the ARM920. It has slightly different + instruction sequences for cache and TLB operations. Curiously, + there is no documentation on it at the ARM corporate website. + + Say Y if you want support for the ARM926T processor. + Otherwise, say N. + Support ARM1020 processor CONFIG_CPU_ARM1020 The ARM1020 is the cached version of the ARM10 processor, @@ -21963,6 +22298,81 @@ Say Y if you want support for the ARM1020 processor. Otherwise, say N. +Enable ARM920T instruction cache +CONFIG_CPU_ARM920_I_CACHE_ON + Say Y here to enable the processor instruction cache. Unless + you have a reason not to, say Y. + +Enable ARM920T data cache +CONFIG_CPU_ARM920_D_CACHE_ON + Say Y here to enable the processor data cache. Unless + you have a reason not to, say Y. + +Use ARM920T data cache in writethrough mode +CONFIG_CPU_ARM920_WRITETHROUGH + Say Y here to use the data cache in writethough mode. Unless you + specifically require this, say N. + +Enable ARM926T instruction cache +CONFIG_CPU_ARM926_I_CACHE_ON + Say Y here to enable the processor instruction cache. Unless + you have a reason not to, say Y. + +Enable ARM926T data cache +CONFIG_CPU_ARM926_D_CACHE_ON + Say Y here to enable the processor data cache. Unless + you have a reason not to, say Y. + +Use ARM926T data cache in writethrough mode +CONFIG_CPU_ARM926_WRITETHROUGH + Say Y here to use the data cache in writethough mode. Unless you + specifically require this, say N. + +Enable ARM1020T instruction cache +CONFIG_CPU_ARM1020_I_CACHE_ON + Say Y here to enable the processor instruction cache. Unless + you have a reason not to, say Y. + +Enable ARM1020T data cache +CONFIG_CPU_ARM1020_D_CACHE_ON + Say Y here to enable the processor data cache. Unless + you have a reason not to, say Y. + +Use ARM1020T data cache in writethrough mode +CONFIG_CPU_ARM1020_FORCE_WRITE_THROUGH + Say Y here to use the data cache in writethough mode. Unless you + specifically require this, say N. + +ARM920T CPU idle +CONFIG_CPU_ARM920_CPU_IDLE + Say Y to allow the idle task to power down an ARM920T CPU until the + next interrupt from a peripheral or the timer. This saves power, + and you should normally enable it. + +ARM926T CPU idle +CONFIG_CPU_ARM926_CPU_IDLE + Say Y to allow the idle task to power down an ARM926T CPU until the + next interrupt from a peripheral or the timer. This saves power, + and you should normally enable it. + +ARM1020 CPU idle +CONFIG_CPU_ARM1020_CPU_IDLE + Say Y to allow the idle task to power down an ARM1020T CPU until the + next interrupt from a peripheral or the timer. This saves power, + and you should normally enable it. + +Round robin I and D cache replacement algorithm +CONFIG_CPU_ARM926_ROUND_ROBIN + Disable the normal speculative caching (non-blocking + "hit-under-miss" operation) and fall back to a round-robin + cache-replenishment algorithm. + +Round robin I and D cache replacement algorithm +CONFIG_CPU_ARM1020_ROUND_ROBIN + Disable the normal speculative caching (non-blocking + "hit-under-miss" operation) and fall back to a round-robin + cache-replenishment algorithm. + Support StrongARM SA-110 processor CONFIG_CPU_SA110 The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and @@ -21973,6 +22383,59 @@ Say Y if you want support for the SA-110 processor. Otherwise, say N. +Tulsa +CONFIG_SA1100_PFS168 + The Radisys Corp. PFS-168 (aka Tulsa) is an Intel® StrongArm® + SA-1110 based computer which includes the SA-1111 Microprocessor + Companion Chip and other custom I/O designed to add connectivity and + multimedia features for vending and business machine + applications. Say Y here if you require support for this target. + +HP Jornada 720 +CONFIG_SA1100_JORNADA720 + Say Y here if you want to build a kernel for the HP Jornada 720 + handheld computer. See + for details. + +InHand Electronics OmniMeter +CONFIG_SA1100_OMNIMETER + Say Y here if you are using the inhand electronics OmniMeter. See + for details. + +SIMpad +CONFIG_SA1100_SIMPAD + The SIEMENS webpad SIMpad is based on the StrongARM 1110. There + are two different versions CL4 and SL4. CL4 has 32MB RAM and 16MB + FLASH. The SL4 version got 64 MB RAM and 32 MB FLASH and a + PCMCIA-Slot. The version for the Germany Telecom (DTAG) is the same + like CL4 in additional it has a PCMCIA-Slot. For more information + visit . + +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. + +CDB89712 +CONFIG_ARCH_CDB89712 + This is an evaluation board from Cirrus for the CS89712 processor. + The board includes 2 serial ports, Ethernet, IRDA, and expansion + headers. It comes with 16 MB SDRAM and 8 MB flash ROM. + +CLPS-711X internal ROM bootstrap +CONFIG_EP72XX_ROM_BOOT + If you say Y here, your CLPS711x-based kernel will use the bootstrap + mode memory map instead of the normal memory map. + + Processors derived from the Cirrus CLPS-711X core support two boot + modes. Normal mode boots from the external memory device at CS0. + Bootstrap mode rearranges parts of the memory map, placing an + internal 128 byte bootstrap ROM at CS0. This option performs the + address map changes required to support booting in this mode. + + You almost surely want to say N here. + Math emulation CONFIG_FPE_NWFPE Say Y to include the NWFPE floating point emulator in the kernel. @@ -22117,76 +22580,6 @@ If you have enabled the serial port on the 21285 footbridge you can make it the console by answering Y to this option. -SA1100 serial port support -CONFIG_SERIAL_SA1100 - * Orphaned entry retained 20 April 2001 by Russell King * - * If you read this note from the configurator, please contact * - * the Configure.help maintainers. * - If you have a machine based on a SA1100/SA1110 StrongARM CPU you can - enable its onboard serial port by enabling this option. - Please read for further - info. - -Console on SA1100 serial port -CONFIG_SERIAL_SA1100_CONSOLE - * Orphaned entry retained 20 April 2001 by Russell King * - * If you read this note from the configurator, please contact * - * the Configure.help maintainers. * - If you have enabled the serial port on the SA1100/SA1110 StrongARM - CPU you can make it the console by answering Y to this option. - -L7200 serial port support -CONFIG_SERIAL_L7200 - * Orphaned entry retained 20 April 2001 by Russell King * - * If you read this note from the configurator, please contact * - * the Configure.help maintainers. * - If you have a LinkUp Systems L7200 board you can enable its two - onboard serial ports by enabling this option. The device numbers - are major ID 4 with minor 64 and 65 respectively. - -Console on L7200 serial port -CONFIG_SERIAL_L7200_CONSOLE - * Orphaned entry retained 20 April 2001 by Russell King * - * If you read this note from the configurator, please contact * - * the Configure.help maintainers. * - If you have enabled the serial ports on the L7200 development board - you can make the first serial port the console by answering Y to - this option. - -L7200 SDB keyboard support -CONFIG_KEYBOARD_L7200 - * Orphaned entry retained 20 April 2001 by Russell King * - * If you read this note from the configurator, please contact * - * the Configure.help maintainers. * - 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 - * Orphaned entry retained 20 April 2001 by Russell King * - * If you read this note from the configurator, please contact * - * the Configure.help maintainers. * - 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 - * Orphaned entry retained 20 April 2001 by Russell King * - * If you read this note from the configurator, please contact * - * the Configure.help maintainers. * - Select the prototype keyboard if you want to play with the - LCD/keyboard combination on the LinkUp SDB. - -Footbridge Mode -CONFIG_HOST_FOOTBRIDGE - * Orphaned entry retained 20 April 2001 by Russell King * - * If you read this note from the configurator, please contact * - * the Configure.help maintainers. * - The 21285 Footbridge chip can operate in either `host mode' or - `add-in' mode. Say Y if your 21285 is in host mode, and therefore - is the configuration master, otherwise say N. This must not be - set to Y if the card is used in 'add-in' mode. - MFM hard disk support CONFIG_BLK_DEV_MFM Support the MFM hard drives on the Acorn Archimedes both @@ -22275,11 +22668,11 @@ Ultra (connectionless) protocol CONFIG_IRDA_ULTRA - Say Y here to support the connectionless Ultra IRDA protocol. - Ultra allows to exchange data over IrDA with really simple devices - (watch, beacon) without the overhead of the IrDA protocol (no handshaking, - no management frames, simple fixed header). - Ultra is available as a special socket : socket(AF_IRDA, SOCK_DGRAM, 1); + Say Y here to support the connectionless Ultra IRDA protocol. Ultra + allows to exchange data over IrDA with really simple devices (watch, + beacon) without the overhead of the IrDA protocol (no handshaking, + no management frames, simple fixed header). Ultra is available as a + special socket: socket(AF_IRDA, SOCK_DGRAM, 1); IrDA cache last LSAP CONFIG_IRDA_CACHE_LAST_LSAP @@ -22314,10 +22707,9 @@ CONFIG_IRDA_DEBUG Say Y here if you want the IrDA subsystem to write debug information to your syslog. You can change the debug level in - /proc/sys/net/irda/debug . - When this option is enabled, the IrDA also perform many extra internal - verifications which will usually prevent the kernel to crash in case of - bugs. + /proc/sys/net/irda/debug . When this option is enabled, the IrDA + also perform many extra internal verifications which will usually + prevent the kernel to crash in case of bugs. If unsure, say Y (since it makes it easier to find the bugs). @@ -22397,6 +22789,27 @@ Please note that the driver is still experimental. And of course, you will need both USB and IrDA support in your kernel... +Datafab MDCFE-B Compact Flash Reader support +CONFIG_USB_STORAGE_DATAFAB + This option enables a sub-driver of the USB Mass Storage driver. + These sub-drivers are considered experimental, and should only be + used by very brave people. System crashes and other bad things are + likely to occur if you use this driver. If in doubt, select N. + +HP CD-Writer 82xx support +CONFIG_USB_STORAGE_HP8200e + This option enables a sub-driver of the USB Mass Storage driver. + These sub-drivers are considered experimental, and should only be + used by very brave people. System crashes and other bad things are + likely to occur if you use this driver. If in doubt, select N. + +Lexar Jumpshot Compact Flash Reader +CONFIG_USB_STORAGE_JUMPSHOT + This option enables a sub-driver of the USB Mass Storage driver. + These sub-drivers are considered experimental, and should only be + used by very brave people. System crashes and other bad things are + likely to occur if you use this driver. If in doubt, select N. + Winbond W83977AF IrDA Device Driver CONFIG_WINBOND_FIR Say Y here if you want to build IrDA support for the Winbond @@ -22418,13 +22831,18 @@ . The module will be called nsc-ircc.o. -National Semiconductor DP83820 series driver +National Semiconductor DP83820 support CONFIG_NS83820 This is a driver for the National Semiconductor DP83820 series - of gigabit ethernet MACs. Cards using this chipset include - the D-Link DGE-500T, PureData's PDP8023Z-TG, SMC's SMC9462TX, - SOHO-GA2000T, SOHO-GA2500T. The driver supports the use of - zero copy. + of gigabit ethernet MACs. Cards using this chipset include: + + SMC 9452TX SMC SMC9462TX + D-Link DGE-500T PureData PDP8023Z-TG + SOHO-GA2000T SOHO-GA2500T. + NetGear GA621 + + This driver supports the use of zero copy on tx, checksum + validation on rx, and 64 bit addressing. Toshiba Type-O IR Port device driver CONFIG_TOSHIBA_FIR @@ -22442,7 +22860,7 @@ here and read . The module will be called smc-ircc.o. -ALi M5123 FIR Controller Driver +ALi M5123 FIR controller driver CONFIG_ALI_FIR Say Y here if you want to build support for the ALi M5123 FIR Controller. The ALi M5123 FIR Controller is embedded in ALi M1543C, @@ -22453,7 +22871,7 @@ . The module will be called ali-ircc.o. -VLSI 82C147 PCI-IrDA Controller Driver +VLSI 82C147 PCI-IrDA SIR/MIR/FIR Controller driver CONFIG_VLSI_FIR Say Y here if you want to build support for the VLSI 82C147 PCI-IrDA Controller. This controller is used by the HP OmniBook 800 @@ -22664,6 +23082,15 @@ CONFIG_ETRAX_FLASH_BUSWIDTH Width in bytes of the Flash bus (1, 2 or 4). Is usually 2. +Root filesystem device +CONFIG_ETRAX_ROOT_DEVICE + Specifies the device that should be mounted as root filesystem + when booting from flash. The axisflashmap driver adds an additional + mtd partition for the appended root filesystem image, so this option + should normally be the mtdblock device for the partition after the + last partition in the partition table. + +# Choice: crisleds LED configuration on PA CONFIG_ETRAX_PA_LEDS The Etrax network driver is responsible for flashing LED's when @@ -22812,14 +23239,27 @@ For products with only one or two controllable LEDs, set this to same as CONFIG_ETRAX_LED1G (normally 2). -Flash LED off during activity -CONFIG_ETRAX_LED_OFF_DURING_ACTIVITY - This option allows you to decide whether the network LED (and - Bluetooth LED in case you use Bluetooth) will be on or off when - the network is connected, and whether it should flash off or on - when there is activity. If you say y to this option the network - LED will be lit when there is a connection, and will flash off - when there is activity. +LED on when link +CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK + Selecting LED_on_when_link will light the LED when there is a + connection and will flash off when there is activity. + + Selecting LED_on_when_activity will light the LED only when + there is activity. + + This setting will also affect the behaviour of other activity LEDs + e.g. Bluetooth. + +LED on when activity +CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY + Selecting LED_on_when_link will light the LED when there is a + connection and will flash off when there is activity. + + Selecting LED_on_when_activity will light the LED only when + there is activity. + + This setting will also affect the behaviour of other activity LEDs + e.g. Bluetooth. PA button configuration CONFIG_ETRAX_PA_BUTTON_BITMASK @@ -22945,9 +23385,24 @@ Etrax General port B data CONFIG_ETRAX_DEF_R_PORT_PB_DATA - Configures the initial data for the general port A bits. Most + Configures the initial data for the general port B bits. Most products should use FF here. +Software Shutdown Support +CONFIG_ETRAX_SOFT_SHUTDOWN + Enable this if Etrax is used with a power-supply that can be turned + off and on with PS_ON signal. Gives the possibility to detect + powerbutton and then do a power off after unmounting disks. + +Shutdown bit on port CSP0 +CONFIG_ETRAX_SHUTDOWN_BIT + Configure what pin on CSPO-port that is used for controlling power + supply. + +Power button bit on port G +CONFIG_ETRAX_POWERBUTTON_BIT + Configure where power button is connected. + Etrax General port device CONFIG_ETRAX_GPIO Enables the Etrax general port device (major 120, minors 0 and 1). @@ -22961,28 +23416,11 @@ Remember that you need to setup the port directions appropriately in the General configuration. -Etrax parallel data support -CONFIG_ETRAX_PARDATA - Adds support for writing data to the parallel port par0 of the ETRAX - 100. If you create a character special file with major number 126, - you can write to the data bits of par0. - Note: you need to disable Etrax100 parallel port support. - -Etrax parallel LCD (HD44780) Driver -CONFIG_ETRAX_LCD_HD44780 - Adds support for a HD44780 controlled LCD connected to the parallel - port par0 of the Etrax. - Etrax Serial port ser0 support CONFIG_ETRAX_SERIAL Enables the ETRAX 100 serial driver for ser0 (ttyS0) You probably want this enabled. -/proc/serial entry -CONFIG_ETRAX_SERIAL_PROC_ENTRY - Enables /proc/serial entry where errors and statistics can be - viewed. CONFIG_PROC_FS must also be set for this to work. - Etrax Serial port fast flush of DMA using fast timer API CONFIG_ETRAX_SERIAL_FAST_TIMER Select this to have the serial DMAs flushed at a higher rate than @@ -22990,20 +23428,26 @@ approx. 4 character times. If unsure, say N. -Etrax Serial port fast flush of DMA +Fast serial port DMA flush CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST Select this to have the serial DMAs flushed at a higher rate than normally possible through a fast timer interrupt (currently at 15360 Hz). If unsure, say N. -Etrax Serial port receive flush timeout +Etrax serial port receive flush timeout (ticks) CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS Number of timer ticks between flush of receive fifo (1 tick = 10ms). Try 0-3 for low latency applications. Approx 5 for high load applications (e.g. PPP). Maybe this should be more adaptive some day... +Etrax Serial port ser0 support +CONFIG_ETRAX_SERIAL_PORT0 + Enables the ETRAX 100 serial driver for ser0 (ttyS0) + Normally you want this on, unless you use external DMA 1 that uses + the same DMA channels. + Etrax Serial port ser0 DTR, RI, DSR and CD support on PB CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB Enables the status and control signals DTR, RI, DSR and CD on PB for @@ -23148,6 +23592,7 @@ CONFIG_ETRAX_I2C_EEPROM_8KB Use a 8kB EEPROM. +# Choice: etrax_eeprom Etrax100 I2C EEPROM (NVRAM) size/probe CONFIG_ETRAX_I2C_EEPROM_PROBE Specifies size or auto probe of the EEPROM size. @@ -23187,22 +23632,25 @@ This is the bit number for the SDA signal line of the DS1302 RTC on Port PB. This is probably best left at 2. +Etrax 100 ATA/IDE support +CONFIG_ETRAX_IDE + Enable this to get support for ATA/IDE. You can't use parallel + ports or SCSI ports at the same time. + +Delay for IDE drives to regain consciousness +CONFIG_ETRAX_IDE_DELAY + Number of seconds to wait for IDE drives to spin up after an IDE + reset. + Etrax 100 IDE Reset CONFIG_ETRAX_IDE_CSP0_8_RESET Configures the pin used to reset the IDE bus. Etrax 100 IDE Reset -CONFIG_ETRAX_IDE_CSPE1_16_RESET - Configures the pin used to reset the IDE bus. - -Etrax 100 ATA/IDE support -CONFIG_ETRAX_IDE_DELAY - Sets the time to wait for disks to regain consciousness after reset. - -Etrax 100 IDE Reset CONFIG_ETRAX_IDE_G27_RESET Configures the pin used to reset the IDE bus. +# Choice: ide_reset IDE reset on PB Bit 7 CONFIG_ETRAX_IDE_PB7_RESET Configures the pin used to reset the IDE bus. @@ -23227,6 +23675,16 @@ This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet controller. +Etrax Ethernet slave support (over lp0/1) +CONFIG_ETRAX_ETHERNET_LPSLAVE + This option enables a slave ETRAX 100 or ETRAX 100LX, connected to a + master ETRAX 100 or ETRAX 100LX through par0 and par1, to act as an + Ethernet controller. + +ETRAX 100 Ethernet slave controller LEDS +CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS + Enable if the slave has it's own LEDs. + ETRAX 100LX Synchronous serial ports CONFIG_ETRAX_SYNCHRONOUS_SERIAL This option enables support for the ETRAX 100LX built-in @@ -23251,11 +23709,6 @@ CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA Makes synchronous serial port 1 use DMA. -Delay for drives to regain consciousness -CONFIG_IDE_DELAY - Number of seconds to wait for IDE drives to spin up after an IDE - reset. - ARTPEC-1 support CONFIG_JULIETTE The ARTPEC-1 is a video-compression chip used in the AXIS 2100 @@ -23411,42 +23864,6 @@ with a B-step CPU. You have a B-step CPU if the "revision" field in /proc/cpuinfo has a value in the range from 1 to 4. -Enable Itanium B0-step specific code -CONFIG_ITANIUM_B0_SPECIFIC - Select this option to build a kernel for an Itanium prototype system - with a B0-step CPU. You have a B0-step CPU if the "revision" field - in /proc/cpuinfo is 1. - -Enable Itanium C-step specific code -CONFIG_ITANIUM_CSTEP_SPECIFIC - Select this option to build a kernel for an Itanium prototype system - with a C-step CPU. You have a C-step CPU if the "revision" field in - /proc/cpuinfo is in the range of 5 to 8. - -Enable Itanium B1-step specific code -CONFIG_ITANIUM_B1_SPECIFIC - Select this option to build a kernel for an Itanium prototype system - with a B1-step CPU. You have a B1-step CPU if the "revision" field - in /proc/cpuinfo is 2. - -Enable Itanium B2-step specific code -CONFIG_ITANIUM_B2_SPECIFIC - Select this option to build a kernel for an Itanium prototype system - with a B2-step CPU. You have a B2-step CPU if the "revision" field - in /proc/cpuinfo is 3. - -Enable Itanium C0-step specific code -CONFIG_ITANIUM_C0_SPECIFIC - Select this option to build a kernel for an Itanium prototype system - with a C0-step CPU. You have a C0-step CPU if the "revision" field - in /proc/cpuinfo is 5. - -Force interrupt redirection -CONFIG_IA64_HAVE_IRQREDIR - Select this option if you know that your system has the ability to - redirect interrupts to different CPUs. Select N here if you're - unsure. - Enable IA-64 Machine Check Abort CONFIG_IA64_MCA Say Y here to enable machine check support for IA-64. If you're @@ -23529,6 +23946,44 @@ To use this option, you have to check that the "/proc file system support" (CONFIG_PROC_FS) is enabled, too. +16MB granules +CONFIG_IA64_GRANULE_16MB + IA64 identity-mapped regions use a large page size. We'll call such + large pages "granules". If you can think of a better name that's + unambiguous, let us know... Unless your identity-mapped regions are + very large, select a granule size of 16MB. + +64MB granules +CONFIG_IA64_GRANULE_64MB + IA64 identity-mapped regions use a large page size. We'll call such + large pages "granules". If you can think of a better name that's + unambiguous, let us know... Unless your identity-mapped regions are + very large, select a granule size of 16MB. (This is the "large" + choice.) + +Enable SGI SN extra debugging code +CONFIG_IA64_SGI_SN_DEBUG + Turns on extra debugging code in the SGI SN (Scalable NUMA) platform + for IA64. Unless you are debugging problems on an SGI SN IA64 box, + say N. + +Enable SGI Medusa Simulator Support +CONFIG_IA64_SGI_SN_SIM + If you are compiling a kernel that will run under SGI's IA64 + simulator (Medusa) then say Y, otherwise say N. + +PCIBA support +CONFIG_PCIBA + IRIX PCIBA-inspired user mode PCI interface for the SGI SN (Scalable + NUMA) platform for IA64. Unless you are compiling a kernel for an + SGI SN IA64 box, say N. + +Enable protocol mode for the L1 console +SERIAL_SGI_L1_PROTOCOL + Uses protocol mode instead of raw mode for the level 1 console on the + SGI SN (Scalable NUMA) platform for IA64. If you are compiling for + an SGI SN box then Y is the recommended value, otherwise say N. + Directly Connected Compact Flash support CONFIG_CF_ENABLER Compact Flash is a small, removable mass storage device introduced @@ -23554,7 +24009,7 @@ allocation as well as poisoning memory on free to catch use of freed memory. -Memory mapped I/O debug support +Memory mapped I/O debugging 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() @@ -23570,6 +24025,19 @@ best used in conjunction with the NMI watchdog so that spinlock deadlocks are also debuggable. +Read-write spinlock debugging +CONFIG_DEBUG_RWLOCK + If you say Y here then read-write lock processing will count how many + times it has tried to get the lock and issue an error message after + too many attempts. If you suspect a rwlock problem or a kernel + hacker asks for this option then say Y. Otherwise say N. + +Semaphore debugging +CONFIG_DEBUG_SEMAPHORE + If you say Y here then semaphore processing will issue lots of + verbose debugging messages. If you suspect a semaphore problem or a + kernel hacker asks for this option then say Y. Otherwise say N. + Verbose BUG() reporting (adds 70K) CONFIG_DEBUG_BUGVERBOSE Say Y here to make BUG() panics output the file name and line number @@ -23726,18 +24194,12 @@ SolutionEngine CONFIG_SH_SOLUTION_ENGINE Select SolutionEngine if configuring for a Hitachi SH7709 - or SH7750 evalutation board. + or SH7750 evaluation board. 7751 SolutionEngine CONFIG_SH_7751_SOLUTION_ENGINE Select 7751 SolutionEngine if configuring for a Hitachi SH7751 - evalutation board. - -Overdrive -CONFIG_SH_OVERDRIVE - Select Overdrive if configuring for a ST407750 Overdrive board. - More information at - . + evaluation board. HP620 CONFIG_SH_HP620 @@ -23827,7 +24289,7 @@ CONFIG_MEMORY_START Computers built with Hitachi SuperH processors always map the ROM starting at address zero. But the processor - does not specify the range that RAM takes. + does not specify the range that RAM takes. The physical memory (RAM) start address will be automatically set to 08000000, unless you selected one of the following @@ -23887,7 +24349,7 @@ The default setting of the HD64465 IO base address is 0xb0000000. Do not change this unless you know what you are doing. - + Early printk support CONFIG_SH_EARLY_PRINTK Say Y here to redirect kernel printk messages to the serial port @@ -24258,5 +24720,6 @@ # case-fold-search:nil # fill-prefix:" " # adaptive-fill:nil +# compile-command: "egrep -n '^ .{71,}' Configure.help /dev/null" # fill-column:70 # End: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/DMA-mapping.txt linux-2.5/Documentation/DMA-mapping.txt --- linux-2.5.1/Documentation/DMA-mapping.txt Fri Oct 12 22:35:53 2001 +++ linux-2.5/Documentation/DMA-mapping.txt Thu Dec 27 16:32:30 2001 @@ -686,6 +686,97 @@ This is possible with the DAC interfaces purely because they are not translated in any way. + Optimizing Unmap State Space Consumption + +On many platforms, pci_unmap_{single,page}() is simply a nop. +Therefore, keeping track of the mapping address and length is a waste +of space. Instead of filling your drivers up with ifdefs and the like +to "work around" this (which would defeat the whole purpose of a +portable API) the following facilities are provided. + +Actually, instead of describing the macros one by one, we'll +transform some example code. + +1) Use DECLARE_PCI_UNMAP_{ADDR,LEN} in state saving structures. + Example, before: + + struct ring_state { + struct sk_buff *skb; + dma_addr_t mapping; + __u32 len; + }; + + after: + + struct ring_state { + struct sk_buff *skb; + DECLARE_PCI_UNMAP_ADDR(mapping) + DECLARE_PCI_UNMAP_LEN(len) + }; + + NOTE: DO NOT put a semicolon at the end of the DECLARE_*() + macro. + +2) Use PCI_UNMAP_{ADDR,LEN}_SET to set these values. + Example, before: + + ringp->mapping = FOO; + ringp->len = BAR; + + after: + + PCI_UNMAP_ADDR_SET(ringp, mapping, FOO); + PCI_UNMAP_LEN_SET(ringp, len, BAR); + +3) Use PCI_UNMAP_{ADDR,LEN} to access these values. + Example, before: + + pci_unmap_single(pdev, ringp->mapping, ringp->len, + PCI_DMA_FROMDEVICE); + + after: + + pci_unmap_single(pdev, + PCI_UNMAP_ADDR(ringp, mapping), + PCI_UNMAP_LEN(ringp, len), + PCI_DMA_FROMDEVICE); + +It really should be self-explanatory. We treat the ADDR and LEN +seperately, because it is possible for an implementation to only +need the address in order to perform the unmap operation. + + Platform Issues + +If you are just writing drivers for Linux and do not maintain +an architecture port for the kernel, you can safely skip down +to "Closing". + +1) Struct scatterlist requirements. + + Struct scatterlist must contain, at a minimum, the following + members: + + char *address; + struct page *page; + unsigned int offset; + unsigned int length; + + The "address" member will disappear in 2.5.x + + This means that your pci_{map,unmap}_sg() and all other + interfaces dealing with scatterlists must be able to cope + properly with page being non NULL. + + A scatterlist is in one of two states. The base address is + either specified by "address" or by a "page+offset" pair. + If "address" is NULL, then "page+offset" is being used. + If "page" is NULL, then "address" is being used. + + In 2.5.x, all scatterlists will use "page+offset". But during + 2.4.x we still have to support the old method. + +2) More to come... + Closing This document, and the API itself, would not be in it's current diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/DocBook/Makefile linux-2.5/Documentation/DocBook/Makefile --- linux-2.5.1/Documentation/DocBook/Makefile Thu Nov 29 21:45:52 2001 +++ linux-2.5/Documentation/DocBook/Makefile Thu Jan 10 13:32:21 2002 @@ -98,6 +98,7 @@ $(TOPDIR)/drivers/sound/sound_firmware.c \ $(TOPDIR)/drivers/net/wan/syncppp.c \ $(TOPDIR)/drivers/net/wan/z85230.c \ + $(TOPDIR)/drivers/usb/hcd.c \ $(TOPDIR)/drivers/usb/usb.c \ $(TOPDIR)/drivers/video/fbmem.c \ $(TOPDIR)/drivers/video/fbcmap.c \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/DocBook/kernel-api.tmpl linux-2.5/Documentation/DocBook/kernel-api.tmpl --- linux-2.5.1/Documentation/DocBook/kernel-api.tmpl Thu Nov 29 21:45:52 2001 +++ linux-2.5/Documentation/DocBook/kernel-api.tmpl Thu Jan 10 13:32:21 2002 @@ -281,6 +281,14 @@ !Edrivers/usb/usb.c + Host Controller APIs + These APIs are only for use by host controller drivers, + most of which implement standard register interfaces such as + EHCI, OHCI, or UHCI. + +!Edrivers/usb/hcd.c + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/DocBook/kernel-hacking.tmpl linux-2.5/Documentation/DocBook/kernel-hacking.tmpl --- linux-2.5.1/Documentation/DocBook/kernel-hacking.tmpl Fri Oct 5 19:06:51 2001 +++ linux-2.5/Documentation/DocBook/kernel-hacking.tmpl Thu Dec 20 19:14:29 2001 @@ -18,8 +18,8 @@ - 2000 - Paul Russell + 2001 + Rusty Russell @@ -651,6 +651,29 @@ + + <function>cpu_to_be32()</function>/<function>be32_to_cpu()</function>/<function>cpu_to_le32()</function>/<function>le32_to_cpu()</function> + <filename class=headerfile>include/asm/byteorder.h</filename> + + + + The cpu_to_be32() family (where the "32" can + be replaced by 64 or 16, and the "be" can be replaced by "le") are + the general way to do endian conversions in the kernel: they + return the converted value. All variations supply the reverse as + well: be32_to_cpu(), etc. + + + + There are two major variations of these functions: the pointer + variation, such as cpu_to_be32p(), which take + a pointer to the given type, and return the converted value. The + other variation is the "in-situ" family, such as + cpu_to_be32s(), which convert value referred + to by the pointer, and return void. + + + <function>local_irq_save()</function>/<function>local_irq_restore()</function> <filename class=headerfile>include/asm/system.h</filename> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/IRQ-affinity.txt linux-2.5/Documentation/IRQ-affinity.txt --- linux-2.5.1/Documentation/IRQ-affinity.txt Fri Feb 25 06:41:16 2000 +++ linux-2.5/Documentation/IRQ-affinity.txt Sat Dec 22 22:20:24 2001 @@ -8,7 +8,7 @@ affinity then the value will not change from the default 0xffffffff. Here is an example of restricting IRQ44 (eth1) to CPU0-3 then restricting -the IRQ to CPU4-8 (this is an 8-CPU SMP box): +the IRQ to CPU4-7 (this is an 8-CPU SMP box): [root@moon 44]# cat smp_affinity ffffffff diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/cachetlb.txt linux-2.5/Documentation/cachetlb.txt --- linux-2.5.1/Documentation/cachetlb.txt Sun Oct 21 17:40:36 2001 +++ linux-2.5/Documentation/cachetlb.txt Thu Dec 13 16:32:35 2001 @@ -275,7 +275,7 @@ for example, uses this technique. The "address" parameter tells the virtual address where the - user will ultimately this page mapped. + user will ultimately have this page mapped. If D-cache aliasing is not an issue, these two routines may simply call memcpy/memset directly and do nothing more. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/filesystems/Locking linux-2.5/Documentation/filesystems/Locking --- linux-2.5.1/Documentation/filesystems/Locking Fri Feb 16 23:53:08 2001 +++ linux-2.5/Documentation/filesystems/Locking Thu Dec 13 16:32:35 2001 @@ -123,6 +123,10 @@ int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); int (*commit_write)(struct file *, struct page *, unsigned, unsigned); int (*bmap)(struct address_space *, long); + int (*flushpage) (struct page *, unsigned long); + int (*releasepage) (struct page *, int); + int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int); + locking rules: All may block BKL PageLocked(page) @@ -132,6 +136,8 @@ prepare_write: no yes commit_write: no yes bmap: yes +flushpage: no yes +releasepage: no yes ->prepare_write(), ->commit_write(), ->sync_page() and ->readpage() may be called from the request handler (/dev/loop). @@ -144,6 +150,15 @@ filesystems and by the swapper. The latter will eventually go away. All instances do not actually need the BKL. Please, keep it that way and don't breed new callers. + ->flushpage() is called when the filesystem must attempt to drop +some or all of the buffers from the page when it is being truncated. It +returns zero on success. If ->flushpage is zero, the kernel uses +block_flushpage() instead. + ->releasepage() is called when the kernel is about to try to drop the +buffers from the page in preparation for freeing it. It returns zero to +indicate that the buffers are (or may be) freeable. If ->flushpage is zero, +the kernel assumes that the fs has no private interest in the buffers. + Note: currently almost all instances of address_space methods are using BKL for internal serialization and that's one of the worst sources of contention. Normally they are calling library functions (in fs/buffer.c) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/filesystems/devfs/ChangeLog linux-2.5/Documentation/filesystems/devfs/ChangeLog --- linux-2.5.1/Documentation/filesystems/devfs/ChangeLog Sat Nov 24 21:06:43 2001 +++ linux-2.5/Documentation/filesystems/devfs/ChangeLog Thu Dec 27 21:24:25 2001 @@ -1794,3 +1794,72 @@ - Use "existing" directory in <_devfs_make_parent_for_leaf> - Use slab cache rather than fixed buffer for devfsd events +=============================================================================== +Changes for patch v199 + +- Removed obsolete usage of DEVFS_FL_NO_PERSISTENCE + +- Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir> + +- Fixed locking bug in <devfs_d_revalidate_wait> due to typo + +- Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from devfsd + or children +=============================================================================== +Changes for patch v200 + +- Ported to kernel 2.5.1-pre2 +=============================================================================== +Changes for patch v201 + +- Fixed bug in <devfsd_read>: was dereferencing freed pointer +=============================================================================== +Changes for patch v202 + +- Fixed bug in <devfsd_close>: was dereferencing freed pointer + +- Added process group check for devfsd privileges +=============================================================================== +Changes for patch v203 + +- Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete> +=============================================================================== +Changes for patch v204 + +- Removed long obsolete rc.devfs + +- Return old entry in <devfs_mk_dir> for 2.4.x kernels + +- Updated README from master HTML file + +- Increment refcount on module in <check_disc_changed> + +- Created <devfs_get_handle> and exported <devfs_put> + +- Increment refcount on module in <devfs_get_ops> + +- Created <devfs_put_ops> and used where needed to fix races + +- Added clarifying comments in response to preliminary EMC code review + +- Added poisoning to <devfs_put> + +- Improved debugging messages + +- Fixed unregister bugs in drivers/md/lvm-fs.c +=============================================================================== +Changes for patch v205 + +- Corrected (made useful) debugging message in <unregister> + +- Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs> + +- Fixed drivers/md/lvm-fs.c to create "lvm" entry + +- Added magic number to guard against scribbling drivers + +- Only return old entry in <devfs_mk_dir> if a directory + +- Defined macros for error and debug messages + +- Updated README from master HTML file diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/filesystems/devfs/README linux-2.5/Documentation/filesystems/devfs/README --- linux-2.5.1/Documentation/filesystems/devfs/README Sat Nov 24 21:06:43 2001 +++ linux-2.5/Documentation/filesystems/devfs/README Thu Dec 27 21:24:26 2001 @@ -3,7 +3,7 @@ Linux Devfs (Device File System) FAQ Richard Gooch -9-NOV-2001 +21-DEC-2001 ----------------------------------------------------------------------------- @@ -66,6 +66,9 @@ Making things work Alternatives to devfs +What I don't like about devfs +How to report bugs +Strange kernel messages Other resources @@ -557,8 +560,10 @@ Devfsd OK, if you're reading this, I assume you want to play with -devfs. First you need to compile devfsd, the device management daemon, -available at +devfs. First you should ensure that /usr/src/linux contains a +recent kernel source tree. Then you need to compile devfsd, the device +management daemon, available at + http://www.atnf.csiro.au/~rgooch/linux/. Because the kernel has a naming scheme which is quite different from the old naming scheme, you need to @@ -1470,6 +1475,8 @@ Making things work Alternatives to devfs What I don't like about devfs +How to report bugs +Strange kernel messages @@ -1733,6 +1740,93 @@ This is not even remotely true. As shown above, both code and data size are quite modest. + + +How to report bugs + +If you have (or think you have) a bug with devfs, please follow the +steps below: + + + +please make sure you have the latest devfs patches applied. The +latest kernel version might not have the latest devfs patches applied +yet (Linus is very busy) + + +save a copy of your complete kernel logs (preferably by +using the dmesg programme) for later inclusion in your bug +report. You may need to use the -s switch to increase the +internal buffer size so you can capture all the boot messages + + +try booting with devfs=dall passed to the kernel boot +command line (read the documentation on your bootloader on how to do +this), and save the result to a file. This may be quite verbose, and +it may overflow the messages buffer, but try to get as much of it as +you can + + +if you get an Oops, run ksymoops to decode it so that the +names of the offending functions are provided. A non-decoded Oops is +pretty useless + + +send a copy of your devfsd configuration file(s) + +send the bug report to me first. +Don't expect that I will see it if you post it to the linux-kernel +mailing list. Include all the information listed above, plus +anything else that you think might be relevant. Put the string +devfs somewhere in the subject line, so my mail filters mark +it as urgent + + + + +Here is a general guide on how to ask questions in a way that greatly +improves your chances of getting a reply: + +http://www.tuxedo.org/~esr/faqs/smart-questions.html. If you have +a bug to report, you should also read + +http://www.chiark.greenend.org.uk/~sgtatham/bugs.html. + + +Strange kernel messages + +You may see devfs-related messages in your kernel logs. Below are some +messages and what they mean (and what you should do about them, if +anything). + + + +devfs_register(fred): could not append to parent, err: -17 + +You need to check what the error code means, but usually 17 means +EEXIST. This means that a driver attempted to create an entry +fred in a directory, but there already was an entry with that +name. This is often caused by flawed boot scripts which untar a bunch +of inodes into /dev, as a way to restore permissions. This +message is harmless, as the device nodes will still +provide access to the driver (unless you use the devfs=only +boot option, which is only for dedicated souls:-). If you want to get +rid of these annoying messages, upgrade to devfsd-v1.3.20 and use the +recommended RESTORE directive to restore permissions. + + +devfs_mk_dir(bill): using old entry in dir: c1808724 "" + +This is similar to the message above, except that a driver attempted +to create a directory named bill, and the parent directory +has an entry with the same name. In this case, to ensure that drivers +continue to work properly, the old entry is re-used and given to the +driver. In 2.5 kernels, the driver is given a NULL entry, and thus, +under rare circumstances, may not create the require device nodes. +The solution is the same as above. + + + ----------------------------------------------------------------------------- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/filesystems/devfs/rc.devfs linux-2.5/Documentation/filesystems/devfs/rc.devfs --- linux-2.5.1/Documentation/filesystems/devfs/rc.devfs Wed Feb 16 23:42:05 2000 +++ linux-2.5/Documentation/filesystems/devfs/rc.devfs Thu Jan 1 00:00:00 1970 @@ -1,104 +0,0 @@ -#! /bin/sh -# -# /etc/rc.d/rc.devfs -# -# Linux Boot Scripts by Richard Gooch <rgooch@atnf.csiro.au> -# Copyright 1993-1999 under GNU Copyleft version 2.0. See /etc/rc for -# copyright notice. -# -# Save and restore devfs ownerships and permissions -# -# Written by Richard Gooch 11-JAN-1998 -# -# Updated by Richard Gooch 23-JAN-1998: Added "start" and "stop". -# -# Updated by Richard Gooch 5-AUG-1998: Robustness improvements by -# Roderich Schupp. -# -# Updated by Richard Gooch 9-AUG-1998: Took account of change from -# ".epoch" to ".devfsd". -# -# Updated by Richard Gooch 19-AUG-1998: Test and tty pattern patch -# by Roderich Schupp. -# -# Updated by Richard Gooch 24-MAY-1999: Use sed instead of tr. -# -# Last updated by Richard Gooch 25-MAY-1999: Don't save /dev/log. -# -# -# Usage: rc.devfs save|restore [savedir] [devfsdir] -# -# Note: "start" is a synonym for "restore" and "stop" is a synonym for "save". - -# Set VERBOSE to "no" if you would like a more quiet operation. -VERBOSE=yes - -# Set TAROPTS to "v" or even "vv" to see which files get saved/restored. -TAROPTS= - -option="$1" - -case "$option" in - save|restore) ;; - start) option=restore ;; - stop) option=save ;; - *) echo "No save or restore option given" ; exit 1 ;; -esac - -if [ "$2" = "" ]; then - savedir=/var/state -else - savedir=$2 -fi - -if [ ! -d $savedir ]; then - echo "Directory: $savedir does not exist" - exit 1 -fi - -if [ "$3" = "" ]; then - if [ -d /devfs ]; then - devfs=/devfs - else - devfs=/dev - fi -else - devfs=$3 -fi - -grep devfs /proc/filesystems >/dev/null || exit 0 - -if [ ! -d $devfs ]; then - echo "Directory: $devfs does not exist" - exit 1 -elif [ ! -c $devfs/.devfsd ]; then - echo "Directory: $devfs is not the root of a devfs filesystem" - exit 1 -fi - -savefile=`echo $devfs | sed 's*/*_*g'` -tarfile=${savedir}/devfssave.${savefile}.tar.gz - -cd $devfs - -case "$option" in - save) - [ "$VERBOSE" != no ] && echo "Saving $devfs permissions..." - - # You might want to adjust the pattern below to control - # which file's permissions will be saved. - # The sample pattern exludes all virtual consoles - # as well as old and new style pseudo terminals. - files=`find * -noleaf -cnewer .devfsd \ - ! -regex 'tty[0-9]+\|vc/.*\|vcsa?[0-9]+\|vcc/.*\|[pt]ty[a-z][0-9a-f]\|pt[ms]/.*\|log' -print` - rm -f $tarfile - [ -n "$files" ] && tar cz${TAROPTS}f $tarfile $files - ;; - - restore) - [ "$VERBOSE" != no ] && echo "Restoring $devfs permissions..." - [ -f $tarfile ] && tar xpz${TAROPTS}f $tarfile - ;; -esac - -exit 0 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/filesystems/tmpfs.txt linux-2.5/Documentation/filesystems/tmpfs.txt --- linux-2.5.1/Documentation/filesystems/tmpfs.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/filesystems/tmpfs.txt Thu Dec 13 16:32:35 2001 @@ -0,0 +1,102 @@ +Tmpfs is a file system which keeps all files in virtual memory. + + +Everything in tmpfs is temporary in the sense that no files will be +created on your hard drive. If you unmount a tmpfs instance, +everything stored therein is lost. + +tmpfs puts everything into the kernel internal caches and grows and +shrinks to accommodate the files it contains and is able to swap +unneeded pages out to swap space. It has maximum size limits which can +be adjusted on the fly via 'mount -o remount ...' + +If you compare it to ramfs (which was the template to create tmpfs) +you gain swapping and limit checking. Another similar thing is the RAM +disk (/dev/ram*), which simulates a fixed size hard disk in physical +RAM, where you have to create an ordinary filesystem on top. Ramdisks +cannot swap and you do not have the possibility to resize them. + +Since tmpfs lives completely in the page cache and on swap, all tmpfs +pages currently in memory will show up as cached. It will not show up +as shared or something like that. Further on you can check the actual +RAM+swap use of a tmpfs instance with df(1) and du(1). + + +tmpfs has the following uses: + +1) There is always a kernel internal mount which you will not see at + all. This is used for shared anonymous mappings and SYSV shared + memory. + + This mount does not depend on CONFIG_TMPFS. If CONFIG_TMPFS is not + set, the user visible part of tmpfs is not build. But the internal + mechanisms are always present. + +2) glibc 2.2 and above expects tmpfs to be mounted at /dev/shm for + POSIX shared memory (shm_open, shm_unlink). Adding the following + line to /etc/fstab should take care of this: + + 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). + + This mount is _not_ needed for SYSV shared memory. The internal + mount is used for that. (In the 2.3 kernel versions it was + necessary to mount the predecessor of tmpfs (shm fs) to use SYSV + shared memory) + +3) Some people (including me) find it very convenient to mount it + e.g. on /tmp and /var/tmp and have a big swap partition. But be + aware: loop mounts of tmpfs files do not work due to the internal + design. So mkinitrd shipped by most distributions will fail with a + tmpfs /tmp. + +4) And probably a lot more I do not know about :-) + + +tmpfs has a couple of mount options: + +size: The limit of allocated bytes for this tmpfs instance. The + default is half of your physical RAM without swap. If you + oversize your tmpfs instances the machine will deadlock + since the OOM handler will not be able to free that memory. +nr_blocks: The same as size, but in blocks of PAGECACHE_SIZE. +nr_inodes: The maximum number of inodes for this instance. The default + is half of the number of your physical RAM pages. + +These parameters accept a suffix k, m or g for kilo, mega and giga and +can be changed on remount. + +To specify the initial root directory you can use the following mount +options: + +mode: The permissions as an octal number +uid: The user id +gid: The group id + +These options do not have any effect on remount. You can change these +parameters with chmod(1), chown(1) and chgrp(1) on a mounted filesystem. + + +So 'mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs' +will give you tmpfs instance on /mytmpfs which can allocate 10GB +RAM/SWAP in 10240 inodes and it is only accessible by root. + + +TODOs: + +1) give the size option a percent semantic: If you give a mount option + size=50% the tmpfs instance should be able to grow to 50 percent of + RAM + swap. So the instance should adapt automatically if you add + or remove swap space. +2) loop mounts: This is difficult since loop.c relies on the readpage + operation. This operation gets a page from the caller to be filled + with the content of the file at that position. But tmpfs always has + the page and thus cannot copy the content to the given page. So it + cannot provide this operation. The VM had to be changed seriously + to achieve this. +3) Show the number of tmpfs RAM pages. (As shared?) + +Author: + Christoph Rohland <cr@sap.com>, 1.12.01 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/i386/boot.txt linux-2.5/Documentation/i386/boot.txt --- linux-2.5.1/Documentation/i386/boot.txt Wed Nov 7 22:46:01 2001 +++ linux-2.5/Documentation/i386/boot.txt Wed Jan 2 03:07:59 2002 @@ -2,7 +2,7 @@ ---------------------------- H. Peter Anvin <hpa@zytor.com> - Last update 2000-10-29 + Last update 2001-12-09 On the i386 platform, the Linux kernel uses a rather complicated boot convention. This has evolved partially due to historical aspects, as @@ -25,12 +25,15 @@ Protocol 2.01: (Kernel 1.3.76) Added a heap overrun warning. Protocol 2.02: (Kernel 2.4.0-test3-pre3) New command line protocol. - Lower the conventional memory ceiling. No overwrite + Lower the conventional memory ceiling. No overwrite of the traditional setup area, thus making booting safe for systems which use the EBDA from SMM or 32-bit BIOS entry points. zImage deprecated but still supported. +Protocol 2.03: (???) Explicitly makes the highest possible initrd address + available to the bootloader. + **** MEMORY LAYOUT @@ -45,7 +48,7 @@ 098000 +------------------------+ | Kernel setup | The kernel real-mode code. 090200 +------------------------+ - | Kernel boot sector | The kernel legacy boot sector. + | Kernel boot sector | The kernel legacy boot sector. 090000 +------------------------+ | Protected-mode kernel | The bulk of the kernel image. 010000 +------------------------+ @@ -62,7 +65,7 @@ When using bzImage, the protected-mode kernel was relocated to 0x100000 ("high memory"), and the kernel real-mode block (boot sector, setup, and stack/heap) was made relocatable to any address between -0x10000 and end of low memory. Unfortunately, in protocols 2.00 and +0x10000 and end of low memory. Unfortunately, in protocols 2.00 and 2.01 the command line is still required to live in the 0x9XXXX memory range, and that memory range is still overwritten by the early kernel. The 2.02 protocol fixes that. @@ -71,7 +74,7 @@ low memory touched by the boot loader -- as low as possible, since some newer BIOSes have begun to allocate some rather large amounts of memory, called the Extended BIOS Data Area, near the top of low -memory. The boot loader should use the "INT 12h" BIOS call to verify +memory. The boot loader should use the "INT 12h" BIOS call to verify how much low memory is available. Unfortunately, if INT 12h reports that the amount of memory is too @@ -123,6 +126,7 @@ 0224/2 2.01+ heap_end_ptr Free memory after setup end 0226/2 N/A pad1 Unused 0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line +022C/4 2.03+ initrd_addr_max Highest legal initrd address For backwards compatibility, if the setup_sects field contains 0, the real value is 4. @@ -180,9 +184,9 @@ The initrd should typically be located as high in memory as possible, as it may otherwise get overwritten by the early - kernel initialization sequence. However, it must never be - located above address 0x3C000000 if you want all kernels to - read it. + kernel initialization sequence. However, it must never be + located above the address specified in the initrd_addr_max + field. The initrd should be at least 4K page aligned. cmd_line_ptr: If the protocol version is 2.02 or higher, this is a 32-bit @@ -192,7 +196,15 @@ command line, in which case you can point this to an empty string (or better yet, to the string "auto".) If this field is left at zero, the kernel will assume that your boot loader - does not support the 2.02 protocol. + does not support the 2.02+ protocol. + + ramdisk_max: + The maximum address that may be occupied by the initrd + contents. For boot protocols 2.02 or earlier, this field is + not present, and the maximum address is 0x37FFFFFF. (This + address is defined as the address of the highest safe byte, so + if your ramdisk is exactly 131072 bytes long and this field is + 0x37FFFFFF, you can start your ramdisk at 0x37FE0000.) **** THE KERNEL COMMAND LINE @@ -254,14 +266,14 @@ if ( protocol >= 0x0202 ) { cmd_line_ptr = base_ptr + 0x9000; } else { - cmd_line_magic = 0xA33F; + cmd_line_magic = 0xA33F; cmd_line_offset = 0x9000; setup_move_size = 0x9100; } } else { /* Very old kernel */ - cmd_line_magic = 0xA33F; + cmd_line_magic = 0xA33F; cmd_line_offset = 0x9000; /* A very old kernel MUST have its real-mode code @@ -411,4 +423,3 @@ After completing your hook, you should jump to the address that was in this field before your boot loader overwrote it. - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/kernel-parameters.txt linux-2.5/Documentation/kernel-parameters.txt --- linux-2.5.1/Documentation/kernel-parameters.txt Wed Jun 20 18:21:33 2001 +++ linux-2.5/Documentation/kernel-parameters.txt Sat Dec 29 11:37:48 2001 @@ -125,6 +125,13 @@ BusLogic= [HW,SCSI] + cachesize= [BUGS=ix86] Override level 2 CPU cache size detection. + Sometimes CPU hardware bugs make them report the cache + size incorrectly. The kernel will attempt work arounds + to fix known problems, but for some CPUs it is not + possible to determine what the correct size should be. + This option provides an override for these situations. + cdu31a= [HW,CD] chandev= [HW,NET] diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/networking/decnet.txt linux-2.5/Documentation/networking/decnet.txt --- linux-2.5.1/Documentation/networking/decnet.txt Fri Feb 16 23:53:08 2001 +++ linux-2.5/Documentation/networking/decnet.txt Thu Dec 13 16:32:35 2001 @@ -4,20 +4,9 @@ 1) Other documentation.... o Project Home Pages - http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html - Kernel info + http://www.chygwyn.com/DECnet/ - Kernel info http://linux-decnet.sourceforge.net/ - Userland tools - - o FTP sites - ftp://ftp.sucs.swan.ac.uk/pub/Linux/DECnet/ - - Swansea University Computer Society DECnet Archive - (contains kernel patches and info) - - Mirror of userland tools on ftp.dreamtime.org - - Mirror of Alexey Kuznetsov's iproute2 package and - other utilities - - ftp://linux-decnet.sourceforge.net/pub/linux-decnet/ - - Patrick Caulfield's archive of userland tools and - Eduardo Serrat's kernel patches + http://www.sourceforge.net/projects/linux-decnet/ - Status page 2) Configuring the kernel @@ -31,9 +20,13 @@ you'll need the following options as well... CONFIG_DECNET_ROUTER (to be able to add/delete routes) - CONFIG_NETLINK (to allow rtnetlink) - CONFIG_RTNETLINK (for communication with the kernel routing layer) CONFIG_NETFILTER (will be required for the DECnet routing daemon) + + CONFIG_DECNET_ROUTE_FWMARK is optional + +Don't turn on SIOCGIFCONF support for DECnet unless you are really sure +that you need it, in general you won't and it can cause ifconfig to +malfunction. 3) Command line options diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/networking/dl2k.txt linux-2.5/Documentation/networking/dl2k.txt --- linux-2.5.1/Documentation/networking/dl2k.txt Mon Nov 19 23:19:42 2001 +++ linux-2.5/Documentation/networking/dl2k.txt Thu Dec 27 16:32:30 2001 @@ -1,7 +1,7 @@ D-Link DL2000-based Gigabit Ethernet Adapter Installation for Linux - Nov 12, 2001 + Nov 21, 2001 Contents ======== @@ -195,8 +195,8 @@ 2 10Mbps full duplex. 3 100Mbps half duplex. 4 100Mbps full duplex. - 5 1000Mbps full duplex. - 6 1000Mbps half duplex. + 5 1000Mbps half duplex. + 6 1000Mbps full duplex. By default, the NIC operates at autosense. Note that only 1000mbps_fd and 1000mbps_hd @@ -212,11 +212,24 @@ Jumbo frame usually improve the performance int gigabit. -int_count - Rx frame count each interrupt. -int_timeout - Rx DMA wait time for an interrupt. Proper - values of int_count and int_timeout bring - a conspicuous performance in the fast machine. - Ex. int_count=5 and int_timeout=750 +rx_coalesce - Rx frame count each interrupt. +rx_timeout - Rx DMA wait time for an interrupt. Proper + values of rx_coalesce and rx_timeout bring + a conspicuous performance in the fast machine. + Ex. rx_coalesce=5 and rx_timeout=750 + +tx_coalesce - Tx transmit count each TxComp interrupt. + Setting value larger than 1 will improve + performance, but this is possible to lower + stability in slow UP machines. By default, + tx_coalesce=8. (dl2k) + +tx_flow - Specifies the Tx flow control. If tx_flow=1, + the Tx flow control enable. + +rx_flow - Specifies the Rx flow control. If rx_flow=1, + the Rx flow control enable. + Configuration Script Sample =========================== diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/networking/ip-sysctl.txt linux-2.5/Documentation/networking/ip-sysctl.txt --- linux-2.5.1/Documentation/networking/ip-sysctl.txt Wed May 16 17:21:45 2001 +++ linux-2.5/Documentation/networking/ip-sysctl.txt Mon Jan 14 22:39:44 2002 @@ -309,13 +309,20 @@ ICMP ECHO requests sent to it or just those to broadcast/multicast addresses, respectively. -icmp_destunreach_rate - INTEGER -icmp_paramprob_rate - INTEGER -icmp_timeexceed_rate - INTEGER -icmp_echoreply_rate - INTEGER (not enabled per default) - Limit the maximal rates for sending ICMP packets to specific targets. +icmp_ratelimit - INTEGER + Limit the maximal rates for sending ICMP packets whose type matches + icmp_ratemask (see below) to specific targets. 0 to disable any limiting, otherwise the maximal rate in jiffies(1) - See the source for more information. + Default: 1 + +icmp_ratemask - INTEGER + Mask made of ICMP types for which rates are being limited. + Default: 6168 + Note: 6168 = 0x1818 = 1<<ICMP_DEST_UNREACH + 1<<ICMP_SOURCE_QUENCH + + 1<<ICMP_TIME_EXCEEDED + 1<<ICMP_PARAMETERPROB, which means + dest unreachable (3), source quench (4), time exceeded (11) + and parameter problem (12) ICMP packets are rate limited + (check values in icmp.h) icmp_ignore_bogus_error_responses - BOOLEAN Some routers violate RFC 1122 by sending bogus responses to broadcast diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/oops-tracing.txt linux-2.5/Documentation/oops-tracing.txt --- linux-2.5.1/Documentation/oops-tracing.txt Sun Sep 30 19:26:08 2001 +++ linux-2.5/Documentation/oops-tracing.txt Tue Jan 1 03:24:58 2002 @@ -219,6 +219,11 @@ 2: 'F' if any module was force loaded by insmod -f, ' ' if all modules were loaded normally. + 3: 'S' if the oops occured on an SMP kernel running on hardware that + hasn't been certified as safe to run multiprocessor. + Currently this occurs only on various Athlons that are not + SMP capable. + The primary reason for the 'Tainted: ' string is to tell kernel debuggers if this is a clean kernel or if anything unusual has occurred. Tainting is permanent, even if an offending module is diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/pci.txt linux-2.5/Documentation/pci.txt --- linux-2.5.1/Documentation/pci.txt Sun Nov 4 17:31:57 2001 +++ linux-2.5/Documentation/pci.txt Thu Dec 13 16:32:35 2001 @@ -104,6 +104,10 @@ If you are sure the driver is not a hotplug driver then use only __init/exit __initdata/exitdata. + Pointers to functions marked as __devexit must be created using + __devexit_p(function_name). That will generate the function + name or NULL if the __devexit function will be discarded. + 2. How to find PCI devices manually (the old style) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/s390/Debugging390.txt linux-2.5/Documentation/s390/Debugging390.txt --- linux-2.5.1/Documentation/s390/Debugging390.txt Wed Nov 7 22:46:01 2001 +++ linux-2.5/Documentation/s390/Debugging390.txt Thu Dec 27 16:32:30 2001 @@ -237,9 +237,10 @@ 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. +For backward compatibility ( because of the psw address hi bit which +indicates whether we are in 31 or 64 bit mode ) 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 on s/390, & more with the Extended memory managment swap device & @@ -2123,6 +2124,12 @@ now do p/x (*(**$sp+56))&0x7fffffff & so on. + +Another good trick to look at addresses on the stack if you've somehow lost +the backchain is. +x/500xa $sp +This displays anything the name of any known functions above the stack pointer +for 500 bytes. Disassembling instructions without debug info --------------------------------------------- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/sonypi.txt linux-2.5/Documentation/sonypi.txt --- linux-2.5.1/Documentation/sonypi.txt Thu Nov 29 15:53:34 2001 +++ linux-2.5/Documentation/sonypi.txt Tue Jan 8 01:17:10 2002 @@ -25,7 +25,8 @@ can be downloaded at: <http://www.alcove-labs.org/en/software/sonypi/> This driver supports also some ioctl commands for setting the LCD screen -brightness (some more commands may be added in the future). +brightness and querying the batteries charge information (some more +commands may be added in the future). This driver can also be used to set the camera controls on Picturebook series (brightness, contrast etc), and is used by the video4linux driver for the diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/sound/AudioExcelDSP16 linux-2.5/Documentation/sound/AudioExcelDSP16 --- linux-2.5.1/Documentation/sound/AudioExcelDSP16 Sat Nov 6 18:38:40 1999 +++ linux-2.5/Documentation/sound/AudioExcelDSP16 Mon Jan 14 22:39:44 2002 @@ -2,7 +2,7 @@ ------ Informations about Audio Excel DSP 16 driver can be found in the source -file lowlevel/aedsp16.c +file aedsp16.c Please, read the head of the source before using it. It contain useful informations. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/usb/auerswald.txt linux-2.5/Documentation/usb/auerswald.txt --- linux-2.5.1/Documentation/usb/auerswald.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/usb/auerswald.txt Tue Jan 8 00:44:24 2002 @@ -0,0 +1,30 @@ + Auerswald USB kernel driver + =========================== + +What is it? What can I do with it? +================================== +The auerswald USB kernel driver connects your linux 2.4.x +system to the auerswald usb-enabled devices. + +There are two types of auerswald usb devices: +a) small PBX systems (ISDN) +b) COMfort system telephones (ISDN) + +The driver installation creates the devices +/dev/usb/auer0..15. These devices carry a vendor- +specific protocol. You may run all auerswald java +software on it. The java software needs a native +library "libAuerUsbJNINative.so" installed on +your system. This library is available from +auerswald and shipped as part of the java software. + +You may create the devices with: + mknod -m 666 /dev/usb/auer0 c 180 80 + ... + mknod -m 666 /dev/usb/auer15 c 180 95 + +Future plans +============ +- Connection to ISDN4LINUX (the hisax interface) + +The maintainer of this driver is wmues@nexgo.de diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/usb/ehci.txt linux-2.5/Documentation/usb/ehci.txt --- linux-2.5.1/Documentation/usb/ehci.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/usb/ehci.txt Thu Jan 3 23:04:39 2002 @@ -0,0 +1,164 @@ +18-Dec-2001 + +The EHCI driver is used to talk to high speed USB 2.0 devices using +USB 2.0-capable host controller hardware. The USB 2.0 standard is +compatible with the USB 1.1 standard. It defines three transfer speeds: + + - "High Speed" 480 Mbit/sec (60 MByte/sec) + - "Full Speed" 12 Mbit/sec (1.5 MByte/sec) + - "Low Speed" 1.5 Mbit/sec + +USB 1.1 only addressed full speed and low speed. High speed devices +can be used on USB 1.1 systems, but they slow down to USB 1.1 speeds. + +USB 1.1 devices may also be used on USB 2.0 systems. When plugged +into an EHCI controller, they are given to a USB 1.1 "companion" +controller, which is a OHCI or UHCI controller as normally used with +such devices. When USB 1.1 devices plug into USB 2.0 hubs, they +interact with the EHCI controller through a "Transaction Translator" +(TT) in the hub, which turns low or full speed transactions into +high speed "split transactions" that don't waste transfer bandwidth. + +At this writing, high speed devices are finally beginning to appear. +While usb-storage devices have been available for some time (working +quite speedily on the 2.4 version of this driver), hubs have only +very recently become available. + +Note that USB 2.0 support involves more than just EHCI. It requires +other changes to the Linux-USB core APIs, including the hub driver, +but those changes haven't needed to really change the basic "usbcore" +APIs exposed to USB device drivers. + +- David Brownell + <dbrownell@users.sourceforge.net> + + +FUNCTIONALITY + +This driver is regularly tested on x86 hardware, and has also been +used on PPC hardware so big/little endianneess issues should be gone. +It's believed to do all the right PCI magic so that I/O works even on +systems with interesting DMA mapping issues. + +At this writing the driver should comfortably handle all control and bulk +transfers, including requests to USB 1.1 devices through transaction +translators (TTs) in USB 2.0 hubs. However, there some situations where +the hub driver needs to clear TT error state, which it doesn't yet do. + +Interrupt transfer support is newly functional and not yet as robust as +control and bulk traffic. As yet there is no support for split transaction +scheduling for interrupt transfers, which means among other things that +connecting USB 1.1 hubs, keyboards, and mice to USB 2.0 hubs won't work. +Connect them to USB 1.1 hubs, or to a root hub. + +Isochronous (ISO) transfer support is not yet working. No production +high speed devices are available which would need it (though high quality +webcams are in the works!). Note that split transaction support for ISO +transfers can't share much code with the code for high speed ISO transfers, +since EHCI represents these with a different data structure. + +The EHCI root hub code should hand off USB 1.1 devices to its companion +controller. This driver doesn't need to know anything about those +drivers; a OHCI or UHCI driver that works already doesn't need to change +just because the EHCI driver is also present. + +There are some issues with power management; suspend/resume doesn't +behave quite right at the moment. + + +USE BY + +Assuming you have an EHCI controller (on a PCI card or motherboard) +and have compiled this driver as a module, load this like: + + # modprobe ehci-hcd + +and remove it by: + + # rmmod ehci-hcd + +You should also have a driver for a "companion controller", such as +"ohci-hcd", "usb-ohci", "usb-uhci", or "uhci". In case of any trouble +with the EHCI driver, remove its module and then the driver for that +companion controller will take over (at lower speed) all the devices +that were previously handled by the EHCI driver. + +Module parameters (pass to "modprobe") include: + + log2_irq_thresh (default 0): + Log2 of default interrupt delay, in microframes. The default + value is 0, indicating 1 microframe (125 usec). Maximum value + is 6, indicating 2^6 = 64 microframes. This controls how often + the EHCI controller can issue interrupts. + +The EHCI interrupt handler just acknowledges interrupts and schedules +a tasklet to handle whatever needs handling. That keeps latencies low, +no matter how often interrupts are issued. + +Device drivers shouldn't care whether they're running over EHCI or not, +but they may want to check for "usb_device->speed == USB_SPEED_HIGH". +High speed devices can do things that full speed (or low speed) ones +can't, such as "high bandwidth" periodic (interrupt or ISO) transfers. + + +PERFORMANCE + +USB 2.0 throughput is gated by two main factors: how fast the host +controller can process requests, and how fast devices can respond to +them. The 480 Mbit/sec "raw transfer rate" is obeyed by all devices, +but aggregate throughput is also affected by issues like delays between +individual high speed packets, driver intelligence, and of course the +overall system load. Latency is also a performance concern. + +Bulk transfers are most often used where throughput is an issue. It's +good to keep in mind that bulk transfers are always in 512 byte packets, +and at most 13 of those fit into one USB 2.0 microframe. Eight USB 2.0 +microframes fit in a USB 1.1 frame; a microframe is 1 msec/8 = 125 usec. + +Hardware Performance + +At this writing, individual USB 2.0 devices tend to max out at around +20 MByte/sec transfer rates. This is of course subject to change; +and some devices now go faster, while others go slower. + +The NEC implementation of EHCI seems to have a hardware bottleneck +at around 28 MByte/sec aggregate transfer rate. While this is clearly +enough for a single device at 20 MByte/sec, putting three such devices +onto one bus does not get you 60 MByte/sec. The issue appears to be +that the controller hardware won't do concurrent USB and PCI access, +so that it's only trying six (or maybe seven) USB transactions each +microframe rather than thirteen. (Seems like a reasonable trade off +for a product that beat all the others to market by over a year!) +It's expected that newer implementations will better this, throwing +more silicon real estate at the problem so that new motherboard chip +sets will get closer to that 60 MByte/sec target. + +There's a minimum latency of one microframe (125 usec) for the host +to receive interrupts from the EHCI controller indicating completion +of requests. That latency is tunable; there's a module option. By +default ehci-hcd driver uses the minimum latency, which means that if +you issue a control or bulk request you can often expect to learn that +it completed in less than 250 usec (depending on transfer size). + +Software Performance + +To get even 20 MByte/sec transfer rates, Linux-USB device drivers will +need to keep the EHCI queue full. That means issuing large requests, +or using bulk queuing if a series of small requests needs to be issued. +When drivers don't do that, their performance results will show it. + +In typical situations, a usb_bulk_msg() loop writing out 4 KB chunks is +going to waste more than half the USB 2.0 bandwidth. Delays between the +I/O completion and the driver issuing the next request will take longer +than the I/O. If that same loop used 16 KB chunks, it'd be better; a +sequence of 128 KB chunks would waste a lot less. + +But rather than depending on such large I/O buffers to make synchronous +I/O be efficient, it's better to just queue all several (bulk) requests +to the HC, and wait for them all to complete (or be canceled on error). +Such URB queuing should work with all the USB 1.1 HC drivers too. + +TBD: Interrupt and ISO transfer performance issues. Those periodic +transfers are fully scheduled, so the main issue is likely to be how +to trigger "high bandwidth" modes. + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/usb/ov511.txt linux-2.5/Documentation/usb/ov511.txt --- linux-2.5.1/Documentation/usb/ov511.txt Mon Nov 13 04:45:18 2000 +++ linux-2.5/Documentation/usb/ov511.txt Sat Jan 5 16:38:08 2002 @@ -8,11 +8,11 @@ INTRODUCTION: This is a driver for the OV511, a USB-only chip used in many "webcam" devices. -Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. It +Any camera using the OV511/OV511+ and the OV6620/OV7610/20/20AE should work. +Video capture devices that use the Philips SAA7111A decoder also work. It supports streaming and capture of color or monochrome video via the Video4Linux -API. Most V4L apps are compatible with it, but a few video-conferencing programs -do not work yet. The following resolutions are supported: 640x480, 448x336, -384x288, 352x288, and 320x240. +API. Most V4L apps are compatible with it. Most resolutions with a width and +height that are a multiple of 8 are supported. If you need more information, please visit the OV511 homepage at the above URL. @@ -27,22 +27,25 @@ HOW TO USE IT: +Note: These are simplified instructions. For complete instructions see: + http://alpha.dyndns.org/ov511/install.html + You must have first compiled USB support, support for your specific USB host controller (UHCI or OHCI), and Video4Linux support for your kernel (I recommend -making them modules.) +making them modules.) Make sure "Enforce bandwidth allocation" is NOT enabled. -Next, (as root) from your appropriate modules directory (lib/modules/2.3.XX): +Next, (as root): - insmod usb/usbcore.o - insmod usb/usb-uhci.o <OR> insmod usb/ohci-hcd.o - insmod misc/videodev.o - insmod usb/ov511.o + modprobe usbcore + modprobe usb-uhci <OR> modprobe usb-ohci + modprobe videodev + modprobe ov511 If it is not already there (it usually is), create the video device: - mknod /dev/video c 81 0 + mknod /dev/video0 c 81 0 -Sometimes /dev/video is a symlink to /dev/video0 +Optionally, symlink /dev/video to /dev/video0 You will have to set permissions on this device to allow you to read/write from it: @@ -55,39 +58,40 @@ [Using vidcat:] - vidcat -s 640x480 > test.jpg + vidcat -s 640x480 -p c > test.jpg xview test.jpg [Using xawtv:] -You must make some modifications to the source and compile it before you use it. -(Note: this may not be applicable to versions other than 3.06) - -In src/Xawtv.ad, change xawtv.tv.width to 640 and xawtv.tv.height to 480. Next, -in src/grab-v4l.c, change SYNC_TIMEOUT from 1 to 2. Then, from the main xawtv -directory: +From the main xawtv directory: make clean ./configure make make install -Now you should be able to run xawtv. Right click for the options dialog. If -you get a scrambled image it is likely that you made a mistake in Xawtv.ad. -Try setting the size to 320x240 if all else fails. +Now you should be able to run xawtv. Right click for the options dialog. MODULE PARAMETERS: You can set these with: insmod ov511 NAME=VALUE There is currently no way to set these on a per-camera basis. - NAME: autoadjust - TYPE: integer (boolean) + NAME: autobright + TYPE: integer (Boolean) DEFAULT: 1 - DESC: The camera normally adjusts exposure, gain, and hue automatically. This - can be set to 0 to disable this automatic adjustment. Note that there is - currently no way to set these parameters manually once autoadjust is - disabled. + DESC: Brightness is normally under automatic control and can't be set + manually by the video app. Set to 0 for manual control. + + NAME: autogain + TYPE: integer (Boolean) + DEFAULT: 1 + DESC: Auto Gain Control enable. This feature is not yet implemented. + + NAME: autoexp + TYPE: integer (Boolean) + DEFAULT: 1 + DESC: Auto Exposure Control enable. This feature is not yet implemented. NAME: debug TYPE: integer (0-6) @@ -102,49 +106,23 @@ 5=highly repetitive mesgs NAME: fix_rgb_offset - TYPE: integer (boolean) + TYPE: integer (Boolean) DEFAULT: 0 DESC: Some people have reported that the blue component of the image is one or so lines higher than the red component. This is only apparent in images with white objects on black backgrounds at 640x480. Setting this - to 1 will realign the color planes correctly. NOTE: This is still - experimental and very buggy. You will likely need a fast (500 MHz) CPU. + to 1 will realign the color planes correctly. NOTE: You will likely + need a fast (500 MHz) CPU. NAME: snapshot - TYPE: integer (boolean) + TYPE: integer (Boolean) DEFAULT: 0 - DESC: Set to 1 to enable snapshot mode. read() will block until the snapshot - button is pressed. Note that this does not yet work with most apps, - including xawtv and vidcat. NOTE: See the section "TODO" for more info. - - NAME: sensor - TYPE: integer ([0, 1, 3]) - DEFAULT: [varies] - DESC: If you know that your camera sensor is not detected correctly, set this - parameter. This is a global option for all attached OV511 cameras. You - will probably never need to set this, but if you do, valid values are: - 0 for OV7620 - 1 for OV7620AE - 3 for OV7610 - - NAME: i2c_detect_tries - TYPE: integer (don't set it insanely high!) - DEFAULT: 5 - DESC: This is the number of times the driver will try to sync and detect the - internal i2c bus (which connects the OV511 and sensor). If you are - getting intermittent detection failures ("Failed to read sensor ID...") - you should increase this by a modest amount. If setting it to 20 or so - doesn't fix things, look elsewhere for the cause of the problem. - - NAME: aperture - TYPE: integer (0 - 15) - DEFAULT: [varies by sensor] - DESC: For legal values, see the OV7610/7620 specs under register Common F. - This setting affects the upper nybble of that reg (bits 4-7). This is - for if you want to play with the camera's pixel saturation. + DESC: Set to 1 to enable snapshot mode. read()/VIDIOCSYNC will block until + the snapshot button is pressed. Note: enabling this mode disables + /proc/video/ov511/<minor#>/button - NAME: force_rgb - TYPE: integer (boolean) + NAME: force_rgb (Deprecated; may be removed in the future) + TYPE: integer (Boolean) DEFAULT: 0 DESC: Force image to be read in RGB instead of BGR. This option allow programs that expect RGB data (e.g. gqcam) to work with this driver. If @@ -169,60 +147,179 @@ both OV511 and OV511+ cameras, trial-and-error may be necessary for finding the optimum setting. - NAME: retry_sync - TYPE: boolean + NAME: compress + TYPE: integer (Boolean) + DEFAULT: 0 + DESC: Set this to 1 to turn on the camera's compression engine. This can + potentially increase the frame rate at the expense of quality, if you + have a fast CPU. You must load the proper compression module for your + camera before starting your application (ov511_decomp or ov518_decomp). + + NAME: testpat + TYPE: integer (Boolean) DEFAULT: 0 - DESC: Prevent apps from timing out if frame is not done in time. This is - useful if you are having problems with Xawtv getting "stuck" on a frame - when your system is under heavy load. + DESC: This configures the camera's sensor to transmit a colored test-pattern + instead of an image. This does not work correctly yet. - NAME: sensor_gbr - TYPE: boolean + NAME: sensor_gbr (*** TEMPORARILY DISABLED ***) + TYPE: integer (Boolean) DEFAULT: 0 DESC: This makes the sensor output GBR422 instead of YUV420. This saves the driver the trouble of converting YUV to RGB, but it currently does not work very well (the colors are not quite right) + NAME: dumppix + TYPE: integer (0-2) + DEFAULT: 0 + DESC: Dumps raw pixel data and skips post-processing and format conversion. + It is for debugging purposes only. Options are: + 0: Disable (default) + 1: Dump raw data from camera, excluding headers and trailers + 2: Dumps data exactly as received from camera + + NAME: led + TYPE: integer (0-2) + DEFAULT: 1 (Always on) + DESC: Controls whether the LED (the little light) on the front of the camera + is always off (0), always on (1), or only on when driver is open (2). + This is only supported with the OV511+ chipset, and even then only on + some cameras (ones that actually have the LED wired to the control pin, + and not just hardwired to be on all the time). + + NAME: dump_bridge + TYPE: integer (Boolean) + DEFAULT: 0 + DESC: Dumps the bridge (OV511[+] or OV518[+]) register values to the system + log. Only useful for serious debugging/development purposes. + + NAME: dump_sensor + TYPE: integer (Boolean) + DEFAULT: 0 + DESC: Dumps the sensor register values to the system log. Only useful for + serious debugging/development purposes. + + NAME: printph + TYPE: integer (Boolean) + DEFAULT: 0 + DESC: Setting this to 1 will dump the first 12 bytes of each isoc frame. This + is only useful if you are trying to debug problems with the isoc data + stream (i.e.: camera initializes, but vidcat hangs until Ctrl-C). Be + warned that this dumps a large number of messages to your kernel log. + + NAME: phy, phuv, pvy, pvuv, qhy, qhuv, qvy, qvuv + TYPE: integer (0-63 for phy and phuv, 0-255 for rest) + DEFAULT: OV511 default values + DESC: These are registers 70h - 77h of the OV511, which control the + prediction ranges and quantization thresholds of the compressor, for + the Y and UV channels in the horizontal and vertical directions. See + the OV511 or OV511+ data sheet for more detailed descriptions. These + normally do not need to be changed. + + NAME: lightfreq + TYPE: integer (0, 50, or 60) + DEFAULT: 0 (use sensor default) + DESC: Sets the sensor to match your lighting frequency. This can reduce the + appearance of "banding", i.e. horizontal lines or waves of light and + dark that are often caused by artificial lighting. Valid values are: + 0 - Use default (depends on sensor, most likely 60 Hz) + 50 - For European and Asian 50 Hz power + 60 - For American 60 Hz power + + NAME: bandingfilter + TYPE: integer (Boolean) + DEFAULT: 0 (off) + DESC: Enables the sensor´s banding filter exposure algorithm. This reduces + or stabilizes the "banding" caused by some artificial light sources + (especially fluorescent). You might have to set lightfreq correctly for + this to work right. As an added bonus, this sometimes makes it + possible to capture your monitor´s output. + + NAME: fastset + TYPE: integer (Boolean) + DEFAULT: 0 (off) + DESC: Allows picture settings (brightness, contrast, color, and hue) to take + effect immediately, even in the middle of a frame. This reduces the + time to change settings, but can ruin frames during the change. Only + affects OmniVision sensors. + + NAME: force_palette + TYPE: integer (Boolean) + DEFAULT: 0 (off) + DESC: Forces the palette (color format) to a specific value. If an + application requests a different palette, it will be rejected, thereby + forcing it to try others until it succeeds. This is useful for forcing + greyscale mode with a color camera, for example. Supported modes are: + 0 (Allows all the following formats) + 1 VIDEO_PALETTE_GREY (Linear greyscale) + 3 VIDEO_PALETTE_RGB565 (565 16 bit RGB) + 4 VIDEO_PALETTE_RGB24 (24bit RGB) + 7 VIDEO_PALETTE_YUV422 (YUV422 capture) + 8 VIDEO_PALETTE_YUYV (YUV422 capture; same as 7) + 10 VIDEO_PALETTE_YUV420 (YUV 4:2:0 Planar) + 13 VIDEO_PALETTE_YUV422P (YUV 4:2:2 Planar) + 15 VIDEO_PALETTE_YUV420P (YUV 4:2:0 Planar, same as 10) + + NAME: tuner + TYPE: integer + DEFAULT: -1 (autodetect) + DESC: This sets the exact type of the tuner module in a device. This is set + automatically based on the custom ID of the OV511 device. In cases + where this fails, you can override this auto-detection. Please see + linux/drivers/media/video/tuner.h for a complete list. + + NAME: backlight + TYPE: integer (Boolean) + DEFAULT: 0 (off) + DESC: Setting this flag changes the exposure algorithm for OmniVision sensors + such that objects in the camera's view (i.e. your head) can be clearly + seen when they are illuminated from behind. It reduces or eliminates + the sensor's auto-exposure function, so it should only be used when + needed. Additionally, it is only supported with the OV6620 and OV7620. + + NAME: unit_video + TYPE: Up to 16 comma-separated integers + DEFAULT: 0,0,0... (automatically assign the next available minor(s)) + DESC: You can specify up to 16 minor numbers to be assigned to ov511 devices. + For example, "unit_video=1,3" will make the driver use /dev/video1 and + /dev/video3 for the first two devices it detects. Additional devices + will be assigned automatically starting at the first available device + node (/dev/video0 in this case). Note that you cannot specify 0 as a + minor number. This feature requires kernel version 2.4.5 or higher. + + NAME: remove_zeros + TYPE: integer (Boolean) + DEFAULT: 0 (do not skip any incoming data) + DESC: Setting this to 1 will remove zero-padding from incoming data. This + will compensate for the blocks of corruption that can appear when the + camera cannot keep up with the speed of the USB bus (eg. at low frame + resolutions). This feature is always enabled when compression is on. + WORKING FEATURES: - o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, and 320x240 - o RGB24, RGB565, YUV420, YUV422, YUYV, and YUV422P color - o Monochrome + o Color streaming/capture at most widths and heights that are multiples of 8. + o RGB24, RGB565, YUV420/YUV420P, YUV422/YUYV, and YUV422P color + o Monochrome (use force_palette=1 to enable) o Setting/getting of saturation, contrast, brightness, and hue (only some of them work the OV7620 and OV7620AE) o /proc status reporting + o SAA7111A video capture support at 320x240 and 640x480 + o Compression support EXPERIMENTAL FEATURES: - o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and - corrupted frames. If you have a very fast CPU, you can try it. - o Snapshot mode (only works with some read() based apps; see below for more) - o OV6620 sensor support - o GBR422 parsing - o 160x120 - -TODO: - o Fix the noise / grainy image problem. - o Get compression working. It would be a nice addition as it improves - frame rate quite a bit. OmniVision wouldn't tell me how the algorithm works, - so we can't really work on that yet. Please kindly inform OmniVision that you - would like them to release their specifications to the Linux community. - o YUV422 - o Fix fixFrameRGBoffset(). It is not stable yet with streaming video. - o V4L2 support (Probably not until it goes into the kernel) - o Get rid of the memory management functions (put them in videodev.c??) - o Setting of contrast and brightness not working with 7620/7620AE - o Driver/camera state save/restore for when USB supports suspend/resume - o Unstable on SMP systems - o OV7620/OV6620 experience frame corruption with moving objects - o OV6620 is too dark - o 176x144 support - o Driver sometimes hangs upon close() with OHCI - o The image should always be written properly to the mmap'ed buffer as long as - the requested image size is at least the minimum size. This will likely - require a rewrite of all the parsing code. + o OV6630 sensor support + o Banding filter + o SMP compatibility + +TO-DO: + o V4L2 support (This will be done after the next kernel patch release) + o Setting of hue not working with OV7620 + o Setting of contrast and hue not working with OV7620AE + o OV8600 sensor support (Not used in anything yet) + o OV518/OV518+ support (all that's needed is the decompressor) + o cams >= 3 not working HOW TO CONTACT ME: -You can email me at mwm@i.am . Please prefix the subject line +You can email me at mmcclell@bigfoot.com . Please prefix the subject line with "OV511: " so that I am certain to notice your message. CREDITS: @@ -232,3 +329,4 @@ and the USB stack. Thanks to Bret Wallach for getting camera reg IO, ISOC, and image capture working. Thanks to Orion Sky Lawlor, Kevin Moore, and Claudio Matsuoka for their work as well. + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/usb/se401.txt linux-2.5/Documentation/usb/se401.txt --- linux-2.5.1/Documentation/usb/se401.txt Wed Jun 27 20:59:32 2001 +++ linux-2.5/Documentation/usb/se401.txt Sat Jan 12 12:32:40 2002 @@ -40,7 +40,7 @@ KNOWN PROBLEMS: The driver works fine with the usb-ohci and uhci host controller drivers, -the default settings also work with usb-uhci. But sending more then one bulk +the default settings also work with usb-uhci. But sending more than one bulk transfer at a time with usb-uhci doesn't work yet. Users of usb-ohci and uhci can safely enlarge SE401_NUMSBUF in se401.h in order to increase the throughput (and thus framerate). diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/usb/stv680.txt linux-2.5/Documentation/usb/stv680.txt --- linux-2.5.1/Documentation/usb/stv680.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/usb/stv680.txt Thu Jan 3 23:04:39 2002 @@ -0,0 +1,55 @@ +Linux driver for STV0680 based USB cameras + +Copyright, 2001, Kevin Sisson + + +INTRODUCTION: + +STMicroelectronics produces the STV0680B chip, which comes in two +types, -001 and -003. The -003 version allows the recording and downloading +of sound clips from the camera, and allows a flash attachment. Otherwise, +it uses the same commands as the -001 version. Both versions support a +variety of SDRAM sizes and sensors, allowing for a maximum of 26 VGA or 20 +CIF pictures. The STV0680 supports either a serial or a usb interface, and +video is possible through the usb interface. + +The following cameras are known to work with this driver, although any +camera with Vendor/Product codes of 0553/0202 should work: + +Aiptek Pencam (various models) +Nisis QuickPix 2 +Radio Shack 'Kid's digital camera' (#60-1207) +At least one Trust Spycam model +Several other European brand models + +WHAT YOU NEED: + +- USB support +- VIDEO4LINUX support + +More information about USB support for linux can be found at: +http://www.linux-usb.org + + +MODULE OPTIONS: + +When the driver is compiled as a module, you can set a "swapRGB=1" +option, if necessary, for those applications that require it +(such as xawtv). However, the driver should detect and set this +automatically, so this option should not normally be used. + + +KNOWN PROBLEMS: + +The driver seems to work better with the usb-ohci than the usb-uhci host +controller driver. + +HELP: + +The latest info on this driver can be found at: +http://personal.clt.bellsouth.net/~kjsisson or at +http://stv0680-usb.sourceforge.net + +Any questions to me can be send to: kjsisson@bellsouth.net + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/usb/usb-serial.txt linux-2.5/Documentation/usb/usb-serial.txt --- linux-2.5.1/Documentation/usb/usb-serial.txt Mon Nov 12 17:50:39 2001 +++ linux-2.5/Documentation/usb/usb-serial.txt Thu Dec 27 16:32:30 2001 @@ -95,6 +95,66 @@ Kroah-Hartman at greg@kroah.com +Compaq iPAQ driver + + This driver can be used to connect to Compaq iPAQ PDAs running + Windows CE 3.0 using a USB autosync cable. It has been tested only on + the Compaq H3135. It should work with the H3600 and later models too. + It may work with other CE based handhelds as well. + + The driver presents a serial interface (usually on /dev/ttyUSB0) over + which one may run ppp and establish a TCP/IP link to the iPAQ. Once this + is done, you can transfer files, backup, download email etc. The most + significant advantage of using USB is speed - you can get 73 to 113 + kbytes/sec for download/upload to the iPAQ. + + The driver works intermittently with the usb-uhci driver but quite + reliably with the uhci driver. Make sure you have the right driver + loaded - usb-uhci is often the default. + + You must setup hotplug to invoke pppd as soon as the iPAQ is connected. + A ppp script like the one below may be used: + + #!/bin/bash + + MYIP=linux.box.ip + REMOTEIP=ipaq.ip + MYDNS=my.dns.server + killall -9 pppd + /usr/sbin/pppd /dev/ttyUSB0 \ + connect "/usr/sbin/chat -v TIMEOUT 60 CLIENT 'CLIENTSERVER\c'" \ + nocrtscts local debug passive $MYIP:$REMOTEIP ms-dns $MYDNS noauth \ + proxyarp + + You must also download and install asyncd from http://synce.sourceforge.net + This is required to emulate keep-alive packets which are exchanged by + ActiveSync and the iPAQ. + + On connecting the cable, you should see the usual "Device Connected", + "User Authenticated" messages flash by on your iPAQ. Once connected, + you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ + and other synce utilities from the Linux side. Remember to enable IP + forwarding. + + To use Pocket IE, follow the instructions given at + http://www.tekguru.co.uk/EM500/usbtonet.htm to achieve the same thing + on Win98. Omit the proxy server part; Linux is quite capable of forwarding + packets unlike Win98. Another modification is required at least for the + iPAQ - disable autosync by going to the Start/Settings/Connections menu + and unchecking the "Automatically synchronize ..." box. Go to + Start/Programs/Connections, connect the cable and select "usbdial" (or + whatever you named your new USB connection). You should finally wind + up with a "Connected to usbdial" window with status shown as connected. + Now start up PIE and browse away. + + If it doesn't work for some reason, load both the usbserial and ipaq module + with the module parameter "debug" set to 1 and examine the system log. + You can also try soft-resetting your iPAQ before attempting a connection. + + For any questions or problems with the driver, please contact Ganesh + Varadarajan <ganesh@veritas.com> + + Keyspan PDA Serial Adapter Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly @@ -301,6 +361,32 @@ For any questions or problems with this driver, please contact Greg Kroah-Hartman at greg@kroah.com + +KL5KUSB105 chipset / PalmConnect USB single-port adapter + +Current status: + The driver was put together by looking at the usb bus transactions + done by Palm's driver under Windows, so a lot of functionality is + still missing. Notably, serial ioctls are sometimes faked or not yet + implemented. Support for finding out about DSR and CTS line status is + however implemented (though not nicely), so your favorite autopilot(1) + and pilot-manager -daemon calls will work. Baud rates up to 115200 + are supported, but handshaking (software or hardware) is not, which is + why it is wise to cut down on the rate used is wise for large + transfers until this is settled. + +Options supported: + If this driver is compiled as a module you can pass the following + options to it: + debug - extra verbose debugging info + (default: 0; nonzero enables) + use_lowlatency - use low_latency flag to speed up tty layer + when reading from from the device. + (default: 0; nonzero enables) + + See http://www.uuhaus.de/linux/palmconnect.html for up-to-date + information on this driver. + Generic Serial driver diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/video4linux/Zoran linux-2.5/Documentation/video4linux/Zoran --- linux-2.5.1/Documentation/video4linux/Zoran Wed Jul 4 21:41:33 2001 +++ linux-2.5/Documentation/video4linux/Zoran Thu Dec 13 16:32:35 2001 @@ -160,9 +160,9 @@ 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 + http://www.polyware.nl/~middelin/hob-v4l.html#bigphysarea + You also have to compile your driver AFTER installing that patch in + order to get it working or diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Documentation/video4linux/w9966.txt linux-2.5/Documentation/video4linux/w9966.txt --- linux-2.5.1/Documentation/video4linux/w9966.txt Wed Jul 4 21:41:33 2001 +++ linux-2.5/Documentation/video4linux/w9966.txt Thu Dec 13 16:32:35 2001 @@ -1,37 +1,33 @@ +W9966 Camera driver, written by Jakob Kemi (jakob.kemi@telia.com) -W9966 Camera driver, written by Jakob Kemi (jakob.kemi@post.utfors.se) +After a lot of work in softice & wdasm, reading .pdf-files and tiresome +trial-and-error work I've finally got everything to work. I needed vision for a +robotics project so I borrowed this camera from a friend and started hacking. +Anyway I've converted my original code from the AVR 8bit RISC C/ASM code into +a working Linux driver. -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 +To get it working simply configure your kernel to support +parport, ieee1284, video4linux and w9966 -If w9966 is statically linked it will perform aggressive probing -for the camera. If built as a module you'll have more configuration options. +If w9966 is statically linked it will always perform aggressive probing for +the camera. If built as a module you'll have more configuration options. Options: -modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp) - + modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp) 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 -(http://hem.fyristorg.com/mogul/w9966.html) and with gqcam. -(you'll need to tweak the code to qcam a bit to make it work, -dimensions and such) +The only thing to keep in mind is that the image format is in Y-U-Y-V format +where every two pixels take 4 bytes. In SDL (www.libsdl.org) this format +is called VIDEO_PALETTE_YUV422 (16 bpp). + +A minimal test application (with source) is available from: + http://hem.fyristorg.com/mogul/w9966.html The slow framerate is due to missing DMA ECP read support in the parport drivers. I might add working EPP support later. Good luck! - - /Jakob + /Jakob Kemi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/MAINTAINERS linux-2.5/MAINTAINERS --- linux-2.5.1/MAINTAINERS Mon Dec 10 18:39:20 2001 +++ linux-2.5/MAINTAINERS Mon Jan 14 22:39:44 2002 @@ -145,6 +145,14 @@ W: http://www.ibm.com/linux/ltc/ S: Supported +AACRAID SCSI RAID DRIVER +P: Adaptec OEM Raid Solutions +M: linux-aacraid-devel@dell.com +L: linux-aacraid-devel@dell.com +L: linux-aacraid-announce@dell.com +W: http://domsch.com/linux +S: Supported + ACPI P: Andy Grover M: andrew.grover@intel.com @@ -412,6 +420,12 @@ L: linux-decnet-user@lists.sourceforge.net S: Maintained +DELL LAPTOP SMM DRIVER +P: Massimo Dal Zotto +M: dz@debian.org +W: http://www.debian.org/~dz/i8k/ +S: Maintained + DEVICE NUMBER REGISTRY P: H. Peter Anvin M: hpa@zytor.com @@ -843,7 +857,7 @@ M: vojtech@suse.cz L: linux-joystick@atrey.karlin.mff.cuni.cz W: http://www.suse.cz/development/joystick/ -S: Supported +S: Maintained KERNEL AUTOMOUNTER (AUTOFS) P: H. Peter Anvin @@ -926,6 +940,12 @@ W: http://www.sistina.com/lvm S: Maintained +LSILOGIC/SYMBIOS/NCR 53C8XX and 53C1010 PCI-SCSI drivers +P: Gerard Roudier +M: groudier@free.fr +L: linux-scsi@vger.kernel.org +S: Maintained + M68K P: Jes Sorensen M: jes@trained-monkey.org @@ -1010,6 +1030,11 @@ M: andrewtv@usa.net S: Maintained +NATSEMI ETHERNET DRIVER (DP8381x) +P: Tim Hockin +M: thockin@hockin.org +S: Maintained + NCP FILESYSTEM P: Petr Vandrovec M: vandrove@vc.cvut.cz @@ -1133,8 +1158,8 @@ S: Maintained OPL3-SA2, SA3, and SAx DRIVER -P: Scott Murray -M: scott@spiteful.org +P: Zwane Mwaikambo +M: zwane@commfireservices.com L: linux-sound@vger.kernel.org S: Maintained @@ -1243,6 +1268,12 @@ W: http://www.alarsen.net/linux/qnx4fs/ S: Maintained +RADEON FRAMEBUFFER DISPLAY DRIVER +P: Ani Joshi +M: ajoshi@shell.unixbox.com +L: linux-fbdev-devel@lists.sourceforge.net +S: Maintained + RAGE128 FRAMEBUFFER DISPLAY DRIVER P: Ani Joshi M: ajoshi@shell.unixbox.com @@ -1322,8 +1353,10 @@ S: Maintained SCSI SUBSYSTEM +P: Jens Axboe +M: axboe@suse.de L: linux-scsi@vger.kernel.org -S: Unmaintained +S: Maintained SCSI TAPE DRIVER P: Kai Mäkisara @@ -1538,7 +1571,7 @@ M: vojtech@suse.cz L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net -S: Supported +S: Maintained USB BLUETOOTH DRIVER P: Greg Kroah-Hartman @@ -1561,7 +1594,7 @@ L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net W: http://www.suse.cz/development/input/ -S: Supported +S: Maintained USB HUB P: Johannes Erdfelt @@ -1594,7 +1627,7 @@ USB OV511 DRIVER P: Mark McClelland -M: mwm@i.am +M: mmcclell@bigfoot.com L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net W: http://alpha.dyndns.org/ov511/ @@ -1612,7 +1645,7 @@ M: vojtech@suse.cz L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net -S: Supported +S: Maintained USB SE401 DRIVER P: Jeroen Vreeken @@ -1651,6 +1684,13 @@ L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net S: Supported + +USB AUERSWALD DRIVER +P: Wolfgang Muees +M: wmues@nexgo.de +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained USB SERIAL EMPEG EMPEG-CAR MARK I/II DRIVER P: Gary Brubaker diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Makefile linux-2.5/Makefile --- linux-2.5.1/Makefile Sun Dec 16 23:53:11 2001 +++ linux-2.5/Makefile Sun Jan 13 20:27:59 2002 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 1 -EXTRAVERSION = +EXTRAVERSION =-dj15 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -169,7 +169,7 @@ DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o -DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o +DRIVERS-$(CONFIG_PNP) += drivers/pnp/pnp.o DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a DRIVERS-$(CONFIG_VT) += drivers/video/video.o DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a @@ -204,7 +204,7 @@ drivers/scsi/aic7xxx/aicasm/aicasm_scan.c \ drivers/scsi/aic7xxx/aicasm/y.tab.h \ drivers/scsi/aic7xxx/aicasm/aicasm \ - drivers/scsi/53c700-mem.c \ + drivers/scsi/53c700_d.h \ net/khttpd/make_times_h \ net/khttpd/times.h \ submenu* @@ -329,11 +329,13 @@ @echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver @mv -f .ver $@ +comma := , + init/version.o: init/version.c include/linux/compile.h include/config/MARKER - $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DUTS_MACHINE='"$(ARCH)"' -c -o init/version.o init/version.c + $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DUTS_MACHINE='"$(ARCH)"' -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o init/version.o init/version.c init/main.o: init/main.c include/config/MARKER - $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -c -o $*.o $< + $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $*.o $< init/do_mounts.o: init/do_mounts.c include/config/MARKER $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -c -o $*.o $< diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/Rules.make linux-2.5/Rules.make --- linux-2.5.1/Rules.make Wed Mar 7 03:31:01 2001 +++ linux-2.5/Rules.make Sat Dec 29 11:10:40 2001 @@ -31,6 +31,8 @@ unexport subdir-n unexport subdir- +comma := , + # # Get things started. # @@ -54,7 +56,7 @@ $(CPP) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) $< > $@ %.o: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -c -o $@ $< + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -c -o $@ $< @ ( \ echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@))),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@))))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ @@ -270,7 +272,7 @@ ifneq "$(strip $(export-objs))" "" $(export-objs): $(export-objs:.o=.c) $(TOPDIR)/include/linux/modversions.h - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c) @ ( \ echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB)),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@) -DEXPORT_SYMTAB)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/alpha/kernel/alpha_ksyms.c linux-2.5/arch/alpha/kernel/alpha_ksyms.c --- linux-2.5.1/arch/alpha/kernel/alpha_ksyms.c Sun Nov 25 17:45:10 2001 +++ linux-2.5/arch/alpha/kernel/alpha_ksyms.c Sat Dec 22 00:11:28 2001 @@ -259,3 +259,8 @@ EXPORT_SYMBOL_NOVERS(memchr); EXPORT_SYMBOL(get_wchan); + +#ifdef CONFIG_ALPHA_IRONGATE +EXPORT_SYMBOL(irongate_ioremap); +EXPORT_SYMBOL(irongate_iounmap); +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/alpha/kernel/pci-noop.c linux-2.5/arch/alpha/kernel/pci-noop.c --- linux-2.5.1/arch/alpha/kernel/pci-noop.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/arch/alpha/kernel/pci-noop.c Sat Jan 5 16:38:08 2002 @@ -104,21 +104,21 @@ } /* stubs for the routines in pci_iommu.c */ void * -pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp) +pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) { } void -pci_free_consistent(struct pci_dev *pdev, long size, void *cpu_addr, +pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr, dma_addr_t dma_addr) { } dma_addr_t -pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, +pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size, int direction) { } void -pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, +pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size, int direction) { } @@ -126,6 +126,7 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) { + return 0; } void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/alpha/kernel/pci_iommu.c linux-2.5/arch/alpha/kernel/pci_iommu.c --- linux-2.5.1/arch/alpha/kernel/pci_iommu.c Mon Nov 5 17:47:41 2001 +++ linux-2.5/arch/alpha/kernel/pci_iommu.c Thu Jan 10 22:41:07 2002 @@ -30,6 +30,10 @@ #define DEBUG_NODIRECT 0 #define DEBUG_FORCEDAC 0 +/* Most Alphas support 32-bit ISA DMA. Exceptions are XL, Ruffian and + Nautilus (see asm/dma.h for details). */ +#define ISA_DMA_MASK (MAX_DMA_ADDRESS - IDENT_ADDR - 1 < 0xffffffff ? \ + MAX_DMA_ADDRESS - IDENT_ADDR - 1 : 0xffffffff) static inline unsigned long mk_iommu_pte(unsigned long paddr) @@ -181,7 +185,7 @@ int dac_allowed) { struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose; - dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + dma_addr_t max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK; struct pci_iommu_arena *arena; long npages, dma_ofs, i; unsigned long paddr; @@ -220,7 +224,7 @@ } arena = hose->sg_pci; - if (!arena || arena->dma_base + arena->size > max_dma) + if (!arena || arena->dma_base + arena->size - 1 > max_dma) arena = hose->sg_isa; npages = calc_npages((paddr & ~PAGE_MASK) + size); @@ -247,20 +251,27 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size, int dir) { + int dac_allowed; + if (dir == PCI_DMA_NONE) BUG(); - return pci_map_single_1(pdev, cpu_addr, size, - pdev ? (pdev->dma_mask >> 32) != 0 : 0); + + dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0; + return pci_map_single_1(pdev, cpu_addr, size, dac_allowed); } dma_addr_t pci_map_page(struct pci_dev *pdev, struct page *page, unsigned long offset, size_t size, int dir) { + int dac_allowed; + if (dir == PCI_DMA_NONE) BUG(); - return pci_map_single_1(pdev, (char *)page_address(page) + offset, - size, pdev ? (pdev->dma_mask >> 32) != 0 : 0); + + dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0; + return pci_map_single_1(pdev, (char *)page_address(page) + offset, + size, dac_allowed); } /* Unmap a single streaming mode DMA translation. The DMA_ADDR and @@ -558,7 +569,7 @@ if (direction == PCI_DMA_NONE) BUG(); - dac_allowed = ((pdev->dma_mask >> 32) != 0); + dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0; /* Fast path single entry scatterlists. */ if (nents == 1) { @@ -578,9 +589,9 @@ /* Second, figure out where we're going to map things. */ if (alpha_mv.mv_pci_tbi) { hose = pdev ? pdev->sysdata : pci_isa_hose; - max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK; arena = hose->sg_pci; - if (!arena || arena->dma_base + arena->size > max_dma) + if (!arena || arena->dma_base + arena->size - 1 > max_dma) arena = hose->sg_isa; } else { max_dma = -1; @@ -641,9 +652,9 @@ return; hose = pdev ? pdev->sysdata : pci_isa_hose; - max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK; arena = hose->sg_pci; - if (!arena || arena->dma_base + arena->size > max_dma) + if (!arena || arena->dma_base + arena->size - 1 > max_dma) arena = hose->sg_isa; fbeg = -1, fend = 0; @@ -710,11 +721,10 @@ struct pci_iommu_arena *arena; /* If there exists a direct map, and the mask fits either - MAX_DMA_ADDRESS defined such that GFP_DMA does something - useful, or the total system memory as shifted by the - map base. */ + the entire direct mapped space or the total system memory as + shifted by the map base */ if (__direct_map_size != 0 - && (__direct_map_base + MAX_DMA_ADDRESS-IDENT_ADDR-1 <= mask + && (__direct_map_base + __direct_map_size - 1 <= mask || __direct_map_base + (max_low_pfn<<PAGE_SHIFT)-1 <= mask)) return 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/alpha/kernel/process.c linux-2.5/arch/alpha/kernel/process.c --- linux-2.5.1/arch/alpha/kernel/process.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/arch/alpha/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -75,7 +75,6 @@ { /* An endless idle loop with no priority at all. */ current->nice = 20; - current->counter = -100; while (1) { /* FIXME -- EV6 and LCA45 know how to power down diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/alpha/kernel/setup.c linux-2.5/arch/alpha/kernel/setup.c --- linux-2.5.1/arch/alpha/kernel/setup.c Sat Nov 17 02:38:39 2001 +++ linux-2.5/arch/alpha/kernel/setup.c Thu Dec 27 15:56:12 2001 @@ -440,12 +440,6 @@ return MKDEV(TTY_MAJOR, 64 + c->index); } -static int srm_console_wait_key(struct console *co) -{ - /* Huh? */ - return 1; -} - static int __init srm_console_setup(struct console *co, char *options) { return 1; @@ -455,7 +449,6 @@ name: "srm0", write: srm_console_write, device: srm_console_device, - wait_key: srm_console_wait_key, setup: srm_console_setup, flags: CON_PRINTBUFFER | CON_ENABLED, /* fake it out */ index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/alpha/kernel/smp.c linux-2.5/arch/alpha/kernel/smp.c --- linux-2.5.1/arch/alpha/kernel/smp.c Wed Nov 21 18:31:09 2001 +++ linux-2.5/arch/alpha/kernel/smp.c Thu Dec 13 16:32:35 2001 @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/irq.h> +#include <linux/cache.h> #include <asm/hwrpb.h> #include <asm/ptrace.h> @@ -65,7 +66,7 @@ IPI_CPU_STOP, }; -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; /* Set to a secondary's cpuid when it comes online. */ static unsigned long smp_secondary_alive; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/alpha/lib/dec_and_lock.c linux-2.5/arch/alpha/lib/dec_and_lock.c --- linux-2.5.1/arch/alpha/lib/dec_and_lock.c Fri Nov 9 21:39:57 2001 +++ linux-2.5/arch/alpha/lib/dec_and_lock.c Sat Jan 5 16:38:08 2002 @@ -27,6 +27,7 @@ br $atomic_dec_and_lock_1..ng \n\ .subsection 2 \n\ 4: br 1b \n\ + .previous \n\ .end atomic_dec_and_lock"); static int __attribute__((unused)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/Makefile linux-2.5/arch/arm/Makefile --- linux-2.5.1/arch/arm/Makefile Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/arm/Makefile Sun Jan 6 01:38:26 2002 @@ -9,7 +9,7 @@ LINKFLAGS :=-p -X -T arch/arm/vmlinux.lds GZFLAGS :=-9 -CFLAGS +=-fno-common -pipe +CFLAGS +=-pipe ifneq ($(CONFIG_NO_FRAME_POINTER),y) CFLAGS :=$(CFLAGS:-fomit-frame-pointer=) @@ -22,9 +22,7 @@ # Select CPU dependent flags. Note that order of declaration is important; # the options further down the list override previous items. # -# Note! For APCS-26 YOU MUST HAVE AN APCS-26 LIBGCC.A -# -apcs-y :=-mapcs-32 +apcs-$(CONFIG_CPU_32) :=-mapcs-32 apcs-$(CONFIG_CPU_26) :=-mapcs-26 -mcpu=arm3 -Os # This selects which instruction set is used. @@ -32,6 +30,7 @@ arch-$(CONFIG_CPU_32v3) :=-march=armv3 arch-$(CONFIG_CPU_32v4) :=-march=armv4 arch-$(CONFIG_CPU_32v5) :=-march=armv5 +arch-$(CONFIG_CPU_XSCALE) :=-march=armv4 -Wa,-mxscale #-march=armv5te # This selects how we optimise for the processor. tune-y := @@ -39,15 +38,19 @@ tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710 tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi +tune-$(CONFIG_CPU_ARM922T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 +tune-$(CONFIG_CPU_XSCALE) :=-mtune=strongarm #-mtune=xscale +CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu -msoft-float ifeq ($(CONFIG_CPU_26),y) -PROCESSOR = armo +PROCESSOR := armo +HEAD := arch/arm/mach-arc/head.o arch/arm/kernel/init_task.o ifeq ($(CONFIG_ROM_KERNEL),y) DATAADDR = 0x02080000 TEXTADDR = 0x03800000 @@ -60,6 +63,7 @@ ifeq ($(CONFIG_CPU_32),y) PROCESSOR = armv +HEAD := arch/arm/kernel/head.o arch/arm/kernel/init_task.o TEXTADDR = 0xC0008000 LDSCRIPT = arch/arm/vmlinux-armv.lds.in endif @@ -134,51 +138,55 @@ MACHINE = anakin endif -export MACHINE PROCESSOR TEXTADDR GZFLAGS +ifeq ($(CONFIG_ARCH_IOP310),y) +MACHINE = iop310 +endif + +ifeq ($(CONFIG_ARCH_ADIFCC),y) +MACHINE = adifcc +endif + +export MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT # Only set INCDIR if its not already defined above # Grr, ?= doesn't work as all the other assignment operators do. Make bug? ifeq ($(origin INCDIR), undefined) -INCDIR := $(MACHINE) +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))) -SUBDIRS += $(MACHDIR) -CORE_FILES := $(MACHDIR)/$(MACHINE).o $(CORE_FILES) +# Do we have FASTFPE? +FASTFPE :=arch/arm/fastfpe +ifeq ($(FASTFPE),$(wildcard $(FASTFPE))) +SUBDIRS +=$(FASTFPE) +FASTFPE_OBJ :=$(FASTFPE)/fast-math-emu.o endif -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 -CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) -LIBS := arch/arm/lib/lib.a $(LIBS) +# If we have a machine-specific directory, then include it in the build. +SUBDIRS +=arch/arm/mach-$(MACHINE) \ + arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe +CORE_FILES :=arch/arm/mach-$(MACHINE)/$(MACHINE).o \ + arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) +LIBS :=arch/arm/lib/lib.a $(LIBS) ifeq ($(CONFIG_FPE_NWFPE),y) -LIBS := arch/arm/nwfpe/math-emu.o $(LIBS) +LIBS :=arch/arm/nwfpe/math-emu.o $(LIBS) endif -# Only include fastfpe if it is part of the kernel tree. -FASTFPE := arch/arm/fastfpe -ifeq ($(FASTFPE),$(wildcard $(FASTFPE))) -SUBDIRS += $(FASTFPE) ifeq ($(CONFIG_FPE_FASTFPE),y) -LIBS := arch/arm/fastfpe/fast-math-emu.o $(LIBS) -endif +LIBS :=$(FASTFPE_OBJ) $(LIBS) endif ifeq ($(findstring y,$(CONFIG_ARCH_CLPS7500) $(CONFIG_ARCH_L7200)),y) -SUBDIRS += drivers/acorn/char -DRIVERS += drivers/acorn/char/acorn-char.o +SUBDIRS +=drivers/acorn/char +DRIVERS +=drivers/acorn/char/acorn-char.o endif -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot -MAKETOOLS = $(MAKE) -C arch/$(ARCH)/tools +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 @@ -254,7 +262,7 @@ @( \ CFG=$(@:_config=); \ if [ -f arch/arm/def-configs/$$CFG ]; then \ - [ -f .config ] && $(MV) .config .config.old; \ + [ -f .config ] && mv -f .config .config.old; \ cp arch/arm/def-configs/$$CFG .config; \ echo "*** Default configuration for $$CFG installed"; \ echo "*** Next, you may run 'make oldconfig'"; \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/boot/Makefile linux-2.5/arch/arm/boot/Makefile --- linux-2.5.1/arch/arm/boot/Makefile Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/boot/Makefile Sun Jan 6 01:38:26 2002 @@ -118,6 +118,22 @@ ZTEXTADDR = 0x20008000 endif +ifeq ($(CONFIG_ARCH_IQ80310),y) +ZRELADDR = 0xa0008000 + +# for serial upload +ZTEXTADDR = 0xa1008000 + +# for direct flash execution +# ZTEXTADDR = 0x00060000 +# ZBSSADDR = 0xa1008000 +endif + +ifeq ($(CONFIG_ARCH_ADIFCC),y) +ZRELADDR = 0xc0008000 +ZTEXTADDR = 0xc1000000 +endif + # # If you don't define ZRELADDR above, # then it defaults to ZTEXTADDR diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/boot/compressed/Makefile linux-2.5/arch/arm/boot/compressed/Makefile --- linux-2.5.1/arch/arm/boot/compressed/Makefile Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/boot/compressed/Makefile Sun Jan 6 01:38:26 2002 @@ -9,7 +9,7 @@ HEAD = head.o OBJS = misc.o -CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC) -msoft-float +CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_BOOT) FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c ZLDFLAGS = -p -X -T vmlinux.lds @@ -57,6 +57,10 @@ endif endif +ifeq ($(CONFIG_CPU_XSCALE),y) +OBJS += head-xscale.o +endif + SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/; ifneq ($(ZBSSADDR),) @@ -84,12 +88,12 @@ font.o: $(FONTC) $(CC) $(CFLAGS) -Dstatic= -c -o $@ $(FONTC) -vmlinux.lds: vmlinux.lds.in +vmlinux.lds: vmlinux.lds.in Makefile $(TOPDIR)/arch/$(ARCH)/boot/Makefile $(TOPDIR)/.config @sed "$(SEDFLAGS)" < vmlinux.lds.in > $@ clean:; rm -f vmlinux core piggy* vmlinux.lds -.PHONY: vmlinux.lds clean +.PHONY: clean misc.o: misc.c $(TOPDIR)/include/asm/arch/uncompress.h $(TOPDIR)/lib/inflate.c diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/boot/compressed/head-shark.S linux-2.5/arch/arm/boot/compressed/head-shark.S --- linux-2.5.1/arch/arm/boot/compressed/head-shark.S Thu Apr 12 19:03:50 2001 +++ linux-2.5/arch/arm/boot/compressed/head-shark.S Sun Jan 6 01:38:26 2002 @@ -1,5 +1,5 @@ /* The head-file for the Shark - * by Alexander Schulz <aschulz@netwinder.org> + * by Alexander Schulz * * Does the following: * - get the memory layout from firmware. This can only be done as long as the mmu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/boot/compressed/head-xscale.S linux-2.5/arch/arm/boot/compressed/head-xscale.S --- linux-2.5.1/arch/arm/boot/compressed/head-xscale.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/boot/compressed/head-xscale.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,66 @@ +/* + * linux/arch/arm/boot/compressed/head-xscale.S + * + * XScale specific tweaks. This is merged into head.S by the linker. + * + */ + +#include <linux/config.h> +#include <linux/linkage.h> +#include <asm/mach-types.h> + + .section ".start", #alloc, #execinstr + +__XScale_start: + + @ Preserve r8/r7 i.e. kernel entry values + + @ Data cache might be active. + @ Be sure to flush kernel binary out of the cache, + @ whatever state it is, before it is turned off. + @ This is done by fetching through currently executed + @ memory to be sure we hit the same cache. + bic r2, pc, #0x1f + add r3, r2, #0x10000 @ 64 kb is quite enough... +1: ldr r0, [r2], #32 + teq r2, r3 + bne 1b + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c7, c7, 0 @ flush I & D caches + + @ disabling MMU and caches + mrc p15, 0, r0, c1, c0, 0 @ read control reg + bic r0, r0, #0x05 @ clear DC, MMU + bic r0, r0, #0x1000 @ clear Icache + mcr p15, 0, r0, c1, c0, 0 + +#ifdef CONFIG_ARCH_LUBBOCK + mov r7, #MACH_TYPE_LUBBOCK +#endif + +#ifdef CONFIG_ARCH_COTULLA_IDP + mov r7, #MACH_TYPE_COTULLA_IDP +#endif + +#ifdef CONFIG_ARCH_IQ80310 + /* + * Crank the CPU up to 733MHz + */ + mov r1, #9 + mcr p14, 0, r1, c6, c0, 0 + + /* + * Disable ECC error notification + * At some point, we should add an ECC handler to Linux + */ + mov r1, #0x1500 + mov r0, #0x4 + str r0, [r1, #0x34] + + mov r7, #MACH_TYPE_IQ80310 +#endif + +#ifdef CONFIG_ARCH_ADI_EVB + mov r7, #MACH_TYPE_ADI_EVB +#endif + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/boot/compressed/head.S linux-2.5/arch/arm/boot/compressed/head.S --- linux-2.5.1/arch/arm/boot/compressed/head.S Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/boot/compressed/head.S Sun Jan 6 01:38:26 2002 @@ -64,7 +64,7 @@ kphex r7, 8 /* architecture id */ kputc #':' mrc p15, 0, r0, c1, c0 - kphex r0, 8 /* control reg + kphex r0, 8 /* control reg */ kputc #'\n' kphex r5, 8 /* decompressed kernel start */ kputc #'-' @@ -218,7 +218,12 @@ ldr r1, proc_sa1110_type eor r1, r1, r6 movs r1, r1, lsr #4 - movne pc, lr + beq 1f + ldr r1, proc_xscale_type + eor r1, r1, r6 + movs r1, r1, lsr #16 +@ movne pc, lr + bne cache_off 1: sub r3, r4, #16384 @ Page directory size bic r3, r3, #0xff @ Align the pointer @@ -379,10 +384,14 @@ ldr r1, proc_sa1110_type eor r1, r1, r6 movs r1, r1, lsr #4 + beq 1f + ldr r1, proc_xscale_type + eor r1, r1, r6 + movs r1, r1, lsr #16 movne pc, lr 1: bic r1, pc, #31 - add r2, r1, #32768 + add r2, r1, #65536 @ 2x the largest dcache size 1: ldr r12, [r1], #32 @ s/w flush D cache teq r1, r2 bne 1b @@ -390,6 +399,12 @@ mcr p15, 0, r1, c7, c7, 0 @ flush I cache mcr p15, 0, r1, c7, c10, 4 @ drain WB mov pc, lr + + .type proc_xscale_type,#object +proc_xscale_type: + .word 0x69050000 + .size proc_xscale_type, . - proc_xscale_type + /* * Various debugging routines for printing hex characters and diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/boot/compressed/ofw-shark.c linux-2.5/arch/arm/boot/compressed/ofw-shark.c --- linux-2.5.1/arch/arm/boot/compressed/ofw-shark.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/boot/compressed/ofw-shark.c Sun Jan 6 01:38:26 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/boot/compressed/ofw-shark.c * - * by Alexander Schulz <aschulz@netwinder.org> + * by Alexander Schulz * * This file is used to get some basic information * about the memory layout of the shark we are running diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/config.in linux-2.5/arch/arm/config.in --- linux-2.5.1/arch/arm/config.in Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/arm/config.in Sun Jan 6 01:38:26 2002 @@ -33,7 +33,8 @@ comment 'System Type' choice 'ARM system type' \ - "Anakin CONFIG_ARCH_ANAKIN \ + "ADIFCC-based CONFIG_ARCH_ADIFCC \ + Anakin CONFIG_ARCH_ANAKIN \ Archimedes/A5000 CONFIG_ARCH_ARCA5K \ Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \ CLPS711x/EP721x-based CONFIG_ARCH_CLPS711X \ @@ -42,6 +43,7 @@ Epxa10db CONFIG_ARCH_CAMELOT \ FootBridge CONFIG_ARCH_FOOTBRIDGE \ Integrator CONFIG_ARCH_INTEGRATOR \ + IOP310-based CONFIG_ARCH_IOP310 \ LinkUp-L7200 CONFIG_ARCH_L7200 \ RiscPC CONFIG_ARCH_RPC \ SA1100-based CONFIG_ARCH_SA1100 \ @@ -85,7 +87,14 @@ 32MB CONFIG_SA1100_CERF_FLASH_32MB" CerfFlash bool 'Cerf w/CPLD support (CerfPDA)' CONFIG_SA1100_CERF_CPLD fi -dep_bool ' Compaq iPAQ H3600' CONFIG_SA1100_H3600 $CONFIG_ARCH_SA1100 +dep_bool ' Compaq iPAQ H3100' CONFIG_SA1100_H3100 $CONFIG_ARCH_SA1100 +dep_bool ' Compaq iPAQ H3600/H3700' CONFIG_SA1100_H3600 $CONFIG_ARCH_SA1100 +dep_bool ' Compaq iPAQ H3800' CONFIG_SA1100_H3800 $CONFIG_ARCH_SA1100 +if [ "$CONFIG_SA1100_H3100" = "y" -o "$CONFIG_SA1100_H3600" = "y" -o "$CONFIG_SA1100_H3800" = "y" ]; then + define_bool CONFIG_SA1100_H3XXX y +else + define_bool CONFIG_SA1100_H3XXX n +fi #dep_bool ' Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100 dep_bool ' Extenex HandHeld Theater (Squashtail)' CONFIG_SA1100_EXTENEX1 $CONFIG_ARCH_SA1100 if [ "$CONFIG_SA1100_EXTENEX1" = "y" ]; then @@ -103,6 +112,8 @@ dep_bool ' OmniMeter' CONFIG_SA1100_OMNIMETER $CONFIG_ARCH_SA1100 dep_bool ' Pangolin' CONFIG_SA1100_PANGOLIN $CONFIG_ARCH_SA1100 dep_bool ' PLEB' CONFIG_SA1100_PLEB $CONFIG_ARCH_SA1100 +dep_bool ' PT System 3' CONFIG_SA1100_PT_SYSTEM3 $CONFIG_ARCH_SA1100 +dep_bool ' Shannon' CONFIG_SA1100_SHANNON $CONFIG_ARCH_SA1100 dep_bool ' Sherman' CONFIG_SA1100_SHERMAN $CONFIG_ARCH_SA1100 dep_bool ' Simpad' CONFIG_SA1100_SIMPAD $CONFIG_ARCH_SA1100 dep_bool ' Tulsa' CONFIG_SA1100_PFS168 $CONFIG_ARCH_SA1100 @@ -116,14 +127,22 @@ "$CONFIG_SA1100_PFS168" = "y" -o \ "$CONFIG_SA1100_XP860" = "y" -o \ "$CONFIG_SA1100_GRAPHICSMASTER" = "y" -o \ + "$CONFIG_SA1100_PT_SYSTEM3" = "y" -o \ "$CONFIG_SA1100_ADSBITSY" = "y" ]; then define_bool CONFIG_SA1111 y define_int CONFIG_FORCE_MAX_ZONEORDER 9 fi + +dep_tristate 'SA1100 USB function support' CONFIG_SA1100_USB $CONFIG_ARCH_SA1100 +dep_tristate ' Support for SA11x0 USB network link function' CONFIG_SA1100_USB_NETLINK $CONFIG_SA1100_USB +dep_tristate ' Support for SA11x0 USB character device emulation' CONFIG_SA1100_USB_CHAR $CONFIG_SA1100_USB + +dep_tristate 'Compaq iPAQ Handheld sleeve support' CONFIG_H3600_SLEEVE $CONFIG_SA1100_H3600 endmenu mainmenu_option next_comment comment 'CLPS711X/EP721X Implementations' +dep_bool ' AUTCPU12' CONFIG_ARCH_AUTCPU12 $CONFIG_ARCH_CLPS711X dep_bool ' CDB89712' CONFIG_ARCH_CDB89712 $CONFIG_ARCH_CLPS711X dep_bool ' CLEP7312' CONFIG_ARCH_CLEP7312 $CONFIG_ARCH_CLPS711X dep_bool ' EDB7211' CONFIG_ARCH_EDB7211 $CONFIG_ARCH_CLPS711X @@ -148,6 +167,19 @@ fi endmenu +if [ "$CONFIG_ARCH_IOP310" = "y" ]; then + mainmenu_option next_comment + comment 'IOP310 Implementation Options' + choice 'IOP310 System Type' \ + "IQ80310 CONFIG_ARCH_IQ80310" IQ80310 + comment 'IOP310 Chipset Features' + bool 'Support Intel 80312 Application Accelerator Unit (EXPERIMENTAL)' CONFIG_IOP310_AAU + bool 'Support Intel 80312 DMA (EXPERIMENTAL)' CONFIG_IOP310_DMA + bool 'Support Intel 80312 Messaging Unit (EXPERIMENTAL)' CONFIG_IOP310_MU + bool 'Support Intel 80312 Performance Monitor (EXPERIMENTAL)' CONFIG_IOP310_PMON + endmenu +fi + # Definitions to make life easier if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \ "$CONFIG_ARCH_RPC" = "y" ]; then @@ -195,6 +227,8 @@ comment 'Processor Type' # Firstly, figure out what processor architecture version we should be using. +# This depends more on the machine type than anything else. + if [ "$CONFIG_ARCH_RPC" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then define_bool CONFIG_CPU_32v3 y else @@ -261,6 +295,21 @@ fi fi +# ARM922T +if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then + define_bool CONFIG_CPU_ARM922T y +else + define_bool CONFIG_CPU_ARM922T n +fi +if [ "$CONFIG_CPU_ARM922T" = "y" ]; then + bool ' ARM922T CPU idle' CONFIG_CPU_ARM922_CPU_IDLE + bool ' ARM922T I-Cache on' CONFIG_CPU_ARM922_I_CACHE_ON + bool ' ARM922T D-Cache on' CONFIG_CPU_ARM922_D_CACHE_ON + if [ "$CONFIG_CPU_ARM922_D_CACHE_ON" = "y" ] ; then + bool ' Force write through caches on ARM922T' CONFIG_CPU_ARM922_WRITETHROUGH + fi +fi + # ARM926T if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then bool 'Support ARM926T processor' CONFIG_CPU_ARM926T @@ -318,6 +367,22 @@ define_bool CONFIG_CPU_SA1100 n fi +# XScale +if [ "$CONFIG_ARCH_IOP310" = "y" -o "$CONFIG_ARCH_ADIFCC" = "y" ]; then + define_bool CONFIG_CPU_32v5 y + define_bool CONFIG_CPU_XSCALE y +fi + +#if [ "$CONFIG_CPU_XSCALE" = "y" ]; then +# bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER +#fi + +if [ "$CONFIG_CPU_XSCALE" = "y" -a "$CONFIG_XSCALE_PMU_TIMER" != "y" ]; then + define_bool CONFIG_XSCALE_PMU y +else + define_bool CONFIG_XSCALE_PMU n +fi + if [ "$CONFIG_CPU_32" = "y" ]; then dep_bool 'Support Thumb instructions (experimental)' CONFIG_ARM_THUMB $CONFIG_EXPERIMENTAL fi @@ -338,7 +403,8 @@ # Now handle the bus types if [ "$CONFIG_ARCH_FTVPCI" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ - "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then + "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ + "$CONFIG_ARCH_IOP310" = "y" ]; then define_bool CONFIG_PCI y else if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then @@ -349,6 +415,20 @@ fi fi +# Select the host bridge type +if [ "$CONFIG_PCI" = "y" ]; then + if [ "$CONFIG_ARCH_FTVPCI" = "y" ]; then + define_bool CONFIG_PCI_HOST_PLX90X0 y + else + define_bool CONFIG_PCI_HOST_PLX90X0 n + fi + if [ "$CONFIG_ARCH_SHARK" = "y" ]; then + define_bool CONFIG_PCI_HOST_VIA82C505 y + else + define_bool CONFIG_PCI_HOST_VIA82C505 n + fi +fi + if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_ARCH_CLPS7500" = "y" -o \ @@ -368,6 +448,13 @@ define_bool CONFIG_ISA_DMA n fi +if [ "$CONFIG_ARCH_ACORN" = "y" -o \ + "$CONFIG_ARCH_L7200" = "y" ]; then + define_bool CONFIG_FIQ y +else + define_bool CONFIG_FIQ n +fi + if [ "$CONFIG_ARCH_SA1100" = "y" -o \ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then dep_bool 'Support CPU clock change (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL @@ -393,7 +480,8 @@ 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 +bool 'Power Management support' CONFIG_PM +dep_tristate 'Advanced Power Management Emulation' CONFIG_APM $CONFIG_PM dep_tristate 'RISC OS personality' CONFIG_ARTHUR $CONFIG_CPU_32 if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ @@ -404,7 +492,9 @@ "$CONFIG_ARCH_P720T" = "y" -o \ "$CONFIG_ARCH_CDB89712" = "y" -o \ "$CONFIG_ARCH_CAMELOT" = "y" -o \ - "$CONFIG_ARCH_ANAKIN" = "y" ]; then + "$CONFIG_ARCH_ANAKIN" = "y" -o \ + "$CONFIG_ARCH_IOP310" = "y" -o \ + "$CONFIG_ARCH_ADIFCC" = "y" ]; then string 'Default kernel command string' CONFIG_CMDLINE "" fi if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ @@ -434,8 +524,16 @@ define_bool CONFIG_LEDS_TIMER y fi fi -if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then - bool 'Kernel-mode alignment trap handler' CONFIG_ALIGNMENT_TRAP + +if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + define_bool CONFIG_ALIGNMENT_TRAP y +else + if [ "$CONFIG_CPU_32" = "y" -a \ + "$CONFIG_ARCH_EBSA110" != "y" ]; then + bool 'Mis-alignment trap handler' CONFIG_ALIGNMENT_TRAP + else + define_bool CONFIG_ALIGNMENT_TRAP n + fi fi endmenu @@ -594,15 +692,20 @@ # Always compile kernel with framepointer (until 2.4 real comes out) # Bug reports aren't much use without this. 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 'Debug memory allocations' CONFIG_DEBUG_SLAB -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ -bool 'Spinlock debugging' CONFIG_DEBUG_SPINLOCK dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26 + +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL +dep_bool ' Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL +dep_bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_DEBUG_KERNEL +dep_bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK $CONFIG_DEBUG_KERNEL +dep_bool ' Wait queue debugging' CONFIG_DEBUG_WAITQ $CONFIG_DEBUG_KERNEL +dep_bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE $CONFIG_DEBUG_KERNEL +dep_bool ' Verbose kernel error messages' CONFIG_DEBUG_ERRORS $CONFIG_DEBUG_KERNEL # 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 +dep_bool ' Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_DEBUG_KERNEL +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 +dep_bool ' Kernel low-level debugging messages via SA1100 Ser3 (otherwise Ser1)' CONFIG_DEBUG_LL_SER3 $CONFIG_DEBUG_LL $CONFIG_ARCH_SA1100 endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/def-configs/adi_evb linux-2.5/arch/arm/def-configs/adi_evb --- linux-2.5.1/arch/arm/def-configs/adi_evb Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/def-configs/adi_evb Sun Jan 6 01:38:26 2002 @@ -0,0 +1,681 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +CONFIG_ARCH_ADIFCC=y +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP310 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +CONFIG_ARCH_ADI_EVB=y +CONFIG_XSCALE_PMU_TIMER=y +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +CONFIG_CPU_32v4=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y +# CONFIG_XSCALE_TOOLS is not set +CONFIG_XSCALE_WRITE_ALLOC=y +CONFIG_XSCALE_PMU=y +CONFIG_ARM_THUMB=y +# CONFIG_DISCONTIGMEM is not set + +# +# General setup +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/mtdblock1" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_BOOTLDR_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +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_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +CONFIG_MTD_ADI_EVB=y +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD 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 + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS 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_CISS_SCSI_TAPE 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=y +CONFIG_BLK_DEV_RAM_SIZE=4192 +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_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +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_ARPD 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 + +# +# 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_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 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_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring 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 + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD 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 + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV 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 + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO 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_INPUT_GAMEPORT 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 +# 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_CMS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG 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_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_FREEVXFS_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=y +# 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_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_INTERMEZZO_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 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 +# 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 +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# 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 + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_ID75 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_SLAB=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/def-configs/flexanet linux-2.5/arch/arm/def-configs/flexanet --- linux-2.5.1/arch/arm/def-configs/flexanet Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/def-configs/flexanet Sun Jan 6 01:38:26 2002 @@ -8,6 +8,8 @@ CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set # # Code maturity level options @@ -25,17 +27,19 @@ # # System Type # +# CONFIG_ARCH_ANAKIN is not set # CONFIG_ARCH_ARCA5K is not set # CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y -# CONFIG_ARCH_CLPS711X is not set -# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_SHARK is not set # # Archimedes/A5000 Implementations @@ -44,22 +48,32 @@ # # Archimedes/A5000 Implementations (select only ONE) # +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set # # Footbridge Implementations # +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set # # SA11x0 Implementations # # CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set # CONFIG_SA1100_BRUTUS is not set # CONFIG_SA1100_CERF is not set -# CONFIG_SA1100_BITSY is not set +# CONFIG_SA1100_H3600 is not set # CONFIG_SA1100_EXTENEX1 is not set CONFIG_SA1100_FLEXANET=y # CONFIG_SA1100_FREEBIRD is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set # CONFIG_SA1100_JORNADA720 is not set # CONFIG_SA1100_HUW_WEBPANEL is not set # CONFIG_SA1100_ITSY is not set @@ -68,7 +82,9 @@ # CONFIG_SA1100_OMNIMETER is not set # CONFIG_SA1100_PANGOLIN is not set # CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHANNON is not set # CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set # CONFIG_SA1100_PFS168 is not set # CONFIG_SA1100_VICTOR is not set # CONFIG_SA1100_XP860 is not set @@ -76,11 +92,17 @@ CONFIG_SA1100_USB=y CONFIG_SA1100_USB_NETLINK=y # CONFIG_SA1100_USB_CHAR is not set -# CONFIG_SA1100_FREQUENCY_SCALE is not set # # CLPS711X/EP721X Implementations # +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set # CONFIG_ARCH_ACORN is not set # CONFIG_FOOTBRIDGE is not set # CONFIG_FOOTBRIDGE_HOST is not set @@ -97,32 +119,40 @@ # CONFIG_CPU_ARM710 is not set # CONFIG_CPU_ARM720T is not set # CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set # CONFIG_CPU_ARM1020 is not set # CONFIG_CPU_SA110 is not set CONFIG_CPU_SA1100=y +# CONFIG_ARM_THUMB is not set CONFIG_DISCONTIGMEM=y -# CONFIG_CPU_BIG_ENDIAN is not set # # General setup # # CONFIG_PCI is not set -# CONFIG_ISA is not set +CONFIG_ISA=y # CONFIG_ISA_DMA is not set -# CONFIG_CPU_CLOCK is not set +CONFIG_CPU_FREQ=y CONFIG_HOTPLUG=y # # PCMCIA/CardBus support # CONFIG_PCMCIA=y +# CONFIG_I82092 is not set # CONFIG_I82365 is not set # CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set CONFIG_PCMCIA_SA1100=y CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# CONFIG_FPE_NWFPE=y CONFIG_FPE_FASTFPE=y CONFIG_KCORE_ELF=y @@ -130,7 +160,7 @@ # CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set -# CONFIG_PM is not set +CONFIG_PM=y # CONFIG_ARTHUR is not set CONFIG_CMDLINE="" CONFIG_LEDS=y @@ -149,7 +179,7 @@ CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set CONFIG_MTD_PARTITIONS=y -# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_REDBOOT_PARTS=y # CONFIG_MTD_BOOTLDR_PARTS is not set # CONFIG_MTD_AFS_PARTS is not set @@ -165,43 +195,42 @@ # RAM/ROM/Flash chip drivers # CONFIG_MTD_CFI=y -# CONFIG_MTD_CFI_VIRTUAL_ER is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y CONFIG_MTD_CFI_ADV_OPTIONS=y CONFIG_MTD_CFI_NOSWAP=y # CONFIG_MTD_CFI_BE_BYTE_SWAP is not set # CONFIG_MTD_CFI_LE_BYTE_SWAP is not set -# CONFIG_MTD_CFI_LART_BIT_SWAP is not set # CONFIG_MTD_CFI_GEOMETRY is not set CONFIG_MTD_CFI_INTELEXT=y # CONFIG_MTD_CFI_AMDSTD is not set -# CONFIG_MTD_AMDSTD is not set -# CONFIG_MTD_SHARP is not set # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set # CONFIG_MTD_JEDEC is not set # # Mapping drivers for chip access # # CONFIG_MTD_PHYSMAP is not set -# CONFIG_MTD_SUN_UFLASH is not set # CONFIG_MTD_NORA is not set -# CONFIG_MTD_PNC2000 is not set -# CONFIG_MTD_RPXLITE is not set -# CONFIG_MTD_SC520CDP is not set -# CONFIG_MTD_NETSC520 is not set -# CONFIG_MTD_SBC_GXX is not set -# CONFIG_MTD_ELAN_104NC is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set CONFIG_MTD_SA1100=y +# CONFIG_MTD_DC21285 is not set # CONFIG_MTD_IQ80310 is not set -# CONFIG_MTD_CFI_FLAGADM is not set -# CONFIG_MTD_ARMFLASH is not set +# CONFIG_MTD_PCI is not set # # Self-contained MTD device drivers # +# CONFIG_MTD_PMC551 is not set # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set # # Disk-On-Chip Device Drivers @@ -220,11 +249,17 @@ # Plug and Play configuration # # CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices # # CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_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=y # CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_RAM=y @@ -235,6 +270,13 @@ # 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_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set # # Networking options @@ -258,6 +300,7 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -293,42 +336,75 @@ # 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_ARM_AM79C961A is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set CONFIG_NET_VENDOR_SMC=y # CONFIG_WD80x3 is not set +# CONFIG_ULTRAMCA is not set # CONFIG_ULTRA is not set +# CONFIG_ULTRA32 is not set CONFIG_SMC9194=y # 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 # # Ethernet (1000 Mbit) # -# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 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_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set # # Wireless LAN (non-hamradio) # -# CONFIG_NET_RADIO is not set +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=m + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=m +# CONFIG_AIRO_CS is not set +CONFIG_NET_WIRELESS=y # # Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set # CONFIG_SHAPER is not set # @@ -347,8 +423,10 @@ # CONFIG_PCMCIA_NMCLAN is not set # CONFIG_PCMCIA_SMC91C92 is not set # CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set # CONFIG_NET_PCMCIA_RADIO is not set -CONFIG_PCMCIA_NETCARD=y # # Amateur Radio support @@ -378,20 +456,33 @@ 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=y # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set # # IDE chipset support/bugfixes # # CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_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 +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set # # SCSI support @@ -402,6 +493,10 @@ # 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 # # ISDN subsystem @@ -412,6 +507,10 @@ # Input core support # # CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set # # Character devices @@ -419,21 +518,38 @@ CONFIG_VT=y # CONFIG_VT_CONSOLE is not set # CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set CONFIG_SERIAL_SA1100=y -# CONFIG_SERIAL_SA1100_OLD is not set CONFIG_SERIAL_SA1100_CONSOLE=y CONFIG_SA1100_DEFAULT_BAUDRATE=57600 +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=32 -CONFIG_UCB1200=y -CONFIG_TOUCHSCREEN_UCB1200=y -CONFIG_AUDIO_UCB1200=y -CONFIG_ADC_UCB1200=y -# CONFIG_TOUCHSCREEN_BITSY is not set -# CONFIG_PROFILER is not set # # I2C support @@ -441,37 +557,35 @@ # CONFIG_I2C is not set # -# Mice +# L3 serial bus support # -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set # -# Joysticks +# Other L3 adapters # +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set # -# Game port support -# - -# -# Gameport joysticks -# - -# -# Serial port support +# Mice # +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set # -# Serial port joysticks +# Joysticks # +# CONFIG_INPUT_GAMEPORT is not set # -# Parallel port joysticks +# Input core support is needed for gameports # # -# Parport support is needed for parallel port joysticks +# Input core support is needed for joysticks # # CONFIG_QIC02_TAPE is not set @@ -479,6 +593,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set CONFIG_SA1100_RTC=y @@ -509,44 +624,74 @@ # 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_REISERFS_PROC_INFO 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_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG 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_JFFS2_FS is not set -CONFIG_CRAMFS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set CONFIG_RAMFS=y # CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_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=y # CONFIG_QNX4FS_FS is not set -CONFIG_ROMFS_FS=y +# CONFIG_QNX4FS_RW 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_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_INTERMEZZO_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 +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -562,6 +707,7 @@ # CONFIG_MINIX_SUBPARTITION is not set # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set @@ -573,15 +719,17 @@ # CONFIG_PC_KEYMAP=y # CONFIG_VGA_CONSOLE is not set -CONFIG_FB=y # # Frame-buffer support # CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set CONFIG_FB_SA1100=y -# CONFIG_FB_E1355 is not set +# CONFIG_FB_CYBER2000 is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB2=y @@ -597,28 +745,49 @@ # Sound # CONFIG_SOUND=y -# CONFIG_SOUND_SA1100_SSP is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set # CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set # CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set # CONFIG_SOUND_SONICVIBES is not set # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_SA1100 is not set +# CONFIG_SOUND_UDA1341 is not set +# CONFIG_SOUND_ASSABET_UDA1341 is not set +# CONFIG_SOUND_H3600_UDA1341 is not set +# CONFIG_SOUND_PANGOLIN_UDA1341 is not set +# CONFIG_SOUND_SA1111_UDA1341 is not set +# CONFIG_SOUND_SA1100SSP is not set # CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_TVMIXER is not set # -# USB support +# Multimedia Capabilities Port drivers # -CONFIG_USB=y -CONFIG_USB_DEBUG=y +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set # -# Miscellaneous USB options +# USB support # -# CONFIG_USB_DEVICEFS is not set -# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB is not set # # USB Controllers @@ -626,15 +795,22 @@ # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set # CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set # # USB Device Class drivers # # CONFIG_USB_AUDIO is not set # CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set # CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set # CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -652,40 +828,83 @@ # CONFIG_USB_DC2XX is not set # CONFIG_USB_MDC800 is not set # CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set # # USB Multimedia devices # -# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set -# CONFIG_USB_NET1080 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set # CONFIG_USB_USBNET is not set # # USB port drivers # +# CONFIG_USB_USS720 is not set # # USB Serial Converter support # # CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set # -# USB misc drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set # +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# # Kernel hacking # # CONFIG_NO_FRAME_POINTER is not set -CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set -CONFIG_MAGIC_SYSRQ=y +# CONFIG_NO_PGT_CACHE is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set # CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/def-configs/iq80310 linux-2.5/arch/arm/def-configs/iq80310 --- linux-2.5.1/arch/arm/def-configs/iq80310 Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/def-configs/iq80310 Sun Jan 6 01:38:26 2002 @@ -0,0 +1,812 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +CONFIG_ARCH_IOP310=y +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set + +# +# IOP310 Implementation Options +# +CONFIG_ARCH_IQ80310=y +# CONFIG_IOP310_AAU is not set +# CONFIG_IOP310_DMA is not set +# CONFIG_IOP310_MU is not set +# CONFIG_IOP310_PMON is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +CONFIG_CPU_32v4=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y +# CONFIG_XSCALE_TOOLS is not set +# CONFIG_XSCALE_CACHE_WRITE_ALLOC is not set +CONFIG_XSCALE_PMU=y +CONFIG_ARM_THUMB=y +# CONFIG_DISCONTIGMEM is not set + +# +# General setup +# +CONFIG_PCI=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_PCI_NAMES=y +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,115200 ip=bootp" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_BOOTLDR_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +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_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +CONFIG_MTD_IQ80310=y +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD 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 + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_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=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +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_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +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_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q 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 + +# +# 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_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_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 is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX 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_8139CP 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 +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 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_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring 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 + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y +# 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=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_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=y +CONFIG_BLK_DEV_ADMA=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_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +CONFIG_BLK_DEV_CMD64X=y +# 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_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS 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_BLK_DEV_SL82C105 is not set +# CONFIG_IDE_CHIPSETS 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 +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 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 + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV 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 + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO 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_INPUT_GAMEPORT 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 +# 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_REISERFS_PROC_INFO 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_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG 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_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_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=y +# 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_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_INTERMEZZO_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 +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# 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_LDM_PARTITION is not set +# 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 + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/def-configs/shannon linux-2.5/arch/arm/def-configs/shannon --- linux-2.5.1/arch/arm/def-configs/shannon Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/def-configs/shannon Sun Jan 6 01:38:26 2002 @@ -0,0 +1,737 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_OBSOLETE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +CONFIG_SA1100_SHANNON=y +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_ARM_THUMB is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_CPU_FREQ is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_SA1100=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttySA0,9600 console=tty1 root=/dev/mtdblock2 init=/linuxrc" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_BOOTLDR_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_SA1100=y +# CONFIG_MTD_IQ80310 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD 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 + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# 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 + +# +# 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 + +# +# 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 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC_OMIT_TIGON_I 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_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_NMCLAN is not set +CONFIG_PCMCIA_SMC91C92=y +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# 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 is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR 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_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 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 +# CONFIG_BLK_DEV_ATARAID is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=9600 +# CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set + +# +# Other L3 adapters +# +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_SERIO is not set + +# +# Joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +CONFIG_SA1100_WATCHDOG=y +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_I810_TCO is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_60XX_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_SA1100_RTC=y +# 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 + +# +# PCMCIA character devices +# + +# +# 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_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_CMS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +CONFIG_MINIX_FS=y +# CONFIG_FREEVXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# 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_LDM_PARTITION is not set +# 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=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_936 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 +# 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_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 + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_SA1100=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=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=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_SOUND_SA1100=y +# CONFIG_SOUND_SA1100SSP is not set +# CONFIG_SOUND_OSS is not set + +# +# Multimedia Capabilities Port drivers +# +CONFIG_MCP=y +CONFIG_MCP_SA1100=y +CONFIG_MCP_UCB1200=y +CONFIG_MCP_UCB1200_AUDIO=y +CONFIG_MCP_UCB1200_TS=y + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Controllers +# + +# +# USB Device Class drivers +# + +# +# USB Human Interface Devices (HID) +# + +# +# USB Imaging devices +# + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# + +# +# USB port drivers +# + +# +# USB Serial Converter support +# + +# +# USB Miscellaneous drivers +# + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +CONFIG_DEBUG_LL=y diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/def-configs/system3 linux-2.5/arch/arm/def-configs/system3 --- linux-2.5.1/arch/arm/def-configs/system3 Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/def-configs/system3 Sun Jan 6 01:38:26 2002 @@ -0,0 +1,977 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +CONFIG_SA1100_PT_SYSTEM3=y +CONFIG_SA1111=y +CONFIG_FORCE_MAX_ZONEORDER=9 +CONFIG_SA1100_USB=m +CONFIG_SA1100_USB_NETLINK=m +CONFIG_SA1100_USB_CHAR=m + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_ARM_THUMB is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +CONFIG_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +CONFIG_PCMCIA_SA1100=m +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_PM=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="noinitrd root=/dev/mtdblock3" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_BOOTLDR_PARTS=m +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +# CONFIG_MTD_CHAR is not set +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +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_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +CONFIG_MTD_SA1100=y +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD 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 + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_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_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_MD_MULTIPATH 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=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_VLAN_8021Q 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 + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +CONFIG_NET_VENDOR_SMC=y +# CONFIG_WD80x3 is not set +# CONFIG_ULTRAMCA is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRA32 is not set +CONFIG_SMC9194=m +# 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 + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 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_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring 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 + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=m +# CONFIG_PCMCIA_NMCLAN is not set +CONFIG_PCMCIA_SMC91C92=m +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +# CONFIG_IRNET is not set +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set +# CONFIG_IRDA_OPTIONS is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m +CONFIG_IRPORT_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_SA1100_FIR=m + +# +# 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=m +# 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_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 +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT 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 + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=38400 +CONFIG_SERIAL_8250=m +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX 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_SA1100_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 + +# +# PCMCIA character devices +# +CONFIG_PCMCIA_SERIAL_CS=m + +# +# 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_REISERFS_PROC_INFO 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_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# 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_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_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=y +# 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_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_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# 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 +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# 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_LDM_PARTITION is not set +# 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=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 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 +# 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_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 + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +CONFIG_FB_SA1100=y +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +CONFIG_USB_OHCI_SA1111=m + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +CONFIG_USB_USBNET=m + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SLAB=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/Makefile linux-2.5/arch/arm/kernel/Makefile --- linux-2.5.1/arch/arm/kernel/Makefile Thu Oct 25 20:53:45 2001 +++ linux-2.5/arch/arm/kernel/Makefile Sun Jan 6 01:38:26 2002 @@ -7,60 +7,45 @@ USE_STANDARD_AS_RULE := true -HEAD_OBJ = head-$(PROCESSOR).o ENTRY_OBJ = entry-$(PROCESSOR).o -AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) +AFLAGS_head.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-ftvpci = plx90x0.o -pci-footbridge = dec21285.o -pci-shark = via82c505.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 +O_TARGET := kernel.o # Object file lists. obj-y := arch.o compat.o dma.o $(ENTRY_OBJ) entry-common.o irq.o \ process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ - time.o traps.o $(O_OBJS_$(MACHINE)) + time.o traps.o obj-m := obj-n := obj- := -export-objs := armksyms.o dma.o ecard.o fiq.o io.o oldlatches.o time.o +export-objs := armksyms.o apm.o dma.o ecard.o fiq.o io.o time.o -no-irq-arch := $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \ - $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \ - $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) - -ifneq ($(findstring y,$(no-irq-arch)),y) - obj-y += irq-arch.o -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) +obj-$(CONFIG_APM) += apm.o +obj-$(CONFIG_ARCH_ACORN) += ecard.o time-acorn.o +obj-$(CONFIG_ARCH_CLPS7500) += time-acorn.o +obj-$(CONFIG_FOOTBRIDGE) += isa.o +obj-$(CONFIG_FIQ) += fiq.o +obj-$(CONFIG_MODULES) += armksyms.o +obj-$(CONFIG_ARTHUR) += arthur.o +obj-$(CONFIG_ISA_DMA) += dma-isa.o +obj-$(CONFIG_PCI) += bios32.o +obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o +obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o ifneq ($(MACHINE),ebsa110) obj-y += io.o endif -all: kernel.o $(HEAD_OBJ) init_task.o +ifeq ($(CONFIG_CPU_32),y) +head-y := head.o +obj-$(CONFIG_DEBUG_LL) += debug.o +endif + +all: kernel.o $(head-y) init_task.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/arch.c linux-2.5/arch/arm/kernel/arch.c --- linux-2.5.1/arch/arm/kernel/arch.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/kernel/arch.c Sun Jan 6 01:38:26 2002 @@ -4,19 +4,13 @@ * Architecture specific fixups. */ #include <linux/config.h> -#include <linux/tty.h> -#include <linux/delay.h> -#include <linux/pm.h> #include <linux/init.h> +#include <linux/types.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 genarch_init_irq(void); unsigned int vram_size; @@ -49,129 +43,4 @@ __tagtable(ATAG_ACORN, parse_tag_acorn); -#ifdef CONFIG_ARCH_RPC -static void __init -fixup_riscpc(struct machine_desc *desc, struct param_struct *unusd, - char **cmdline, struct meminfo *mi) -{ - /* - * RiscPC can't handle half-word loads and stores - */ - elf_hwcap &= ~HWCAP_HALF; -} - -extern void __init rpc_map_io(void); - -MACHINE_START(RISCPC, "Acorn-RiscPC") - MAINTAINER("Russell King") - BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) - BOOT_PARAMS(0x10000100) - DISABLE_PARPORT(0) - DISABLE_PARPORT(1) - FIXUP(fixup_riscpc) - MAPIO(rpc_map_io) - INITIRQ(genarch_init_irq) -MACHINE_END -#endif -#ifdef CONFIG_ARCH_ARC -MACHINE_START(ARCHIMEDES, "Acorn-Archimedes") - MAINTAINER("Dave Gilbert") - BOOT_PARAMS(0x0207c000) - INITIRQ(genarch_init_irq) -MACHINE_END -#endif -#ifdef CONFIG_ARCH_A5K -MACHINE_START(A5K, "Acorn-A5000") - MAINTAINER("Russell King") - BOOT_PARAMS(0x0207c000) - 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 *unused, - char **cmdline, struct meminfo *mi) -{ - mi->nr_banks = 1; - mi->bank[0].start = PHYS_OFFSET; - mi->bank[0].size = (32*1024*1024); - mi->bank[0].node = 0; - - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); - setup_initrd( __phys_to_virt(0xf1000000), 0x005dac7b); - - /* 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 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_NEXUSPCI - -extern void __init nexuspci_map_io(void); - -MACHINE_START(NEXUSPCI, "FTV/PCI") - MAINTAINER("Philip Blundell") - BOOT_MEM(0x40000000, 0x10000000, 0xe0000000) - MAPIO(nexuspci_map_io) - INITIRQ(genarch_init_irq) -MACHINE_END -#endif -#ifdef CONFIG_ARCH_TBOX - -extern void __init tbox_map_io(void); - -MACHINE_START(TBOX, "unknown-TBOX") - 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 - -extern void __init clps7500_map_io(void); - -MACHINE_START(CLPS7500, "CL-PS7500") - MAINTAINER("Philip Blundell") - BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) - MAPIO(clps7500_map_io) - INITIRQ(genarch_init_irq) -MACHINE_END #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/armksyms.c linux-2.5/arch/arm/kernel/armksyms.c --- linux-2.5.1/arch/arm/kernel/armksyms.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/kernel/armksyms.c Sun Jan 6 01:38:26 2002 @@ -19,6 +19,7 @@ #include <linux/in6.h> #include <linux/interrupt.h> #include <linux/pm.h> +#include <linux/tty.h> #include <linux/vt_kern.h> #include <asm/byteorder.h> @@ -77,7 +78,7 @@ extern void __do_softirq(void); #define EXPORT_SYMBOL_ALIAS(sym,orig) \ - const char __kstrtab_##sym##[] \ + const char __kstrtab_##sym[] \ __attribute__((section(".kstrtab"))) = \ __MODULE_STRING(sym); \ const struct module_symbol __ksymtab_##sym \ @@ -115,7 +116,9 @@ EXPORT_SYMBOL(system_rev); EXPORT_SYMBOL(system_serial_low); EXPORT_SYMBOL(system_serial_high); +#ifdef CONFIG_DEBUG_BUGVERBOSE EXPORT_SYMBOL(__bug); +#endif EXPORT_SYMBOL(__bad_xchg); EXPORT_SYMBOL(__readwrite_bug); EXPORT_SYMBOL(enable_irq); @@ -231,14 +234,25 @@ EXPORT_SYMBOL_NOVERS(__umodsi3); /* bitops */ -EXPORT_SYMBOL(set_bit); -EXPORT_SYMBOL(test_and_set_bit); -EXPORT_SYMBOL(clear_bit); -EXPORT_SYMBOL(test_and_clear_bit); -EXPORT_SYMBOL(change_bit); -EXPORT_SYMBOL(test_and_change_bit); -EXPORT_SYMBOL(find_first_zero_bit); -EXPORT_SYMBOL(find_next_zero_bit); +EXPORT_SYMBOL(_set_bit_le); +EXPORT_SYMBOL(_test_and_set_bit_le); +EXPORT_SYMBOL(_clear_bit_le); +EXPORT_SYMBOL(_test_and_clear_bit_le); +EXPORT_SYMBOL(_change_bit_le); +EXPORT_SYMBOL(_test_and_change_bit_le); +EXPORT_SYMBOL(_find_first_zero_bit_le); +EXPORT_SYMBOL(_find_next_zero_bit_le); + +#ifdef __ARMEB__ +EXPORT_SYMBOL(_set_bit_be); +EXPORT_SYMBOL(_test_and_set_bit_be); +EXPORT_SYMBOL(_clear_bit_be); +EXPORT_SYMBOL(_test_and_clear_bit_be); +EXPORT_SYMBOL(_change_bit_be); +EXPORT_SYMBOL(_test_and_change_bit_be); +EXPORT_SYMBOL(_find_first_zero_bit_be); +EXPORT_SYMBOL(_find_next_zero_bit_be); +#endif /* elf */ EXPORT_SYMBOL(elf_platform); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/bios32.c linux-2.5/arch/arm/kernel/bios32.c --- linux-2.5.1/arch/arm/kernel/bios32.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/kernel/bios32.c Sun Jan 6 01:38:26 2002 @@ -19,20 +19,6 @@ static int debug_pci; int have_isa_bridge; -struct pci_sys_data { - /* - * The hardware we are attached to - */ - struct hw_pci *hw; - - unsigned long mem_offset; - - /* - * These are the resources for the root bus. - */ - struct resource *resource[3]; -}; - void pcibios_report_status(u_int status_mask, int warn) { struct pci_dev *dev; @@ -153,8 +139,7 @@ } /* - * PCI IDE controllers use non-standard I/O port - * decoding, respect it. + * PCI IDE controllers use non-standard I/O port decoding, respect it. */ static void __init pci_fixup_ide_bases(struct pci_dev *dev) { @@ -181,9 +166,82 @@ pci_write_config_dword(dev, 0x40, 0x80000000); } +/* + * The CY82C693 needs some rather major fixups to ensure that it does + * the right thing. Idea from the Alpha people, with a few additions. + * + * We ensure that the IDE base registers are set to 1f0/3f4 for the + * primary bus, and 170/374 for the secondary bus. Also, hide them + * from the PCI subsystem view as well so we won't try to perform + * our own auto-configuration on them. + * + * In addition, we ensure that the PCI IDE interrupts are routed to + * IRQ 14 and IRQ 15 respectively. + * + * The above gets us to a point where the IDE on this device is + * functional. However, The CY82C693U _does not work_ in bus + * master mode without locking the PCI bus solid. + */ +static void __init pci_fixup_cy82c693(struct pci_dev *dev) +{ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + u32 base0, base1; + + if (dev->class & 0x80) { /* primary */ + base0 = 0x1f0; + base1 = 0x3f4; + } else { /* secondary */ + base0 = 0x170; + base1 = 0x374; + } + + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + base0 | PCI_BASE_ADDRESS_SPACE_IO); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, + base1 | PCI_BASE_ADDRESS_SPACE_IO); + + dev->resource[0].start = 0; + dev->resource[0].end = 0; + dev->resource[0].flags = 0; + + dev->resource[1].start = 0; + dev->resource[1].end = 0; + dev->resource[1].flags = 0; + } else if (PCI_FUNC(dev->devfn) == 0) { + /* + * Setup IDE IRQ routing. + */ + pci_write_config_byte(dev, 0x4b, 14); + pci_write_config_byte(dev, 0x4c, 15); + + /* + * Disable FREQACK handshake, enable USB. + */ + pci_write_config_byte(dev, 0x4d, 0x41); + + /* + * Enable PCI retry, and PCI post-write buffer. + */ + pci_write_config_byte(dev, 0x44, 0x17); + + /* + * Enable ISA master and DMA post write buffering. + */ + pci_write_config_byte(dev, 0x45, 0x03); + } +} + struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, + PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, + pci_fixup_cy82c693 + }, { + PCI_FIXUP_HEADER, + PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, + pci_fixup_dec21142 + }, { + PCI_FIXUP_HEADER, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, pci_fixup_dec21285 }, { @@ -198,10 +256,6 @@ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases - }, { - PCI_FIXUP_HEADER, - PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, - pci_fixup_dec21142 }, { 0 } }; @@ -232,6 +286,8 @@ val = res->start; if (res->flags & IORESOURCE_MEM) val -= sys->mem_offset; + else + val -= sys->io_offset; val |= res->flags & PCI_REGION_FLAG_MASK; pci_write_config_dword(dev, reg, val); @@ -268,15 +324,19 @@ static void __init pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev) { + unsigned long offset; int i; for (i = 0; i < PCI_NUM_RESOURCES; i++) { if (dev->resource[i].start == 0) continue; - if (dev->resource[i].flags & IORESOURCE_MEM) { - dev->resource[i].start += root->mem_offset; - dev->resource[i].end += root->mem_offset; - } + if (dev->resource[i].flags & IORESOURCE_MEM) + offset = root->mem_offset; + else + offset = root->io_offset; + + dev->resource[i].start += offset; + dev->resource[i].end += offset; } } @@ -388,15 +448,116 @@ { struct pci_sys_data *root = bus->sysdata; + ranges->io_start -= root->io_offset; + ranges->io_end -= root->io_offset; ranges->mem_start -= root->mem_offset; ranges->mem_end -= root->mem_offset; ranges->prefetch_start -= root->mem_offset; ranges->prefetch_end -= root->mem_offset; } -u8 __init no_swizzle(struct pci_dev *dev, u8 *pin) +/* + * This is the standard PCI-PCI bridge swizzling algorithm: + * + * Dev: 0 1 2 3 + * A A B C D + * B B C D A + * C C D A B + * D D A B C + * ^^^^^^^^^^ irq pin on bridge + */ +u8 __devinit pci_std_swizzle(struct pci_dev *dev, u8 *pinp) +{ + int pin = *pinp; + + if (pin != 0) { + pin -= 1; + while (dev->bus->self) { + pin = (pin + PCI_SLOT(dev->devfn)) & 3; + /* + * move up the chain of bridges, + * swizzling as we go. + */ + dev = dev->bus->self; + } + *pinp = pin + 1; + } + + return PCI_SLOT(dev->devfn); +} + +/* + * Swizzle the device pin each time we cross a bridge. + * This might update pin and returns the slot number. + */ +static u8 __devinit pcibios_swizzle(struct pci_dev *dev, u8 *pin) +{ + struct pci_sys_data *sys = dev->sysdata; + int slot = 0, oldpin = *pin; + + if (sys->swizzle) + slot = sys->swizzle(dev, pin); + + if (debug_pci) + printk("PCI: %s swizzling pin %d => pin %d slot %d\n", + dev->slot_name, oldpin, *pin, slot); + + return slot; +} + +/* + * Map a slot/pin to an IRQ. + */ +static int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { - return 0; + struct pci_sys_data *sys = dev->sysdata; + int irq = -1; + + if (sys->map_irq) + irq = sys->map_irq(dev, slot, pin); + + if (debug_pci) + printk("PCI: %s mapping slot %d pin %d => irq %d\n", + dev->slot_name, slot, pin, irq); + + return irq; +} + +static void __init pcibios_init_hw(struct hw_pci *hw) +{ + struct pci_sys_data *sys = NULL; + int ret; + int nr, busnr; + + for (nr = busnr = 0; nr < hw->nr_controllers; nr++) { + sys = kmalloc(sizeof(struct pci_sys_data), GFP_KERNEL); + if (!sys) + panic("PCI: unable to allocate sys data!"); + + memset(sys, 0, sizeof(struct pci_sys_data)); + + sys->hw = hw; + sys->busnr = busnr; + sys->swizzle = hw->swizzle; + sys->map_irq = hw->map_irq; + sys->resource[0] = &ioport_resource; + sys->resource[1] = &iomem_resource; + + ret = hw->setup(nr, sys); + + if (ret > 0) { + sys->bus = hw->scan(nr, sys); + + if (!sys->bus) + panic("PCI: unable to scan bus!"); + + busnr = sys->bus->subordinate + 1; + } else if (ret < 0) + break; + } + + kfree(sys); + } extern struct hw_pci ebsa285_pci; @@ -406,10 +567,10 @@ extern struct hw_pci ftv_pci; extern struct hw_pci shark_pci; extern struct hw_pci integrator_pci; +extern struct hw_pci iq80310_pci; void __init pcibios_init(void) { - struct pci_sys_data *root; struct hw_pci *hw = NULL; do { @@ -455,44 +616,28 @@ break; } #endif +#ifdef CONFIG_ARCH_IQ80310 + if (machine_is_iq80310()) { + hw = &iq80310_pci; + break; + } +#endif } while (0); if (hw == NULL) return; - root = kmalloc(sizeof(*root), GFP_KERNEL); - if (!root) - panic("PCI: unable to allocate root data!"); - - root->hw = hw; - root->mem_offset = hw->mem_offset; - - memset(root->resource, 0, sizeof(root->resource)); - - /* - * Setup the resources for this bus. - * resource[0] - IO ports - * resource[1] - non-prefetchable memory - * resource[2] - prefetchable memory - */ - if (root->hw->setup_resources) - root->hw->setup_resources(root->resource); - else { - root->resource[0] = &ioport_resource; - root->resource[1] = &iomem_resource; - root->resource[2] = NULL; - } - - /* - * Set up the host bridge, and scan the bus. - */ - root->hw->init(root); + if (hw->preinit) + hw->preinit(); + pcibios_init_hw(hw); + if (hw->postinit) + hw->postinit(); /* * Assign any unassigned resources. */ pci_assign_unassigned_resources(); - pci_fixup_irqs(root->hw->swizzle, root->hw->map_irq); + pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); } char * __init pcibios_setup(char *str) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/compat.c linux-2.5/arch/arm/kernel/compat.c --- linux-2.5.1/arch/arm/kernel/compat.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/kernel/compat.c Sun Jan 6 01:38:26 2002 @@ -89,10 +89,12 @@ } #ifdef CONFIG_FOOTBRIDGE - tag = tag_next(tag); - tag->hdr.tag = ATAG_MEMCLK; - tag->hdr.size = tag_size(tag_memclk); - tag->u.memclk.fmemclk = params->u1.s.mem_fclk_21285; + if (params->u1.s.mem_fclk_21285) { + tag = tag_next(tag); + tag->hdr.tag = ATAG_MEMCLK; + tag->hdr.size = tag_size(tag_memclk); + tag->u.memclk.fmemclk = params->u1.s.mem_fclk_21285; + } #endif #ifdef CONFIG_ARCH_ACORN diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/debug-armo.S linux-2.5/arch/arm/kernel/debug-armo.S --- linux-2.5.1/arch/arm/kernel/debug-armo.S Mon Sep 18 22:15:24 2000 +++ linux-2.5/arch/arm/kernel/debug-armo.S Thu Jan 1 00:00:00 1970 @@ -1,90 +0,0 @@ -/* - * linux/arch/arm/kernel/debug-armo.S - * - * Copyright (C) 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. - * - * 26-bit debugging code - */ -#include <linux/linkage.h> - - .macro addruart,rx - mov \rx, #0x03000000 - orr \rx, \rx, #0x00010000 - orr \rx, \rx, #0x00000fe0 - .endm - - .macro senduart,rd,rx - strb \rd, [\rx] - .endm - - .macro busyuart,rd,rx -1002: ldrb \rd, [\rx, #0x14] - and \rd, \rd, #0x60 - teq \rd, #0x60 - bne 1002b - .endm - - .macro waituart,rd,rx -1001: ldrb \rd, [\rx, #0x18] - tst \rd, #0x10 - beq 1001b - .endm - - .text -/* - * Useful debugging routines - */ -ENTRY(printhex8) - mov r1, #8 - b printhex - -ENTRY(printhex4) - mov r1, #4 - b printhex - -ENTRY(printhex2) - mov r1, #2 -printhex: ldr r2, =hexbuf - add r3, r2, r1 - mov r1, #0 - strb r1, [r3] -1: and r1, r0, #15 - mov r0, r0, lsr #4 - cmp r1, #10 - addlt r1, r1, #'0' - addge r1, r1, #'a' - 10 - strb r1, [r3, #-1]! - teq r3, r2 - bne 1b - mov r0, r2 - b printascii - - .ltorg - -ENTRY(printascii) - addruart r3 - b 2f -1: waituart r2, r3 - senduart r1, r3 - busyuart r2, r3 - teq r1, #'\n' - moveq r1, #'\r' - beq 1b -2: teq r0, #0 - ldrneb r1, [r0], #1 - teqne r1, #0 - bne 1b - mov pc, lr - -ENTRY(printch) - addruart r3 - mov r1, r0 - mov r0, #0 - b 1b - - .bss -hexbuf: .space 16 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/debug.S linux-2.5/arch/arm/kernel/debug.S --- linux-2.5.1/arch/arm/kernel/debug.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/kernel/debug.S Tue Jan 8 00:44:24 2002 @@ -0,0 +1,422 @@ +/* + * linux/arch/arm/kernel/debug-armv.S + * + * Copyright (C) 1994-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. + * + * 32-bit debugging code + */ +#include <linux/config.h> +#include <linux/linkage.h> +#include <asm/hardware.h> + + .text + +/* + * Some debugging routines (useful if you've got MM problems and + * printk isn't working). For DEBUGGING ONLY!!! Do not leave + * references to these in a production kernel! + */ +#if defined(CONFIG_ARCH_RPC) + .macro addruart,rx + mov \rx, #0xe0000000 + orr \rx, \rx, #0x00010000 + orr \rx, \rx, #0x00000fe0 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1001: ldrb \rd, [\rx, #0x14] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1001b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x18] + tst \rd, #0x10 + beq 1001b + .endm + +#elif defined(CONFIG_ARCH_EBSA110) + .macro addruart,rx + mov \rx, #0xf0000000 + orr \rx, \rx, #0x00000be0 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x14] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x18] + 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 + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x7c000000 @ physical + movne \rx, #0xff000000 @ virtual + orr \rx, \rx, #0x000003f8 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x5] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x6] + tst \rd, #0x10 + beq 1001b + .endm +#else + /* For EBSA285 debugging */ + .equ dc21285_high, ARMCSR_BASE & 0xff000000 + .equ dc21285_low, ARMCSR_BASE & 0x00ffffff + + .macro addruart,rx + mov \rx, #dc21285_high + .if dc21285_low + orr \rx, \rx, #dc21285_low + .endif + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0x160] @ UARTDR + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x178] @ UARTFLG + tst \rd, #1 << 3 + bne 1001b + .endm + + .macro waituart,rd,rx + .endm +#endif +#elif defined(CONFIG_ARCH_FTVPCI) + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + movne \rx, #0xe0000000 + moveq \rx, #0x10000000 + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0xc] + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x4] + tst \rd, #1 << 2 + beq 1001b + .endm + + .macro waituart,rd,rx + .endm + +#elif defined(CONFIG_ARCH_SA1100) + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x80000000 @ physical base address + movne \rx, #0xf8000000 @ virtual address + @add \rx, \rx, #0x00050000 @ Ser3 + add \rx, \rx, #0x00010000 @ Ser1 + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0x14] @ UTDR + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x20] @ UTSR1 + tst \rd, #1 << 2 @ UTSR1_TNF + beq 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x20] @ UTSR1 + tst \rd, #1 << 0 @ UTSR1_TBY + bne 1001b + .endm + +#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 + .equ io_phys, IO_START + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #io_phys @ physical base address + movne \rx, #io_virt @ virtual address + add \rx, \rx, #0x00044000 @ UART1 +@ add \rx, \rx, #0x00045000 @ UART2 + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0x0] @ UARTDR + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full + bne 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy + bne 1001b + .endm + +#elif defined(CONFIG_ARCH_INTEGRATOR) + +#include <asm/hardware/serial_amba.h> + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x16000000 @ physical base address + movne \rx, #0xf0000000 @ virtual base + addne \rx, \rx, #0x16000000 >> 4 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx, #AMBA_UARTDR] + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full + bne 1001b + .endm + + .macro busyuart,rd,rx +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 + +#elif defined(CONFIG_ARCH_ANAKIN) + +//#//include <asm/arch/serial_reg.h> + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #IO_START + movne \rx, #IO_BASE + add \rx, \rx, #UART0 + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0x14] @ tx + ldr \rd, [\rx, #0x18] + orr \rd, \rd, #SENDREQUEST + str \rd, [\rx, #0x18] + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x10] + tst \rd, #TXEMPTY + beq 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x10] + tst \rd, #CTS + bne 1001b + .endm + +#elif defined(CONFIG_ARCH_CAMELOT) + +#include <asm/arch/excalibur.h> +#define UART00_TYPE +#include <asm/arch/uart00.h> + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + ldr \rx, =EXC_UART00_BASE @ physical base address + orrne \rx, \rx, #0xff000000 @ virtual base + orrne \rx, \rx, #0x00f00000 + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #UART_TD(0)] + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #UART_TSR(0)] + and \rd, \rd, #UART_TSR_TX_LEVEL_MSK + cmp \rd, #15 + beq 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #UART_TSR(0)] + ands \rd, \rd, #UART_TSR_TX_LEVEL_MSK + bne 1001b + .endm + +#else +#error Unknown architecture +#endif + +/* + * Useful debugging routines + */ +ENTRY(printhex8) + mov r1, #8 + b printhex + +ENTRY(printhex4) + mov r1, #4 + b printhex + +ENTRY(printhex2) + mov r1, #2 +printhex: adr r2, hexbuf + add r3, r2, r1 + mov r1, #0 + strb r1, [r3] +1: and r1, r0, #15 + mov r0, r0, lsr #4 + cmp r1, #10 + addlt r1, r1, #'0' + addge r1, r1, #'a' - 10 + strb r1, [r3, #-1]! + teq r3, r2 + bne 1b + mov r0, r2 + b printascii + + .ltorg + +ENTRY(printascii) + addruart r3 + b 2f +1: waituart r2, r3 + senduart r1, r3 + busyuart r2, r3 + teq r1, #'\n' + moveq r1, #'\r' + beq 1b +2: teq r0, #0 + ldrneb r1, [r0], #1 + teqne r1, #0 + bne 1b + mov pc, lr + +ENTRY(printch) + addruart r3 + mov r1, r0 + mov r0, #0 + b 1b + +hexbuf: .space 16 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/dec21285.c linux-2.5/arch/arm/kernel/dec21285.c --- linux-2.5.1/arch/arm/kernel/dec21285.c Wed Jul 4 22:43:05 2001 +++ linux-2.5/arch/arm/kernel/dec21285.c Thu Jan 1 00:00:00 1970 @@ -1,382 +0,0 @@ -/* - * linux/arch/arm/kernel/dec21285.c: PCI functions for DC21285 - * - * Copyright (C) 1998-2000 Russell King, Phil Blundell - * - * 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/kernel.h> -#include <linux/pci.h> -#include <linux/ptrace.h> -#include <linux/interrupt.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/ioport.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/mach/pci.h> -#include <asm/hardware/dec21285.h> - -#define MAX_SLOTS 21 - -#define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \ - PCI_STATUS_REC_MASTER_ABORT | \ - PCI_STATUS_REC_TARGET_ABORT | \ - PCI_STATUS_PARITY) << 16) - -extern int setup_arm_irq(int, struct irqaction *); -extern void pcibios_report_status(u_int status_mask, int warn); -extern void register_isa_ports(unsigned int, unsigned int, unsigned int); - -static unsigned long -dc21285_base_address(struct pci_dev *dev) -{ - unsigned long addr = 0; - unsigned int devfn = dev->devfn; - - if (dev->bus->number == 0) { - if (PCI_SLOT(devfn) == 0) - /* - * For devfn 0, point at the 21285 - */ - addr = ARMCSR_BASE; - else { - devfn -= 1 << 3; - - if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) - addr = PCICFG0_BASE | 0xc00000 | (devfn << 8); - } - } else - addr = PCICFG1_BASE | (dev->bus->number << 16) | (devfn << 8); - - return addr; -} - -static int -dc21285_read_config_byte(struct pci_dev *dev, int where, u8 *value) -{ - unsigned long addr = dc21285_base_address(dev); - u8 v; - - if (addr) - asm("ldr%?b %0, [%1, %2]" - : "=r" (v) : "r" (addr), "r" (where)); - else - v = 0xff; - - *value = v; - - return PCIBIOS_SUCCESSFUL; -} - -static int -dc21285_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - unsigned long addr = dc21285_base_address(dev); - u16 v; - - if (addr) - asm("ldr%?h %0, [%1, %2]" - : "=r" (v) : "r" (addr), "r" (where)); - else - v = 0xffff; - - *value = v; - - return PCIBIOS_SUCCESSFUL; -} - -static int -dc21285_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - unsigned long addr = dc21285_base_address(dev); - u32 v; - - if (addr) - asm("ldr%? %0, [%1, %2]" - : "=r" (v) : "r" (addr), "r" (where)); - else - v = 0xffffffff; - - *value = v; - - return PCIBIOS_SUCCESSFUL; -} - -static int -dc21285_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - unsigned long addr = dc21285_base_address(dev); - - if (addr) - asm("str%?b %0, [%1, %2]" - : : "r" (value), "r" (addr), "r" (where)); - - return PCIBIOS_SUCCESSFUL; -} - -static int -dc21285_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - unsigned long addr = dc21285_base_address(dev); - - if (addr) - asm("str%?h %0, [%1, %2]" - : : "r" (value), "r" (addr), "r" (where)); - - return PCIBIOS_SUCCESSFUL; -} - -static int -dc21285_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - unsigned long addr = dc21285_base_address(dev); - - if (addr) - asm("str%? %0, [%1, %2]" - : : "r" (value), "r" (addr), "r" (where)); - - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops dc21285_ops = { - dc21285_read_config_byte, - dc21285_read_config_word, - dc21285_read_config_dword, - dc21285_write_config_byte, - dc21285_write_config_word, - dc21285_write_config_dword, -}; - -static struct timer_list serr_timer; -static struct timer_list perr_timer; - -static void dc21285_enable_error(unsigned long __data) -{ - switch (__data) { - case IRQ_PCI_SERR: - del_timer(&serr_timer); - break; - - case IRQ_PCI_PERR: - del_timer(&perr_timer); - break; - } - - enable_irq(__data); -} - -/* - * Warn on PCI errors. - */ -static void dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned int cmd; - unsigned int status; - - cmd = *CSR_PCICMD; - status = cmd >> 16; - cmd = cmd & 0xffff; - - if (status & PCI_STATUS_REC_MASTER_ABORT) { - printk(KERN_DEBUG "PCI: master abort: "); - pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT, 1); - printk("\n"); - - cmd |= PCI_STATUS_REC_MASTER_ABORT << 16; - } - - if (status & PCI_STATUS_REC_TARGET_ABORT) { - printk(KERN_DEBUG "PCI: target abort: "); - pcibios_report_status(PCI_STATUS_SIG_TARGET_ABORT, 1); - printk("\n"); - - cmd |= PCI_STATUS_REC_TARGET_ABORT << 16; - } - - *CSR_PCICMD = cmd; -} - -static void dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - struct timer_list *timer = dev_id; - unsigned int cntl; - - printk(KERN_DEBUG "PCI: system error received: "); - pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1); - printk("\n"); - - cntl = *CSR_SA110_CNTL & 0xffffdf07; - *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; - - /* - * back off this interrupt - */ - disable_irq(irq); - timer->expires = jiffies + HZ; - add_timer(timer); -} - -static void dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - printk(KERN_DEBUG "PCI: discard timer expired\n"); - *CSR_SA110_CNTL &= 0xffffde07; -} - -static void dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned int cmd; - - printk(KERN_DEBUG "PCI: data parity error detected: "); - pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); - printk("\n"); - - cmd = *CSR_PCICMD & 0xffff; - *CSR_PCICMD = cmd | 1 << 24; -} - -static void dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - struct timer_list *timer = dev_id; - unsigned int cmd; - - printk(KERN_DEBUG "PCI: parity error detected: "); - pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); - printk("\n"); - - cmd = *CSR_PCICMD & 0xffff; - *CSR_PCICMD = cmd | 1 << 31; - - /* - * back off this interrupt - */ - disable_irq(irq); - timer->expires = jiffies + HZ; - add_timer(timer); -} - -void __init dc21285_setup_resources(struct resource **resource) -{ - struct resource *busmem, *busmempf; - - busmem = kmalloc(sizeof(*busmem), GFP_KERNEL); - busmempf = kmalloc(sizeof(*busmempf), GFP_KERNEL); - memset(busmem, 0, sizeof(*busmem)); - memset(busmempf, 0, sizeof(*busmempf)); - - busmem->flags = IORESOURCE_MEM; - busmem->name = "Footbridge non-prefetch"; - busmempf->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; - busmempf->name = "Footbridge prefetch"; - - allocate_resource(&iomem_resource, busmempf, 0x20000000, - 0x80000000, 0xffffffff, 0x20000000, NULL, NULL); - allocate_resource(&iomem_resource, busmem, 0x40000000, - 0x80000000, 0xffffffff, 0x40000000, NULL, NULL); - - resource[0] = &ioport_resource; - resource[1] = busmem; - resource[2] = busmempf; -} - -void __init dc21285_init(void *sysdata) -{ - unsigned int mem_size, mem_mask; - int cfn_mode; - - mem_size = (unsigned int)high_memory - PAGE_OFFSET; - for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1) - if (mem_mask >= mem_size) - break; - - /* - * These registers need to be set up whether we're the - * central function or not. - */ - *CSR_SDRAMBASEMASK = (mem_mask - 1) & 0x0ffc0000; - *CSR_SDRAMBASEOFFSET = 0; - *CSR_ROMBASEMASK = 0x80000000; - *CSR_CSRBASEMASK = 0; - *CSR_CSRBASEOFFSET = 0; - *CSR_PCIADDR_EXTN = 0; - - cfn_mode = __footbridge_cfn_mode(); - - printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in " - "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ? - "central function" : "addin"); - - if (cfn_mode) { - static struct resource csrmem, csrio; - - csrio.flags = IORESOURCE_IO; - csrio.name = "Footbridge"; - csrmem.flags = IORESOURCE_MEM; - csrmem.name = "Footbridge"; - - allocate_resource(&ioport_resource, &csrio, 128, - 0xff00, 0xffff, 128, NULL, NULL); - allocate_resource(&iomem_resource, &csrmem, 128, - 0xf4000000, 0xf8000000, 128, NULL, NULL); - - /* - * Map our SDRAM at a known address in PCI space, just in case - * the firmware had other ideas. Using a nonzero base is - * necessary, since some VGA cards forcefully use PCI addresses - * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). - */ - *CSR_PCICSRBASE = csrmem.start; - *CSR_PCICSRIOBASE = csrio.start; - *CSR_PCISDRAMBASE = __virt_to_bus(PAGE_OFFSET); - *CSR_PCIROMBASE = 0; - *CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | - PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS; - - pci_scan_bus(0, &dc21285_ops, sysdata); - - /* - * Clear any existing errors - we aren't - * interested in historical data... - */ - *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) | - SA110_CNTL_RXSERR; - *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS; - } else if (footbridge_cfn_mode() != 0) { - /* - * If we are not compiled to accept "add-in" mode, then - * we are using a constant virt_to_bus translation which - * can not hope to cater for the way the host BIOS has - * set up the machine. - */ - panic("PCI: this kernel is compiled for central " - "function mode only"); - } - - /* - * Initialise PCI error IRQ after we've finished probing - */ - request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, SA_INTERRUPT, "PCI abort", NULL); - request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT, "Discard timer", NULL); - request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, SA_INTERRUPT, "PCI data parity", NULL); - - init_timer(&serr_timer); - init_timer(&perr_timer); - - serr_timer.data = IRQ_PCI_SERR; - serr_timer.function = dc21285_enable_error; - perr_timer.data = IRQ_PCI_PERR; - perr_timer.function = dc21285_enable_error; - - request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT, - "PCI system error", &serr_timer); - request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT, - "PCI parity error", &perr_timer); - - register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/dma-arc.c linux-2.5/arch/arm/kernel/dma-arc.c --- linux-2.5.1/arch/arm/kernel/dma-arc.c Wed Jul 4 21:56:44 2001 +++ linux-2.5/arch/arm/kernel/dma-arc.c Thu Jan 1 00:00:00 1970 @@ -1,208 +0,0 @@ -/* - * linux/arch/arm/kernel/dma-arc.c - * - * Copyright (C) 1998-1999 Dave Gilbert / 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. - * - * DMA functions specific to Archimedes and A5000 architecture - */ -#include <linux/config.h> -#include <linux/sched.h> -#include <linux/init.h> - -#include <asm/dma.h> -#include <asm/fiq.h> -#include <asm/irq.h> -#include <asm/io.h> -#include <asm/hardware.h> -#include <asm/mach-types.h> - -#include <asm/mach/dma.h> - -#define DPRINTK(x...) printk(KERN_DEBUG x) - -#if defined(CONFIG_BLK_DEV_FD1772) || defined(CONFIG_BLK_DEV_FD1772_MODULE) -static void arc_floppy_data_enable_dma(dmach_t channel, dma_t *dma) -{ - DPRINTK("arc_floppy_data_enable_dma\n"); - switch (dma->dma_mode) { - case DMA_MODE_READ: { /* read */ - extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end; - extern void fdc1772_setupdma(unsigned int count,unsigned int addr); - unsigned long flags; - DPRINTK("enable_dma fdc1772 data read\n"); - save_flags(flags); - clf(); - - memcpy ((void *)0x1c, (void *)&fdc1772_dma_read, - &fdc1772_dma_read_end - &fdc1772_dma_read); - fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */ - enable_fiq(FIQ_FLOPPYDATA); - restore_flags(flags); - } - break; - - case DMA_MODE_WRITE: { /* write */ - extern unsigned char fdc1772_dma_write, fdc1772_dma_write_end; - extern void fdc1772_setupdma(unsigned int count,unsigned int addr); - unsigned long flags; - DPRINTK("enable_dma fdc1772 data write\n"); - save_flags(flags); - clf(); - memcpy ((void *)0x1c, (void *)&fdc1772_dma_write, - &fdc1772_dma_write_end - &fdc1772_dma_write); - fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */ - enable_fiq(FIQ_FLOPPYDATA; - - restore_flags(flags); - } - break; - default: - printk ("enable_dma: dma%d not initialised\n", channel); - } -} - -static int arc_floppy_data_get_dma_residue(dmach_t channel, dma_t *dma) -{ - extern unsigned int fdc1772_bytestogo; - - /* 10/1/1999 DAG - I presume its the number of bytes left? */ - return fdc1772_bytestogo; -} - -static void arc_floppy_cmdend_enable_dma(dmach_t channel, dma_t *dma) -{ - /* Need to build a branch at the FIQ address */ - extern void fdc1772_comendhandler(void); - unsigned long flags; - - DPRINTK("arc_floppy_cmdend_enable_dma\n"); - /*printk("enable_dma fdc1772 command end FIQ\n");*/ - save_flags(flags); - clf(); - - /* B fdc1772_comendhandler */ - *((unsigned int *)0x1c)=0xea000000 | - (((unsigned int)fdc1772_comendhandler-(0x1c+8))/4); - - restore_flags(flags); -} - -static int arc_floppy_cmdend_get_dma_residue(dmach_t channel, dma_t *dma) -{ - /* 10/1/1999 DAG - Presume whether there is an outstanding command? */ - extern unsigned int fdc1772_fdc_int_done; - - * Explicit! If the int done is 0 then 1 int to go */ - return (fdc1772_fdc_int_done==0)?1:0; -} - -static void arc_disable_dma(dmach_t channel, dma_t *dma) -{ - disable_fiq(dma->dma_irq); -} - -static struct dma_ops arc_floppy_data_dma_ops = { - type: "FIQDMA", - enable: arc_floppy_data_enable_dma, - disable: arc_disable_dma, - residue: arc_floppy_data_get_dma_residue, -}; - -static struct dma_ops arc_floppy_cmdend_dma_ops = { - type: "FIQCMD", - enable: arc_floppy_cmdend_enable_dma, - disable: arc_disable_dma, - residue: arc_floppy_cmdend_get_dma_residue, -}; -#endif - -#ifdef CONFIG_ARCH_A5K -static struct fiq_handler fh = { - name: "floppydata" -}; - -static int a5k_floppy_get_dma_residue(dmach_t channel, dma_t *dma) -{ - struct pt_regs regs; - get_fiq_regs(®s); - return regs.ARM_r9; -} - -static void a5k_floppy_enable_dma(dmach_t channel, dma_t *dma) -{ - struct pt_regs regs; - void *fiqhandler_start; - unsigned int fiqhandler_length; - extern void floppy_fiqsetup(unsigned long len, unsigned long addr, - unsigned long port); - - if (dma->dma_mode == DMA_MODE_READ) { - extern unsigned char floppy_fiqin_start, floppy_fiqin_end; - fiqhandler_start = &floppy_fiqin_start; - fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start; - } else { - extern unsigned char floppy_fiqout_start, floppy_fiqout_end; - fiqhandler_start = &floppy_fiqout_start; - fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start; - } - if (claim_fiq(&fh)) { - printk("floppydma: couldn't claim FIQ.\n"); - return; - } - memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length); - regs.ARM_r9 = dma->buf.length; - regs.ARM_r10 = (unsigned long)dma->buf.address; - regs.ARM_fp = FLOPPYDMA_BASE; - set_fiq_regs(®s); - enable_fiq(dma->dma_irq); -} - -static void a5k_floppy_disable_dma(dmach_t channel, dma_t *dma) -{ - disable_fiq(dma->dma_irq); - release_fiq(&fh); -} - -static struct dma_ops a5k_floppy_dma_ops = { - type: "FIQDMA", - enable: a5k_floppy_enable_dma, - disable: a5k_floppy_disable_dma, - residue: a5k_floppy_get_dma_residue, -}; -#endif - -/* - * This is virtual DMA - we don't need anything here - */ -static void sound_enable_disable_dma(dmach_t channel, dma_t *dma) -{ -} - -static struct dma_ops sound_dma_ops = { - type: "VIRTUAL", - enable: sound_enable_disable_dma, - disable: sound_enable_disable_dma, -}; - -void __init arch_dma_init(dma_t *dma) -{ -#if defined(CONFIG_BLK_DEV_FD1772) || defined(CONFIG_BLK_DEV_FD1772_MODULE) - if (machine_is_archimedes()) { - dma[DMA_VIRTUAL_FLOPPY0].dma_irq = FIQ_FLOPPYDATA; - dma[DMA_VIRTUAL_FLOPPY0].d_ops = &arc_floppy_data_dma_ops; - dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 1; - dma[DMA_VIRTUAL_FLOPPY1].d_ops = &arc_floppy_cmdend_dma_ops; - } -#endif -#ifdef CONFIG_ARCH_A5K - if (machine_is_a5k()) { - dma[DMA_VIRTUAL_FLOPPY0].dma_irq = FIQ_FLOPPYDATA; - dma[DMA_VIRTUAL_FLOPPY0].d_ops = &a5k_floppy_dma_ops; - } -#endif - dma[DMA_VIRTUAL_SOUND].d_ops = &sound_dma_ops; -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/dma-footbridge.c linux-2.5/arch/arm/kernel/dma-footbridge.c --- linux-2.5.1/arch/arm/kernel/dma-footbridge.c Mon Sep 18 22:15:24 2000 +++ linux-2.5/arch/arm/kernel/dma-footbridge.c Thu Jan 1 00:00:00 1970 @@ -1,55 +0,0 @@ -/* - * linux/arch/arm/kernel/dma-ebsa285.c - * - * Copyright (C) 1998 Phil Blundell - * - * DMA functions specific to EBSA-285/CATS architectures - * - * Changelog: - * 09-Nov-1998 RMK Split out ISA DMA functions to dma-isa.c - * 17-Mar-1999 RMK Allow any EBSA285-like architecture to have - * ISA DMA controllers. - */ -#include <linux/config.h> -#include <linux/sched.h> -#include <linux/init.h> - -#include <asm/dma.h> -#include <asm/io.h> - -#include <asm/mach/dma.h> -#include <asm/hardware/dec21285.h> - -#if 0 -static int fb_dma_request(dmach_t channel, dma_t *dma) -{ - return -EINVAL; -} - -static void fb_dma_enable(dmach_t channel, dma_t *dma) -{ -} - -static void fb_dma_disable(dmach_t channel, dma_t *dma) -{ -} - -static struct dma_ops fb_dma_ops = { - type: "fb", - request: fb_dma_request, - enable: fb_dma_enable, - disable: fb_dma_disable, -}; -#endif - -void __init arch_dma_init(dma_t *dma) -{ -#if 0 - dma[_DC21285_DMA(0)].d_ops = &fb_dma_ops; - dma[_DC21285_DMA(1)].d_ops = &fb_dma_ops; -#endif -#ifdef CONFIG_ISA_DMA - if (footbridge_cfn_mode()) - isa_init_dma(dma + _ISA_DMA(0)); -#endif -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/dma-isa.c linux-2.5/arch/arm/kernel/dma-isa.c --- linux-2.5.1/arch/arm/kernel/dma-isa.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/kernel/dma-isa.c Sun Jan 6 01:38:26 2002 @@ -95,7 +95,7 @@ * coherence. */ dma->buf.dma_address = pci_map_single(NULL, - dma->buf.address, dma->buf.length, + dma->buf.__address, dma->buf.length, direction); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/dma-rpc.c linux-2.5/arch/arm/kernel/dma-rpc.c --- linux-2.5.1/arch/arm/kernel/dma-rpc.c Fri Feb 9 19:29:44 2001 +++ linux-2.5/arch/arm/kernel/dma-rpc.c Thu Jan 1 00:00:00 1970 @@ -1,371 +0,0 @@ -/* - * linux/arch/arm/kernel/dma-rpc.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. - * - * DMA functions specific to RiscPC architecture - */ -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/mman.h> -#include <linux/init.h> -#include <linux/pci.h> - -#include <asm/page.h> -#include <asm/dma.h> -#include <asm/fiq.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/hardware.h> -#include <asm/uaccess.h> - -#include <asm/mach/dma.h> -#include <asm/hardware/iomd.h> - -#if 0 -typedef enum { - dma_size_8 = 1, - dma_size_16 = 2, - dma_size_32 = 4, - dma_size_128 = 16 -} dma_size_t; - -typedef struct { - dma_size_t transfersize; -} dma_t; -#endif - -#define TRANSFER_SIZE 2 - -#define CURA (0) -#define ENDA (IOMD_IO0ENDA - IOMD_IO0CURA) -#define CURB (IOMD_IO0CURB - IOMD_IO0CURA) -#define ENDB (IOMD_IO0ENDB - IOMD_IO0CURA) -#define CR (IOMD_IO0CR - IOMD_IO0CURA) -#define ST (IOMD_IO0ST - IOMD_IO0CURA) - -#define state_prog_a 0 -#define state_wait_a 1 -#define state_wait_b 2 - -static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma) -{ - unsigned long end, offset, flags = 0; - - if (dma->sg) { - sg->dma_address = dma->sg->dma_address; - offset = sg->dma_address & ~PAGE_MASK; - - end = offset + dma->sg->length; - - if (end > PAGE_SIZE) - end = PAGE_SIZE; - - if (offset + (int) TRANSFER_SIZE > end) - flags |= DMA_END_L; - - sg->length = end - TRANSFER_SIZE; - - dma->sg->length -= end - offset; - dma->sg->dma_address += end - offset; - - if (dma->sg->length == 0) { - if (dma->sgcount > 1) { - dma->sg++; - dma->sgcount--; - } else { - dma->sg = NULL; - flags |= DMA_END_S; - } - } - } else { - flags = DMA_END_S | DMA_END_L; - sg->dma_address = 0; - sg->length = 0; - } - - sg->length |= flags; -} - -static inline void iomd_setup_dma_a(struct scatterlist *sg, dma_t *dma) -{ - iomd_writel(sg->dma_address, dma->dma_base + CURA); - iomd_writel(sg->length, dma->dma_base + ENDA); -} - -static inline void iomd_setup_dma_b(struct scatterlist *sg, dma_t *dma) -{ - iomd_writel(sg->dma_address, dma->dma_base + CURB); - iomd_writel(sg->length, dma->dma_base + ENDB); -} - -static void iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs) -{ - dma_t *dma = (dma_t *)dev_id; - unsigned int status = 0, no_buffer = dma->sg == NULL; - - do { - switch (dma->state) { - case state_prog_a: - iomd_get_next_sg(&dma->cur_sg, dma); - iomd_setup_dma_a(&dma->cur_sg, dma); - dma->state = state_wait_a; - - case state_wait_a: - status = iomd_readb(dma->dma_base + ST); - switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) { - case DMA_ST_OFL|DMA_ST_INT: - iomd_get_next_sg(&dma->cur_sg, dma); - iomd_setup_dma_a(&dma->cur_sg, dma); - break; - - case DMA_ST_INT: - iomd_get_next_sg(&dma->cur_sg, dma); - iomd_setup_dma_b(&dma->cur_sg, dma); - dma->state = state_wait_b; - break; - - case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB: - iomd_setup_dma_b(&dma->cur_sg, dma); - dma->state = state_wait_b; - break; - } - break; - - case state_wait_b: - status = iomd_readb(dma->dma_base + ST); - switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) { - case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB: - iomd_get_next_sg(&dma->cur_sg, dma); - iomd_setup_dma_b(&dma->cur_sg, dma); - break; - - case DMA_ST_INT|DMA_ST_AB: - iomd_get_next_sg(&dma->cur_sg, dma); - iomd_setup_dma_a(&dma->cur_sg, dma); - dma->state = state_wait_a; - break; - - case DMA_ST_OFL|DMA_ST_INT: - iomd_setup_dma_a(&dma->cur_sg, dma); - dma->state = state_wait_a; - break; - } - break; - } - } while (dma->sg && (status & DMA_ST_INT)); - - if (no_buffer) - disable_irq(irq); -} - -static int iomd_request_dma(dmach_t channel, dma_t *dma) -{ - return request_irq(dma->dma_irq, iomd_dma_handle, - SA_INTERRUPT, dma->device_id, dma); -} - -static void iomd_free_dma(dmach_t channel, dma_t *dma) -{ - free_irq(dma->dma_irq, dma); -} - -static void iomd_enable_dma(dmach_t channel, dma_t *dma) -{ - unsigned long dma_base = dma->dma_base; - unsigned int ctrl = TRANSFER_SIZE | DMA_CR_E; - - if (dma->invalid) { - dma->invalid = 0; - - /* - * Cope with ISA-style drivers which expect cache - * coherence. - */ - if (!dma->using_sg) { - dma->buf.dma_address = pci_map_single(NULL, - dma->buf.address, dma->buf.length, - dma->dma_mode == DMA_MODE_READ ? - PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); - } - - iomd_writeb(DMA_CR_C, dma_base + CR); - dma->state = state_prog_a; - } - - if (dma->dma_mode == DMA_MODE_READ) - ctrl |= DMA_CR_D; - - iomd_writeb(ctrl, dma_base + CR); - enable_irq(dma->dma_irq); -} - -static void iomd_disable_dma(dmach_t channel, dma_t *dma) -{ - unsigned long dma_base = dma->dma_base; - unsigned int ctrl; - - disable_irq(dma->dma_irq); - ctrl = iomd_readb(dma_base + CR); - iomd_writeb(ctrl & ~DMA_CR_E, dma_base + CR); -} - -static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle) -{ - int tcr, speed; - - if (cycle < 188) - speed = 3; - else if (cycle <= 250) - speed = 2; - else if (cycle < 438) - speed = 1; - else - speed = 0; - - tcr = iomd_readb(IOMD_DMATCR); - speed &= 3; - - switch (channel) { - case DMA_0: - tcr = (tcr & ~0x03) | speed; - break; - - case DMA_1: - tcr = (tcr & ~0x0c) | (speed << 2); - break; - - case DMA_2: - tcr = (tcr & ~0x30) | (speed << 4); - break; - - case DMA_3: - tcr = (tcr & ~0xc0) | (speed << 6); - break; - - default: - break; - } - - iomd_writeb(tcr, IOMD_DMATCR); - - return speed; -} - -static struct dma_ops iomd_dma_ops = { - type: "IOMD", - request: iomd_request_dma, - free: iomd_free_dma, - enable: iomd_enable_dma, - disable: iomd_disable_dma, - setspeed: iomd_set_dma_speed, -}; - -static struct fiq_handler fh = { - name: "floppydma" -}; - -static void floppy_enable_dma(dmach_t channel, dma_t *dma) -{ - void *fiqhandler_start; - unsigned int fiqhandler_length; - struct pt_regs regs; - - if (dma->dma_mode == DMA_MODE_READ) { - extern unsigned char floppy_fiqin_start, floppy_fiqin_end; - fiqhandler_start = &floppy_fiqin_start; - fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start; - } else { - extern unsigned char floppy_fiqout_start, floppy_fiqout_end; - fiqhandler_start = &floppy_fiqout_start; - fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start; - } - - regs.ARM_r9 = dma->buf.length; - regs.ARM_r10 = (unsigned long)dma->buf.address; - regs.ARM_fp = FLOPPYDMA_BASE; - - if (claim_fiq(&fh)) { - printk("floppydma: couldn't claim FIQ.\n"); - return; - } - - set_fiq_handler(fiqhandler_start, fiqhandler_length); - set_fiq_regs(®s); - enable_fiq(dma->dma_irq); -} - -static void floppy_disable_dma(dmach_t channel, dma_t *dma) -{ - disable_fiq(dma->dma_irq); - release_fiq(&fh); -} - -static int floppy_get_residue(dmach_t channel, dma_t *dma) -{ - struct pt_regs regs; - get_fiq_regs(®s); - return regs.ARM_r9; -} - -static struct dma_ops floppy_dma_ops = { - type: "FIQDMA", - enable: floppy_enable_dma, - disable: floppy_disable_dma, - residue: floppy_get_residue, -}; - -/* - * This is virtual DMA - we don't need anything here. - */ -static void sound_enable_disable_dma(dmach_t channel, dma_t *dma) -{ -} - -static struct dma_ops sound_dma_ops = { - type: "VIRTUAL", - enable: sound_enable_disable_dma, - disable: sound_enable_disable_dma, -}; - -void __init arch_dma_init(dma_t *dma) -{ - iomd_writeb(0, IOMD_IO0CR); - iomd_writeb(0, IOMD_IO1CR); - iomd_writeb(0, IOMD_IO2CR); - iomd_writeb(0, IOMD_IO3CR); - - iomd_writeb(0xa0, IOMD_DMATCR); - - dma[DMA_0].dma_base = IOMD_IO0CURA; - dma[DMA_0].dma_irq = IRQ_DMA0; - dma[DMA_0].d_ops = &iomd_dma_ops; - dma[DMA_1].dma_base = IOMD_IO1CURA; - dma[DMA_1].dma_irq = IRQ_DMA1; - dma[DMA_1].d_ops = &iomd_dma_ops; - dma[DMA_2].dma_base = IOMD_IO2CURA; - dma[DMA_2].dma_irq = IRQ_DMA2; - dma[DMA_2].d_ops = &iomd_dma_ops; - dma[DMA_3].dma_base = IOMD_IO3CURA; - dma[DMA_3].dma_irq = IRQ_DMA3; - dma[DMA_3].d_ops = &iomd_dma_ops; - dma[DMA_S0].dma_base = IOMD_SD0CURA; - dma[DMA_S0].dma_irq = IRQ_DMAS0; - dma[DMA_S0].d_ops = &iomd_dma_ops; - dma[DMA_S1].dma_base = IOMD_SD1CURA; - dma[DMA_S1].dma_irq = IRQ_DMAS1; - dma[DMA_S1].d_ops = &iomd_dma_ops; - dma[DMA_VIRTUAL_FLOPPY].dma_irq = FIQ_FLOPPYDATA; - dma[DMA_VIRTUAL_FLOPPY].d_ops = &floppy_dma_ops; - dma[DMA_VIRTUAL_SOUND].d_ops = &sound_dma_ops; - - /* - * Setup DMA channels 2,3 to be for podules - * and channels 0,1 for internal devices - */ - iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/dma.c linux-2.5/arch/arm/kernel/dma.c --- linux-2.5.1/arch/arm/kernel/dma.c Fri Feb 9 19:29:44 2001 +++ linux-2.5/arch/arm/kernel/dma.c Sun Jan 6 01:38:26 2002 @@ -139,7 +139,7 @@ dma->sg = &dma->buf; dma->sgcount = 1; - dma->buf.address = bus_to_virt(physaddr); + dma->buf.__address = bus_to_virt(physaddr); dma->using_sg = 0; dma->invalid = 1; } @@ -275,6 +275,8 @@ #endif +EXPORT_SYMBOL(request_dma); +EXPORT_SYMBOL(free_dma); EXPORT_SYMBOL(enable_dma); EXPORT_SYMBOL(disable_dma); EXPORT_SYMBOL(set_dma_addr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/entry-armo.S linux-2.5/arch/arm/kernel/entry-armo.S --- linux-2.5.1/arch/arm/kernel/entry-armo.S Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/kernel/entry-armo.S Sun Jan 6 01:38:26 2002 @@ -169,7 +169,7 @@ bne __und_svc save_user_regs zero_fp - teqp pc, #I_BIT | MODE_SVC + teqp pc, #PSR_I_BIT | MODE_SVC .Lbug_undef: ldr r4, .LC2 ldr pc, [r4] @ Call FP module USR entry point diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/entry-armv.S linux-2.5/arch/arm/kernel/entry-armv.S --- linux-2.5.1/arch/arm/kernel/entry-armv.S Thu Oct 25 20:53:45 2001 +++ linux-2.5/arch/arm/kernel/entry-armv.S Sun Jan 6 01:38:26 2002 @@ -548,6 +548,39 @@ .text .endm +#elif defined(CONFIG_ARCH_IOP310) || defined(CONFIG_ARCH_ADIFCC) + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + mrc p13, 0, \irqstat, c4, c0, 0 @ get INTSRC + mrc p13, 0, \base, c0, c0, 0 @ get INTCTL + + tst \irqstat, #(1<<29) @ if INTSRC_BI + tstne \base, #(1<<3) @ and INTCTL_BM + movne \irqnr, #IRQ_XS80200_BCU + bne 1001f + + tst \irqstat, #(1<<28) @ if INTSRC_PI + tstne \base, #(1<<2) @ and INTCTL_PM + movne \irqnr, #IRQ_XS80200_PMU + bne 1001f + + tst \irqstat, #(1<<31) @ if INTSRC_FI + tstne \base, #(1<<0) @ and INTCTL_FM + movne \irqnr, #IRQ_XS80200_EXTFIQ + bne 1001f + + tst \irqstat, #(1<<30) @ if INTSRC_II + tstne \base, #(1<<1) @ and INTCTL_IM + movne \irqnr, #IRQ_XS80200_EXTIRQ + +1001: + .endm + + .macro irq_prio_table + .endm #else #error Unknown architecture #endif @@ -641,23 +674,23 @@ mov r1, lr stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro mrs r9, cpsr @ Enable interrupts if they were - tst r3, #I_BIT - biceq r9, r9, #I_BIT @ previously - mov r0, r2 + tst r3, #PSR_I_BIT + biceq r9, r9, #PSR_I_BIT @ previously + mov r0, r2 @ *** remove once everyones in sync /* * This routine must not corrupt r9 */ #ifdef MULTI_CPU - ldr r2, .LCprocfns @ pass r0, r3 to + ldr r4, .LCprocfns @ pass r0, r3 to mov lr, pc @ processor code - ldr pc, [r2] @ call processor specific code + ldr pc, [r4] @ call processor specific code #else bl cpu_data_abort #endif msr cpsr_c, r9 mov r2, sp bl SYMBOL_NAME(do_DataAbort) - mov r0, #I_BIT | MODE_SVC + mov r0, #PSR_I_BIT | MODE_SVC msr cpsr_c, r0 ldr r0, [sp, #S_PSR] msr spsr, r0 @@ -700,7 +733,7 @@ mov r1, sp @ struct pt_regs *regs bl SYMBOL_NAME(do_undefinstr) -1: mov r0, #I_BIT | MODE_SVC +1: mov r0, #PSR_I_BIT | MODE_SVC msr cpsr_c, r0 ldr lr, [sp, #S_PSR] @ Get SVC cpsr msr spsr, lr @@ -716,13 +749,13 @@ mov r1, lr stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro mrs r9, cpsr @ Enable interrupts if they were - tst r3, #I_BIT - biceq r9, r9, #I_BIT @ previously + tst r3, #PSR_I_BIT + biceq r9, r9, #PSR_I_BIT @ previously msr cpsr_c, r9 mov r0, r2 @ address (pc) mov r1, sp @ regs bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler - mov r0, #I_BIT | MODE_SVC + mov r0, #PSR_I_BIT | MODE_SVC msr cpsr_c, r0 ldr r0, [sp, #S_PSR] msr spsr, r0 @@ -747,15 +780,16 @@ stmia sp, {r0 - r12} @ save r0 - r12 ldr r7, .LCabt add r5, sp, #S_PC - ldmia r7, {r0, r3, r4} @ Get USR pc, cpsr - stmia r5, {r0, r3, r4} @ Save USR pc, cpsr, old_r0 + ldmia r7, {r2 - r4} @ Get USR pc, cpsr + stmia r5, {r2 - r4} @ Save USR pc, cpsr, old_r0 stmdb r5, {sp, lr}^ alignment_trap r7, r7, __temp_abt zero_fp + mov r0, r2 @ remove once everyones in sync #ifdef MULTI_CPU - ldr r2, .LCprocfns @ pass r0, r3 to + ldr r4, .LCprocfns @ pass r0, r3 to mov lr, pc @ processor code - ldr pc, [r2] @ call processor specific code + ldr pc, [r4] @ call processor specific code #else bl cpu_data_abort #endif @@ -883,7 +917,7 @@ @ @ now branch to the relevent MODE handling routine @ - mov r13, #I_BIT | MODE_SVC + mov r13, #PSR_I_BIT | MODE_SVC msr spsr_c, r13 @ switch to SVC_32 mode and lr, lr, #15 @@ -924,7 +958,7 @@ @ @ now branch to the relevent MODE handling routine @ - mov r13, #I_BIT | MODE_SVC + mov r13, #PSR_I_BIT | MODE_SVC msr spsr_c, r13 @ switch to SVC_32 mode and lr, lr, #15 @@ -966,7 +1000,7 @@ @ @ now branch to the relevent MODE handling routine @ - mov r13, #I_BIT | MODE_SVC + mov r13, #PSR_I_BIT | MODE_SVC msr spsr_c, r13 @ switch to SVC_32 mode ands lr, lr, #15 @@ -1007,7 +1041,7 @@ @ @ now branch to the relevent MODE handling routine @ - mov r13, #I_BIT | MODE_SVC + mov r13, #PSR_I_BIT | MODE_SVC msr spsr_c, r13 @ switch to SVC_32 mode and lr, lr, #15 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/entry-common.S linux-2.5/arch/arm/kernel/entry-common.S --- linux-2.5.1/arch/arm/kernel/entry-common.S Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/kernel/entry-common.S Sat Dec 29 11:10:40 2001 @@ -22,12 +22,10 @@ * Our do_softirq out of line code. See include/asm-arm/softirq.h for * the calling assembly. */ - .section ".text.lock","ax" ENTRY(__do_softirq) stmfd sp!, {r0 - r3, ip, lr} bl do_softirq ldmfd sp!, {r0 - r3, ip, pc} - .previous .align 5 /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/entry-header.S linux-2.5/arch/arm/kernel/entry-header.S --- linux-2.5.1/arch/arm/kernel/entry-header.S Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/kernel/entry-header.S Sun Jan 6 01:38:26 2002 @@ -83,7 +83,7 @@ .macro restore_user_regs ldr r0, [sp, #S_PSR] @ Get calling cpsr - mov ip, #I_BIT | MODE_SVC + mov ip, #PSR_I_BIT | MODE_SVC msr cpsr_c, ip @ disable IRQs msr spsr, r0 @ save in spsr_svc ldr lr, [sp, #S_PC] @ Get PC @@ -94,7 +94,7 @@ .endm .macro fast_restore_user_regs - mov ip, #I_BIT | MODE_SVC + mov ip, #PSR_I_BIT | MODE_SVC msr cpsr_c, ip @ disable IRQs ldr r1, [sp, #S_OFF + S_PSR] @ get calling cpsr ldr lr, [sp, #S_OFF + S_PC]! @ get pc @@ -207,7 +207,7 @@ */ .macro get_scno #ifdef CONFIG_ARM_THUMB - tst r8, #T_BIT @ this is SPSR from save_user_regs + tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs addne scno, r7, #OS_NUMBER << 20 @ put OS number in ldreq scno, [lr, #-4] diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/fiq.c linux-2.5/arch/arm/kernel/fiq.c --- linux-2.5.1/arch/arm/kernel/fiq.c Wed Nov 28 21:22:25 2001 +++ linux-2.5/arch/arm/kernel/fiq.c Sun Jan 6 01:38:26 2002 @@ -139,7 +139,7 @@ mov r0, r0" #endif : "=&r" (tmp), "=&r" (tmp2) - : "r" (®s->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE) + : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_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 @@ -171,7 +171,7 @@ mov r0, r0" #endif : "=&r" (tmp), "=&r" (tmp2) - : "r" (®s->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE) + : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/ftv-pci.c linux-2.5/arch/arm/kernel/ftv-pci.c --- linux-2.5.1/arch/arm/kernel/ftv-pci.c Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/kernel/ftv-pci.c Thu Jan 1 00:00:00 1970 @@ -1,51 +0,0 @@ -/* - * linux/arch/arm/kernel/ftv-pci.c - * - * PCI bios-type initialisation for PCI machines - * - * Bits taken from various places. - */ -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/init.h> - -#include <asm/irq.h> -#include <asm/mach/pci.h> - -/* - * Owing to a PCB cockup, issue A backplanes are wired thus: - * - * Slot 1 2 3 4 5 Bridge S1 S2 S3 S4 - * IRQ D C B A A C B A D - * A D C B B D C B A - * B A D C C A D C B - * C B A D D B A D C - * - * ID A31 A30 A29 A28 A27 A26 DEV4 DEV5 DEV6 DEV7 - * - * Actually, this isn't too bad, because with the processor card - * in slot 5 on the primary bus, the IRQs rotate on both sides - * as you'd expect. - */ - -static int irqmap_ftv[] __initdata = { IRQ_PCI_D, IRQ_PCI_C, IRQ_PCI_B, IRQ_PCI_A }; - -static int __init ftv_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - if (slot > 0x10) - slot--; - return irqmap_ftv[(slot - pin) & 3]; -} - -static u8 __init ftv_swizzle(struct pci_dev *dev, u8 *pin) -{ - return PCI_SLOT(dev->devfn); -} - -/* ftv host-specific stuff */ -struct hw_pci ftv_pci __initdata = { - init: plx90x0_init, - swizzle: ftv_swizzle, - map_irq: ftv_map_irq, -}; - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/head-armo.S linux-2.5/arch/arm/kernel/head-armo.S --- linux-2.5.1/arch/arm/kernel/head-armo.S Thu Apr 12 19:20:31 2001 +++ linux-2.5/arch/arm/kernel/head-armo.S Thu Jan 1 00:00:00 1970 @@ -1,92 +0,0 @@ -/* - * linux/arch/arm/kernel/head-armo.S - * - * Copyright (C) 1994-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. - * - * 26-bit kernel startup code - */ -#include <linux/config.h> -#include <linux/linkage.h> -#include <asm/mach-types.h> - - .globl SYMBOL_NAME(swapper_pg_dir) - .equ SYMBOL_NAME(swapper_pg_dir), 0x0207d000 - -/* - * Entry point. - */ - .section ".text.init",#alloc,#execinstr -ENTRY(stext) -__entry: cmp pc, #0x02000000 - ldrlt pc, LC0 @ if 0x01800000, call at 0x02080000 - teq r0, #0 @ Check for old calling method - blne oldparams @ Move page if old - adr r0, LC0 - ldmib r0, {r2-r5, sp} @ Setup stack - mov r0, #0 -1: cmp r2, r3 @ Clear BSS - strcc r0, [r2], #4 - bcc 1b - - bl detect_proc_type - str r0, [r4] - bl detect_arch_type - str r0, [r5] - - mov fp, #0 - b SYMBOL_NAME(start_kernel) - -LC0: .word SYMBOL_NAME(_stext) - .word SYMBOL_NAME(__bss_start) @ r2 - .word SYMBOL_NAME(_end) @ r3 - .word SYMBOL_NAME(processor_id) @ r4 - .word SYMBOL_NAME(__machine_arch_type) @ r5 - .word SYMBOL_NAME(init_task_union)+8192 @ sp -arm2_id: .long 0x41560200 -arm250_id: .long 0x41560250 - .align - -oldparams: mov r4, #0x02000000 - add r3, r4, #0x00080000 - add r4, r4, #0x0007c000 -1: ldmia r0!, {r5 - r12} - stmia r4!, {r5 - r12} - cmp r4, r3 - blt 1b - mov pc, lr - -/* - * We need some way to automatically detect the difference between - * these two machines. Unfortunately, it is not possible to detect - * the presence of the SuperIO chip, because that will hang the old - * Archimedes machines solid. - */ -/* DAG: Outdated, these have been combined !!!!!!! */ -detect_arch_type: -#if defined(CONFIG_ARCH_ARC) - mov r0, #MACH_TYPE_ARCHIMEDES -#elif defined(CONFIG_ARCH_A5K) - mov r0, #MACH_TYPE_A5K -#endif - mov pc, lr - -detect_proc_type: - mov ip, lr - mov r2, #0xea000000 @ Point undef instr to continuation - adr r0, continue - 12 - orr r0, r2, r0, lsr #2 - mov r1, #0 - str r0, [r1, #4] - ldr r0, arm2_id - swp r2, r2, [r1] @ check for swp (ARM2 cant) - ldr r0, arm250_id - 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 - str r2, [r1, #4] - mov pc, ip diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/head.S linux-2.5/arch/arm/kernel/head.S --- linux-2.5.1/arch/arm/kernel/head.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/kernel/head.S Tue Jan 8 00:44:24 2002 @@ -0,0 +1,421 @@ +/* + * linux/arch/arm/kernel/head-armv.S + * + * Copyright (C) 1994-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. + * + * 32-bit kernel startup code for all architectures + */ +#include <linux/config.h> +#include <linux/linkage.h> + +#include <asm/assembler.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#define K(a,b,c) ((a) << 24 | (b) << 12 | (c)) + +/* + * We place the page tables 16K below TEXTADDR. Therefore, we must make sure + * that TEXTADDR is correctly set. Currently, we expect the least significant + * "short" to be 0x8000, but we could probably relax this restriction to + * TEXTADDR > PAGE_OFFSET + 0x4000 + * + * 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 == TEXTADDR + * + * swapper_pg_dir, pgtbl and krnladr are all closely related. + */ +#if (TEXTADDR & 0xffff) != 0x8000 +#error TEXTADDR must start at 0xXXXX8000 +#endif + + .globl SYMBOL_NAME(swapper_pg_dir) + .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000 + + .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) + mov r12, r0 +/* + * NOTE! Any code which is placed here should be done for one of + * the following reasons: + * + * 1. Compatability with old production boot firmware (ie, users + * actually have and are booting the kernel with the old firmware) + * and therefore will be eventually removed. + * 2. Cover the case when there is no boot firmware. This is not + * ideal, but in this case, it should ONLY set r0 and r1 to the + * appropriate value. + */ +#if defined(CONFIG_ARCH_NETWINDER) +/* + * Compatability cruft for old NetWinder NeTTroms. This + * code is currently scheduled for destruction in 2.5.xx + */ + .rept 8 + mov r0, r0 + .endr + + adr r2, 1f + ldmdb r2, {r7, r8} + and r3, r2, #0xc000 + teq r3, #0x8000 + beq __entry + bic r3, r2, #0xc000 + orr r3, r3, #0x8000 + mov r0, r3 + mov r4, #64 + sub r5, r8, r7 + b 1f + + .word _stext + .word __bss_start + +1: + .rept 4 + ldmia r2!, {r6, r7, r8, r9} + stmia r3!, {r6, r7, r8, r9} + .endr + subs r4, r4, #64 + bcs 1b + movs r4, r5 + mov r5, #0 + movne pc, r0 + + mov r1, #MACH_TYPE_NETWINDER @ (will go in 2.5) + mov r12, #2 << 24 @ scheduled for removal in 2.5.xx + orr r12, r12, #5 << 12 +__entry: +#endif +#if defined(CONFIG_ARCH_L7200) +/* + * FIXME - No bootloader, so manually set 'r1' with our architecture number. + */ + mov r1, #MACH_TYPE_L7200 +#endif + + mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + bl __lookup_processor_type + teq r10, #0 @ invalid processor? + moveq r0, #'p' @ yes, error 'p' + beq __error + bl __lookup_architecture_type + teq r7, #0 @ invalid architecture? + moveq r0, #'a' @ yes, error 'a' + beq __error + bl __create_page_tables + adr lr, __ret @ return address + 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) + .long SYMBOL_NAME(_end) + .long SYMBOL_NAME(processor_id) + .long SYMBOL_NAME(__machine_arch_type) + .long SYMBOL_NAME(cr_alignment) + .long SYMBOL_NAME(init_task_union)+8192 + + .type __ret, %function +__ret: ldr lr, __switch_data + mcr p15, 0, r0, c1, c0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov pc, lr + + /* + * This code follows on after the page + * table switch and jump above. + * + * r0 = processor control register + * r1 = machine ID + * r9 = processor ID + */ + .align 5 +__mmap_switched: + adr r3, __switch_data + 4 + ldmia r3, {r2, r4, r5, r6, r7, r8, sp}@ r2 = compat + @ sp = stack pointer + str r12, [r2] + + mov fp, #0 @ Clear BSS (and zero fp) +1: cmp r4, r5 + strcc fp, [r4],#4 + bcc 1b + + str r9, [r6] @ Save processor ID + str r1, [r7] @ Save machine type +#ifdef CONFIG_ALIGNMENT_TRAP + orr r0, r0, #2 @ ...........A. +#endif + bic r2, r0, #2 @ Clear 'A' bit + stmia r8, {r0, r2} @ Save control register values + b SYMBOL_NAME(start_kernel) + + + +/* + * Setup the initial page tables. We only setup the barest + * amount which are required to get the kernel running, which + * generally means mapping in the kernel code. + * + * We only map in 4MB of RAM, which should be sufficient in + * all cases. + * + * r5 = physical address of start of RAM + * r6 = physical IO address + * r7 = byte offset into page tables for IO + * r8 = page table flags + */ +__create_page_tables: + pgtbl r4, r5 @ page table address + + /* + * Clear the 16K level 1 swapper page table + */ + mov r0, r4 + mov r3, #0 + 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 to + * cater for the MMU enable. This identity mapping + * will be removed by paging_init() + */ + 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 & 0xff000000) >> 18 @ start of kernel + bic r2, r3, #0x00f00000 + str r2, [r0] @ PAGE_OFFSET + 0MB + add r0, r0, #(TEXTADDR & 0x00f00000) >> 18 + str r3, [r0], #4 @ KERNEL + 0MB + add r3, r3, #1 << 20 + str r3, [r0], #4 @ KERNEL + 1MB + add r3, r3, #1 << 20 + str r3, [r0], #4 @ KERNEL + 2MB + add r3, r3, #1 << 20 + str r3, [r0], #4 @ KERNEL + 3MB + + /* + * Ensure that the first section of RAM is present. + * we assume that: + * 1. the RAM is aligned to a 32MB boundary + * 2. the kernel is executing in the same 32MB chunk + * as the start of RAM. + */ + bic r0, r0, #0x01f00000 >> 18 @ round down + and r2, r5, #0xfe000000 @ 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 console before paging_init. + */ + add r0, r4, r7 + rsb r3, r7, #0x4000 @ PTRS_PER_PGD*sizeof(long) + cmp r3, #0x0800 + addge r2, r0, #0x0800 + addlt r2, r0, r3 + orr r3, r6, r8 +1: str r3, [r0], #4 + add r3, r3, #1 << 20 + teq r0, r2 + bne 1b +#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, #MACH_TYPE_NETWINDER + teqne r1, #MACH_TYPE_CATS + bne 1f + add r0, r4, #0x3fc0 + mov r3, #0x7c000000 + orr r3, r3, r8 + str r3, [r0], #4 + add r3, r3, #1 << 20 + str r3, [r0], #4 +1: +#endif +#endif +#ifdef CONFIG_ARCH_RPC + /* + * Map in screen at 0x02000000 & SCREEN2_BASE + * Similar reasons here - for debug. This is + * only for Acorn RiscPC architectures. + */ + 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 + + + +/* + * Exception handling. Something went wrong and we can't + * proceed. We ought to tell the user, but since we + * don't have any guarantee that we're even running on + * the right architecture, we do virtually nothing. + * r0 = ascii error character: + * a = invalid architecture + * p = invalid processor + * i = invalid calling convention + * + * Generally, only serious errors cause this. + */ +__error: +#ifdef CONFIG_DEBUG_LL + mov r8, r0 @ preserve r0 + adr r0, err_str + bl printascii + mov r0, r8 + bl printch +#endif +#ifdef CONFIG_ARCH_RPC +/* + * Turn the screen red on a error - RiscPC only. + */ + mov r0, #0x02000000 + mov r3, #0x11 + orr r3, r3, r3, lsl #8 + orr r3, r3, r3, lsl #16 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 +#endif +1: mov r0, r0 + b 1b + +#ifdef CONFIG_DEBUG_LL +err_str: .asciz "\nError: " + .align +#endif + +/* + * Read processor ID register (CP#15, CR0), and look up in the linker-built + * supported processor list. Note that we can't use the absolute addresses + * for the __proc_info lists since we aren't running with the MMU on + * (and therefore, we are not in the correct address space). We have to + * calculate the offset. + * + * Returns: + * r5, r6, r7 corrupted + * r8 = page table flags + * r9 = processor ID + * r10 = pointer to processor structure + */ +__lookup_processor_type: + adr r5, 2f + ldmia r5, {r7, r9, r10} + sub r5, r5, r10 @ convert addresses + add r7, r7, r5 @ to our address space + add r10, r9, r5 + mrc p15, 0, r9, c0, c0 @ get processor id +1: ldmia r10, {r5, r6, r8} @ value, mask, mmuflags + and r6, r6, r9 @ mask wanted bits + teq r5, r6 + moveq pc, lr + add r10, r10, #36 @ sizeof(proc_info_list) + cmp r10, r7 + blt 1b + mov r10, #0 @ unknown processor + mov pc, lr + +/* + * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for + * more information about the __proc_info and __arch_info structures. + */ +2: .long __proc_info_end + .long __proc_info_begin + .long 2b + .long __arch_info_begin + .long __arch_info_end + +/* + * Lookup machine architecture in the linker-build list of architectures. + * Note that we can't use the absolute addresses for the __arch_info + * lists since we aren't running with the MMU on (and therefore, we are + * not in the correct address space). We have to calculate the offset. + * + * r1 = machine architecture number + * Returns: + * r2, r3, r4 corrupted + * r5 = physical start address of RAM + * r6 = physical address of IO + * r7 = byte offset into page tables for IO + */ +__lookup_architecture_type: + adr r4, 2b + ldmia r4, {r2, r3, r5, r6, r7} @ throw away r2, r3 + sub r5, r4, r5 @ convert addresses + add r4, r6, r5 @ to our address space + add r7, r7, r5 +1: ldr r5, [r4] @ get machine type + teq r5, r1 + beq 2f + add r4, r4, #SIZEOF_MACHINE_DESC + cmp r4, r7 + blt 1b + mov r7, #0 @ unknown architecture + mov pc, lr +2: ldmib r4, {r5, r6, r7} @ found, get results + mov pc, lr diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/init_task.c linux-2.5/arch/arm/kernel/init_task.c --- linux-2.5.1/arch/arm/kernel/init_task.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/kernel/init_task.c Sun Jan 6 01:38:26 2002 @@ -9,7 +9,6 @@ #include <asm/uaccess.h> #include <asm/pgtable.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; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/irq-arch.c linux-2.5/arch/arm/kernel/irq-arch.c --- linux-2.5.1/arch/arm/kernel/irq-arch.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/kernel/irq-arch.c Thu Jan 1 00:00:00 1970 @@ -1,41 +0,0 @@ -/* - * 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/slab.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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/irq.c linux-2.5/arch/arm/kernel/irq.c --- linux-2.5.1/arch/arm/kernel/irq.c Wed Nov 28 21:22:25 2001 +++ linux-2.5/arch/arm/kernel/irq.c Sun Jan 6 01:38:26 2002 @@ -114,7 +114,7 @@ } #ifdef CONFIG_ARCH_ACORN - show_fiq_list(p); + show_fiq_list(p, v); #endif seq_printf(p, "Err: %10lu\n", irq_err_count); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/leds-ftvpci.c linux-2.5/arch/arm/kernel/leds-ftvpci.c --- linux-2.5.1/arch/arm/kernel/leds-ftvpci.c Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/kernel/leds-ftvpci.c Thu Jan 1 00:00:00 1970 @@ -1,31 +0,0 @@ -/* - * linux/arch/arm/kernel/leds-ftvpci.c - * - * Copyright (C) 1999 FutureTV Labs Ltd - */ - -#include <linux/module.h> - -#include <asm/hardware.h> -#include <asm/leds.h> -#include <asm/system.h> -#include <asm/io.h> - -static void ftvpci_leds_event(led_event_t ledevt) -{ - static int led_state = 0; - - switch(ledevt) { - case led_timer: - led_state ^= 1; - raw_writeb(0x1a | led_state, INTCONT_BASE); - break; - - default: - break; - } -} - -void (*leds_event)(led_event_t) = ftvpci_leds_event; - -EXPORT_SYMBOL(leds_event); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/oldlatches.c linux-2.5/arch/arm/kernel/oldlatches.c --- linux-2.5.1/arch/arm/kernel/oldlatches.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/kernel/oldlatches.c Thu Jan 1 00:00:00 1970 @@ -1,72 +0,0 @@ -/* - * linux/arch/arm/kernel/oldlatches.c - * - * Copyright (C) David Alan Gilbert 1995/1996,2000 - * - * 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. - * - * Support for the latches on the old Archimedes which control the floppy, - * hard disc and printer - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/sched.h> - -#include <asm/io.h> -#include <asm/hardware.h> -#include <asm/mach-types.h> -#include <asm/arch/oldlatches.h> - -static unsigned char latch_a_copy; -static unsigned char latch_b_copy; - -/* newval=(oldval & ~mask)|newdata */ -void oldlatch_aupdate(unsigned char mask,unsigned char newdata) -{ - if (machine_is_archimedes()) { - unsigned long flags; - - local_save_flags(flags); - latch_a_copy = (latch_a_copy & ~mask) | newdata; - __raw_writeb(latch_a_copy, LATCHA_BASE); - local_restore_flags(flags); - - printk("Latch: A = 0x%02x\n", latch_a_copy); - } else - BUG(); -} - - -/* newval=(oldval & ~mask)|newdata */ -void oldlatch_bupdate(unsigned char mask,unsigned char newdata) -{ - if (machine_is_archimedes()) { - unsigned long flags; - - local_save_flags(flags); - latch_b_copy = (latch_b_copy & ~mask) | newdata; - __raw_writeb(latch_b_copy, LATCHB_BASE); - local_restore_flags(flags); - - printk("Latch: B = 0x%02x\n", latch_b_copy); - } else - BUG(); -} - -static int __init oldlatch_init(void) -{ - if (machine_is_archimedes()) { - oldlatch_aupdate(0xff, 0xff); - /* Thats no FDC reset...*/ - oldlatch_bupdate(0xff, LATCHB_FDCRESET); - } - return 0; -} - -__initcall(oldlatch_init); - -EXPORT_SYMBOL(oldlatch_aupdate); -EXPORT_SYMBOL(oldlatch_bupdate); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/process.c linux-2.5/arch/arm/kernel/process.c --- linux-2.5.1/arch/arm/kernel/process.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/arch/arm/kernel/process.c Sun Jan 6 01:38:26 2002 @@ -85,7 +85,6 @@ /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; - current->counter = -100; while (1) { void (*idle)(void) = pm_idle; @@ -173,10 +172,10 @@ regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0); printk("Flags: %c%c%c%c", - flags & CC_N_BIT ? 'N' : 'n', - flags & CC_Z_BIT ? 'Z' : 'z', - flags & CC_C_BIT ? 'C' : 'c', - flags & CC_V_BIT ? 'V' : 'v'); + flags & PSR_N_BIT ? 'N' : 'n', + flags & PSR_Z_BIT ? 'Z' : 'z', + flags & PSR_C_BIT ? 'C' : 'c', + flags & PSR_V_BIT ? 'V' : 'v'); printk(" IRQs %s FIQs %s Mode %s%s Segment %s\n", interrupts_enabled(regs) ? "on" : "off", fast_interrupts_enabled(regs) ? "on" : "off", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/semaphore.c linux-2.5/arch/arm/kernel/semaphore.c --- linux-2.5.1/arch/arm/kernel/semaphore.c Fri Apr 27 21:11:59 2001 +++ linux-2.5/arch/arm/kernel/semaphore.c Sat Dec 29 11:10:40 2001 @@ -177,8 +177,7 @@ * value in some cases.. */ #ifdef CONFIG_CPU_26 -asm(" .section .text.lock, \"ax\" - .align 5 +asm(" .align 5 .globl __down_failed __down_failed: stmfd sp!, {r0 - r3, lr} @@ -212,13 +211,11 @@ bl __up ldmfd sp!, {r0 - r3, pc}^ - .previous "); #else /* 32 bit version */ -asm(" .section .text.lock, \"ax\" - .align 5 +asm(" .align 5 .globl __down_failed __down_failed: stmfd sp!, {r0 - r3, lr} @@ -252,7 +249,6 @@ bl __up ldmfd sp!, {r0 - r3, pc} - .previous "); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/setup.c linux-2.5/arch/arm/kernel/setup.c --- linux-2.5.1/arch/arm/kernel/setup.c Fri Nov 16 18:07:47 2001 +++ linux-2.5/arch/arm/kernel/setup.c Sun Jan 6 01:38:26 2002 @@ -17,6 +17,7 @@ #include <linux/console.h> #include <linux/bootmem.h> #include <linux/seq_file.h> +#include <linux/tty.h> #include <linux/init.h> #include <asm/elf.h> @@ -105,6 +106,109 @@ #define lp1 io_res[1] #define lp2 io_res[2] +#ifdef CONFIG_CPU_32 +static const char *cache_types[16] = { + "write-through", + "write-back", + "write-back", + "undefined 3", + "undefined 4", + "undefined 5", + "write-back", + "write-back", + "undefined 8", + "undefined 9", + "undefined 10", + "undefined 11", + "undefined 12", + "undefined 13", + "undefined 14", + "undefined 15", +}; + +static const char *cache_clean[16] = { + "not required", + "read-block", + "cp15 c7 ops", + "undefined 3", + "undefined 4", + "undefined 5", + "cp15 c7 ops", + "cp15 c7 ops", + "undefined 8", + "undefined 9", + "undefined 10", + "undefined 11", + "undefined 12", + "undefined 13", + "undefined 14", + "undefined 15", +}; + +static const char *cache_lockdown[16] = { + "not supported", + "not supported", + "not supported", + "undefined 3", + "undefined 4", + "undefined 5", + "format A", + "format B", + "undefined 8", + "undefined 9", + "undefined 10", + "undefined 11", + "undefined 12", + "undefined 13", + "undefined 14", + "undefined 15", +}; + +#define CACHE_TYPE(x) (((x) >> 25) & 15) +#define CACHE_S(x) ((x) & (1 << 24)) +#define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */ +#define CACHE_ISIZE(x) ((x) & 4095) + +#define CACHE_SIZE(y) (((y) >> 6) & 7) +#define CACHE_ASSOC(y) (((y) >> 3) & 7) +#define CACHE_M(y) ((y) & (1 << 2)) +#define CACHE_LINE(y) ((y) & 3) + +static inline void dump_cache(const char *prefix, unsigned int cache) +{ + unsigned int mult = 2 + CACHE_M(cache) ? 1 : 0; + + printk("%s size %dK associativity %d line length %d sets %d\n", + prefix, + mult << (8 + CACHE_SIZE(cache)), + (mult << CACHE_ASSOC(cache)) >> 1, + 8 << CACHE_LINE(cache), + 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) - + CACHE_LINE(cache))); +} + +static inline void dump_cpu_cache_id(void) +{ + unsigned int cache_info; + + asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info)); + + if (cache_info == processor_id) + return; + + printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(cache_info)]); + if (CACHE_S(cache_info)) { + dump_cache("CPU: I cache", CACHE_ISIZE(cache_info)); + dump_cache("CPU: D cache", CACHE_DSIZE(cache_info)); + } else { + dump_cache("CPU: cache", CACHE_ISIZE(cache_info)); + } +} + +#else +#define dump_cpu_cache_id() do { } while (0) +#endif + static void __init setup_processor(void) { extern struct proc_info_list __proc_info_begin, __proc_info_end; @@ -139,6 +243,8 @@ proc_info.manufacturer, proc_info.cpu_name, (int)processor_id & 15); + dump_cpu_cache_id(); + sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); elf_hwcap = list->elf_hwcap; @@ -146,7 +252,7 @@ cpu_proc_init(); } -static struct machine_desc * __init setup_architecture(unsigned int nr) +static struct machine_desc * __init setup_machine(unsigned int nr) { extern struct machine_desc __arch_info_begin, __arch_info_end; struct machine_desc *list; @@ -168,7 +274,7 @@ while (1); } - printk("Architecture: %s\n", list->name); + printk("Machine: %s\n", list->name); if (compat) printk(KERN_WARNING "Using compatibility code " "scheduled for removal in v%d.%d.%d\n", @@ -231,7 +337,7 @@ setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) { #ifdef CONFIG_BLK_DEV_RAM - extern int rd_size; + extern int rd_size, rd_image_start, rd_prompt, rd_doload; rd_image_start = image_start; rd_prompt = prompt; @@ -458,10 +564,10 @@ struct machine_desc *mdesc; char *from = default_command_line; - ROOT_DEV = MKDEV(0, 255); + ROOT_DEV = mk_kdev(0, 255); setup_processor(); - mdesc = setup_architecture(machine_arch_type); + mdesc = setup_machine(machine_arch_type); machine_name = mdesc->name; if (mdesc->soft_reboot) @@ -533,6 +639,41 @@ NULL }; +static const char *proc_arch[16] = { + "undefined 0", + "4", + "4T", + "5", + "5T", + "5TE", + "undefined 6", + "undefined 7", + "undefined 8", + "undefined 9", + "undefined 10", + "undefined 11", + "undefined 12", + "undefined 13", + "undefined 14", + "undefined 15" +}; + +static void +c_show_cache(struct seq_file *m, const char *type, unsigned int cache) +{ + unsigned int mult = 2 + CACHE_M(cache) ? 1 : 0; + + seq_printf(m, "%s size\t\t: %d\n" + "%s assoc\t\t: %d\n" + "%s line length\t: %d\n" + "%s sets\t\t: %d\n", + type, mult << (8 + CACHE_SIZE(cache)), + type, (mult << CACHE_ASSOC(cache)) >> 1, + type, 8 << CACHE_LINE(cache), + type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) - + CACHE_LINE(cache))); +} + static int c_show(struct seq_file *m, void *v) { int i; @@ -552,7 +693,60 @@ if (elf_hwcap & (1 << i)) seq_printf(m, "%s ", hwcap_str[i]); - seq_puts(m, "\n\n"); + seq_puts(m, "\n"); + + if ((processor_id & 0x0000f000) == 0x00000000) { + /* pre-ARM7 */ + seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4); + } else if ((processor_id & 0x0000f000) == 0x00007000) { + /* ARM7 */ + seq_printf(m, "CPU implementor\t: 0x%02x\n" + "CPU architecture: %s\n" + "CPU variant\t: 0x%02x\n" + "CPU part\t: 0x%03x\n", + processor_id >> 24, + processor_id & (1 << 23) ? "4T" : "3", + (processor_id >> 16) & 127, + (processor_id >> 4) & 0xfff); + } else { + /* post-ARM7 */ + seq_printf(m, "CPU implementor\t: 0x%02x\n" + "CPU architecture: %s\n" + "CPU variant\t: 0x%x\n" + "CPU part\t: 0x%03x\n", + processor_id >> 24, + proc_arch[(processor_id >> 16) & 15], + (processor_id >> 20) & 15, + (processor_id >> 4) & 0xfff); + } + seq_printf(m, "CPU revision\t: %d\n", processor_id & 15); + +#ifdef CONFIG_CPU_32 + { + unsigned int cache_info; + + asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info)); + if (cache_info != processor_id) { + seq_printf(m, "Cache type\t: %s\n" + "Cache clean\t: %s\n" + "Cache lockdown\t: %s\n" + "Cache unified\t: %s\n", + cache_types[CACHE_TYPE(cache_info)], + cache_clean[CACHE_TYPE(cache_info)], + cache_lockdown[CACHE_TYPE(cache_info)], + CACHE_S(cache_info) ? "separate I,D" : "unified"); + + if (CACHE_S(cache_info)) { + c_show_cache(m, "I", CACHE_ISIZE(cache_info)); + c_show_cache(m, "D", CACHE_DSIZE(cache_info)); + } else { + c_show_cache(m, "Cache", CACHE_ISIZE(cache_info)); + } + } + } +#endif + + seq_puts(m, "\n"); seq_printf(m, "Hardware\t: %s\n", machine_name); seq_printf(m, "Revision\t: %04x\n", system_rev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/signal.c linux-2.5/arch/arm/kernel/signal.c --- linux-2.5.1/arch/arm/kernel/signal.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/kernel/signal.c Sun Jan 6 01:38:26 2002 @@ -344,7 +344,7 @@ /* * This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(sp)) + if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) sp = current->sas_ss_sp + current->sas_ss_size; /* @@ -378,9 +378,9 @@ thumb = handler & 1; if (thumb) - cpsr |= T_BIT; + cpsr |= PSR_T_BIT; else - cpsr &= ~T_BIT; + cpsr &= ~PSR_T_BIT; } #endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/time.c linux-2.5/arch/arm/kernel/time.c --- linux-2.5.1/arch/arm/kernel/time.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/kernel/time.c Sun Jan 6 01:38:26 2002 @@ -2,7 +2,7 @@ * linux/arch/arm/kernel/time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King + * Modifications for ARM (C) 1994-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 @@ -24,13 +24,12 @@ #include <linux/time.h> #include <linux/init.h> #include <linux/smp.h> +#include <linux/timex.h> -#include <asm/uaccess.h> +#include <asm/hardware.h> #include <asm/io.h> #include <asm/irq.h> - -#include <linux/timex.h> -#include <asm/hardware.h> +#include <asm/leds.h> extern int setup_arm_irq(int, struct irqaction *); extern rwlock_t xtime_lock; @@ -122,18 +121,14 @@ #ifdef CONFIG_LEDS -#include <asm/leds.h> - static void dummy_leds_event(led_event_t evt) { } void (*leds_event)(led_event_t) = dummy_leds_event; -#ifdef CONFIG_MODULES EXPORT_SYMBOL(leds_event); #endif -#endif #ifdef CONFIG_LEDS_TIMER static void do_leds(void) @@ -152,16 +147,15 @@ void do_gettimeofday(struct timeval *tv) { unsigned long flags; - unsigned long usec, sec; + unsigned long usec, sec, lost; read_lock_irqsave(&xtime_lock, flags); usec = gettimeoffset(); - { - unsigned long lost = jiffies - wall_jiffies; - if (lost) - usec += lost * USECS_PER_JIFFY; - } + lost = jiffies - wall_jiffies; + if (lost) + usec += lost * USECS_PER_JIFFY; + sec = xtime.tv_sec; usec += xtime.tv_usec; read_unlock_irqrestore(&xtime_lock, flags); @@ -179,11 +173,11 @@ 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! + /* + * 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) * USECS_PER_JIFFY; @@ -209,17 +203,3 @@ * Include architecture specific code */ #include <asm/arch/time.h> - -/* - * This must cause the timer to start ticking. - * It doesn't have to set the current time though - * from an RTC - it can be done later once we have - * some buses initialised. - */ -void __init time_init(void) -{ - xtime.tv_usec = 0; - xtime.tv_sec = 0; - - setup_timer(); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/kernel/traps.c linux-2.5/arch/arm/kernel/traps.c --- linux-2.5.1/arch/arm/kernel/traps.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/kernel/traps.c Sun Jan 6 01:38:26 2002 @@ -53,7 +53,7 @@ */ static int verify_stack(unsigned long sp) { - if (sp < PAGE_OFFSET || sp > (unsigned long)high_memory) + if (sp < PAGE_OFFSET || (sp > (unsigned long)high_memory && high_memory != 0)) return -EFAULT; return 0; @@ -62,13 +62,16 @@ /* * Dump out the contents of some memory nicely... */ -void dump_mem(unsigned long bottom, unsigned long top) +static void dump_mem(const char *str, unsigned long bottom, unsigned long top) { unsigned long p = bottom & ~31; int i; + printk("%s", str); + printk("(0x%08lx to 0x%08lx)\n", bottom, top); + for (p = bottom & ~31; p < top;) { - printk("%08lx: ", p); + printk("%04lx: ", p & 0xffff); for (i = 0; i < 8; i++, p += 4) { unsigned int val; @@ -79,21 +82,11 @@ __get_user(val, (unsigned long *)p); printk("%08x ", val); } - if (i == 3) - printk(" "); } printk ("\n"); } } -/* - * These constants are for searching for possible module text - * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is - * a guess of how much space is likely to be vmalloced. - */ -#define VMALLOC_OFFSET (8*1024*1024) -#define MODULE_RANGE (8*1024*1024) - static void dump_instr(struct pt_regs *regs) { unsigned long addr = instruction_pointer(regs); @@ -122,8 +115,7 @@ static void dump_stack(struct task_struct *tsk, unsigned long sp) { - printk("Stack:\n"); - dump_mem(sp - 16, 8192+(unsigned long)tsk); + dump_mem("Stack: ", sp - 16, 8192+(unsigned long)tsk); } static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) @@ -289,10 +281,9 @@ handler[reason], processor_modes[proc_mode]); /* - * We need to switch to kernel mode so that we can - * use __get_user to safely read from kernel space. - * Note that we now dump the code first, just in case - * the backtrace kills us. + * We need to switch to kernel mode so that we can use __get_user + * to safely read from kernel space. Note that we now dump the + * code first, just in case the backtrace kills us. */ fs = get_fs(); set_fs(KERNEL_DS); @@ -301,10 +292,8 @@ * Dump out the vectors and stub routines. Maybe a better solution * would be to dump them out only if we detect that they are corrupted. */ - printk(KERN_CRIT "Vectors:\n"); - dump_mem(vectors, 0x40); - printk(KERN_CRIT "Stubs:\n"); - dump_mem(vectors + 0x200, 0x4b8); + dump_mem(KERN_CRIT "Vectors: ", vectors, vectors + 0x40); + dump_mem(KERN_CRIT "Stubs: ", vectors + 0x200, vectors + 0x4b8); set_fs(fs); @@ -528,11 +517,6 @@ void abort(void) { - void *lr = __builtin_return_address(0); - - printk(KERN_CRIT "abort() called from %p! (Please " - "report to rmk@arm.linux.org.uk)\n", lr); - BUG(); /* if that doesn't kill us, halt */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/Makefile linux-2.5/arch/arm/lib/Makefile --- linux-2.5.1/arch/arm/lib/Makefile Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/lib/Makefile Sun Jan 6 01:38:26 2002 @@ -43,9 +43,9 @@ obj-$(v4) += io-readsw-armv4.o io-writesw-armv4.o io-readsl-armv4.o obj-y += io-writesl.o -ifeq ($(PROCESSOR),armo) - obj-y += uaccess-armo.o -endif +obj-$(CONFIG_CPU_26) += uaccess-armo.o +obj-$(CONFIG_CPU_32) += copy_page-armv3.o copy_page-armv4.o copy_page-armv4mc.o +obj-$(CONFIG_CPU_32v5) += copy_page-armv5te.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/changebit.S linux-2.5/arch/arm/lib/changebit.S --- linux-2.5.1/arch/arm/lib/changebit.S Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/lib/changebit.S Thu Dec 27 22:10:28 2001 @@ -14,7 +14,9 @@ /* Purpose : Function to change a bit * Prototype: int change_bit(int bit, void *addr) */ -ENTRY(change_bit) +ENTRY(_change_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_change_bit_le) and r2, r0, #7 mov r3, #1 mov r3, r3, lsl r2 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/clearbit.S linux-2.5/arch/arm/lib/clearbit.S --- linux-2.5.1/arch/arm/lib/clearbit.S Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/lib/clearbit.S Thu Dec 27 22:10:28 2001 @@ -15,8 +15,9 @@ * Purpose : Function to clear a bit * Prototype: int clear_bit(int bit, void *addr) */ - -ENTRY(clear_bit) +ENTRY(_clear_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_clear_bit_le) and r2, r0, #7 mov r3, #1 mov r3, r3, lsl r2 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/copy_page-armv3.S linux-2.5/arch/arm/lib/copy_page-armv3.S --- linux-2.5.1/arch/arm/lib/copy_page-armv3.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/lib/copy_page-armv3.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,59 @@ +/* + * linux/arch/arm/lib/copypage.S + * + * Copyright (C) 1995-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. + * + * ASM optimised string functions + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/constants.h> + + .text + .align 5 +/* + * ARMv3 optimised copy_user_page + * + * FIXME: do we need to handle cache stuff... + */ +ENTRY(armv3_copy_user_page) + stmfd sp!, {r4, lr} @ 2 + mov r2, #PAGE_SZ/64 @ 1 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 +1: stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmneia r1!, {r3, r4, ip, lr} @ 4 + bne 1b @ 1 + LOADREGS(fd, sp!, {r4, pc}) @ 3 + + .align 5 +/* + * ARMv3 optimised clear_user_page + * + * FIXME: do we need to handle cache stuff... + */ +ENTRY(armv3_clear_user_page) + str lr, [sp, #-4]! + mov r1, #PAGE_SZ/64 @ 1 + mov r2, #0 @ 1 + mov r3, #0 @ 1 + mov ip, #0 @ 1 + mov lr, #0 @ 1 +1: stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + bne 1b @ 1 + ldr pc, [sp], #4 + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/copy_page-armv4.S linux-2.5/arch/arm/lib/copy_page-armv4.S --- linux-2.5.1/arch/arm/lib/copy_page-armv4.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/lib/copy_page-armv4.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,70 @@ +/* + * linux/arch/arm/lib/copypage.S + * + * Copyright (C) 1995-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. + * + * ASM optimised string functions + */ +#include <linux/linkage.h> +#include <asm/constants.h> + + .text + .align 5 +/* + * ARMv4 optimised copy_user_page + * + * We flush the destination cache lines just before we write the data into the + * corresponding address. Since the Dcache is read-allocate, this removes the + * Dcache aliasing issue. The writes will be forwarded to the write buffer, + * and merged as appropriate. + * + * Note: We rely on all ARMv4 processors implementing the "invalidate D line" + * instruction. If your processor does not supply this, you have to write your + * own copy_user_page that does the right thing. + */ +ENTRY(armv4_copy_user_page) + stmfd sp!, {r4, lr} @ 2 + mov r2, #PAGE_SZ/64 @ 1 + ldmia r1!, {r3, r4, ip, lr} @ 4 +1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4 + mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmneia r1!, {r3, r4, ip, lr} @ 4 + bne 1b @ 1 + mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB + ldmfd sp!, {r4, pc} @ 3 + + .align 5 +/* + * ARMv4 optimised clear_user_page + * + * Same story as above. + */ +ENTRY(armv4_clear_user_page) + str lr, [sp, #-4]! + mov r1, #PAGE_SZ/64 @ 1 + mov r2, #0 @ 1 + mov r3, #0 @ 1 + mov ip, #0 @ 1 + mov lr, #0 @ 1 +1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + bne 1b @ 1 + mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB + ldr pc, [sp], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/copy_page-armv4mc.S linux-2.5/arch/arm/lib/copy_page-armv4mc.S --- linux-2.5.1/arch/arm/lib/copy_page-armv4mc.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/lib/copy_page-armv4mc.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/lib/copy_page-armv4mc.S + * + * 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 + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include <linux/linkage.h> +#include <asm/constants.h> + + .text + .align 5 +/* + * ARMv4 mini-dcache optimised copy_user_page + * + * We flush the destination cache lines just before we write the data into the + * corresponding address. Since the Dcache is read-allocate, this removes the + * Dcache aliasing issue. The writes will be forwarded to the write buffer, + * and merged as appropriate. + * + * Note: We rely on all ARMv4 processors implementing the "invalidate D line" + * instruction. If your processor does not supply this, you have to write your + * own copy_user_page that does the right thing. + */ +ENTRY(armv4_mc_copy_user_page) + stmfd sp!, {r4, lr} @ 2 + mov r4, r0 + mov r0, r1 + bl map_page_minicache + mov r1, #PAGE_SZ/64 @ 1 + ldmia r0!, {r2, r3, ip, lr} @ 4 +1: mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line + stmia r4!, {r2, r3, ip, lr} @ 4 + ldmia r0!, {r2, r3, ip, lr} @ 4+1 + stmia r4!, {r2, r3, ip, lr} @ 4 + ldmia r0!, {r2, r3, ip, lr} @ 4 + mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line + stmia r4!, {r2, r3, ip, lr} @ 4 + ldmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + stmia r4!, {r2, r3, ip, lr} @ 4 + ldmneia r0!, {r2, r3, ip, lr} @ 4 + bne 1b @ 1 + ldmfd sp!, {r4, pc} @ 3 + + .align 5 +/* + * ARMv4 optimised clear_user_page + * + * Same story as above. + */ +ENTRY(armv4_mc_clear_user_page) + str lr, [sp, #-4]! + mov r1, #PAGE_SZ/64 @ 1 + mov r2, #0 @ 1 + mov r3, #0 @ 1 + mov ip, #0 @ 1 + mov lr, #0 @ 1 +1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + bne 1b @ 1 + ldr pc, [sp], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/copy_page-armv5te.S linux-2.5/arch/arm/lib/copy_page-armv5te.S --- linux-2.5.1/arch/arm/lib/copy_page-armv5te.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/lib/copy_page-armv5te.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,79 @@ +/* + * linux/arch/arm/lib/copypage-armv5te.S + * + * 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/linkage.h> +#include <asm/constants.h> + +/* + * General note: + * We don't really want write-allocate cache behaviour for these functions + * since that will just eat through 8K of the cache. + */ + + .text + .align 5 +/* + * ARMv5TE optimised copy_user_page + * r0 = destination + * r1 = source + * r2 = virtual user address of ultimate destination page + * + * The source page may have some clean entries in the cache already, but we + * can safely ignore them - break_cow() will flush them out of the cache + * if we eventually end up using our copied page. + * + * What we could do is use the mini-cache to buffer reads from the source + * page. We rely on the mini-cache being smaller than one page, so we'll + * cycle through the complete cache anyway. + */ +ENTRY(armv5te_copy_user_page) + stmfd sp!, {r4, r5, lr} + mov r5, r0 + mov r0, r1 + bl map_page_minicache + mov r1, r5 + mov lr, #PAGE_SZ/32 + +1: mov ip, r1 + ldrd r2, [r0], #8 + ldrd r4, [r0], #8 + strd r2, [r1], #8 + ldrd r2, [r0], #8 + strd r4, [r1], #8 + ldrd r4, [r0], #8 + strd r2, [r1], #8 + strd r4, [r1], #8 + mcr p15, 0, ip, c7, c10, 1 @ clean D line + mcr p15, 0, ip, c7, c6, 1 @ invalidate D line + subs lr, lr, #1 + bne 1b + + ldmfd sp!, {r4, r5, pc} + + .align 5 +/* + * ARMv5TE optimised clear_user_page + * r0 = destination + * r1 = virtual user address of ultimate destination page + */ +ENTRY(armv5te_clear_user_page) + str lr, [sp, #-4]! + mov r1, #PAGE_SZ/32 + mov r2, #0 + mov r3, #0 +1: mov ip, r0 + strd r2, [r0], #8 + strd r2, [r0], #8 + strd r2, [r0], #8 + strd r2, [r0], #8 + mcr p15, 0, ip, c7, c10, 1 @ clean D line + mcr p15, 0, ip, c7, c6, 1 @ invalidate D line + subs r1, r1, #1 + bne 1b + ldr pc, [sp], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/delay.S linux-2.5/arch/arm/lib/delay.S --- linux-2.5.1/arch/arm/lib/delay.S Thu Apr 12 19:20:31 2001 +++ linux-2.5/arch/arm/lib/delay.S Sun Jan 6 01:38:26 2002 @@ -29,25 +29,29 @@ RETINSTR(moveq,pc,lr) /* - * loops = (r0 * 0x10c6 * 100 * loops_per_jiffie) / 2^32 + * loops = (r0 * 0x10c6 * 100 * loops_per_jiffy) / 2^32 + * + * Oh, if only we had a cycle counter... */ @ Delay routine ENTRY(__delay) subs r0, r0, #1 - RETINSTR(movcc,pc,lr) +#if 0 + RETINSTR(movls,pc,lr) subs r0, r0, #1 - RETINSTR(movcc,pc,lr) + RETINSTR(movls,pc,lr) subs r0, r0, #1 - RETINSTR(movcc,pc,lr) + RETINSTR(movls,pc,lr) subs r0, r0, #1 - RETINSTR(movcc,pc,lr) + RETINSTR(movls,pc,lr) subs r0, r0, #1 - RETINSTR(movcc,pc,lr) + RETINSTR(movls,pc,lr) subs r0, r0, #1 - RETINSTR(movcc,pc,lr) + RETINSTR(movls,pc,lr) subs r0, r0, #1 - RETINSTR(movcc,pc,lr) + RETINSTR(movls,pc,lr) subs r0, r0, #1 - bcs SYMBOL_NAME(__delay) +#endif + bhi SYMBOL_NAME(__delay) RETINSTR(mov,pc,lr) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/findbit.S linux-2.5/arch/arm/lib/findbit.S --- linux-2.5.1/arch/arm/lib/findbit.S Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/lib/findbit.S Thu Dec 27 22:10:28 2001 @@ -15,14 +15,14 @@ * Purpose : Find a 'zero' bit * Prototype: int find_first_zero_bit(void *addr, int maxbit); */ -ENTRY(find_first_zero_bit) +ENTRY(_find_first_zero_bit_le) mov r2, #0 -.bytelp: ldrb r3, [r0, r2, lsr #3] +1: ldrb r3, [r0, r2, lsr #3] eors r3, r3, #0xff @ invert bits bne .found @ any now set - found zero bit add r2, r2, #8 @ next bit pointer cmp r2, r1 @ any more? - bcc .bytelp + bcc 1b add r0, r1, #1 @ no free bits RETINSTR(mov,pc,lr) @@ -30,15 +30,43 @@ * Purpose : Find next 'zero' bit * Prototype: int find_next_zero_bit(void *addr, int maxbit, int offset) */ -ENTRY(find_next_zero_bit) +ENTRY(_find_next_zero_bit_le) ands ip, r2, #7 - beq .bytelp @ If new byte, goto old routine + beq 1b @ If new byte, goto old routine ldrb r3, [r0, r2, lsr#3] eor r3, r3, #0xff @ now looking for a 1 bit movs r3, r3, lsr ip @ shift off unused bits + bne .found + orr r2, r2, #7 @ if zero, then no bits here + add r2, r2, #1 @ align bit pointer + b 1b @ loop for next bit + +#ifdef __ARMEB__ + +ENTRY(_find_first_zero_bit_be) + mov r2, #0 +1: eor r3, r2, #0x18 @ big endian byte ordering + ldrb r3, [r0, r3, lsr #3] + eors r3, r3, #0xff @ invert bits + bne .found @ any now set - found zero bit + add r2, r2, #8 @ next bit pointer + cmp r2, r1 @ any more? + bcc 1b + add r0, r1, #1 @ no free bits + RETINSTR(mov,pc,lr) + +ENTRY(_find_next_zero_bit_be) + ands ip, r2, #7 + beq 1b @ If new byte, goto old routine + eor r3, r2, #0x18 @ big endian byte ordering + ldrb r3, [r0, r3, lsr#3] + eor r3, r3, #0xff @ now looking for a 1 bit + movs r3, r3, lsr ip @ shift off unused bits orreq r2, r2, #7 @ if zero, then no bits here addeq r2, r2, #1 @ align bit pointer - beq .bytelp @ loop for next bit + beq 1b @ loop for next bit + +#endif /* * One or more bits in the LSB of r3 are assumed to be set. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/getuser.S linux-2.5/arch/arm/lib/getuser.S --- linux-2.5.1/arch/arm/lib/getuser.S Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/lib/getuser.S Sun Jan 6 01:38:26 2002 @@ -49,7 +49,11 @@ cmp r0, r2 2: ldrlsbt r1, [r0], #1 3: ldrlsbt r2, [r0] +#ifndef __ARMEB__ orrls r1, r1, r2, lsl #8 +#else + orrls r1, r2, r1, lsl #8 +#endif movls r0, #0 movls pc, lr b __get_user_bad @@ -80,8 +84,9 @@ /* fall through */ -__get_user_bad: +__get_user_bad_8: mov r2, #0 +__get_user_bad: mov r1, #0 mov r0, #-14 mov pc, lr @@ -91,6 +96,6 @@ .long 2b, __get_user_bad .long 3b, __get_user_bad .long 4b, __get_user_bad - .long 5b, __get_user_bad - .long 6b, __get_user_bad + .long 5b, __get_user_bad_8 + .long 6b, __get_user_bad_8 .previous diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/io-shark.c linux-2.5/arch/arm/lib/io-shark.c --- linux-2.5.1/arch/arm/lib/io-shark.c Thu Apr 12 19:20:31 2001 +++ linux-2.5/arch/arm/lib/io-shark.c Sun Jan 6 01:38:26 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/lib/io-shark.c * - * by Alexander Schulz <aschulz@netwinder.org> + * by Alexander Schulz * * derived from: * linux/arch/arm/lib/io-ebsa.S diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/memcpy.S linux-2.5/arch/arm/lib/memcpy.S --- linux-2.5.1/arch/arm/lib/memcpy.S Wed Mar 7 03:44:35 2001 +++ linux-2.5/arch/arm/lib/memcpy.S Sun Jan 6 01:38:26 2002 @@ -99,24 +99,24 @@ cmp r2, #12 blt 10f sub r2, r2, #12 -9: mov r3, r7, lsr #8 +9: mov r3, r7, pull #8 ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 + orr r3, r3, r4, push #24 + mov r4, r4, pull #8 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 stmia r0!, {r3 - r6} subs r2, r2, #16 bge 9b adds r2, r2, #12 blt 100f -10: mov r3, r7, lsr #8 +10: mov r3, r7, pull #8 ldr r7, [r1], #4 subs r2, r2, #4 - orr r3, r3, r7, lsl #24 + orr r3, r3, r7, push #24 str r3, [r0], #4 bge 10b 100: sub r1, r1, #3 @@ -125,24 +125,24 @@ 11: cmp r2, #12 blt 13f /* */ sub r2, r2, #12 -12: mov r3, r7, lsr #16 +12: mov r3, r7, pull #16 ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #16 - mov r4, r4, lsr #16 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7,LSL#16 + orr r3, r3, r4, push #16 + mov r4, r4, pull #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 stmia r0!, {r3 - r6} subs r2, r2, #16 bge 12b adds r2, r2, #12 blt 14f -13: mov r3, r7, lsr #16 +13: mov r3, r7, pull #16 ldr r7, [r1], #4 subs r2, r2, #4 - orr r3, r3, r7, lsl #16 + orr r3, r3, r7, push #16 str r3, [r0], #4 bge 13b 14: sub r1, r1, #2 @@ -151,24 +151,24 @@ 15: cmp r2, #12 blt 17f sub r2, r2, #12 -16: mov r3, r7, lsr #24 - ldmia r1!,{r4 - r7} - orr r3, r3, r4, lsl #8 - mov r4, r4, lsr #24 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 +16: mov r3, r7, pull #24 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, push #8 + mov r4, r4, pull #24 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 stmia r0!, {r3 - r6} subs r2, r2, #16 bge 16b adds r2, r2, #12 blt 18f -17: mov r3, r7, lsr #24 +17: mov r3, r7, pull #24 ldr r7, [r1], #4 subs r2, r2, #4 - orr r3, r3, r7, lsl#8 + orr r3, r3, r7, push #8 str r3, [r0], #4 bge 17b 18: sub r1, r1, #1 @@ -240,24 +240,24 @@ cmp r2, #12 blt 28f sub r2, r2, #12 -27: mov r7, r3, lsl #8 +27: mov r7, r3, push #8 ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #24 - mov r6, r6, lsl #8 - orr r6, r6, r5, lsr #24 - mov r5, r5, lsl #8 - orr r5, r5, r4, lsr #24 - mov r4, r4, lsl #8 - orr r4, r4, r3, lsr #24 + orr r7, r7, r6, pull #24 + mov r6, r6, push #8 + orr r6, r6, r5, pull #24 + mov r5, r5, push #8 + orr r5, r5, r4, pull #24 + mov r4, r4, push #8 + orr r4, r4, r3, pull #24 stmdb r0!, {r4, r5, r6, r7} subs r2, r2, #16 bge 27b adds r2, r2, #12 blt 29f -28: mov ip, r3, lsl #8 +28: mov ip, r3, push #8 ldr r3, [r1, #-4]! subs r2, r2, #4 - orr ip, ip, r3, lsr #24 + orr ip, ip, r3, pull #24 str ip, [r0, #-4]! bge 28b 29: add r1, r1, #3 @@ -266,24 +266,24 @@ 30: cmp r2, #12 blt 32f sub r2, r2, #12 -31: mov r7, r3, lsl #16 +31: mov r7, r3, push #16 ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #16 - mov r6, r6, lsl #16 - orr r6, r6, r5, lsr #16 - mov r5, r5, lsl #16 - orr r5, r5, r4, lsr #16 - mov r4, r4, lsl #16 - orr r4, r4, r3, lsr #16 + orr r7, r7, r6, pull #16 + mov r6, r6, push #16 + orr r6, r6, r5, pull #16 + mov r5, r5, push #16 + orr r5, r5, r4, pull #16 + mov r4, r4, push #16 + orr r4, r4, r3, pull #16 stmdb r0!, {r4, r5, r6, r7} subs r2, r2, #16 bge 31b adds r2, r2, #12 blt 33f -32: mov ip, r3, lsl #16 +32: mov ip, r3, push #16 ldr r3, [r1, #-4]! subs r2, r2, #4 - orr ip, ip, r3, lsr #16 + orr ip, ip, r3, pull #16 str ip, [r0, #-4]! bge 32b 33: add r1, r1, #2 @@ -292,24 +292,24 @@ 34: cmp r2, #12 blt 36f sub r2, r2, #12 -35: mov r7, r3, lsl #24 +35: mov r7, r3, push #24 ldmdb r1!, {r3, r4, r5, r6} - orr r7, r7, r6, lsr #8 - mov r6, r6, lsl #24 - orr r6, r6, r5, lsr #8 - mov r5, r5, lsl #24 - orr r5, r5, r4, lsr #8 - mov r4, r4, lsl #24 - orr r4, r4, r3, lsr #8 + orr r7, r7, r6, pull #8 + mov r6, r6, push #24 + orr r6, r6, r5, pull #8 + mov r5, r5, push #24 + orr r5, r5, r4, pull #8 + mov r4, r4, push #24 + orr r4, r4, r3, pull #8 stmdb r0!, {r4, r5, r6, r7} subs r2, r2, #16 bge 35b adds r2, r2, #12 blt 37f -36: mov ip, r3, lsl #24 +36: mov ip, r3, push #24 ldr r3, [r1, #-4]! subs r2, r2, #4 - orr ip, ip, r3, lsr #8 + orr ip, ip, r3, pull #8 str ip, [r0, #-4]! bge 36b 37: add r1, r1, #1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/putuser.S linux-2.5/arch/arm/lib/putuser.S --- linux-2.5.1/arch/arm/lib/putuser.S Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/lib/putuser.S Sun Jan 6 01:38:26 2002 @@ -47,9 +47,14 @@ ldr r2, [r2, #TSK_ADDR_LIMIT] sub r2, r2, #2 cmp r0, r2 + movls r2, r1, lsr #8 +#ifndef __ARMEB__ 2: strlsbt r1, [r0], #1 - movls r1, r1, lsr #8 +3: strlsbt r2, [r0] +#else +2: strlsbt r2, [r0], #1 3: strlsbt r1, [r0] +#endif movls r0, #0 movls pc, lr b __put_user_bad diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/setbit.S linux-2.5/arch/arm/lib/setbit.S --- linux-2.5.1/arch/arm/lib/setbit.S Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/lib/setbit.S Thu Dec 27 22:10:28 2001 @@ -9,22 +9,21 @@ */ #include <linux/linkage.h> #include <asm/assembler.h> - .text + .text /* * Purpose : Function to set a bit * Prototype: int set_bit(int bit, void *addr) */ - -ENTRY(set_bit) - and r2, r0, #7 - mov r3, #1 - mov r3, r3, lsl r2 +ENTRY(_set_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_set_bit_le) + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 save_and_disable_irqs ip, r2 ldrb r2, [r1, r0, lsr #3] orr r2, r2, r3 strb r2, [r1, r0, lsr #3] restore_irqs ip RETINSTR(mov,pc,lr) - - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/testchangebit.S linux-2.5/arch/arm/lib/testchangebit.S --- linux-2.5.1/arch/arm/lib/testchangebit.S Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/lib/testchangebit.S Thu Dec 27 22:10:28 2001 @@ -11,7 +11,9 @@ #include <asm/assembler.h> .text -ENTRY(test_and_change_bit) +ENTRY(_test_and_change_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_test_and_change_bit_le) add r1, r1, r0, lsr #3 and r3, r0, #7 mov r0, #1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/testclearbit.S linux-2.5/arch/arm/lib/testclearbit.S --- linux-2.5.1/arch/arm/lib/testclearbit.S Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/lib/testclearbit.S Thu Dec 27 22:10:28 2001 @@ -11,7 +11,9 @@ #include <asm/assembler.h> .text -ENTRY(test_and_clear_bit) +ENTRY(_test_and_clear_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_test_and_clear_bit_le) add r1, r1, r0, lsr #3 @ Get byte offset and r3, r0, #7 @ Get bit offset mov r0, #1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/testsetbit.S linux-2.5/arch/arm/lib/testsetbit.S --- linux-2.5.1/arch/arm/lib/testsetbit.S Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/lib/testsetbit.S Thu Dec 27 22:10:28 2001 @@ -11,7 +11,9 @@ #include <asm/assembler.h> .text -ENTRY(test_and_set_bit) +ENTRY(_test_and_set_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_test_and_set_bit_le) add r1, r1, r0, lsr #3 @ Get byte offset and r3, r0, #7 @ Get bit offset mov r0, #1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/lib/uaccess.S linux-2.5/arch/arm/lib/uaccess.S --- linux-2.5.1/arch/arm/lib/uaccess.S Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/lib/uaccess.S Sun Jan 6 01:38:26 2002 @@ -115,9 +115,9 @@ .c2u_1fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .c2u_1nowords - mov r3, r7, lsr #8 + mov r3, r7, pull #8 ldr r7, [r1], #4 - orr r3, r3, r7, lsl #24 + orr r3, r3, r7, push #24 USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -129,49 +129,49 @@ subs ip, ip, #16 blt .c2u_1rem8lp -.c2u_1cpy8lp: mov r3, r7, lsr #8 +.c2u_1cpy8lp: mov r3, r7, pull #8 ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 + orr r3, r3, r4, push #24 + mov r4, r4, pull #8 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 stmia r0!, {r3 - r6} @ Shouldnt fault subs ip, ip, #16 bpl .c2u_1cpy8lp .c2u_1rem8lp: tst ip, #8 - movne r3, r7, lsr #8 + movne r3, r7, pull #8 ldmneia r1!, {r4, r7} - orrne r3, r3, r4, lsl #24 - movne r4, r4, lsr #8 - orrne r4, r4, r7, lsl #24 + orrne r3, r3, r4, push #24 + movne r4, r4, pull #8 + orrne r4, r4, r7, push #24 stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 - movne r3, r7, lsr #8 + movne r3, r7, pull #8 ldrne r7, [r1], #4 - orrne r3, r3, r7, lsl #24 + orrne r3, r3, r7, push #24 strnet r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .c2u_1fupi -.c2u_1nowords: mov r3, r7, lsr #8 +.c2u_1nowords: mov r3, r7, lsr #byte(1) teq ip, #0 beq .c2u_finished cmp ip, #2 USER( strbt r3, [r0], #1) @ May fault - movge r3, r3, lsr #8 + movge r3, r7, lsr #byte(2) USER( strgebt r3, [r0], #1) @ May fault - movgt r3, r3, lsr #8 + movgt r3, r7, lsr #byte(3) USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished .c2u_2fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .c2u_2nowords - mov r3, r7, lsr #16 + mov r3, r7, pull #16 ldr r7, [r1], #4 - orr r3, r3, r7, lsl #16 + orr r3, r3, r7, push #16 USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -183,38 +183,38 @@ subs ip, ip, #16 blt .c2u_2rem8lp -.c2u_2cpy8lp: mov r3, r7, lsr #16 +.c2u_2cpy8lp: mov r3, r7, pull #16 ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #16 - mov r4, r4, lsr #16 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7, lsl #16 + orr r3, r3, r4, push #16 + mov r4, r4, pull #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 stmia r0!, {r3 - r6} @ Shouldnt fault subs ip, ip, #16 bpl .c2u_2cpy8lp .c2u_2rem8lp: tst ip, #8 - movne r3, r7, lsr #16 + movne r3, r7, pull #16 ldmneia r1!, {r4, r7} - orrne r3, r3, r4, lsl #16 - movne r4, r4, lsr #16 - orrne r4, r4, r7, lsl #16 + orrne r3, r3, r4, push #16 + movne r4, r4, pull #16 + orrne r4, r4, r7, push #16 stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 - movne r3, r7, lsr #16 + movne r3, r7, pull #16 ldrne r7, [r1], #4 - orrne r3, r3, r7, lsl #16 + orrne r3, r3, r7, push #16 strnet r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .c2u_2fupi -.c2u_2nowords: mov r3, r7, lsr #16 +.c2u_2nowords: mov r3, r7, lsr #byte(2) teq ip, #0 beq .c2u_finished cmp ip, #2 USER( strbt r3, [r0], #1) @ May fault - movge r3, r3, lsr #8 + movge r3, r7, lsr #byte(3) USER( strgebt r3, [r0], #1) @ May fault ldrgtb r3, [r1], #0 USER( strgtbt r3, [r0], #1) @ May fault @@ -223,9 +223,9 @@ .c2u_3fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .c2u_3nowords - mov r3, r7, lsr #24 + mov r3, r7, pull #24 ldr r7, [r1], #4 - orr r3, r3, r7, lsl #8 + orr r3, r3, r7, push #8 USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -237,40 +237,40 @@ subs ip, ip, #16 blt .c2u_3rem8lp -.c2u_3cpy8lp: mov r3, r7, lsr #24 +.c2u_3cpy8lp: mov r3, r7, pull #24 ldmia r1!, {r4 - r7} - orr r3, r3, r4, lsl #8 - mov r4, r4, lsr #24 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 + orr r3, r3, r4, push #8 + mov r4, r4, pull #24 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 stmia r0!, {r3 - r6} @ Shouldnt fault subs ip, ip, #16 bpl .c2u_3cpy8lp .c2u_3rem8lp: tst ip, #8 - movne r3, r7, lsr #24 + movne r3, r7, pull #24 ldmneia r1!, {r4, r7} - orrne r3, r3, r4, lsl #8 - movne r4, r4, lsr #24 - orrne r4, r4, r7, lsl #8 + orrne r3, r3, r4, push #8 + movne r4, r4, pull #24 + orrne r4, r4, r7, push #8 stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 - movne r3, r7, lsr #24 + movne r3, r7, pull #24 ldrne r7, [r1], #4 - orrne r3, r3, r7, lsl #8 + orrne r3, r3, r7, push #8 strnet r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .c2u_3fupi -.c2u_3nowords: mov r3, r7, lsr #24 +.c2u_3nowords: mov r3, r7, lsr #byte(3) teq ip, #0 beq .c2u_finished cmp ip, #2 USER( strbt r3, [r0], #1) @ May fault - ldrge r3, [r1], #0 + ldrgeb r3, [r1], #1 USER( strgebt r3, [r0], #1) @ May fault - movgt r3, r3, lsr #8 + ldrgtb r3, [r1], #0 USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished @@ -374,9 +374,9 @@ .cfu_1fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .cfu_1nowords - mov r3, r7, lsr #8 + mov r3, r7, pull #8 USER( ldrt r7, [r1], #4) @ May fault - orr r3, r3, r7, lsl #24 + orr r3, r3, r7, push #24 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -388,49 +388,49 @@ subs ip, ip, #16 blt .cfu_1rem8lp -.cfu_1cpy8lp: mov r3, r7, lsr #8 +.cfu_1cpy8lp: mov r3, r7, pull #8 ldmia r1!, {r4 - r7} @ Shouldnt fault - orr r3, r3, r4, lsl #24 - mov r4, r4, lsr #8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 + orr r3, r3, r4, push #24 + mov r4, r4, pull #8 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 stmia r0!, {r3 - r6} subs ip, ip, #16 bpl .cfu_1cpy8lp .cfu_1rem8lp: tst ip, #8 - movne r3, r7, lsr #8 + movne r3, r7, pull #8 ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, lsl #24 - movne r4, r4, lsr #8 - orrne r4, r4, r7, lsl #24 + orrne r3, r3, r4, push #24 + movne r4, r4, pull #8 + orrne r4, r4, r7, push #24 stmneia r0!, {r3 - r4} tst ip, #4 - movne r3, r7, lsr #8 + movne r3, r7, pull #8 USER( ldrnet r7, [r1], #4) @ May fault - orrne r3, r3, r7, lsl #24 + orrne r3, r3, r7, push #24 strne r3, [r0], #4 ands ip, ip, #3 beq .cfu_1fupi -.cfu_1nowords: mov r3, r7, lsr #8 +.cfu_1nowords: mov r3, r7, lsr #byte(1) teq ip, #0 beq .cfu_finished cmp ip, #2 strb r3, [r0], #1 - movge r3, r3, lsr #8 + movge r3, r7, lsr #byte(2) strgeb r3, [r0], #1 - movgt r3, r3, lsr #8 + movgt r3, r7, lsr #byte(3) strgtb r3, [r0], #1 b .cfu_finished .cfu_2fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .cfu_2nowords - mov r3, r7, lsr #16 + mov r3, r7, pull #16 USER( ldrt r7, [r1], #4) @ May fault - orr r3, r3, r7, lsl #16 + orr r3, r3, r7, push #16 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -442,38 +442,38 @@ subs ip, ip, #16 blt .cfu_2rem8lp -.cfu_2cpy8lp: mov r3, r7, lsr #16 +.cfu_2cpy8lp: mov r3, r7, pull #16 ldmia r1!, {r4 - r7} @ Shouldnt fault - orr r3, r3, r4, lsl #16 - mov r4, r4, lsr #16 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7, lsl #16 + orr r3, r3, r4, push #16 + mov r4, r4, pull #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 stmia r0!, {r3 - r6} subs ip, ip, #16 bpl .cfu_2cpy8lp .cfu_2rem8lp: tst ip, #8 - movne r3, r7, lsr #16 + movne r3, r7, pull #16 ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, lsl #16 - movne r4, r4, lsr #16 - orrne r4, r4, r7, lsl #16 + orrne r3, r3, r4, push #16 + movne r4, r4, pull #16 + orrne r4, r4, r7, push #16 stmneia r0!, {r3 - r4} tst ip, #4 - movne r3, r7, lsr #16 + movne r3, r7, pull #16 USER( ldrnet r7, [r1], #4) @ May fault - orrne r3, r3, r7, lsl #16 + orrne r3, r3, r7, push #16 strne r3, [r0], #4 ands ip, ip, #3 beq .cfu_2fupi -.cfu_2nowords: mov r3, r7, lsr #16 +.cfu_2nowords: mov r3, r7, lsr #byte(2) teq ip, #0 beq .cfu_finished cmp ip, #2 strb r3, [r0], #1 - movge r3, r3, lsr #8 + movge r3, r7, lsr #byte(3) strgeb r3, [r0], #1 USER( ldrgtbt r3, [r1], #0) @ May fault strgtb r3, [r0], #1 @@ -482,9 +482,9 @@ .cfu_3fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .cfu_3nowords - mov r3, r7, lsr #24 + mov r3, r7, pull #24 USER( ldrt r7, [r1], #4) @ May fault - orr r3, r3, r7, lsl #8 + orr r3, r3, r7, push #8 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 @@ -496,40 +496,40 @@ subs ip, ip, #16 blt .cfu_3rem8lp -.cfu_3cpy8lp: mov r3, r7, lsr #24 +.cfu_3cpy8lp: mov r3, r7, pull #24 ldmia r1!, {r4 - r7} @ Shouldnt fault - orr r3, r3, r4, lsl #8 - mov r4, r4, lsr #24 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 + orr r3, r3, r4, push #8 + mov r4, r4, pull #24 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 stmia r0!, {r3 - r6} subs ip, ip, #16 bpl .cfu_3cpy8lp .cfu_3rem8lp: tst ip, #8 - movne r3, r7, lsr #24 + movne r3, r7, pull #24 ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, lsl #8 - movne r4, r4, lsr #24 - orrne r4, r4, r7, lsl #8 + orrne r3, r3, r4, push #8 + movne r4, r4, pull #24 + orrne r4, r4, r7, push #8 stmneia r0!, {r3 - r4} tst ip, #4 - movne r3, r7, lsr #24 + movne r3, r7, pull #24 USER( ldrnet r7, [r1], #4) @ May fault - orrne r3, r3, r7, lsl #8 + orrne r3, r3, r7, push #8 strne r3, [r0], #4 ands ip, ip, #3 beq .cfu_3fupi -.cfu_3nowords: mov r3, r7, lsr #24 +.cfu_3nowords: mov r3, r7, lsr #byte(3) teq ip, #0 beq .cfu_finished cmp ip, #2 strb r3, [r0], #1 -USER( ldrget r3, [r1], #0) @ May fault +USER( ldrgebt r3, [r1], #1) @ May fault strgeb r3, [r0], #1 - movgt r3, r3, lsr #8 +USER( ldrgtbt r3, [r1], #1) @ May fault strgtb r3, [r0], #1 b .cfu_finished diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-adifcc/Makefile linux-2.5/arch/arm/mach-adifcc/Makefile --- linux-2.5.1/arch/arm/mach-adifcc/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-adifcc/Makefile Sun Jan 6 01:38:26 2002 @@ -0,0 +1,21 @@ +# +# 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 := adifcc.o + +# Object file lists. + +obj-y := arch.o irq.o mm.o +obj-m := +obj-n := +obj- := + +export-objs := + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-adifcc/arch.c linux-2.5/arch/arm/mach-adifcc/arch.c --- linux-2.5.1/arch/arm/mach-adifcc/arch.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-adifcc/arch.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,49 @@ +/* + * linux/arch/arm/mach-adifcc/arch.c + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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/init.h> +#include <linux/major.h> +#include <linux/fs.h> +#include <asm/types.h> +#include <asm/setup.h> +#include <asm/memory.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +extern void adifcc_map_io(void); +extern void adifcc_init_irq(void); + +static void __init +fixup_adifcc(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ +#ifdef CONFIG_ARCH_ADI_EVB + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].size = (32*1024*1024); + mi->bank[0].node = 0; + mi->nr_banks = 1; + + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( 0xc0800000, 3*1024*1024 ); + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); +#endif +} + +#ifdef CONFIG_ARCH_ADI_EVB +MACHINE_START(ADI_EVB, "ADI 80200FCC Evaluation Board") + MAINTAINER("MontaVista Software Inc.") + BOOT_MEM(0xc0000000, 0x00400000, 0xff400000) + FIXUP(fixup_adifcc) + MAPIO(adifcc_map_io) + INITIRQ(adifcc_init_irq) +MACHINE_END +#endif + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-adifcc/irq.c linux-2.5/arch/arm/mach-adifcc/irq.c --- linux-2.5.1/arch/arm/mach-adifcc/irq.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-adifcc/irq.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,66 @@ +/* + * linux/arch/arm/mach-xscale/irq.c + * + * Author: Deepak Saxena + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + * Based on IOP80310 code. Currently there's nothing more than the + * 80200 on chip interrupts. That'll change once the hardware adds + * support for PCI though. + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include <asm/mach/irq.h> +#include <asm/irq.h> +#include <asm/hardware.h> + +#include <asm/mach-types.h> + +static void xs80200_irq_mask (unsigned int irq) +{ + long INTCTL; + asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); + switch (irq) { + case IRQ_XS80200_BCU: INTCTL &= ~(1<<3); break; + case IRQ_XS80200_PMU: INTCTL &= ~(1<<2); break; + case IRQ_XS80200_EXTIRQ: INTCTL &= ~(1<<1); break; + case IRQ_XS80200_EXTFIQ: INTCTL &= ~(1<<0); break; + } + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); +} + +static void xs80200_irq_unmask (unsigned int irq) +{ + long INTCTL; + asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); + switch (irq) { + case IRQ_XS80200_BCU: INTCTL |= (1<<3); break; + case IRQ_XS80200_PMU: INTCTL |= (1<<2); break; + case IRQ_XS80200_EXTIRQ: INTCTL |= (1<<1); break; + case IRQ_XS80200_EXTFIQ: INTCTL |= (1<<0); break; + } + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); +} + +void __init adifcc_init_irq(void) +{ + int i; + + for (i = 0; i < NR_XS80200_IRQS; i++) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 0; + irq_desc[i].mask_ack = xs80200_irq_mask; + irq_desc[i].mask = xs80200_irq_mask; + irq_desc[i].unmask = xs80200_irq_unmask; + } +} + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-adifcc/mm.c linux-2.5/arch/arm/mach-adifcc/mm.c --- linux-2.5.1/arch/arm/mach-adifcc/mm.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-adifcc/mm.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,24 @@ +/* + * linux/arch/arm/mach-xscale/mm.c + */ + +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> + +#include <asm/mach/map.h> + + +static struct map_desc adifcc_io_desc[] __initdata = { + /* on-board devices */ + { 0xff400000, 0x00400000, 0x00300000, DOMAIN_IO, 1, 1, 0, 0}, + LAST_DESC +}; + +void __init adifcc_map_io(void) +{ + iotable_init(adifcc_io_desc); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-arc/Makefile linux-2.5/arch/arm/mach-arc/Makefile --- linux-2.5.1/arch/arm/mach-arc/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-arc/Makefile Sun Jan 6 01:38:26 2002 @@ -0,0 +1,28 @@ +# +# 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 := arc.o + +# Object file lists. + +obj-y := arch.o dma.o fault.o irq.o mm.o oldlatches.o \ + small_page.o +obj-m := +obj-n := +obj- := + +export-objs := oldlatches.o + +obj-$(CONFIG_DEBUG_LL) += debug.o + +all: arc.o head.o + +include $(TOPDIR)/Rules.make + +AFLAGS_head.o := -DTEXTADDR=$(TEXTADDR) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-arc/arch.c linux-2.5/arch/arm/mach-arc/arch.c --- linux-2.5.1/arch/arm/mach-arc/arch.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-arc/arch.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,39 @@ +/* + * linux/arch/arm/mach-arc/arch.c + * + * Copyright (C) 1998-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. + * + * Architecture specific fixups. + */ +#include <linux/tty.h> +#include <linux/init.h> + +#include <asm/mach-types.h> +#include <asm/hardware.h> +#include <asm/page.h> +#include <asm/setup.h> + +#include <asm/mach/map.h> +#include <asm/mach/arch.h> + +extern void arc_init_irq(void); + +#ifdef CONFIG_ARCH_ARC +MACHINE_START(ARCHIMEDES, "Acorn-Archimedes") + MAINTAINER("Dave Gilbert") + BOOT_PARAMS(0x0207c000) + INITIRQ(arc_init_irq) +MACHINE_END +#endif +#ifdef CONFIG_ARCH_A5K +MACHINE_START(A5K, "Acorn-A5000") + MAINTAINER("Russell King") + BOOT_PARAMS(0x0207c000) + INITIRQ(arc_init_irq) +MACHINE_END +#endif + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-arc/debug.S linux-2.5/arch/arm/mach-arc/debug.S --- linux-2.5.1/arch/arm/mach-arc/debug.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-arc/debug.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,90 @@ +/* + * linux/arch/arm/kernel/debug-armo.S + * + * Copyright (C) 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. + * + * 26-bit debugging code + */ +#include <linux/linkage.h> + + .macro addruart,rx + mov \rx, #0x03000000 + orr \rx, \rx, #0x00010000 + orr \rx, \rx, #0x00000fe0 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] + .endm + + .macro busyuart,rd,rx +1002: ldrb \rd, [\rx, #0x14] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b + .endm + + .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x18] + tst \rd, #0x10 + beq 1001b + .endm + + .text +/* + * Useful debugging routines + */ +ENTRY(printhex8) + mov r1, #8 + b printhex + +ENTRY(printhex4) + mov r1, #4 + b printhex + +ENTRY(printhex2) + mov r1, #2 +printhex: ldr r2, =hexbuf + add r3, r2, r1 + mov r1, #0 + strb r1, [r3] +1: and r1, r0, #15 + mov r0, r0, lsr #4 + cmp r1, #10 + addlt r1, r1, #'0' + addge r1, r1, #'a' - 10 + strb r1, [r3, #-1]! + teq r3, r2 + bne 1b + mov r0, r2 + b printascii + + .ltorg + +ENTRY(printascii) + addruart r3 + b 2f +1: waituart r2, r3 + senduart r1, r3 + busyuart r2, r3 + teq r1, #'\n' + moveq r1, #'\r' + beq 1b +2: teq r0, #0 + ldrneb r1, [r0], #1 + teqne r1, #0 + bne 1b + mov pc, lr + +ENTRY(printch) + addruart r3 + mov r1, r0 + mov r0, #0 + b 1b + + .bss +hexbuf: .space 16 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-arc/dma.c linux-2.5/arch/arm/mach-arc/dma.c --- linux-2.5.1/arch/arm/mach-arc/dma.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-arc/dma.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,208 @@ +/* + * linux/arch/arm/kernel/dma-arc.c + * + * Copyright (C) 1998-1999 Dave Gilbert / 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. + * + * DMA functions specific to Archimedes and A5000 architecture + */ +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/dma.h> +#include <asm/fiq.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> + +#include <asm/mach/dma.h> + +#define DPRINTK(x...) printk(KERN_DEBUG x) + +#if defined(CONFIG_BLK_DEV_FD1772) || defined(CONFIG_BLK_DEV_FD1772_MODULE) +static void arc_floppy_data_enable_dma(dmach_t channel, dma_t *dma) +{ + DPRINTK("arc_floppy_data_enable_dma\n"); + switch (dma->dma_mode) { + case DMA_MODE_READ: { /* read */ + extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end; + extern void fdc1772_setupdma(unsigned int count,unsigned int addr); + unsigned long flags; + DPRINTK("enable_dma fdc1772 data read\n"); + save_flags(flags); + clf(); + + memcpy ((void *)0x1c, (void *)&fdc1772_dma_read, + &fdc1772_dma_read_end - &fdc1772_dma_read); + fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */ + enable_fiq(FIQ_FLOPPYDATA); + restore_flags(flags); + } + break; + + case DMA_MODE_WRITE: { /* write */ + extern unsigned char fdc1772_dma_write, fdc1772_dma_write_end; + extern void fdc1772_setupdma(unsigned int count,unsigned int addr); + unsigned long flags; + DPRINTK("enable_dma fdc1772 data write\n"); + save_flags(flags); + clf(); + memcpy ((void *)0x1c, (void *)&fdc1772_dma_write, + &fdc1772_dma_write_end - &fdc1772_dma_write); + fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */ + enable_fiq(FIQ_FLOPPYDATA; + + restore_flags(flags); + } + break; + default: + printk ("enable_dma: dma%d not initialised\n", channel); + } +} + +static int arc_floppy_data_get_dma_residue(dmach_t channel, dma_t *dma) +{ + extern unsigned int fdc1772_bytestogo; + + /* 10/1/1999 DAG - I presume its the number of bytes left? */ + return fdc1772_bytestogo; +} + +static void arc_floppy_cmdend_enable_dma(dmach_t channel, dma_t *dma) +{ + /* Need to build a branch at the FIQ address */ + extern void fdc1772_comendhandler(void); + unsigned long flags; + + DPRINTK("arc_floppy_cmdend_enable_dma\n"); + /*printk("enable_dma fdc1772 command end FIQ\n");*/ + save_flags(flags); + clf(); + + /* B fdc1772_comendhandler */ + *((unsigned int *)0x1c)=0xea000000 | + (((unsigned int)fdc1772_comendhandler-(0x1c+8))/4); + + restore_flags(flags); +} + +static int arc_floppy_cmdend_get_dma_residue(dmach_t channel, dma_t *dma) +{ + /* 10/1/1999 DAG - Presume whether there is an outstanding command? */ + extern unsigned int fdc1772_fdc_int_done; + + * Explicit! If the int done is 0 then 1 int to go */ + return (fdc1772_fdc_int_done==0)?1:0; +} + +static void arc_disable_dma(dmach_t channel, dma_t *dma) +{ + disable_fiq(dma->dma_irq); +} + +static struct dma_ops arc_floppy_data_dma_ops = { + type: "FIQDMA", + enable: arc_floppy_data_enable_dma, + disable: arc_disable_dma, + residue: arc_floppy_data_get_dma_residue, +}; + +static struct dma_ops arc_floppy_cmdend_dma_ops = { + type: "FIQCMD", + enable: arc_floppy_cmdend_enable_dma, + disable: arc_disable_dma, + residue: arc_floppy_cmdend_get_dma_residue, +}; +#endif + +#ifdef CONFIG_ARCH_A5K +static struct fiq_handler fh = { + name: "floppydata" +}; + +static int a5k_floppy_get_dma_residue(dmach_t channel, dma_t *dma) +{ + struct pt_regs regs; + get_fiq_regs(®s); + return regs.ARM_r9; +} + +static void a5k_floppy_enable_dma(dmach_t channel, dma_t *dma) +{ + struct pt_regs regs; + void *fiqhandler_start; + unsigned int fiqhandler_length; + extern void floppy_fiqsetup(unsigned long len, unsigned long addr, + unsigned long port); + + if (dma->dma_mode == DMA_MODE_READ) { + extern unsigned char floppy_fiqin_start, floppy_fiqin_end; + fiqhandler_start = &floppy_fiqin_start; + fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start; + } else { + extern unsigned char floppy_fiqout_start, floppy_fiqout_end; + fiqhandler_start = &floppy_fiqout_start; + fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start; + } + if (claim_fiq(&fh)) { + printk("floppydma: couldn't claim FIQ.\n"); + return; + } + memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length); + regs.ARM_r9 = dma->buf.length; + regs.ARM_r10 = (unsigned long)dma->buf.address; + regs.ARM_fp = FLOPPYDMA_BASE; + set_fiq_regs(®s); + enable_fiq(dma->dma_irq); +} + +static void a5k_floppy_disable_dma(dmach_t channel, dma_t *dma) +{ + disable_fiq(dma->dma_irq); + release_fiq(&fh); +} + +static struct dma_ops a5k_floppy_dma_ops = { + type: "FIQDMA", + enable: a5k_floppy_enable_dma, + disable: a5k_floppy_disable_dma, + residue: a5k_floppy_get_dma_residue, +}; +#endif + +/* + * This is virtual DMA - we don't need anything here + */ +static void sound_enable_disable_dma(dmach_t channel, dma_t *dma) +{ +} + +static struct dma_ops sound_dma_ops = { + type: "VIRTUAL", + enable: sound_enable_disable_dma, + disable: sound_enable_disable_dma, +}; + +void __init arch_dma_init(dma_t *dma) +{ +#if defined(CONFIG_BLK_DEV_FD1772) || defined(CONFIG_BLK_DEV_FD1772_MODULE) + if (machine_is_archimedes()) { + dma[DMA_VIRTUAL_FLOPPY0].dma_irq = FIQ_FLOPPYDATA; + dma[DMA_VIRTUAL_FLOPPY0].d_ops = &arc_floppy_data_dma_ops; + dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 1; + dma[DMA_VIRTUAL_FLOPPY1].d_ops = &arc_floppy_cmdend_dma_ops; + } +#endif +#ifdef CONFIG_ARCH_A5K + if (machine_is_a5k()) { + dma[DMA_VIRTUAL_FLOPPY0].dma_irq = FIQ_FLOPPYDATA; + dma[DMA_VIRTUAL_FLOPPY0].d_ops = &a5k_floppy_dma_ops; + } +#endif + dma[DMA_VIRTUAL_SOUND].d_ops = &sound_dma_ops; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-arc/fault.c linux-2.5/arch/arm/mach-arc/fault.c --- linux-2.5.1/arch/arm/mach-arc/fault.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-arc/fault.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,66 @@ +/* + * linux/arch/arm/mm/fault-armo.c + * + * Copyright (C) 1995 Linus Torvalds + * Modifications for ARM processor (c) 1995-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. + */ +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/interrupt.h> + +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/pgtable.h> + +#define FAULT_CODE_LDRSTRPOST 0x80 +#define FAULT_CODE_LDRSTRPRE 0x40 +#define FAULT_CODE_LDRSTRREG 0x20 +#define FAULT_CODE_LDMSTM 0x10 +#define FAULT_CODE_LDCSTC 0x08 +#define FAULT_CODE_PREFETCH 0x04 +#define FAULT_CODE_WRITE 0x02 +#define FAULT_CODE_FORCECOW 0x01 + +#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) +#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) + +extern int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs); +extern void show_pte(struct mm_struct *mm, unsigned long addr); + +/* + * Handle a data abort. Note that we have to handle a range of addresses + * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force + * a copy-on-write. However, on the second page, we always force COW. + */ +asmlinkage void +do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs) +{ + do_page_fault(min_addr, mode, regs); + + if ((min_addr ^ max_addr) >> PAGE_SHIFT) + do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs); +} + +asmlinkage int +do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) +{ +#if 0 + if (the memc mapping for this page exists) { + printk ("Page in, but got abort (undefined instruction?)\n"); + return 0; + } +#endif + do_page_fault(addr, FAULT_CODE_PREFETCH, regs); + return 1; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-arc/head.S linux-2.5/arch/arm/mach-arc/head.S --- linux-2.5.1/arch/arm/mach-arc/head.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-arc/head.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,92 @@ +/* + * linux/arch/arm/kernel/head-armo.S + * + * Copyright (C) 1994-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. + * + * 26-bit kernel startup code + */ +#include <linux/config.h> +#include <linux/linkage.h> +#include <asm/mach-types.h> + + .globl SYMBOL_NAME(swapper_pg_dir) + .equ SYMBOL_NAME(swapper_pg_dir), 0x0207d000 + +/* + * Entry point. + */ + .section ".text.init",#alloc,#execinstr +ENTRY(stext) +__entry: cmp pc, #0x02000000 + ldrlt pc, LC0 @ if 0x01800000, call at 0x02080000 + teq r0, #0 @ Check for old calling method + blne oldparams @ Move page if old + adr r0, LC0 + ldmib r0, {r2-r5, sp} @ Setup stack + mov r0, #0 +1: cmp r2, r3 @ Clear BSS + strcc r0, [r2], #4 + bcc 1b + + bl detect_proc_type + str r0, [r4] + bl detect_arch_type + str r0, [r5] + + mov fp, #0 + b SYMBOL_NAME(start_kernel) + +LC0: .word SYMBOL_NAME(_stext) + .word SYMBOL_NAME(__bss_start) @ r2 + .word SYMBOL_NAME(_end) @ r3 + .word SYMBOL_NAME(processor_id) @ r4 + .word SYMBOL_NAME(__machine_arch_type) @ r5 + .word SYMBOL_NAME(init_task_union)+8192 @ sp +arm2_id: .long 0x41560200 +arm250_id: .long 0x41560250 + .align + +oldparams: mov r4, #0x02000000 + add r3, r4, #0x00080000 + add r4, r4, #0x0007c000 +1: ldmia r0!, {r5 - r12} + stmia r4!, {r5 - r12} + cmp r4, r3 + blt 1b + mov pc, lr + +/* + * We need some way to automatically detect the difference between + * these two machines. Unfortunately, it is not possible to detect + * the presence of the SuperIO chip, because that will hang the old + * Archimedes machines solid. + */ +/* DAG: Outdated, these have been combined !!!!!!! */ +detect_arch_type: +#if defined(CONFIG_ARCH_ARC) + mov r0, #MACH_TYPE_ARCHIMEDES +#elif defined(CONFIG_ARCH_A5K) + mov r0, #MACH_TYPE_A5K +#endif + mov pc, lr + +detect_proc_type: + mov ip, lr + mov r2, #0xea000000 @ Point undef instr to continuation + adr r0, continue - 12 + orr r0, r2, r0, lsr #2 + mov r1, #0 + str r0, [r1, #4] + ldr r0, arm2_id + swp r2, r2, [r1] @ check for swp (ARM2 cant) + ldr r0, arm250_id + 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 + str r2, [r1, #4] + mov pc, ip diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-arc/irq.c linux-2.5/arch/arm/mach-arc/irq.c --- linux-2.5.1/arch/arm/mach-arc/irq.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-arc/irq.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,153 @@ +/* + * linux/arch/arm/mach-arc/irq.c + * + * Copyright (C) 1996 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: + * 24-09-1996 RMK Created + * 10-10-1996 RMK Brought up to date with arch-sa110eval + * 22-10-1996 RMK Changed interrupt numbers & uses new inb/outb macros + * 11-01-1998 RMK Added mask_and_ack_irq + * 22-08-1998 RMK Restructured IRQ routines + */ +#include <linux/config.h> +#include <linux/init.h> + +#include <asm/mach/irq.h> +#include <asm/hardware/ioc.h> +#include <asm/io.h> +#include <asm/system.h> + +extern void init_FIQ(void); + +#ifdef CONFIG_ARCH_ARC +#define a_clf() clf() +#define a_stf() stf() +#else +#define a_clf() do { } while (0) +#define a_stf() do { } while (0) +#endif + +static void arc_mask_irq_ack_a(unsigned int irq) +{ + unsigned int val, mask; + + mask = 1 << irq; + a_clf(); + 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 val, mask; + + mask = 1 << irq; + a_clf(); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val & ~mask, IOC_IRQMASKA); + a_stf(); +} + +static void arc_unmask_irq_a(unsigned int irq) +{ + unsigned int val, mask; + + mask = 1 << irq; + a_clf(); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val | mask, IOC_IRQMASKA); + a_stf(); +} + +static void arc_mask_irq_b(unsigned int irq) +{ + unsigned int val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + mask = 1 << (irq & 7); + val = ioc_readb(IOC_FIQMASK); + ioc_writeb(val | mask, IOC_FIQMASK); +} + +void __init arc_init_irq(void) +{ + int irq; + + ioc_writeb(0, IOC_IRQMASKA); + ioc_writeb(0, IOC_IRQMASKB); + ioc_writeb(0, IOC_FIQMASK); + + for (irq = 0; irq < NR_IRQS; irq++) { + switch (irq) { + case 0 ... 6: + irq_desc[irq].probe_ok = 1; + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = arc_mask_irq_ack_a; + irq_desc[irq].mask = arc_mask_irq_a; + irq_desc[irq].unmask = arc_unmask_irq_a; + break; + + case 7: + irq_desc[irq].noautoenable = 1; + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = arc_mask_irq_ack_a; + irq_desc[irq].mask = arc_mask_irq_a; + irq_desc[irq].unmask = arc_unmask_irq_a; + break; + + case 9 ... 15: + irq_desc[irq].probe_ok = 1; + case 8: + irq_desc[irq].valid = 1; + 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 64 ... 72: + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = arc_mask_irq_fiq; + irq_desc[irq].mask = arc_mask_irq_fiq; + irq_desc[irq].unmask = arc_unmask_irq_fiq; + break; + } + } + + irq_desc[IRQ_KEYBOARDTX].noautoenable = 1; + + init_FIQ(); +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-arc/mm.c linux-2.5/arch/arm/mach-arc/mm.c --- linux-2.5.1/arch/arm/mach-arc/mm.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-arc/mm.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,184 @@ +/* + * linux/arch/arm/mm/mm-armo.c + * + * Copyright (C) 1998-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. + * + * Page table sludge for older ARM processor architectures. + */ +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/bootmem.h> + +#include <asm/pgtable.h> +#include <asm/pgalloc.h> +#include <asm/page.h> +#include <asm/arch/memory.h> + +#include <asm/mach/map.h> + +#define MEMC_TABLE_SIZE (256*sizeof(unsigned long)) + +kmem_cache_t *pte_cache, *pgd_cache; +int page_nr; + +/* + * 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. + */ +static inline pgd_t *alloc_pgd_table(int priority) +{ + void *pg2k = kmem_cache_alloc(pgd_cache, GFP_KERNEL); + + if (pg2k) + pg2k += MEMC_TABLE_SIZE; + + 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; + + kmem_cache_free(pgd_cache, (void *)tbl); +} + +pgd_t *get_pgd_slow(struct mm_struct *mm) +{ + 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; + + 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); + free_pgd_slow(new_pgd); + return NULL; + +no_pmd: + spin_unlock(&mm->page_table_lock); + free_pgd_slow(new_pgd); + return NULL; + +no_pgd: + return NULL; +} + +/* + * No special code is required here. + */ +void setup_mm_for_reboot(char mode) +{ +} + +/* + * This contains the code to setup the memory map on an ARM2/ARM250/ARM3 + * machine. This is both processor & architecture specific, and requires + * some more work to get it to fit into our separate processor and + * architecture structure. + */ +void __init memtable_init(struct meminfo *mi) +{ + pte_t *pte; + int i; + + page_nr = max_low_pfn; + + pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t)); + pte[0] = mk_pte_phys(PAGE_OFFSET + 491520, PAGE_READONLY); + 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; +} + +void __init iotable_init(struct map_desc *io_desc) +{ + /* nothing to do */ +} + +/* + * We never have holes in the memmap + */ +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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-arc/oldlatches.c linux-2.5/arch/arm/mach-arc/oldlatches.c --- linux-2.5.1/arch/arm/mach-arc/oldlatches.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-arc/oldlatches.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,72 @@ +/* + * linux/arch/arm/kernel/oldlatches.c + * + * Copyright (C) David Alan Gilbert 1995/1996,2000 + * + * 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. + * + * Support for the latches on the old Archimedes which control the floppy, + * hard disc and printer + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> + +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/arch/oldlatches.h> + +static unsigned char latch_a_copy; +static unsigned char latch_b_copy; + +/* newval=(oldval & ~mask)|newdata */ +void oldlatch_aupdate(unsigned char mask,unsigned char newdata) +{ + if (machine_is_archimedes()) { + unsigned long flags; + + local_save_flags(flags); + latch_a_copy = (latch_a_copy & ~mask) | newdata; + __raw_writeb(latch_a_copy, LATCHA_BASE); + local_restore_flags(flags); + + printk("Latch: A = 0x%02x\n", latch_a_copy); + } else + BUG(); +} + + +/* newval=(oldval & ~mask)|newdata */ +void oldlatch_bupdate(unsigned char mask,unsigned char newdata) +{ + if (machine_is_archimedes()) { + unsigned long flags; + + local_save_flags(flags); + latch_b_copy = (latch_b_copy & ~mask) | newdata; + __raw_writeb(latch_b_copy, LATCHB_BASE); + local_restore_flags(flags); + + printk("Latch: B = 0x%02x\n", latch_b_copy); + } else + BUG(); +} + +static int __init oldlatch_init(void) +{ + if (machine_is_archimedes()) { + oldlatch_aupdate(0xff, 0xff); + /* Thats no FDC reset...*/ + oldlatch_bupdate(0xff, LATCHB_FDCRESET); + } + return 0; +} + +__initcall(oldlatch_init); + +EXPORT_SYMBOL(oldlatch_aupdate); +EXPORT_SYMBOL(oldlatch_bupdate); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-arc/small_page.c linux-2.5/arch/arm/mach-arc/small_page.c --- linux-2.5.1/arch/arm/mach-arc/small_page.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-arc/small_page.c Tue Jan 8 00:44:24 2002 @@ -0,0 +1,213 @@ +/* + * linux/arch/arm/mm/small_page.c + * + * Copyright (C) 1996 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: + * 26/01/1996 RMK Cleaned up various areas to make little more generic + * 07/02/1999 RMK Support added for 16K and 32K page sizes + * containing 8K blocks + */ +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/swap.h> +#include <linux/smp.h> + +#include <asm/bitops.h> +#include <asm/pgtable.h> + +#define PEDANTIC + +/* + * Requirement: + * We need to be able to allocate naturally aligned memory of finer + * granularity than the page size. This is typically used for the + * second level page tables on 32-bit ARMs. + * + * Theory: + * We "misuse" the Linux memory management system. We use alloc_page + * to allocate a page and then mark it as reserved. The Linux memory + * management system will then ignore the "offset", "next_hash" and + * "pprev_hash" entries in the mem_map for this page. + * + * We then use a bitstring in the "offset" field to mark which segments + * of the page are in use, and manipulate this as required during the + * allocation and freeing of these small pages. + * + * We also maintain a queue of pages being used for this purpose using + * the "next_hash" and "pprev_hash" entries of mem_map; + */ + +struct order { + struct page *queue; + unsigned int mask; /* (1 << shift) - 1 */ + unsigned int shift; /* (1 << shift) size of page */ + unsigned int block_mask; /* nr_blocks - 1 */ + unsigned int all_used; /* (1 << nr_blocks) - 1 */ +}; + + +static struct order orders[] = { +#if PAGE_SIZE == 4096 + { NULL, 2047, 11, 1, 0x00000003 } +#elif PAGE_SIZE == 32768 + { NULL, 2047, 11, 15, 0x0000ffff }, + { NULL, 8191, 13, 3, 0x0000000f } +#else +#error unsupported page size +#endif +}; + +#define USED_MAP(pg) ((pg)->index) +#define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &USED_MAP(pg))) +#define SET_USED(pg,off) (set_bit(off, &USED_MAP(pg))) + +static spinlock_t small_page_lock = SPIN_LOCK_UNLOCKED; + +static void add_page_to_queue(struct page *page, struct page **p) +{ +#ifdef PEDANTIC + if (page->pprev_hash) + PAGE_BUG(page); +#endif + page->next_hash = *p; + if (*p) + (*p)->pprev_hash = &page->next_hash; + *p = page; + page->pprev_hash = p; +} + +static void remove_page_from_queue(struct page *page) +{ + if (page->pprev_hash) { + if (page->next_hash) + page->next_hash->pprev_hash = page->pprev_hash; + *page->pprev_hash = page->next_hash; + page->pprev_hash = NULL; + } +} + +static unsigned long __get_small_page(int priority, struct order *order) +{ + unsigned long flags; + struct page *page; + int offset; + + if (!order->queue) + goto need_new_page; + + spin_lock_irqsave(&small_page_lock, flags); + page = order->queue; +again: +#ifdef PEDANTIC + if (USED_MAP(page) & ~order->all_used) + PAGE_BUG(page); +#endif + offset = ffz(USED_MAP(page)); + SET_USED(page, offset); + if (USED_MAP(page) == order->all_used) + remove_page_from_queue(page); + spin_unlock_irqrestore(&small_page_lock, flags); + + return (unsigned long) page_address(page) + (offset << order->shift); + +need_new_page: + page = alloc_page(priority); + + spin_lock_irqsave(&small_page_lock, flags); + if (!order->queue) { + if (!page) + goto no_page; + SetPageReserved(page); + USED_MAP(page) = 0; + cli(); + add_page_to_queue(page, &order->queue); + } else { + __free_page(page); + cli(); + page = order->queue; + } + goto again; + +no_page: + spin_unlock_irqrestore(&small_page_lock, flags); + return 0; +} + +static void __free_small_page(unsigned long spage, struct order *order) +{ + unsigned long flags; + struct page *page; + + page = virt_to_page(spage); + if (VALID_PAGE(page)) { + + /* + * The container-page must be marked Reserved + */ + if (!PageReserved(page) || spage & order->mask) + goto non_small; + +#ifdef PEDANTIC + if (USED_MAP(page) & ~order->all_used) + PAGE_BUG(page); +#endif + + spage = spage >> order->shift; + spage &= order->block_mask; + + /* + * the following must be atomic wrt get_page + */ + spin_lock_irqsave(&small_page_lock, flags); + + if (USED_MAP(page) == order->all_used) + add_page_to_queue(page, &order->queue); + + if (!TEST_AND_CLEAR_USED(page, spage)) + goto already_free; + + if (USED_MAP(page) == 0) + goto free_page; + + spin_unlock_irqrestore(&small_page_lock, flags); + } + return; + +free_page: + /* + * unlink the page from the small page queue and free it + */ + remove_page_from_queue(page); + spin_unlock_irqrestore(&small_page_lock, flags); + ClearPageReserved(page); + __free_page(page); + return; + +non_small: + printk("Trying to free non-small page from %p\n", __builtin_return_address(0)); + return; +already_free: + printk("Trying to free free small page from %p\n", __builtin_return_address(0)); +} + +unsigned long get_page_8k(int priority) +{ + return __get_small_page(priority, orders+1); +} + +void free_page_8k(unsigned long spage) +{ + __free_small_page(spage, orders+1); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/Makefile linux-2.5/arch/arm/mach-clps711x/Makefile --- linux-2.5.1/arch/arm/mach-clps711x/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/Makefile Sun Jan 6 01:38:26 2002 @@ -0,0 +1,29 @@ +# +# 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 := clps711x.o + +# Object file lists. + +obj-y := irq.o mm.o time.o +obj-m := +obj-n := +obj- := + +export-objs := leds-p720t.o + +obj-$(CONFIG_ARCH_AUTCPU12) += autcpu12.o +obj-$(CONFIG_ARCH_CDB89712) += cdb89712.o +obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o +obj-$(CONFIG_ARCH_EDB7211) += edb7211-arch.o edb7211-mm.o +obj-$(CONFIG_ARCH_P720T) += p720t.o +leds-$(CONFIG_ARCH_P720T) += p720t-leds.o +obj-$(CONFIG_LEDS) += $(leds-y) + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/autcpu12.c linux-2.5/arch/arm/mach-clps711x/autcpu12.c --- linux-2.5.1/arch/arm/mach-clps711x/autcpu12.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/autcpu12.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,72 @@ +/* + * linux/arch/arm/mach-clps711x/autcpu12.c + * + * (c) 2001 Thomas Gleixner, autronix automation <gleixner@autronix.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/init.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/blk.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/hardware.h> +#include <asm/sizes.h> +#include <asm/io.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/pgtable.h> +#include <asm/page.h> + +#include <asm/mach/map.h> +#include <asm/arch/autcpu12.h> + +extern void clps711x_map_io(void); +extern void clps711x_init_irq(void); + +/* + * The on-chip registers are given a size of 1MB so that a section can + * be used to map them; this saves a page table. This is the place to + * add mappings for ROM, expansion memory, PCMCIA, etc. (if static + * mappings are chosen for those areas). + * +*/ + +static struct map_desc autcpu12_io_desc[] __initdata = { + /* virtual, physical, length, domain, r, w, c, b */ + /* memory-mapped extra io and CS8900A Ethernet chip */ + /* ethernet chip */ + { AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, DOMAIN_IO, 1, 1, 0, 0 }, + + LAST_DESC +}; + +void __init autcpu12_map_io(void) +{ + clps711x_map_io(); + iotable_init(autcpu12_io_desc); +} + +MACHINE_START(AUTCPU12, "autronix autcpu12") + MAINTAINER("Thomas Gleixner") + BOOT_MEM(0xc0000000, 0x80000000, 0xff000000) + BOOT_PARAMS(0xc0020000) + MAPIO(autcpu12_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/cdb89712.c linux-2.5/arch/arm/mach-clps711x/cdb89712.c --- linux-2.5.1/arch/arm/mach-clps711x/cdb89712.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/cdb89712.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,75 @@ +/* + * linux/arch/arm/mach-clps711x/cdb89712.c + * + * Copyright (C) 2000-2001 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 + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +extern void clps711x_init_irq(void); +extern void clps711x_map_io(void); + +/* + * Map the CS89712 Ethernet port. That should be moved to the + * ethernet driver, perhaps. + */ +static struct map_desc cdb89712_io_desc[] __initdata = { + { ETHER_BASE, ETHER_START, ETHER_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +static void __init +fixup_cdb89712(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ +} + +static void __init cdb89712_map_io(void) +{ + clps711x_map_io(); + iotable_init(cdb89712_io_desc); +} + +MACHINE_START(CDB89712, "Cirrus-CDB89712") + MAINTAINER("Ray Lehtiniemi") + BOOT_MEM(0xc0000000, 0x80000000, 0xff000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_cdb89712) + MAPIO(cdb89712_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END + +static int cdb89712_hw_init(void) +{ + return 0; +} + +__initcall(cdb89712_hw_init); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/clep7312.c linux-2.5/arch/arm/mach-clps711x/clep7312.c --- linux-2.5.1/arch/arm/mach-clps711x/clep7312.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/clep7312.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,49 @@ +/* + * linux/arch/arm/mach-clps711x/clep7312.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/init.h> +#include <linux/types.h> +#include <linux/string.h> + +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +extern void clps711x_init_irq(void); +extern void clps711x_map_io(void); + +static void __init +fixup_clep7312(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks=1; + mi->end = 0xc0FFFFFF; + mi->bank[0].start = 0xc0000000; + mi->bank[0].size = 0x01000000; + mi->bank[0].node = 0; +} + + +MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312") + MAINTAINER("Nobody") + BOOT_MEM(0xc0000000, 0x80000000, 0xff000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_clep7312) + MAPIO(clps711x_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/dma.c linux-2.5/arch/arm/mach-clps711x/dma.c --- linux-2.5.1/arch/arm/mach-clps711x/dma.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/dma.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,35 @@ +/* + * linux/arch/arm/mach-clps711x/dma.c + * + * 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 + */ +#include <linux/sched.h> +#include <linux/malloc.h> +#include <linux/mman.h> +#include <linux/init.h> + +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/hardware.h> + +#include <asm/mach/dma.h> + +void __init arch_dma_init(dma_t *dma) +{ +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/edb7211-arch.c linux-2.5/arch/arm/mach-clps711x/edb7211-arch.c --- linux-2.5.1/arch/arm/mach-clps711x/edb7211-arch.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/edb7211-arch.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,59 @@ +/* + * linux/arch/arm/mach-clps711x/arch-edb7211.c + * + * Copyright (C) 2000, 2001 Blue Mug, 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 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/init.h> +#include <linux/types.h> +#include <linux/string.h> + +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +extern void clps711x_init_irq(void); +extern void edb7211_map_io(void); + +static void __init +fixup_edb7211(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + /* + * Bank start addresses are not present in the information + * passed in from the boot loader. We could potentially + * detect them, but instead we hard-code them. + * + * Banks sizes _are_ present in the param block, but we're + * not using that information yet. + */ + mi->bank[0].start = 0xc0000000; + mi->bank[0].size = 8*1024*1024; + mi->bank[0].node = 0; + mi->bank[1].start = 0xc1000000; + mi->bank[1].size = 8*1024*1024; + mi->bank[1].node = 1; + mi->nr_banks = 2; +} + +MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)") + MAINTAINER("Jon McClintock") + BOOT_MEM(0xc0000000, 0x80000000, 0xff000000) + BOOT_PARAMS(0xc0020100) /* 0xc0000000 - 0xc001ffff can be video RAM */ + FIXUP(fixup_edb7211) + MAPIO(edb7211_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/edb7211-mm.c linux-2.5/arch/arm/mach-clps711x/edb7211-mm.c --- linux-2.5.1/arch/arm/mach-clps711x/edb7211-mm.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/edb7211-mm.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,74 @@ +/* + * linux/arch/arm/mach-clps711x/mm.c + * + * Extra MM routines for the EDB7211 board + * + * Copyright (C) 2000, 2001 Blue Mug, 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 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/mm.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/pgtable.h> +#include <asm/page.h> + +#include <asm/mach/map.h> + +#define MB1 1048576 /* one megabyte == size of an MMU section */ + +extern void clps711x_map_io(void); + +/* + * The on-chip registers are given a size of 1MB so that a section can + * be used to map them; this saves a page table. This is the place to + * add mappings for ROM, expansion memory, PCMCIA, etc. (if static + * mappings are chosen for those areas). + * + * Here is a physical memory map (to be fleshed out later): + * + * Physical Address Size Description + * ----------------- ----- --------------------------------- + * c0000000-c001ffff 128KB reserved for video RAM [1] + * c0020000-c0023fff 16KB parameters (see Documentation/arm/Setup) + * c0024000-c0027fff 16KB swapper_pg_dir (task 0 page directory) + * c0028000-... kernel image (TEXTADDR) + * + * [1] Unused pages should be given back to the VM; they are not yet. + * The parameter block should also be released (not sure if this + * happens). + */ +static struct map_desc edb7211_io_desc[] __initdata = { + /* virtual, physical, length, domain, r, w, c, b */ + + /* memory-mapped extra keyboard row and CS8900A Ethernet chip */ + { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, MB1, DOMAIN_IO, 1, 1, 0, 0 }, + { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, MB1, DOMAIN_IO, 1, 1, 0, 0 }, + + /* flash banks */ + { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, MB1 * 8, DOMAIN_KERNEL, 1, 1, 0, 0 }, + { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, MB1 * 8, DOMAIN_KERNEL, 1, 1, 0, 0 }, + + LAST_DESC +}; + +void __init edb7211_map_io(void) +{ + clps711x_map_io(); + iotable_init(edb7211_io_desc); +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/irq.c linux-2.5/arch/arm/mach-clps711x/irq.c --- linux-2.5.1/arch/arm/mach-clps711x/irq.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/irq.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,138 @@ +/* + * linux/arch/arm/mach-clps711x/irq.c + * + * 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 + */ +#include <linux/init.h> + +#include <asm/mach/irq.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> + +#include <asm/hardware/clps7111.h> + +static void mask_irq_int1(unsigned int irq) +{ + u32 intmr1; + + intmr1 = clps_readl(INTMR1); + intmr1 &= ~(1 << irq); + clps_writel(intmr1, INTMR1); +} + +static void mask_ack_irq_int1(unsigned int irq) +{ + u32 intmr1; + + intmr1 = clps_readl(INTMR1); + intmr1 &= ~(1 << irq); + clps_writel(intmr1, INTMR1); + + switch (irq) { + case IRQ_CSINT: clps_writel(0, COEOI); break; + case IRQ_TC1OI: clps_writel(0, TC1EOI); break; + case IRQ_TC2OI: clps_writel(0, TC2EOI); break; + case IRQ_RTCMI: clps_writel(0, RTCEOI); break; + case IRQ_TINT: clps_writel(0, TEOI); break; + case IRQ_UMSINT: clps_writel(0, UMSEOI); break; + } +} + +static void unmask_irq_int1(unsigned int irq) +{ + u32 intmr1; + + intmr1 = clps_readl(INTMR1); + intmr1 |= 1 << irq; + clps_writel(intmr1, INTMR1); +} + +static void mask_irq_int2(unsigned int irq) +{ + u32 intmr2; + + intmr2 = clps_readl(INTMR2); + intmr2 &= ~(1 << (irq - 16)); + clps_writel(intmr2, INTMR2); +} + +static void mask_ack_irq_int2(unsigned int irq) +{ + u32 intmr2; + + intmr2 = clps_readl(INTMR2); + intmr2 &= ~(1 << (irq - 16)); + clps_writel(intmr2, INTMR2); + + switch (irq) { + case IRQ_KBDINT: clps_writel(0, KBDEOI); break; + } +} + +static void unmask_irq_int2(unsigned int irq) +{ + u32 intmr2; + + intmr2 = clps_readl(INTMR2); + intmr2 |= 1 << (irq - 16); + clps_writel(intmr2, INTMR2); +} + +void __init clps711x_init_irq(void) +{ + unsigned int i; + + for (i = 0; i < NR_IRQS; i++) { + if (INT1_IRQS & (1 << i)) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = (INT1_ACK_IRQS & (1 << i)) ? + mask_ack_irq_int1 : + mask_irq_int1; + irq_desc[i].mask = mask_irq_int1; + irq_desc[i].unmask = unmask_irq_int1; + } + if (INT2_IRQS & (1 << i)) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = (INT2_ACK_IRQS & (1 << i)) ? + mask_ack_irq_int2 : + mask_irq_int2; + irq_desc[i].mask = mask_irq_int2; + irq_desc[i].unmask = unmask_irq_int2; + } + } + + /* + * Disable interrupts + */ + clps_writel(0, INTMR1); + clps_writel(0, INTMR2); + + /* + * Clear down any pending interrupts + */ + clps_writel(0, COEOI); + clps_writel(0, TC1EOI); + clps_writel(0, TC2EOI); + clps_writel(0, RTCEOI); + clps_writel(0, TEOI); + clps_writel(0, UMSEOI); + clps_writel(0, SYNCIO); + clps_writel(0, KBDEOI); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/mm.c linux-2.5/arch/arm/mach-clps711x/mm.c --- linux-2.5.1/arch/arm/mach-clps711x/mm.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/mm.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,70 @@ +/* + * linux/arch/arm/mach-clps711x/mm.c + * + * Generic MM setup for the CLPS711x-based machines. + * + * Copyright (C) 2001 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 + */ +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/config.h> +#include <linux/bootmem.h> + +#include <asm/hardware.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/mach/map.h> +#include <asm/hardware/clps7111.h> + +#if 0 //def CONFIG_DISCONTIGMEM + +/* + * The assumption of maximum 4 discontiguous memory banks is present + * in several places in the ARM kernel, including the parameter block + * (this affects boot loaders, too). Banks do not necessarily + * correspond 1:1 with NUMA nodes, although they usually will, + * especially if they are widely discontiguous. + * + * - note that the parameter block is depreciated for new implementations + * - also note that discontig_node_data is actually used + * -- rmk + */ + +static bootmem_data_t node_bootmem_data[4]; + +pg_data_t clps711x_node_data[4] = { + { bdata: &node_bootmem_data[0] }, + { bdata: &node_bootmem_data[1] }, + { bdata: &node_bootmem_data[2] }, + { bdata: &node_bootmem_data[3] }, +}; + +#endif + +/* + * This maps the generic CLPS711x registers + */ +static struct map_desc clps711x_io_desc[] __initdata = { + { CLPS7111_VIRT_BASE, CLPS7111_PHYS_BASE, 1048576, DOMAIN_IO, 0, 1 }, + LAST_DESC +}; + +void __init clps711x_map_io(void) +{ + iotable_init(clps711x_io_desc); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/p720t-leds.c linux-2.5/arch/arm/mach-clps711x/p720t-leds.c --- linux-2.5.1/arch/arm/mach-clps711x/p720t-leds.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/p720t-leds.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,67 @@ +/* + * linux/arch/arm/mach-clps711x/leds.c + * + * Integrator LED control routines + * + * 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 + */ +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/leds.h> +#include <asm/system.h> +#include <asm/mach-types.h> + +#include <asm/hardware/clps7111.h> +#include <asm/hardware/ep7212.h> + +static void p720t_leds_event(led_event_t ledevt) +{ + unsigned long flags; + u32 pddr; + + local_irq_save(flags); + switch(ledevt) { + case led_idle_start: + break; + + case led_idle_end: + break; + + case led_timer: + pddr = clps_readb(PDDR); + clps_writeb(pddr ^ 1, PDDR); + break; + + default: + break; + } + + local_irq_restore(flags); +} + +static int __init leds_init(void) +{ + if (machine_is_p720t()) + leds_event = p720t_leds_event; + + return 0; +} + +__initcall(leds_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/p720t.c linux-2.5/arch/arm/mach-clps711x/p720t.c --- linux-2.5.1/arch/arm/mach-clps711x/p720t.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/p720t.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,118 @@ +/* + * linux/arch/arm/mach-clps711x/p720t.c + * + * Copyright (C) 2000-2001 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 + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/arch/syspld.h> + +extern void clps711x_init_irq(void); +extern void clps711x_map_io(void); + +/* + * Map the P720T system PLD. It occupies two address spaces: + * SYSPLD_PHYS_BASE and SYSPLD_PHYS_BASE + 0x00400000 + * We map both here. + */ +static struct map_desc p720t_io_desc[] __initdata = { + { SYSPLD_VIRT_BASE, SYSPLD_PHYS_BASE, 1048576, DOMAIN_IO, 0, 1 }, + { 0xfe400000, 0x10400000, 1048576, DOMAIN_IO, 0, 1 }, + LAST_DESC +}; + +static void __init +fixup_p720t(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + struct tag *tag = (struct tag *)params; + + /* + * Our bootloader doesn't setup any tags (yet). + */ + if (tag->hdr.tag != ATAG_CORE) { + tag->hdr.tag = ATAG_CORE; + tag->hdr.size = tag_size(tag_core); + tag->u.core.flags = 0; + tag->u.core.pagesize = PAGE_SIZE; + tag->u.core.rootdev = 0x0100; + + tag = tag_next(tag); + tag->hdr.tag = ATAG_MEM; + tag->hdr.size = tag_size(tag_mem32); + tag->u.mem.size = 4096; + tag->u.mem.start = PHYS_OFFSET; + + tag = tag_next(tag); + tag->hdr.tag = ATAG_NONE; + tag->hdr.size = 0; + } +} + +static void __init p720t_map_io(void) +{ + clps711x_map_io(); + iotable_init(p720t_io_desc); +} + +MACHINE_START(P720T, "ARM-Prospector720T") + MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") + BOOT_MEM(0xc0000000, 0x80000000, 0xff000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_p720t) + MAPIO(p720t_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END + +static int p720t_hw_init(void) +{ + /* + * Power down as much as possible in case we don't + * have the drivers loaded. + */ + PLD_LCDEN = 0; + PLD_PWR &= ~(PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON); + + PLD_KBD = 0; + PLD_IO = 0; + PLD_IRDA = 0; + PLD_CODEC = 0; + PLD_TCH = 0; + PLD_SPI = 0; +#ifndef CONFIG_DEBUG_LL + PLD_COM2 = 0; + PLD_COM1 = 0; +#endif + + return 0; +} + +__initcall(p720t_hw_init); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps711x/time.c linux-2.5/arch/arm/mach-clps711x/time.c --- linux-2.5.1/arch/arm/mach-clps711x/time.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/time.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,54 @@ +/* + * linux/arch/arm/mach-clps711x/time.c + * + * Copyright (C) 2001 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 version 2 as + * published by the Free Software Foundation. + * + * 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/init.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/hardware/clps7111.h> + +extern unsigned long (*gettimeoffset)(void); + +/* + * gettimeoffset() returns time since last timer tick, in usecs. + * + * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy. + * 'tick' is usecs per jiffy. + */ +static unsigned long clps711x_gettimeoffset(void) +{ + unsigned long hwticks; + hwticks = LATCH - (clps_readl(TC2D) & 0xffff); /* since last underflow */ + return (hwticks * tick) / LATCH; +} + +void __init clps711x_setup_timer(void) +{ + unsigned int syscon; + + gettimeoffset = clps711x_gettimeoffset; + + syscon = clps_readl(SYSCON1); + syscon |= SYSCON1_TC2S | SYSCON1_TC2M; + clps_writel(syscon, SYSCON1); + + clps_writel(LATCH-1, TC2D); /* 512kHz / 100Hz - 1 */ + + xtime.tv_sec = clps_readl(RTCDR); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps7500/Makefile linux-2.5/arch/arm/mach-clps7500/Makefile --- linux-2.5.1/arch/arm/mach-clps7500/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps7500/Makefile Sun Jan 6 01:38:26 2002 @@ -0,0 +1,21 @@ +# +# 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 := clps7500.o + +# Object file lists. + +obj-y := core.o +obj-m := +obj-n := +obj- := + +export-objs := + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-clps7500/core.c linux-2.5/arch/arm/mach-clps7500/core.c --- linux-2.5.1/arch/arm/mach-clps7500/core.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps7500/core.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,236 @@ +/* + * linux/arch/arm/mm/mm-cl7500.c + * + * Copyright (C) 1998 Russell King + * Copyright (C) 1999 Nexus Electronics Ltd + * + * Extra MM routines for CL7500 architecture + */ +#include <linux/types.h> +#include <linux/init.h> + +#include <asm/mach/map.h> + +#include <asm/hardware.h> +#include <asm/hardware/iomd.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/proc/domain.h> +#include <asm/setup.h> +#include <asm/mach-types.h> + +static void cl7500_mask_irq_ack_a(unsigned int irq) +{ + unsigned int val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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) +{ +} + +static struct irqaction irq_isa = { no_action, 0, 0, "isa", NULL, NULL }; + +static void __init clps7500_init_irq(void) +{ + int irq; + + 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) { + case 0 ... 6: + irq_desc[irq].probe_ok = 1; + case 7: + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = cl7500_mask_irq_ack_a; + irq_desc[irq].mask = cl7500_mask_irq_a; + irq_desc[irq].unmask = cl7500_unmask_irq_a; + break; + + case 9 ... 15: + irq_desc[irq].probe_ok = 1; + case 8: + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = cl7500_mask_irq_b; + irq_desc[irq].mask = cl7500_mask_irq_b; + irq_desc[irq].unmask = cl7500_unmask_irq_b; + break; + + case 16 ... 22: + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = cl7500_mask_irq_dma; + irq_desc[irq].mask = cl7500_mask_irq_dma; + irq_desc[irq].unmask = cl7500_unmask_irq_dma; + break; + + case 24 ... 31: + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = cl7500_mask_irq_c; + irq_desc[irq].mask = cl7500_mask_irq_c; + irq_desc[irq].unmask = cl7500_unmask_irq_c; + break; + + 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 48 ... 55: + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = no_action; + irq_desc[irq].mask = no_action; + irq_desc[irq].unmask = no_action; + break; + + case 64 ... 72: + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = cl7500_mask_irq_fiq; + irq_desc[irq].mask = cl7500_mask_irq_fiq; + irq_desc[irq].unmask = cl7500_unmask_irq_fiq; + break; + } + } + + setup_arm_irq(IRQ_ISA, &irq_isa); +} + +static struct map_desc cl7500_io_desc[] __initdata = { + { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1 }, /* IO space */ + { ISA_BASE, ISA_START, ISA_SIZE , DOMAIN_IO, 0, 1 }, /* ISA space */ + { FLASH_BASE, FLASH_START, FLASH_SIZE, DOMAIN_IO, 0, 1 }, /* Flash */ + { LED_BASE, LED_START, LED_SIZE , DOMAIN_IO, 0, 1 }, /* LED */ + LAST_DESC +}; + +static void __init clps7500_map_io(void) +{ + iotable_init(cl7500_io_desc); +} + +MACHINE_START(CLPS7500, "CL-PS7500") + MAINTAINER("Philip Blundell") + BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) + MAPIO(clps7500_map_io) + INITIRQ(clps7500_init_irq) +MACHINE_END + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ebsa110/Makefile linux-2.5/arch/arm/mach-ebsa110/Makefile --- linux-2.5.1/arch/arm/mach-ebsa110/Makefile Thu Apr 12 19:20:31 2001 +++ linux-2.5/arch/arm/mach-ebsa110/Makefile Sun Jan 6 01:38:26 2002 @@ -11,7 +11,7 @@ # Object file lists. -obj-y := arch.o io.o irq.o mm.o time.o +obj-y := core.o io.o time.o obj-m := obj-n := obj- := diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ebsa110/arch.c linux-2.5/arch/arm/mach-ebsa110/arch.c --- linux-2.5.1/arch/arm/mach-ebsa110/arch.c Wed Jun 27 21:12:04 2001 +++ linux-2.5/arch/arm/mach-ebsa110/arch.c Thu Jan 1 00:00:00 1970 @@ -1,30 +0,0 @@ -/* - * linux/arch/arm/mach-ebsa110/arch.c - * - * Architecture specific fixups. - */ -#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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ebsa110/core.c linux-2.5/arch/arm/mach-ebsa110/core.c --- linux-2.5.1/arch/arm/mach-ebsa110/core.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-ebsa110/core.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,97 @@ +/* + * linux/arch/arm/mach-ebsa110/core.c + * + * Copyright (C) 1998-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. + * + * Extra MM routines for the EBSA-110 architecture + */ +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/system.h> + +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> + +#define IRQ_MASK 0xfe000000 /* read */ +#define IRQ_MSET 0xfe000000 /* write */ +#define IRQ_STAT 0xff000000 /* read */ +#define IRQ_MCLR 0xff000000 /* write */ + +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); +} + +static 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; + } +} + +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 +}; + +static void __init ebsa110_map_io(void) +{ + iotable_init(ebsa110_io_desc); +} + +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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ebsa110/hardware.h linux-2.5/arch/arm/mach-ebsa110/hardware.h --- linux-2.5.1/arch/arm/mach-ebsa110/hardware.h Wed Jun 27 21:12:04 2001 +++ linux-2.5/arch/arm/mach-ebsa110/hardware.h Thu Jan 1 00:00:00 1970 @@ -1,16 +0,0 @@ -/* - * linux/arch/arm/mach-ebsa110/hardware.h - * - * Copyright (C) 2001 Russell King - * - * Local hardware definitions. - */ -#ifndef HARDWARE_H -#define HARDWARE_H - -#define IRQ_MASK 0xfe000000 /* read */ -#define IRQ_MSET 0xfe000000 /* write */ -#define IRQ_STAT 0xff000000 /* read */ -#define IRQ_MCLR 0xff000000 /* write */ - -#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ebsa110/io.c linux-2.5/arch/arm/mach-ebsa110/io.c --- linux-2.5.1/arch/arm/mach-ebsa110/io.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-ebsa110/io.c Sun Jan 6 01:38:26 2002 @@ -67,9 +67,9 @@ u32 ret, a = __isamem_convert_addr(addr); if ((int)addr & 1) - ret = __arch_getl(a); + ret = __raw_getl(a); else - ret = __arch_getb(a); + ret = __raw_getb(a); return ret; } @@ -80,7 +80,7 @@ if ((int)addr & 1) BUG(); - return __arch_getw(a); + return __raw_getw(a); } u32 __readl(void *addr) @@ -90,8 +90,8 @@ if ((int)addr & 3) BUG(); - ret = __arch_getw(a); - ret |= __arch_getw(a + 4) << 16; + ret = __raw_getw(a); + ret |= __raw_getw(a + 4) << 16; return ret; } @@ -104,9 +104,9 @@ u32 a = __isamem_convert_addr(addr); if ((int)addr & 1) - __arch_putl(val, a); + __raw_putl(val, a); else - __arch_putb(val, a); + __raw_putb(val, a); } void __writew(u16 val, void *addr) @@ -116,7 +116,7 @@ if ((int)addr & 1) BUG(); - __arch_putw(val, a); + __raw_putw(val, a); } void __writel(u32 val, void *addr) @@ -126,8 +126,8 @@ if ((int)addr & 3) BUG(); - __arch_putw(val, a); - __arch_putw(val >> 16, a + 4); + __raw_putw(val, a); + __raw_putw(val >> 16, a + 4); } EXPORT_SYMBOL(__writeb); @@ -147,7 +147,7 @@ * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) - ret = __arch_getb(ISAIO_BASE + (port << 2)); + ret = __raw_getb(ISAIO_BASE + (port << 2)); else { u32 a = ISAIO_BASE + ((port & ~1) << 1); @@ -155,9 +155,9 @@ * Shame nothing else does */ if (port & 1) - ret = __arch_getl(a); + ret = __raw_getl(a); else - ret = __arch_getb(a); + ret = __raw_getb(a); } return ret; } @@ -170,7 +170,7 @@ * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) - ret = __arch_getw(ISAIO_BASE + (port << 2)); + ret = __raw_getw(ISAIO_BASE + (port << 2)); else { u32 a = ISAIO_BASE + ((port & ~1) << 1); @@ -180,7 +180,7 @@ if (port & 1) BUG(); - ret = __arch_getw(a); + ret = __raw_getw(a); } return ret; } @@ -201,7 +201,7 @@ * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) - __arch_putb(val, ISAIO_BASE + (port << 2)); + __raw_putb(val, ISAIO_BASE + (port << 2)); else { u32 a = ISAIO_BASE + ((port & ~1) << 1); @@ -209,9 +209,9 @@ * Shame nothing else does */ if (port & 1) - __arch_putl(val, a); + __raw_putl(val, a); else - __arch_putb(val, a); + __raw_putb(val, a); } } @@ -230,7 +230,7 @@ BUG(); } - __arch_putw(val, ISAIO_BASE + off); + __raw_putw(val, ISAIO_BASE + off); } void __outl(u32 val, int port) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ebsa110/irq.c linux-2.5/arch/arm/mach-ebsa110/irq.c --- linux-2.5.1/arch/arm/mach-ebsa110/irq.c Thu Apr 12 19:20:31 2001 +++ linux-2.5/arch/arm/mach-ebsa110/irq.c Thu Jan 1 00:00:00 1970 @@ -1,55 +0,0 @@ -/* - * 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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ebsa110/mm.c linux-2.5/arch/arm/mach-ebsa110/mm.c --- linux-2.5.1/arch/arm/mach-ebsa110/mm.c Thu Apr 12 19:20:31 2001 +++ linux-2.5/arch/arm/mach-ebsa110/mm.c Thu Jan 1 00:00:00 1970 @@ -1,43 +0,0 @@ -/* - * 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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-epxa10db/mm.c linux-2.5/arch/arm/mach-epxa10db/mm.c --- linux-2.5.1/arch/arm/mach-epxa10db/mm.c Thu Oct 25 20:53:45 2001 +++ linux-2.5/arch/arm/mach-epxa10db/mm.c Sun Jan 6 01:38:26 2002 @@ -27,6 +27,7 @@ #include <asm/io.h> #include <asm/pgtable.h> #include <asm/page.h> +#include <asm/sizes.h> #include <asm/mach/map.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-footbridge/Makefile linux-2.5/arch/arm/mach-footbridge/Makefile --- linux-2.5.1/arch/arm/mach-footbridge/Makefile Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-footbridge/Makefile Sun Jan 6 01:38:26 2002 @@ -11,7 +11,7 @@ # Object file lists. -obj-y := arch.o irq.o mm.o #dma.o +obj-y := arch.o dc21285.o dma.o irq.o mm.o obj-m := obj-n := obj- := diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-footbridge/cats-pci.c linux-2.5/arch/arm/mach-footbridge/cats-pci.c --- linux-2.5.1/arch/arm/mach-footbridge/cats-pci.c Wed Jul 4 22:43:05 2001 +++ linux-2.5/arch/arm/mach-footbridge/cats-pci.c Sun Jan 6 01:38:26 2002 @@ -11,7 +11,6 @@ #include <asm/irq.h> #include <asm/mach/pci.h> -#include <asm/hardware/dec21285.h> /* cats host-specific stuff */ static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; @@ -31,10 +30,16 @@ return -1; } +/* + * why not the standard PCI swizzle? does this prevent 4-port tulip + * cards being used (ie, pci-pci bridge based cards)? + */ struct hw_pci cats_pci __initdata = { - setup_resources: dc21285_setup_resources, - init: dc21285_init, - mem_offset: DC21285_PCI_MEM, - swizzle: no_swizzle, + swizzle: NULL, map_irq: cats_map_irq, + nr_controllers: 1, + setup: dc21285_setup, + scan: dc21285_scan_bus, + preinit: dc21285_preinit, + postinit: dc21285_postinit, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-footbridge/dc21285.c linux-2.5/arch/arm/mach-footbridge/dc21285.c --- linux-2.5.1/arch/arm/mach-footbridge/dc21285.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-footbridge/dc21285.c Tue Jan 8 00:44:24 2002 @@ -0,0 +1,382 @@ +/* + * linux/arch/arm/kernel/dec21285.c: PCI functions for DC21285 + * + * Copyright (C) 1998-2000 Russell King, Phil Blundell + * + * 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/kernel.h> +#include <linux/pci.h> +#include <linux/ptrace.h> +#include <linux/interrupt.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/ioport.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/mach/pci.h> +#include <asm/hardware/dec21285.h> + +#define MAX_SLOTS 21 + +#define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \ + PCI_STATUS_REC_MASTER_ABORT | \ + PCI_STATUS_REC_TARGET_ABORT | \ + PCI_STATUS_PARITY) << 16) + +extern int setup_arm_irq(int, struct irqaction *); +extern void pcibios_report_status(u_int status_mask, int warn); +extern void register_isa_ports(unsigned int, unsigned int, unsigned int); + +static unsigned long +dc21285_base_address(struct pci_dev *dev) +{ + unsigned long addr = 0; + unsigned int devfn = dev->devfn; + + if (dev->bus->number == 0) { + if (PCI_SLOT(devfn) == 0) + /* + * For devfn 0, point at the 21285 + */ + addr = ARMCSR_BASE; + else { + devfn -= 1 << 3; + + if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) + addr = PCICFG0_BASE | 0xc00000 | (devfn << 8); + } + } else + addr = PCICFG1_BASE | (dev->bus->number << 16) | (devfn << 8); + + return addr; +} + +static int +dc21285_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + unsigned long addr = dc21285_base_address(dev); + u8 v; + + if (addr) + asm("ldr%?b %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); + else + v = 0xff; + + *value = v; + + return PCIBIOS_SUCCESSFUL; +} + +static int +dc21285_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + unsigned long addr = dc21285_base_address(dev); + u16 v; + + if (addr) + asm("ldr%?h %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); + else + v = 0xffff; + + *value = v; + + return PCIBIOS_SUCCESSFUL; +} + +static int +dc21285_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + unsigned long addr = dc21285_base_address(dev); + u32 v; + + if (addr) + asm("ldr%? %0, [%1, %2]" + : "=r" (v) : "r" (addr), "r" (where)); + else + v = 0xffffffff; + + *value = v; + + return PCIBIOS_SUCCESSFUL; +} + +static int +dc21285_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + unsigned long addr = dc21285_base_address(dev); + + if (addr) + asm("str%?b %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + + return PCIBIOS_SUCCESSFUL; +} + +static int +dc21285_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + unsigned long addr = dc21285_base_address(dev); + + if (addr) + asm("str%?h %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + + return PCIBIOS_SUCCESSFUL; +} + +static int +dc21285_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + unsigned long addr = dc21285_base_address(dev); + + if (addr) + asm("str%? %0, [%1, %2]" + : : "r" (value), "r" (addr), "r" (where)); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops dc21285_ops = { + dc21285_read_config_byte, + dc21285_read_config_word, + dc21285_read_config_dword, + dc21285_write_config_byte, + dc21285_write_config_word, + dc21285_write_config_dword, +}; + +static struct timer_list serr_timer; +static struct timer_list perr_timer; + +static void dc21285_enable_error(unsigned long __data) +{ + switch (__data) { + case IRQ_PCI_SERR: + del_timer(&serr_timer); + break; + + case IRQ_PCI_PERR: + del_timer(&perr_timer); + break; + } + + enable_irq(__data); +} + +/* + * Warn on PCI errors. + */ +static void dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int cmd; + unsigned int status; + + cmd = *CSR_PCICMD; + status = cmd >> 16; + cmd = cmd & 0xffff; + + if (status & PCI_STATUS_REC_MASTER_ABORT) { + printk(KERN_DEBUG "PCI: master abort: "); + pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT, 1); + printk("\n"); + + cmd |= PCI_STATUS_REC_MASTER_ABORT << 16; + } + + if (status & PCI_STATUS_REC_TARGET_ABORT) { + printk(KERN_DEBUG "PCI: target abort: "); + pcibios_report_status(PCI_STATUS_SIG_TARGET_ABORT, 1); + printk("\n"); + + cmd |= PCI_STATUS_REC_TARGET_ABORT << 16; + } + + *CSR_PCICMD = cmd; +} + +static void dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct timer_list *timer = dev_id; + unsigned int cntl; + + printk(KERN_DEBUG "PCI: system error received: "); + pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1); + printk("\n"); + + cntl = *CSR_SA110_CNTL & 0xffffdf07; + *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; + + /* + * back off this interrupt + */ + disable_irq(irq); + timer->expires = jiffies + HZ; + add_timer(timer); +} + +static void dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_DEBUG "PCI: discard timer expired\n"); + *CSR_SA110_CNTL &= 0xffffde07; +} + +static void dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int cmd; + + printk(KERN_DEBUG "PCI: data parity error detected: "); + pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); + printk("\n"); + + cmd = *CSR_PCICMD & 0xffff; + *CSR_PCICMD = cmd | 1 << 24; +} + +static void dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct timer_list *timer = dev_id; + unsigned int cmd; + + printk(KERN_DEBUG "PCI: parity error detected: "); + pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); + printk("\n"); + + cmd = *CSR_PCICMD & 0xffff; + *CSR_PCICMD = cmd | 1 << 31; + + /* + * back off this interrupt + */ + disable_irq(irq); + timer->expires = jiffies + HZ; + add_timer(timer); +} + +void __init dc21285_setup_resources(struct resource **resource) +{ + struct resource *busmem, *busmempf; + + busmem = kmalloc(sizeof(*busmem), GFP_KERNEL); + busmempf = kmalloc(sizeof(*busmempf), GFP_KERNEL); + memset(busmem, 0, sizeof(*busmem)); + memset(busmempf, 0, sizeof(*busmempf)); + + busmem->flags = IORESOURCE_MEM; + busmem->name = "Footbridge non-prefetch"; + busmempf->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; + busmempf->name = "Footbridge prefetch"; + + allocate_resource(&iomem_resource, busmempf, 0x20000000, + 0x80000000, 0xffffffff, 0x20000000, NULL, NULL); + allocate_resource(&iomem_resource, busmem, 0x40000000, + 0x80000000, 0xffffffff, 0x40000000, NULL, NULL); + + resource[0] = &ioport_resource; + resource[1] = busmem; + resource[2] = busmempf; +} + +void __init dc21285_init(void *sysdata) +{ + unsigned int mem_size, mem_mask; + int cfn_mode; + + mem_size = (unsigned int)high_memory - PAGE_OFFSET; + for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1) + if (mem_mask >= mem_size) + break; + + /* + * These registers need to be set up whether we're the + * central function or not. + */ + *CSR_SDRAMBASEMASK = (mem_mask - 1) & 0x0ffc0000; + *CSR_SDRAMBASEOFFSET = 0; + *CSR_ROMBASEMASK = 0x80000000; + *CSR_CSRBASEMASK = 0; + *CSR_CSRBASEOFFSET = 0; + *CSR_PCIADDR_EXTN = 0; + + cfn_mode = __footbridge_cfn_mode(); + + printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in " + "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ? + "central function" : "addin"); + + if (cfn_mode) { + static struct resource csrmem, csrio; + + csrio.flags = IORESOURCE_IO; + csrio.name = "Footbridge"; + csrmem.flags = IORESOURCE_MEM; + csrmem.name = "Footbridge"; + + allocate_resource(&ioport_resource, &csrio, 128, + 0xff00, 0xffff, 128, NULL, NULL); + allocate_resource(&iomem_resource, &csrmem, 128, + 0xf4000000, 0xf8000000, 128, NULL, NULL); + + /* + * Map our SDRAM at a known address in PCI space, just in case + * the firmware had other ideas. Using a nonzero base is + * necessary, since some VGA cards forcefully use PCI addresses + * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). + */ + *CSR_PCICSRBASE = csrmem.start; + *CSR_PCICSRIOBASE = csrio.start; + *CSR_PCISDRAMBASE = __virt_to_bus(PAGE_OFFSET); + *CSR_PCIROMBASE = 0; + *CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS; + + pci_scan_bus(0, &dc21285_ops, sysdata); + + /* + * Clear any existing errors - we aren't + * interested in historical data... + */ + *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) | + SA110_CNTL_RXSERR; + *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS; + } else if (footbridge_cfn_mode() != 0) { + /* + * If we are not compiled to accept "add-in" mode, then + * we are using a constant virt_to_bus translation which + * can not hope to cater for the way the host BIOS has + * set up the machine. + */ + panic("PCI: this kernel is compiled for central " + "function mode only"); + } + + /* + * Initialise PCI error IRQ after we've finished probing + */ + request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, SA_INTERRUPT, "PCI abort", NULL); + request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT, "Discard timer", NULL); + request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, SA_INTERRUPT, "PCI data parity", NULL); + + init_timer(&serr_timer); + init_timer(&perr_timer); + + serr_timer.data = IRQ_PCI_SERR; + serr_timer.function = dc21285_enable_error; + perr_timer.data = IRQ_PCI_PERR; + perr_timer.function = dc21285_enable_error; + + request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT, + "PCI system error", &serr_timer); + request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT, + "PCI parity error", &perr_timer); + + register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-footbridge/dma.c linux-2.5/arch/arm/mach-footbridge/dma.c --- linux-2.5.1/arch/arm/mach-footbridge/dma.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-footbridge/dma.c Tue Jan 8 00:44:24 2002 @@ -0,0 +1,55 @@ +/* + * linux/arch/arm/kernel/dma-ebsa285.c + * + * Copyright (C) 1998 Phil Blundell + * + * DMA functions specific to EBSA-285/CATS architectures + * + * Changelog: + * 09-Nov-1998 RMK Split out ISA DMA functions to dma-isa.c + * 17-Mar-1999 RMK Allow any EBSA285-like architecture to have + * ISA DMA controllers. + */ +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/dma.h> +#include <asm/io.h> + +#include <asm/mach/dma.h> +#include <asm/hardware/dec21285.h> + +#if 0 +static int fb_dma_request(dmach_t channel, dma_t *dma) +{ + return -EINVAL; +} + +static void fb_dma_enable(dmach_t channel, dma_t *dma) +{ +} + +static void fb_dma_disable(dmach_t channel, dma_t *dma) +{ +} + +static struct dma_ops fb_dma_ops = { + type: "fb", + request: fb_dma_request, + enable: fb_dma_enable, + disable: fb_dma_disable, +}; +#endif + +void __init arch_dma_init(dma_t *dma) +{ +#if 0 + dma[_DC21285_DMA(0)].d_ops = &fb_dma_ops; + dma[_DC21285_DMA(1)].d_ops = &fb_dma_ops; +#endif +#ifdef CONFIG_ISA_DMA + if (footbridge_cfn_mode()) + isa_init_dma(dma + _ISA_DMA(0)); +#endif +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-footbridge/ebsa285-pci.c linux-2.5/arch/arm/mach-footbridge/ebsa285-pci.c --- linux-2.5.1/arch/arm/mach-footbridge/ebsa285-pci.c Wed Jul 4 22:43:05 2001 +++ linux-2.5/arch/arm/mach-footbridge/ebsa285-pci.c Sun Jan 6 01:38:26 2002 @@ -11,15 +11,9 @@ #include <asm/irq.h> #include <asm/mach/pci.h> -#include <asm/hardware/dec21285.h> static int irqmap_ebsa285[] __initdata = { IRQ_IN3, IRQ_IN1, IRQ_IN0, IRQ_PCI }; -static u8 __init ebsa285_swizzle(struct pci_dev *dev, u8 *pin) -{ - return PCI_SLOT(dev->devfn); -} - static int __init ebsa285_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { if (dev->vendor == PCI_VENDOR_ID_CONTAQ && @@ -34,9 +28,11 @@ } struct hw_pci ebsa285_pci __initdata = { - setup_resources: dc21285_setup_resources, - init: dc21285_init, - mem_offset: DC21285_PCI_MEM, - swizzle: ebsa285_swizzle, + swizzle: pci_std_swizzle, map_irq: ebsa285_map_irq, + nr_controllers: 1, + setup: dc21285_setup, + scan: dc21285_scan_bus, + preinit: dc21285_preinit, + postinit: dc21285_postinit, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-footbridge/netwinder-pci.c linux-2.5/arch/arm/mach-footbridge/netwinder-pci.c --- linux-2.5.1/arch/arm/mach-footbridge/netwinder-pci.c Wed Jul 4 22:43:05 2001 +++ linux-2.5/arch/arm/mach-footbridge/netwinder-pci.c Sun Jan 6 01:38:26 2002 @@ -11,47 +11,42 @@ #include <asm/irq.h> #include <asm/mach/pci.h> -#include <asm/hardware/dec21285.h> -/* netwinder host-specific stuff */ +/* + * We now use the slot ID instead of the device identifiers to select + * which interrupt is routed where. + */ static int __init netwinder_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { -#define DEV(v,d) ((v)<<16|(d)) - switch (DEV(dev->vendor, dev->device)) { - case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): - case DEV(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885): - case DEV(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_YELLOWFIN): - return IRQ_NETWINDER_ETHER100; + switch (slot) { + case 0: /* host bridge */ + return 0; - case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a): - return IRQ_NETWINDER_ETHER10; + case 9: /* CyberPro */ + return IRQ_NETWINDER_VGA; - case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553): - return 0; + case 10: /* DC21143 */ + return IRQ_NETWINDER_ETHER100; - case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105): + case 12: /* Winbond 553 */ return IRQ_ISA_HARDDISK1; - case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000): - case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010): - case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000): - return IRQ_NETWINDER_VGA; - - case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285): - return 0; + case 13: /* Winbond 89C940F */ + return IRQ_NETWINDER_ETHER10; default: - printk(KERN_ERR "PCI: %02X:%02X [%04X:%04X] unknown device\n", - dev->bus->number, dev->devfn, - dev->vendor, dev->device); + printk(KERN_ERR "PCI: unknown device in slot %s: %s\n", + dev->slot_name, dev->name); return 0; } } struct hw_pci netwinder_pci __initdata = { - setup_resources: dc21285_setup_resources, - init: dc21285_init, - mem_offset: DC21285_PCI_MEM, - swizzle: no_swizzle, + swizzle: pci_std_swizzle, map_irq: netwinder_map_irq, + nr_controllers: 1, + setup: dc21285_setup, + scan: dc21285_scan_bus, + preinit: dc21285_preinit, + postinit: dc21285_postinit, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-footbridge/personal-pci.c linux-2.5/arch/arm/mach-footbridge/personal-pci.c --- linux-2.5.1/arch/arm/mach-footbridge/personal-pci.c Wed Jul 4 22:43:05 2001 +++ linux-2.5/arch/arm/mach-footbridge/personal-pci.c Sun Jan 6 01:38:26 2002 @@ -11,7 +11,6 @@ #include <asm/irq.h> #include <asm/mach/pci.h> -#include <asm/hardware/dec21285.h> static int irqmap_personal_server[] __initdata = { IRQ_IN0, IRQ_IN1, IRQ_IN2, IRQ_IN3, 0, 0, 0, @@ -38,9 +37,10 @@ } struct hw_pci personal_server_pci __initdata = { - setup_resources: dc21285_setup_resources, - init: dc21285_init, - mem_offset: DC21285_PCI_MEM, - swizzle: no_swizzle, map_irq: personal_server_map_irq, + nr_controllers: 1, + setup: dc21285_setup, + scan: dc21285_scan_bus, + preinit: dc21285_preinit, + postinit: dc21285_postinit, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ftvpci/Makefile linux-2.5/arch/arm/mach-ftvpci/Makefile --- linux-2.5.1/arch/arm/mach-ftvpci/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-ftvpci/Makefile Sun Jan 6 01:38:26 2002 @@ -0,0 +1,24 @@ +# +# 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 := ftvpci.o + +# Object file lists. + +obj-y := core.o +obj-m := +obj-n := +obj- := + +export-objs := + +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_LEDS) += leds.o + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ftvpci/core.c linux-2.5/arch/arm/mach-ftvpci/core.c --- linux-2.5.1/arch/arm/mach-ftvpci/core.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-ftvpci/core.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,98 @@ +/* + * linux/arch/arm/mach-ftvpci/core.c + * + * Architecture specific fixups. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the 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/sched.h> +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/setup.h> +#include <asm/mach-types.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> + +extern unsigned long soft_irq_mask; + +static const unsigned char irq_cmd[] = +{ + INTCONT_IRQ_DUART, + INTCONT_IRQ_PLX, + INTCONT_IRQ_D, + INTCONT_IRQ_C, + INTCONT_IRQ_B, + INTCONT_IRQ_A, + INTCONT_IRQ_SYSERR +}; + +static void ftvpci_mask_irq(unsigned int irq) +{ + __raw_writel(irq_cmd[irq], INTCONT_BASE); + soft_irq_mask &= ~(1<<irq); +} + +static void ftvpci_unmask_irq(unsigned int irq) +{ + soft_irq_mask |= (1<<irq); + __raw_writel(irq_cmd[irq] | 1, INTCONT_BASE); +} + +static void __init ftvpci_init_irq(void) +{ + unsigned int i; + + /* Mask all FIQs */ + __raw_writel(INTCONT_FIQ_PLX, INTCONT_BASE); + __raw_writel(INTCONT_FIQ_D, INTCONT_BASE); + __raw_writel(INTCONT_FIQ_C, INTCONT_BASE); + __raw_writel(INTCONT_FIQ_B, INTCONT_BASE); + __raw_writel(INTCONT_FIQ_A, INTCONT_BASE); + __raw_writel(INTCONT_FIQ_SYSERR, INTCONT_BASE); + + /* Disable all interrupts initially. */ + for (i = 0; i < NR_IRQS; i++) { + if (i >= FIRST_IRQ && i <= LAST_IRQ) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = ftvpci_mask_irq; + irq_desc[i].mask = ftvpci_mask_irq; + irq_desc[i].unmask = ftvpci_unmask_irq; + ftvpci_mask_irq(i); + } else { + irq_desc[i].valid = 0; + irq_desc[i].probe_ok = 0; + } + } +} + +static struct map_desc ftvpci_io_desc[] __initdata = { + { INTCONT_BASE, INTCONT_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { PLX_BASE, PLX_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIO_BASE, PLX_IO_START, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, + { DUART_BASE, DUART_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + { STATUS_BASE, STATUS_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +static void __init ftvpci_map_io(void) +{ + iotable_init(ftvpci_io_desc); +} + +MACHINE_START(NEXUSPCI, "FTV/PCI") + MAINTAINER("Philip Blundell") + BOOT_MEM(0x40000000, 0x10000000, 0xe0000000) + MAPIO(ftvpci_map_io) + INITIRQ(ftvpci_init_irq) +MACHINE_END diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ftvpci/leds.c linux-2.5/arch/arm/mach-ftvpci/leds.c --- linux-2.5.1/arch/arm/mach-ftvpci/leds.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-ftvpci/leds.c Tue Jan 8 00:44:24 2002 @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/kernel/leds-ftvpci.c + * + * Copyright (C) 1999 FutureTV Labs Ltd + */ + +#include <linux/module.h> + +#include <asm/hardware.h> +#include <asm/leds.h> +#include <asm/system.h> +#include <asm/io.h> + +static void ftvpci_leds_event(led_event_t ledevt) +{ + static int led_state = 0; + + switch(ledevt) { + case led_timer: + led_state ^= 1; + raw_writeb(0x1a | led_state, INTCONT_BASE); + break; + + default: + break; + } +} + +void (*leds_event)(led_event_t) = ftvpci_leds_event; + +EXPORT_SYMBOL(leds_event); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-ftvpci/pci.c linux-2.5/arch/arm/mach-ftvpci/pci.c --- linux-2.5.1/arch/arm/mach-ftvpci/pci.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-ftvpci/pci.c Tue Jan 8 00:44:24 2002 @@ -0,0 +1,51 @@ +/* + * linux/arch/arm/kernel/ftv-pci.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/irq.h> +#include <asm/mach/pci.h> + +/* + * Owing to a PCB cockup, issue A backplanes are wired thus: + * + * Slot 1 2 3 4 5 Bridge S1 S2 S3 S4 + * IRQ D C B A A C B A D + * A D C B B D C B A + * B A D C C A D C B + * C B A D D B A D C + * + * ID A31 A30 A29 A28 A27 A26 DEV4 DEV5 DEV6 DEV7 + * + * Actually, this isn't too bad, because with the processor card + * in slot 5 on the primary bus, the IRQs rotate on both sides + * as you'd expect. + */ + +static int irqmap_ftv[] __initdata = { IRQ_PCI_D, IRQ_PCI_C, IRQ_PCI_B, IRQ_PCI_A }; + +static int __init ftv_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (slot > 0x10) + slot--; + return irqmap_ftv[(slot - pin) & 3]; +} + +static u8 __init ftv_swizzle(struct pci_dev *dev, u8 *pin) +{ + return PCI_SLOT(dev->devfn); +} + +/* ftv host-specific stuff */ +struct hw_pci ftv_pci __initdata = { + init: plx90x0_init, + swizzle: ftv_swizzle, + map_irq: ftv_map_irq, +}; + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-integrator/pci.c linux-2.5/arch/arm/mach-integrator/pci.c --- linux-2.5.1/arch/arm/mach-integrator/pci.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-integrator/pci.c Sun Jan 6 01:38:26 2002 @@ -114,9 +114,11 @@ extern void pci_v3_init(void *); struct hw_pci integrator_pci __initdata = { - setup_resources: pci_v3_setup_resources, - init: pci_v3_init, mem_offset: 0x40000000, swizzle: integrator_swizzle, map_irq: integrator_map_irq, + setup: pci_v3_setup, + scan: pci_v3_scan_bus, + preinit: pci_v3_preinit, + postinit: pci_v3_postinit, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-integrator/pci_v3.c linux-2.5/arch/arm/mach-integrator/pci_v3.c --- linux-2.5.1/arch/arm/mach-integrator/pci_v3.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-integrator/pci_v3.c Sun Jan 6 01:38:26 2002 @@ -37,6 +37,8 @@ #include <asm/hardware/pci_v3.h> +int setup_arm_irq(int irq, struct irqaction * new); + /* * The V3 PCI interface chip in Integrator provides several windows from * local bus memory into the PCI memory areas. Unfortunately, there @@ -411,7 +413,7 @@ flags: IORESOURCE_MEM | IORESOURCE_PREFETCH, }; -void __init pci_v3_setup_resources(struct resource **resource) +static void __init pci_v3_setup_resources(struct resource **resource) { if (request_resource(&iomem_resource, &non_mem)) printk("PCI: unable to allocate non-prefetchable memory region\n"); @@ -433,18 +435,21 @@ * means I can't get additional information on the reason for the pm2fb * problems. I suppose I'll just have to mind-meld with the machine. ;) */ -#define SC_PCI (IO_ADDRESS(INTEGRATOR_SC_PCIENABLE)) -#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE+0x20)) -#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE+0x24)) +#define SC_PCI (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_PCIENABLE_OFFSET) +#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x20) +#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x24) static int v3_fault(unsigned long addr, struct pt_regs *regs) { unsigned long pc = instruction_pointer(regs); unsigned long instr = *(unsigned long *)pc; +// char buf[128]; - printk("V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", - addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255, - v3_readb(V3_LB_ISTAT)); +// sprintf(buf, "V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", +// addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255, +// v3_readb(V3_LB_ISTAT)); +// printk("%s", buf); +// printascii(buf); v3_writeb(V3_LB_ISTAT, 0); __raw_writel(3, SC_PCI); @@ -467,11 +472,20 @@ return 0; } + if ((instr & 0x0e100090) == 0x00100090) { + int reg = (instr >> 12) & 15; + + regs->uregs[reg] = -1; + regs->ARM_pc += 4; + return 0; + } + return 1; } static void v3_irq(int irq, void *devid, struct pt_regs *regs) { +#ifdef CONFIG_DEBUG_LL unsigned long pc = instruction_pointer(regs); unsigned long instr = *(unsigned long *)pc; char buf[128]; @@ -480,10 +494,13 @@ pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255, v3_readb(V3_LB_ISTAT)); printascii(buf); +#endif + v3_writew(V3_PCI_STAT, 0xf000); v3_writeb(V3_LB_ISTAT, 0); __raw_writel(3, SC_PCI); +#ifdef CONFIG_DEBUG_LL /* * If the instruction being executed was a read, * make it look like it read all-ones. @@ -493,12 +510,14 @@ sprintf(buf, " reg%d = %08lx\n", reg, regs->uregs[reg]); printascii(buf); } +#endif } static struct irqaction v3_int = { name: "V3", handler: v3_irq, }; + static struct irqaction v3_int2 = { name: "V3TM", handler: v3_irq, @@ -506,14 +525,26 @@ extern int (*external_fault)(unsigned long addr, struct pt_regs *regs); +int pci_v3_setup(int nr, struct pci_sys_data *sys) +{ + if (nr) + pci_v3_setup_resources(sys->resource); + return nr ? 0 : 1; +} + +struct pci_bus *pci_v3_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(sys->busnr, &pci_v3_ops, sys); +} + /* * V3_LB_BASE? - local bus address * V3_LB_MAP? - pci bus address */ -void __init pci_v3_init(void *sysdata) +void __init pci_v3_preinit(void) { - unsigned int pci_cmd; unsigned long flags; + unsigned int temp; /* * Hook in our fault handler for PCI errors @@ -523,6 +554,12 @@ spin_lock_irqsave(&v3_lock, flags); /* + * Unlock V3 registers, but only if they were previously locked. + */ + if (v3_readw(V3_SYSTEM) & V3_SYSTEM_M_LOCK) + v3_writew(V3_SYSTEM, 0xa05f); + + /* * Setup window 0 - PCI non-prefetchable memory * Local: 0x40000000 Bus: 0x00000000 Size: 256MB */ @@ -548,27 +585,56 @@ V3_LB_BASE_ENABLE); v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0)); + /* + * Disable PCI to host IO cycles + */ + temp = v3_readw(V3_PCI_CFG) & ~V3_PCI_CFG_M_I2O_EN; + temp |= V3_PCI_CFG_M_IO_REG_DIS | V3_PCI_CFG_M_IO_DIS; + v3_writew(V3_PCI_CFG, temp); + + printk("FIFO_CFG: %04x FIFO_PRIO: %04x\n", + v3_readw(V3_FIFO_CFG), v3_readw(V3_FIFO_PRIORITY)); + + /* + * Set the V3 FIFO such that writes have higher priority than + * reads, and local bus write causes local bus read fifo flush. + * Same for PCI. + */ + v3_writew(V3_FIFO_PRIORITY, 0x0a0a); + + /* + * Re-lock the system register. + */ + temp = v3_readw(V3_SYSTEM) | V3_SYSTEM_M_LOCK; + v3_writew(V3_SYSTEM, temp); + + /* + * Clear any error conditions, and enable write errors. + */ + v3_writeb(V3_LB_ISTAT, 0); + v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10)); + v3_writeb(V3_LB_IMASK, 0x28); + __raw_writel(3, SC_PCI); + + /* + * Grab the PCI error interrupt. + */ + setup_arm_irq(IRQ_V3INT, &v3_int); + spin_unlock_irqrestore(&v3_lock, flags); +} - pci_scan_bus(0, &pci_v3_ops, sysdata); +void __init pci_v3_postinit(void) +{ + unsigned int pci_cmd; pci_cmd = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; v3_writew(V3_PCI_CMD, pci_cmd); - /* - * Clear any error conditions. - */ - __raw_writel(3, SC_PCI); - v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10)); - v3_writeb(V3_LB_ISTAT, 0); + v3_writeb(V3_LB_ISTAT, ~0x40); v3_writeb(V3_LB_IMASK, 0x68); - printk("LB_CFG: %04x LB_ISTAT: %02x LB_IMASK: %02x\n", - v3_readw(V3_LB_CFG), - v3_readb(V3_LB_ISTAT), - v3_readb(V3_LB_IMASK)); - setup_arm_irq(IRQ_V3INT, &v3_int); // setup_arm_irq(IRQ_LBUSTIMEOUT, &v3_int2); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-iop310/Makefile linux-2.5/arch/arm/mach-iop310/Makefile --- linux-2.5.1/arch/arm/mach-iop310/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-iop310/Makefile Sun Jan 6 01:38:26 2002 @@ -0,0 +1,33 @@ +# +# 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 := iop310.o + +# Object file lists. + +obj-y := arch.o mm.o xs80200-irq.o iop310-irq.o \ + iop310-pci.o +obj-m := +obj-n := +obj- := + +export-objs := + +obj-$(CONFIG_ARCH_IQ80310) += iq80310-pci.o iq80310-irq.o + +ifneq ($(CONFIG_XSCALE_PMU_TIMER),y) +obj-y += iq80310-time.o +endif + +obj-$(CONFIG_IOP310_AAU) += aau.o +obj-$(CONFIG_IOP310_DMA) += dma.o +obj-$(CONFIG_IOP310_MU) += message.o +obj-$(CONFIG_IOP310_PMON) += pmon.o + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-iop310/arch.c linux-2.5/arch/arm/mach-iop310/arch.c --- linux-2.5.1/arch/arm/mach-iop310/arch.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-iop310/arch.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,61 @@ +/* + * linux/arch/arm/mach-iop310/arch.c + * + * Author: Nicolas Pitre <nico@cam.org> + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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/init.h> +#include <linux/major.h> +#include <linux/fs.h> +#include <asm/types.h> +#include <asm/setup.h> +#include <asm/system.h> +#include <asm/memory.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#ifdef CONFIG_ARCH_IQ80310 +extern void iq80310_map_io(void); +extern void iq80310_init_irq(void); + +static void __init +fixup_iq80310(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + system_rev = (*(volatile unsigned int*)0xfe830000) & 0x0f; + + if(system_rev) + system_rev = 0xF; + + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].size = (32*1024*1024); + mi->bank[0].node = 0; + mi->nr_banks = 1; + +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = to_kdev_t(0x00FF); /* /dev/nfs pseudo device */ +#elif defined(CONFIG_BLK_DEV_INITRD) + setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE ); + setup_initrd( 0xc0800000, 4*1024*1024 ); + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */ +#endif +} + +MACHINE_START(IQ80310, "Cyclone IQ80310") + MAINTAINER("MontaVista Software Inc.") + BOOT_MEM(0xa0000000, 0xfe000000, 0xfe000000) + FIXUP(fixup_iq80310) + MAPIO(iq80310_map_io) + INITIRQ(iq80310_init_irq) +MACHINE_END + +#else +#error No machine descriptor defined for this IOP310 implementation +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-iop310/iop310-irq.c linux-2.5/arch/arm/mach-iop310/iop310-irq.c --- linux-2.5.1/arch/arm/mach-iop310/iop310-irq.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-iop310/iop310-irq.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,109 @@ +/* + * linux/arch/arm/mach-iop310/iop310-irq.c + * + * Generic IOP310 IRQ handling functionality + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + * Added IOP310 chipset and IQ80310 board demuxing, masking code. - DS + * + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include <asm/mach/irq.h> +#include <asm/irq.h> +#include <asm/hardware.h> + +#include <asm/mach-types.h> + +extern void xs80200_irq_mask(unsigned int); +extern void xs80200_irq_unmask(unsigned int); +extern void xs80200_init_irq(void); + +extern void do_IRQ(int, struct pt_regs *); + +u32 iop310_mask = 0; + +static void +iop310_irq_mask (unsigned int irq) +{ + iop310_mask |= (1 << (irq - IOP310_IRQ_OFS)); + + /* + * No mask bits on the 80312, so we have to + * mask everything from the outside! + */ + xs80200_irq_mask(IRQ_XS80200_EXTIRQ); +} + +static void +iop310_irq_unmask (unsigned int irq) +{ + iop310_mask &= ~(1 << (irq - IOP310_IRQ_OFS)); + + /* + * Check if all 80312 sources are unmasked now + */ + if(!iop310_mask) + { + xs80200_irq_unmask(IRQ_XS80200_EXTIRQ); + + } +} + +void iop310_irq_demux(int irq, void *dev_id, + struct pt_regs *regs) +{ + u32 fiq1isr = *((volatile u32*)IOP310_FIQ1ISR); + u32 fiq2isr = *((volatile u32*)IOP310_FIQ2ISR); + unsigned int irqno = 0; + + if(fiq1isr) + { + if(fiq1isr & 0x1) + irqno = IRQ_IOP310_DMA0; + if(fiq1isr & 0x2) + irqno = IRQ_IOP310_DMA1; + if(fiq1isr & 0x4) + irqno = IRQ_IOP310_DMA2; + if(fiq1isr & 0x10) + irqno = IRQ_IOP310_PMON; + if(fiq1isr & 0x20) + irqno = IRQ_IOP310_AAU; + } + else + { + if(fiq2isr & 0x2) + irqno = IRQ_IOP310_I2C; + if(fiq2isr & 0x4) + irqno = IRQ_IOP310_MU; + } + + do_IRQ(irqno, regs); +} + +void __init iop310_init_irq(void) +{ + int i; + + for(i = IOP310_IRQ_OFS; i < NR_IOP310_IRQS; i++) + { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = iop310_irq_mask; + irq_desc[i].mask = iop310_irq_mask; + irq_desc[i].unmask = iop310_irq_unmask; + } + + xs80200_init_irq(); +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-iop310/iop310-pci.c linux-2.5/arch/arm/mach-iop310/iop310-pci.c --- linux-2.5.1/arch/arm/mach-iop310/iop310-pci.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-iop310/iop310-pci.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,500 @@ +/* + * arch/arm/mach-iop310/iop310-pci.c + * + * PCI support for the Intel IOP310 chipset + * + * Matt Porter <mporter@mvista.com> + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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/kernel.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/ioport.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/hardware.h> +#include <asm/mach/pci.h> + +#include <asm/arch/iop310.h> + +/* + * *** Special note - why the IOP310 should NOT be used *** + * + * The PCI ATU is a brain dead implementation, only allowing 32-bit + * accesses to PCI configuration space. This is especially brain + * dead for writes to this space. A simple for-instance: + * + * You want to modify the command register *without* corrupting the + * status register. + * + * To perform this, you need to read *32* bits of data from offset 4, + * mask off the low 16, replace them with the new data, and write *32* + * bits back. + * + * Writing the status register at offset 6 with status bits set *clears* + * the status. + * + * Hello? Could we have a *SANE* implementation of a PCI ATU some day + * *PLEASE*? + */ +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +extern int (*external_fault)(unsigned long, struct pt_regs *); + +static u32 iop310_cfg_address(struct pci_dev *dev, int where) +{ + struct pci_sys_data *sys = dev->sysdata; + u32 addr; + + where &= ~3; + + if (sys->busnr == dev->bus->number) + addr = 1 << (PCI_SLOT(dev->devfn) + 16); + else + addr = dev->bus->number << 16 | + PCI_SLOT(dev->devfn) << 11 | 1; + + addr |= PCI_FUNC(dev->devfn) << 8 | where; + + return addr; +} + +/* + * Primary PCI interface support. + */ +static int iop310_pri_pci_status(void) +{ + unsigned int status; + int ret = 0; + + status = *IOP310_PATUSR; + if (status & 0xf900) { + *IOP310_PATUSR = status & 0xf900; + ret = 1; + } + status = *IOP310_PATUISR; + if (status & 0x0000018f) { + *IOP310_PATUISR = status & 0x0000018f; + ret = 1; + } + status = *IOP310_PSR; + if (status & 0xf900) { + *IOP310_PSR = status & 0xf900; + ret = 1; + } + status = *IOP310_PBISR; + if (status & 0x003f) { + *IOP310_PBISR = status & 0x003f; + ret = 1; + } + return ret; +} + +static int +iop310_pri_rd_cfg_byte(struct pci_dev *dev, int where, u8 *p) +{ + int ret; + u8 val; + + *IOP310_POCCAR = iop310_cfg_address(dev, where); + + val = (*IOP310_POCCDR) >> ((where & 3) * 8); + __asm__ __volatile__("nop; nop; nop; nop"); + + ret = iop310_pri_pci_status(); + if (ret) + val = 0xff; + + *p = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_pri_rd_cfg_word(struct pci_dev *dev, int where, u16 *p) +{ + int ret; + u16 val; + + *IOP310_POCCAR = iop310_cfg_address(dev, where); + + val = (*IOP310_POCCDR) >> ((where & 2) * 8); + __asm__ __volatile__("nop; nop; nop; nop"); + + ret = iop310_pri_pci_status(); + if (ret) + val = 0xffff; + + *p = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_pri_rd_cfg_dword(struct pci_dev *dev, int where, u32 *p) +{ + int ret; + u32 val; + + *IOP310_POCCAR = iop310_cfg_address(dev, where); + + val = *IOP310_POCCDR; + __asm__ __volatile__("nop; nop; nop; nop"); + + ret = iop310_pri_pci_status(); + if (ret) + val = 0xffffffff; + + *p = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_pri_wr_cfg_byte(struct pci_dev *dev, int where, u8 v) +{ + int ret; + u32 val; + + *IOP310_POCCAR = iop310_cfg_address(dev, where); + + val = *IOP310_POCCDR; + __asm__ __volatile__("nop; nop; nop; nop"); + + ret = iop310_pri_pci_status(); + if (ret == 0) { + where = (where & 3) * 8; + val &= ~(0xff << where); + val |= v << where; + *IOP310_POCCDR = val; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_pri_wr_cfg_word(struct pci_dev *dev, int where, u16 v) +{ + int ret; + u32 val; + + *IOP310_POCCAR = iop310_cfg_address(dev, where); + + val = *IOP310_POCCDR; + __asm__ __volatile__("nop; nop; nop; nop"); + + ret = iop310_pri_pci_status(); + if (ret == 0) { + where = (where & 2) * 8; + val &= ~(0xffff << where); + val |= v << where; + *IOP310_POCCDR = val; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_pri_wr_cfg_dword(struct pci_dev *dev, int where, u32 v) +{ + *IOP310_POCCAR = iop310_cfg_address(dev, where); + *IOP310_POCCDR = v; + __asm__ __volatile__("nop; nop; nop; nop"); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops iop310_primary_ops = { + iop310_pri_rd_cfg_byte, + iop310_pri_rd_cfg_word, + iop310_pri_rd_cfg_dword, + iop310_pri_wr_cfg_byte, + iop310_pri_wr_cfg_word, + iop310_pri_wr_cfg_dword, +}; + +/* + * Secondary PCI interface support. + */ +static int iop310_sec_pci_status(void) +{ + unsigned int usr, uisr; + int ret = 0; + + usr = *IOP310_SATUSR; + uisr = *IOP310_SATUISR; + if (usr & 0xf900) { + *IOP310_SATUSR = usr & 0xf900; + ret = 1; + } + if (uisr & 0x0000069f) { + *IOP310_SATUISR = uisr & 0x0000069f; + ret = 1; + } +//if (ret) printk("ERROR (%08lx %08lx)", usr, uisr); + return ret; +} + +static int +iop310_sec_rd_cfg_byte(struct pci_dev *dev, int where, u8 *p) +{ + int ret; + u8 val; +//printk("rdb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + *IOP310_SOCCAR = iop310_cfg_address(dev, where); + + val = (*IOP310_SOCCDR) >> ((where & 3) * 8); + __asm__ __volatile__("nop; nop; nop; nop"); +//printk(">= %08lx ", val); + ret = iop310_sec_pci_status(); + if (ret) + val = 0xff; +//printk("\n"); + *p = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_sec_rd_cfg_word(struct pci_dev *dev, int where, u16 *p) +{ + int ret; + u16 val; +//printk("rdw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + *IOP310_SOCCAR = iop310_cfg_address(dev, where); + + val = (*IOP310_SOCCDR) >> ((where & 3) * 8); + __asm__ __volatile__("nop; nop; nop; nop"); +//printk(">= %08lx ", val); + ret = iop310_sec_pci_status(); + if (ret) + val = 0xffff; +//printk("\n"); + *p = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_sec_rd_cfg_dword(struct pci_dev *dev, int where, u32 *p) +{ + int ret; + u32 val; +//printk("rdl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + *IOP310_SOCCAR = iop310_cfg_address(dev, where); + + val = *IOP310_SOCCDR; + __asm__ __volatile__("nop; nop; nop; nop"); +//printk(">= %08lx ", val); + ret = iop310_sec_pci_status(); + if (ret) + val = 0xffffffff; +//printk("\n"); + *p = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_sec_wr_cfg_byte(struct pci_dev *dev, int where, u8 v) +{ + int ret; + u32 val; +//printk("wrb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + *IOP310_SOCCAR = iop310_cfg_address(dev, where); + + val = *IOP310_SOCCDR; + __asm__ __volatile__("nop; nop; nop; nop"); +//printk("<= %08lx", v); + ret = iop310_sec_pci_status(); + if (ret == 0) { + where = (where & 3) * 8; + val &= ~(0xff << where); + val |= v << where; + *IOP310_SOCCDR = val; + } +//printk("\n"); + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_sec_wr_cfg_word(struct pci_dev *dev, int where, u16 v) +{ + int ret; + u32 val; +//printk("wrw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + *IOP310_SOCCAR = iop310_cfg_address(dev, where); + + val = *IOP310_SOCCDR; + __asm__ __volatile__("nop; nop; nop; nop"); +//printk("<= %08lx", v); + ret = iop310_sec_pci_status(); + if (ret == 0) { + where = (where & 2) * 8; + val &= ~(0xffff << where); + val |= v << where; + *IOP310_SOCCDR = val; + } +//printk("\n"); + return PCIBIOS_SUCCESSFUL; +} + +static int +iop310_sec_wr_cfg_dword(struct pci_dev *dev, int where, u32 v) +{ +//printk("wrl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + *IOP310_SOCCAR = iop310_cfg_address(dev, where); + *IOP310_SOCCDR = v; + __asm__ __volatile__("nop; nop; nop; nop"); +//printk("<= %08lx\n", v); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops iop310_secondary_ops = { + iop310_sec_rd_cfg_byte, + iop310_sec_rd_cfg_word, + iop310_sec_rd_cfg_dword, + iop310_sec_wr_cfg_byte, + iop310_sec_wr_cfg_word, + iop310_sec_wr_cfg_dword, +}; + +/* + * When a PCI device does not exist during config cycles, the 80200 gets a + * bus error instead of returning 0xffffffff. This handler simply returns. + */ +int iop310_pci_abort_handler(unsigned long addr, struct pt_regs *regs) +{ +// printk("PCI abort: address = %08x PC = %08x LR = %08lx\n", +// addr, regs->ARM_pc, regs->ARM_lr); + return 0; +} + +/* + * Scan an IOP310 PCI bus. sys->bus defines which bus we scan. + */ +struct pci_bus *iop310_scan_bus(int nr, struct pci_sys_data *sys) +{ + struct pci_ops *ops; + + if (nr) + ops = &iop310_secondary_ops; + else + ops = &iop310_primary_ops; + + return pci_scan_bus(sys->busnr, ops, sys); +} + +/* + * Setup the system data for controller 'nr'. Return 0 if none found, + * 1 if found, or negative error. + * + * We can alter: + * io_offset - offset between IO resources and PCI bus BARs + * mem_offset - offset between mem resources and PCI bus BARs + * resource[0] - parent IO resource + * resource[1] - parent non-prefetchable memory resource + * resource[2] - parent prefetchable memory resource + * swizzle - bridge swizzling function + * map_irq - irq mapping function + * + * Note that 'io_offset' and 'mem_offset' are left as zero since + * the IOP310 doesn't attempt to perform any address translation + * on accesses from the host to the bus. + */ +int iop310_setup(int nr, struct pci_sys_data *sys) +{ + struct resource *res; + + if (nr >= 2) + return 0; + + res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL); + if (!res) + panic("PCI: unable to alloc resources"); + + switch (nr) { + case 0: + res[0].start = IOP310_PCIPRI_LOWER_IO + 0x6e000000; + res[0].end = IOP310_PCIPRI_LOWER_IO + 0x6e00ffff; + res[0].name = "PCI IO Primary"; + + res[1].start = IOP310_PCIPRI_LOWER_MEM; + res[1].end = IOP310_PCIPRI_LOWER_MEM + IOP310_PCI_WINDOW_SIZE; + res[1].name = "PCI Memory Primary"; + break; + + case 1: + res[0].start = IOP310_PCISEC_LOWER_IO + 0x6e000000; + res[0].end = IOP310_PCISEC_LOWER_IO + 0x6e00ffff; + res[0].name = "PCI IO Primary"; + + res[1].start = IOP310_PCISEC_LOWER_MEM; + res[1].end = IOP310_PCISEC_LOWER_MEM + IOP310_PCI_WINDOW_SIZE; + res[1].name = "PCI Memory Primary"; + break; + } + + request_resource(&ioport_resource, &res[0]); + request_resource(&iomem_resource, &res[1]); + + sys->resource[0] = &res[0]; + sys->resource[1] = &res[1]; + sys->resource[2] = NULL; + sys->io_offset = 0x6e000000; + + return 1; +} + +void iop310_init(void) +{ + DBG("PCI: Intel 80312 PCI-to-PCI init code.\n"); + DBG(" ATU secondary: IOP310_SOMWVR=0x%04x, IOP310_SOIOWVR=0x%04x\n", + *IOP310_SOMWVR, + *IOP310_SOIOWVR); + DBG(" ATU secondary: IOP310_ATUCR=0x%08x\n", *IOP310_ATUCR); + DBG(" ATU secondary: IOP310_SIABAR=0x%08x IOP310_SIALR=0x%08x IOP310_SIATVR=%08x\n", *IOP310_SIABAR, *IOP310_SIALR, *IOP310_SIATVR); + + DBG(" ATU primary: IOP310_POMWVR=0x%04x, IOP310_POIOWVR=0x%04x\n", + *IOP310_POMWVR, + *IOP310_POIOWVR); + DBG(" ATU secondary: IOP310_PIABAR=0x%08x IOP310_PIALR=0x%08x IOP310_PIATVR=%08x\n", *IOP310_PIABAR, *IOP310_PIALR, *IOP310_PIATVR); + + DBG(" P2P: IOP310_PCR=0x%04x IOP310_BCR=0x%04x IOP310_EBCR=0x%04x\n", *IOP310_PCR, *IOP310_BCR, *IOP310_EBCR); + + /* + * Windows have to be carefully opened via a nice set of calls + * here or just some direct register fiddling in the board + * specific init when we want transactions to occur between the + * two PCI hoses. + * + * To do this, we will have manage RETRY assertion between the + * firmware and the kernel. This will ensure that the host + * system's enumeration code is held off until we have tweaked + * the interrupt routing and public/private IDSELs. + * + * For now we will simply default to disabling the integrated type + * 81 P2P bridge. + */ + *IOP310_PCR &= 0xfff8; + + external_fault = iop310_pci_abort_handler; + +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-iop310/iq80310-irq.c linux-2.5/arch/arm/mach-iop310/iq80310-irq.c --- linux-2.5.1/arch/arm/mach-iop310/iq80310-irq.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-iop310/iq80310-irq.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,172 @@ +/* + * linux/arch/arm/mach-iop310/iq80310-irq.c + * + * IRQ hadling/demuxing for IQ80310 board + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + * 2.4.7-rmk1-iop310.1 + * Moved demux from asm to C - DS + * Fixes for various revision boards - DS + */ + +#include <linux/config.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/smp.h> +#include <linux/init.h> + +#include <asm/irq.h> +#include <asm/mach/irq.h> +#include <asm/hardware.h> +#include <asm/system.h> + +#include <asm/mach-types.h> + +extern void xs80200_irq_mask(unsigned int); +extern void xs80200_irq_unmask(unsigned int); +extern void xs80200_init_irq(void); + +extern void do_IRQ(int, struct pt_regs *); + +extern u32 iop310_mask; + +extern void iop310_irq_demux(int, void *, struct pt_regs *); + +extern int iop310_init_irq(void); + +static void +iq80310_irq_mask (unsigned int irq) +{ + volatile char *mask = (volatile char *)IQ80310_INT_MASK; + *mask |= (1 << (irq - IQ80310_IRQ_OFS)); + + /* + * There's no mask for PCI INT A-C, so we just mask out all + * external interrupts on the CPU. + * + * We set a bit of the iop310 mask so that the iop310_irq_mask + * function does not unmask EXTINT + */ + if (irq > IRQ_IQ80310_INTD) + { + xs80200_irq_mask(IRQ_XS80200_EXTIRQ); + iop310_mask |= (0x80000000 >> (irq - IRQ_IQ80310_INTD)); + } +} + +static void +iq80310_irq_unmask (unsigned int irq) +{ + volatile char *mask = (volatile char *)IQ80310_INT_MASK; + *mask &= ~(1 << (irq - IQ80310_IRQ_OFS)); + + /* + * See comment above + */ + if (irq > IRQ_IQ80310_INTD) + { + xs80200_irq_unmask(IRQ_XS80200_EXTIRQ); + iop310_mask &= ~((0x80000000 >> (irq - IRQ_IQ80310_INTD))); + } +} + +static void iq80310_cpld_irq_demux(int irq, void *dev_id, + struct pt_regs *regs) +{ + u8 irq_stat = *((volatile u8*)IQ80310_INT_STAT); + u8 irq_mask = *((volatile u8*)IQ80310_INT_MASK); + unsigned int irqno = 0xffffffff; + + // Needed? If IRQ is masked, it shouldn't get through... + irq_stat &= ~irq_mask; + + + if(irq_stat & 0x01) + irqno = IRQ_IQ80310_TIMER; + else if(irq_stat & 0x02) + irqno = IRQ_IQ80310_I82559; + else if(irq_stat & 0x04) + irqno = IRQ_IQ80310_UART1; + else if(irq_stat & 0x08) + irqno = IRQ_IQ80310_UART2; + else if(irq_stat & 0x10) + irqno = IRQ_IQ80310_INTD; + else if(system_rev) + { + irq_stat = *((volatile u8*)IQ80310_PCI_INT_STAT) & 0xf; + + if(irq_stat & 0x1) + irqno = IRQ_IQ80310_INTA; + else if(irq_stat & 0x2) + irqno = IRQ_IQ80310_INTB; + else if(irq_stat & 0x4) + irqno = IRQ_IQ80310_INTC; + } + else /* Running on a REV D.1 or older, assume PCI INTA */ + irqno = IRQ_IQ80310_INTA; + + /* + * If we didn't read a CPLD interrupt, we assume it's from + * a device on the chipset itself. + */ + if(irqno == 0xffffffff) + { + iop310_irq_demux(irq, dev_id, regs); + return; + } + + /* + * If on a REV D.1 or lower board, we just assumed INTA since + * PCI is not routed, and it may actually be an on-chip interrupt. + * + * Note that we're giving on-chip interrupts slightly higher + * priority than PCI by handling them first. + */ + if(irqno == IRQ_IQ80310_INTA && !system_rev) + iop310_irq_demux(irq, dev_id, regs); + + do_IRQ(irqno, regs); +} + + +static struct irqaction iq80310_cpld_irq = { + name: "CPLD_IRQ", + handler: iq80310_cpld_irq_demux, + flags: SA_INTERRUPT +}; + +extern int setup_arm_irq(int, struct irqaction *); + +void __init iq80310_init_irq(void) +{ + volatile char *mask = (volatile char *)IQ80310_INT_MASK; + unsigned int i; + + iop310_init_irq(); + + /* + * Setup PIRSR to route PCI interrupts into xs80200 + */ + *IOP310_PIRSR = 0xff; + + for (i = IQ80310_IRQ_OFS; i < NR_IRQS; i++) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = iq80310_irq_mask; + irq_desc[i].mask = iq80310_irq_mask; + irq_desc[i].unmask = iq80310_irq_unmask; + } + + *mask = 0xff; /* mask all sources */ + setup_arm_irq(IRQ_XS80200_EXTIRQ, &iq80310_cpld_irq); + + /* enable only external IRQ in the INTCTL for now */ + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (1<<1)); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-iop310/iq80310-pci.c linux-2.5/arch/arm/mach-iop310/iq80310-pci.c --- linux-2.5.1/arch/arm/mach-iop310/iq80310-pci.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-iop310/iq80310-pci.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,149 @@ +/* + * arch/arm/mach-iop310/iq80310-pci.c + * + * PCI support for the Intel IQ80310 reference board + * + * Matt Porter <mporter@mvista.com> + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/mach/pci.h> + +/* + * The following macro is used to lookup irqs in a standard table + * format for those systems that do not already have PCI + * interrupts properly routed. We assume 1 <= pin <= 4 + */ +#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \ +({ int _ctl_ = -1; \ + if (idsel >= minid && idsel <= maxid && pin >= 1 && pin <= 4) \ + _ctl_ = pci_irq_table[idsel - minid][pin-1]; \ + _ctl_; }) + +#define INTA IRQ_IQ80310_INTA +#define INTB IRQ_IQ80310_INTB +#define INTC IRQ_IQ80310_INTC +#define INTD IRQ_IQ80310_INTD + +#define INTE IRQ_IQ80310_I82559 + +typedef u8 irq_table[4]; + +/* + * IRQ tables for primary bus. + * + * On a Rev D.1 and older board, INT A-C are not routed, so we + * just fake it as INTA and than we take care of handling it + * correctly in the IRQ demux routine. + */ +static irq_table pci_pri_d_irq_table[] = { +/* Pin: A B C D */ + { INTA, INTD, INTA, INTA }, /* PCI Slot J3 */ + { INTD, INTA, INTA, INTA }, /* PCI Slot J4 */ +}; + +static irq_table pci_pri_f_irq_table[] = { +/* Pin: A B C D */ + { INTC, INTD, INTA, INTB }, /* PCI Slot J3 */ + { INTD, INTA, INTB, INTC }, /* PCI Slot J4 */ +}; + +static int __init +iq80310_pri_map_irq(struct pci_dev *dev, u8 idsel, u8 pin) +{ + irq_table *pci_irq_table; + + if (!system_rev) { + pci_irq_table = pci_pri_d_irq_table; + } else { + pci_irq_table = pci_pri_f_irq_table; + } + + return PCI_IRQ_TABLE_LOOKUP(2, 3); +} + +/* + * IRQ tables for secondary bus. + * + * On a Rev D.1 and older board, INT A-C are not routed, so we + * just fake it as INTA and than we take care of handling it + * correctly in the IRQ demux routine. + */ +static irq_table pci_sec_d_irq_table[] = { +/* Pin: A B C D */ + { INTA, INTA, INTA, INTD }, /* PCI Slot J1 */ + { INTA, INTA, INTD, INTA }, /* PCI Slot J5 */ + { INTE, INTE, INTE, INTE }, /* P2P Bridge */ +}; + +static irq_table pci_sec_f_irq_table[] = { +/* Pin: A B C D */ + { INTA, INTB, INTC, INTD }, /* PCI Slot J1 */ + { INTB, INTC, INTD, INTA }, /* PCI Slot J5 */ + { INTE, INTE, INTE, INTE }, /* P2P Bridge */ +}; + +static int __init +iq80310_sec_map_irq(struct pci_dev *dev, u8 idsel, u8 pin) +{ + irq_table *pci_irq_table; + + if (!system_rev) { + pci_irq_table = pci_sec_d_irq_table; + } else { + pci_irq_table = pci_sec_f_irq_table; + } + + return PCI_IRQ_TABLE_LOOKUP(0, 2); +} + +static int iq80310_pri_host; + +static int iq80310_setup(int nr, struct pci_sys_data *sys) +{ + switch (nr) { + case 0: + if (!iq80310_pri_host) + return 0; + + sys->map_irq = iq80310_pri_map_irq; + break; + + case 1: + sys->map_irq = iq80310_sec_map_irq; + break; + + default: + return 0; + } + + return iop310_setup(nr, sys); +} + +static void iq80310_preinit(void) +{ + iq80310_pri_host = *(volatile u32 *)IQ80310_BACKPLANE & 1; + + printk(KERN_INFO "PCI: IQ80310 is a%s\n", + iq80310_pri_host ? " system controller" : "n agent"); + + iop310_init(); +} + +struct hw_pci iq80310_pci __initdata = { + swizzle: pci_std_swizzle, + nr_controllers: 2, + setup: iq80310_setup, + scan: iop310_scan_bus, + preinit: iq80310_preinit, +}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-iop310/iq80310-time.c linux-2.5/arch/arm/mach-iop310/iq80310-time.c --- linux-2.5.1/arch/arm/mach-iop310/iq80310-time.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-iop310/iq80310-time.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,125 @@ +/* + * linux/arch/arm/mach-iop310/time-iq80310.c + * + * Timer functions for IQ80310 onboard timer + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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/config.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/smp.h> + +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/irq.h> + +#include <linux/timex.h> +#include <asm/hardware.h> + +#include <asm/mach-types.h> + +static void iq80310_write_timer (u_long val) +{ + volatile u_char *la0 = (volatile u_char *)IQ80310_TIMER_LA0; + volatile u_char *la1 = (volatile u_char *)IQ80310_TIMER_LA1; + volatile u_char *la2 = (volatile u_char *)IQ80310_TIMER_LA2; + + *la0 = val; + *la1 = val >> 8; + *la2 = (val >> 16) & 0x3f; +} + +static u_long iq80310_read_timer (void) +{ + volatile u_char *la0 = (volatile u_char *)IQ80310_TIMER_LA0; + volatile u_char *la1 = (volatile u_char *)IQ80310_TIMER_LA1; + volatile u_char *la2 = (volatile u_char *)IQ80310_TIMER_LA2; + volatile u_char *la3 = (volatile u_char *)IQ80310_TIMER_LA3; + u_long b0, b1, b2, b3, val; + + b0 = *la0; b1 = *la1; b2 = *la2; b3 = *la3; + b0 = (((b0 & 0x20) >> 1) | (b0 & 0x1f)); + b1 = (((b1 & 0x20) >> 1) | (b1 & 0x1f)); + b2 = (((b2 & 0x20) >> 1) | (b2 & 0x1f)); + b3 = (b3 & 0x0f); + val = ((b0 << 0) | (b1 << 6) | (b2 << 12) | (b3 << 18)); + return val; +} + +/* IRQs are disabled before entering here from do_gettimeofday() */ +static unsigned long iq80310_gettimeoffset (void) +{ + unsigned long elapsed, usec; + + /* We need elapsed timer ticks since last interrupt */ + elapsed = iq80310_read_timer(); + + /* Now convert them to usec */ + usec = (unsigned long)(elapsed*tick)/LATCH; + + return usec; +} + + +static void iq80310_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile u_char *timer_en = (volatile u_char *)IQ80310_TIMER_EN; + + /* clear timer interrupt */ + *timer_en &= ~2; + *timer_en |= 2; + + /* + * AHEM..HACK + * + * Since the timer interrupt is cascaded through the CPLD and + * the 80312 and the demux code calls do_IRQ, the irq count is + * going to be atleast 2 when we get here and this will cause the + * kernel to increment the system tick counter even if we're + * idle. This causes it to look like there's always 100% system + * time, which is not the case. To get around it, we just decrement + * the IRQ count before calling do_timer. We increment it again + * b/c otherwise it will go negative and than bad things happen. + * + * -DS + */ + irq_exit(smp_processor_id(), irq); + do_timer(regs); + irq_enter(smp_processor_id(), irq); +} + +extern unsigned long (*gettimeoffset)(void); + +static struct irqaction timer_irq = { + name: "timer", + handler: iq80310_timer_interrupt, +}; + + +extern int setup_arm_irq(int, struct irqaction*); + +void __init time_init(void) +{ + volatile u_char *timer_en = (volatile u_char *)IQ80310_TIMER_EN; + + gettimeoffset = iq80310_gettimeoffset; + setup_arm_irq(IRQ_IQ80310_TIMER, &timer_irq); + *timer_en = 0; + iq80310_write_timer(LATCH); + *timer_en |= 2; + *timer_en |= 1; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-iop310/mm.c linux-2.5/arch/arm/mach-iop310/mm.c --- linux-2.5.1/arch/arm/mach-iop310/mm.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-iop310/mm.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/mach-iop310/mm.c + * + * Low level memory intialization for IOP310 based systems + * + * Author: Nicolas Pitre <npitre@mvista.com> + * + * Copyright 2000-2001 MontaVista Software 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. + * + */ + +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> + +#include <asm/mach/map.h> +#include <asm/mach-types.h> + +#ifdef CONFIG_IOP310_MU +#include "message.h" +#endif + +/* + * Standard IO mapping for all IOP310 based systems + */ +static struct map_desc iop80310_std_desc[] __initdata = { + /* virtual physical length domain r w c b */ + // IOP310 Memory Mapped Registers + { 0xe8001000, 0x00001000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + // PCI I/O Space + { 0xfe000000, 0x90000000, 0x00020000, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +void __init iop310_map_io(void) +{ + iotable_init(iop80310_std_desc); +} + +/* + * IQ80310 specific IO mappings + */ +#ifdef CONFIG_ARCH_IQ80310 +static struct map_desc iq80310_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + // IQ80310 On-Board Devices + { 0xfe800000, 0xfe800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +void __init iq80310_map_io(void) +{ +#ifdef CONFIG_IOP310_MU + /* acquiring 1MB of memory aligned on 1MB boundary for MU */ + mu_mem = __alloc_bootmem(0x100000, 0x100000, 0); +#endif + + iop310_map_io(); + + iotable_init(iq80310_io_desc); +} +#endif // CONFIG_ARCH_IQ80310 + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-iop310/xs80200-irq.c linux-2.5/arch/arm/mach-iop310/xs80200-irq.c --- linux-2.5.1/arch/arm/mach-iop310/xs80200-irq.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-iop310/xs80200-irq.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,66 @@ +/* + * linux/arch/arm/mach-iop310/xs80200-irq.c + * + * Generic IRQ handling for the XS80200 XScale core. + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include <asm/mach/irq.h> +#include <asm/irq.h> +#include <asm/hardware.h> + +#include <asm/mach-types.h> + +void +xs80200_irq_mask (unsigned int irq) +{ + long INTCTL; + asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); + switch (irq) { + case IRQ_XS80200_BCU: INTCTL &= ~(1<<3); break; + case IRQ_XS80200_PMU: INTCTL &= ~(1<<2); break; + case IRQ_XS80200_EXTIRQ: INTCTL &= ~(1<<1); break; + case IRQ_XS80200_EXTFIQ: INTCTL &= ~(1<<0); break; + } + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); +} + +void +xs80200_irq_unmask (unsigned int irq) +{ + long INTCTL; + asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); + switch (irq) { + case IRQ_XS80200_BCU: INTCTL |= (1<<3); break; + case IRQ_XS80200_PMU: INTCTL |= (1<<2); break; + case IRQ_XS80200_EXTIRQ: INTCTL |= (1<<1); break; + case IRQ_XS80200_EXTFIQ: INTCTL |= (1<<0); break; + } + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); +} + +void __init xs80200_init_irq(void) +{ + int i; + + for (i = 0; i < NR_XS80200_IRQS; i++) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 0; + irq_desc[i].mask_ack = xs80200_irq_mask; + irq_desc[i].mask = xs80200_irq_mask; + irq_desc[i].unmask = xs80200_irq_unmask; + } +} + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-l7200/Makefile linux-2.5/arch/arm/mach-l7200/Makefile --- linux-2.5.1/arch/arm/mach-l7200/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-l7200/Makefile Sun Jan 6 01:38:26 2002 @@ -0,0 +1,21 @@ +# +# 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 := l7200.o + +# Object file lists. + +obj-y := core.o +obj-m := +obj-n := +obj- := + +export-objs := + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-l7200/core.c linux-2.5/arch/arm/mach-l7200/core.c --- linux-2.5.1/arch/arm/mach-l7200/core.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-l7200/core.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,114 @@ +/* + * linux/arch/arm/mm/mm-lusl7200.c + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * + * Extra MM routines for L7200 architecture + */ +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/page.h> +#include <asm/proc/domain.h> + +#include <asm/mach/map.h> +#include <asm/arch/hardware.h> + +/* + * IRQ base register + */ +#define IRQ_BASE (IO_BASE_2 + 0x1000) + +/* + * Normal IRQ registers + */ +#define IRQ_STATUS (*(volatile unsigned long *) (IRQ_BASE + 0x000)) +#define IRQ_RAWSTATUS (*(volatile unsigned long *) (IRQ_BASE + 0x004)) +#define IRQ_ENABLE (*(volatile unsigned long *) (IRQ_BASE + 0x008)) +#define IRQ_ENABLECLEAR (*(volatile unsigned long *) (IRQ_BASE + 0x00c)) +#define IRQ_SOFT (*(volatile unsigned long *) (IRQ_BASE + 0x010)) +#define IRQ_SOURCESEL (*(volatile unsigned long *) (IRQ_BASE + 0x018)) + +/* + * Fast IRQ registers + */ +#define FIQ_STATUS (*(volatile unsigned long *) (IRQ_BASE + 0x100)) +#define FIQ_RAWSTATUS (*(volatile unsigned long *) (IRQ_BASE + 0x104)) +#define FIQ_ENABLE (*(volatile unsigned long *) (IRQ_BASE + 0x108)) +#define FIQ_ENABLECLEAR (*(volatile unsigned long *) (IRQ_BASE + 0x10c)) +#define FIQ_SOFT (*(volatile unsigned long *) (IRQ_BASE + 0x110)) +#define FIQ_SOURCESEL (*(volatile unsigned long *) (IRQ_BASE + 0x118)) + +static void l7200_mask_irq(unsigned int irq) +{ + IRQ_ENABLECLEAR = 1 << irq; +} + +static void l7200_unmask_irq(unsigned int irq) +{ + IRQ_ENABLE = 1 << irq; +} + +static void __init l7200_init_irq(void) +{ + int irq; + + IRQ_ENABLECLEAR = 0xffffffff; /* clear all interrupt enables */ + FIQ_ENABLECLEAR = 0xffffffff; /* clear all fast interrupt enables */ + + for (irq = 0; irq < NR_IRQS; irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = l7200_mask_irq; + irq_desc[irq].mask = l7200_mask_irq; + irq_desc[irq].unmask = l7200_unmask_irq; + } + + init_FIQ(); +} + +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 +}; + +static void __init l7200_map_io(void) +{ + iotable_init(l7200_io_desc); +} + +static void __init +fixup_l7200(struct machine_desc *desc, struct param_struct *unused, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks = 1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].size = (32*1024*1024); + mi->bank[0].node = 0; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); + setup_initrd( __phys_to_virt(0xf1000000), 0x005dac7b); + + /* 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 L7200") + MAINTAINER("Steve Hill / Scott McConnell") + BOOT_MEM(0xf0000000, 0x80040000, 0xd0000000) + FIXUP(fixup_l7200) + MAPIO(l7200_map_io) + INITIRQ(l7200_init_irq) +MACHINE_END + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-rpc/Makefile linux-2.5/arch/arm/mach-rpc/Makefile --- linux-2.5.1/arch/arm/mach-rpc/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-rpc/Makefile Sun Jan 6 01:38:26 2002 @@ -0,0 +1,22 @@ +# +# 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 := rpc.o + +# Object file lists. + +obj-y := dma.o irq.o riscpc.o +obj-m := +obj-n := +obj- := + +export-objs := + + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-rpc/dma.c linux-2.5/arch/arm/mach-rpc/dma.c --- linux-2.5.1/arch/arm/mach-rpc/dma.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-rpc/dma.c Tue Jan 8 00:44:24 2002 @@ -0,0 +1,371 @@ +/* + * linux/arch/arm/kernel/dma-rpc.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. + * + * DMA functions specific to RiscPC architecture + */ +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/mman.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/page.h> +#include <asm/dma.h> +#include <asm/fiq.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/uaccess.h> + +#include <asm/mach/dma.h> +#include <asm/hardware/iomd.h> + +#if 0 +typedef enum { + dma_size_8 = 1, + dma_size_16 = 2, + dma_size_32 = 4, + dma_size_128 = 16 +} dma_size_t; + +typedef struct { + dma_size_t transfersize; +} dma_t; +#endif + +#define TRANSFER_SIZE 2 + +#define CURA (0) +#define ENDA (IOMD_IO0ENDA - IOMD_IO0CURA) +#define CURB (IOMD_IO0CURB - IOMD_IO0CURA) +#define ENDB (IOMD_IO0ENDB - IOMD_IO0CURA) +#define CR (IOMD_IO0CR - IOMD_IO0CURA) +#define ST (IOMD_IO0ST - IOMD_IO0CURA) + +#define state_prog_a 0 +#define state_wait_a 1 +#define state_wait_b 2 + +static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma) +{ + unsigned long end, offset, flags = 0; + + if (dma->sg) { + sg->dma_address = dma->sg->dma_address; + offset = sg->dma_address & ~PAGE_MASK; + + end = offset + dma->sg->length; + + if (end > PAGE_SIZE) + end = PAGE_SIZE; + + if (offset + (int) TRANSFER_SIZE > end) + flags |= DMA_END_L; + + sg->length = end - TRANSFER_SIZE; + + dma->sg->length -= end - offset; + dma->sg->dma_address += end - offset; + + if (dma->sg->length == 0) { + if (dma->sgcount > 1) { + dma->sg++; + dma->sgcount--; + } else { + dma->sg = NULL; + flags |= DMA_END_S; + } + } + } else { + flags = DMA_END_S | DMA_END_L; + sg->dma_address = 0; + sg->length = 0; + } + + sg->length |= flags; +} + +static inline void iomd_setup_dma_a(struct scatterlist *sg, dma_t *dma) +{ + iomd_writel(sg->dma_address, dma->dma_base + CURA); + iomd_writel(sg->length, dma->dma_base + ENDA); +} + +static inline void iomd_setup_dma_b(struct scatterlist *sg, dma_t *dma) +{ + iomd_writel(sg->dma_address, dma->dma_base + CURB); + iomd_writel(sg->length, dma->dma_base + ENDB); +} + +static void iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs) +{ + dma_t *dma = (dma_t *)dev_id; + unsigned int status = 0, no_buffer = dma->sg == NULL; + + do { + switch (dma->state) { + case state_prog_a: + iomd_get_next_sg(&dma->cur_sg, dma); + iomd_setup_dma_a(&dma->cur_sg, dma); + dma->state = state_wait_a; + + case state_wait_a: + status = iomd_readb(dma->dma_base + ST); + switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) { + case DMA_ST_OFL|DMA_ST_INT: + iomd_get_next_sg(&dma->cur_sg, dma); + iomd_setup_dma_a(&dma->cur_sg, dma); + break; + + case DMA_ST_INT: + iomd_get_next_sg(&dma->cur_sg, dma); + iomd_setup_dma_b(&dma->cur_sg, dma); + dma->state = state_wait_b; + break; + + case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB: + iomd_setup_dma_b(&dma->cur_sg, dma); + dma->state = state_wait_b; + break; + } + break; + + case state_wait_b: + status = iomd_readb(dma->dma_base + ST); + switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) { + case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB: + iomd_get_next_sg(&dma->cur_sg, dma); + iomd_setup_dma_b(&dma->cur_sg, dma); + break; + + case DMA_ST_INT|DMA_ST_AB: + iomd_get_next_sg(&dma->cur_sg, dma); + iomd_setup_dma_a(&dma->cur_sg, dma); + dma->state = state_wait_a; + break; + + case DMA_ST_OFL|DMA_ST_INT: + iomd_setup_dma_a(&dma->cur_sg, dma); + dma->state = state_wait_a; + break; + } + break; + } + } while (dma->sg && (status & DMA_ST_INT)); + + if (no_buffer) + disable_irq(irq); +} + +static int iomd_request_dma(dmach_t channel, dma_t *dma) +{ + return request_irq(dma->dma_irq, iomd_dma_handle, + SA_INTERRUPT, dma->device_id, dma); +} + +static void iomd_free_dma(dmach_t channel, dma_t *dma) +{ + free_irq(dma->dma_irq, dma); +} + +static void iomd_enable_dma(dmach_t channel, dma_t *dma) +{ + unsigned long dma_base = dma->dma_base; + unsigned int ctrl = TRANSFER_SIZE | DMA_CR_E; + + if (dma->invalid) { + dma->invalid = 0; + + /* + * Cope with ISA-style drivers which expect cache + * coherence. + */ + if (!dma->using_sg) { + dma->buf.dma_address = pci_map_single(NULL, + dma->buf.address, dma->buf.length, + dma->dma_mode == DMA_MODE_READ ? + PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + } + + iomd_writeb(DMA_CR_C, dma_base + CR); + dma->state = state_prog_a; + } + + if (dma->dma_mode == DMA_MODE_READ) + ctrl |= DMA_CR_D; + + iomd_writeb(ctrl, dma_base + CR); + enable_irq(dma->dma_irq); +} + +static void iomd_disable_dma(dmach_t channel, dma_t *dma) +{ + unsigned long dma_base = dma->dma_base; + unsigned int ctrl; + + disable_irq(dma->dma_irq); + ctrl = iomd_readb(dma_base + CR); + iomd_writeb(ctrl & ~DMA_CR_E, dma_base + CR); +} + +static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle) +{ + int tcr, speed; + + if (cycle < 188) + speed = 3; + else if (cycle <= 250) + speed = 2; + else if (cycle < 438) + speed = 1; + else + speed = 0; + + tcr = iomd_readb(IOMD_DMATCR); + speed &= 3; + + switch (channel) { + case DMA_0: + tcr = (tcr & ~0x03) | speed; + break; + + case DMA_1: + tcr = (tcr & ~0x0c) | (speed << 2); + break; + + case DMA_2: + tcr = (tcr & ~0x30) | (speed << 4); + break; + + case DMA_3: + tcr = (tcr & ~0xc0) | (speed << 6); + break; + + default: + break; + } + + iomd_writeb(tcr, IOMD_DMATCR); + + return speed; +} + +static struct dma_ops iomd_dma_ops = { + type: "IOMD", + request: iomd_request_dma, + free: iomd_free_dma, + enable: iomd_enable_dma, + disable: iomd_disable_dma, + setspeed: iomd_set_dma_speed, +}; + +static struct fiq_handler fh = { + name: "floppydma" +}; + +static void floppy_enable_dma(dmach_t channel, dma_t *dma) +{ + void *fiqhandler_start; + unsigned int fiqhandler_length; + struct pt_regs regs; + + if (dma->dma_mode == DMA_MODE_READ) { + extern unsigned char floppy_fiqin_start, floppy_fiqin_end; + fiqhandler_start = &floppy_fiqin_start; + fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start; + } else { + extern unsigned char floppy_fiqout_start, floppy_fiqout_end; + fiqhandler_start = &floppy_fiqout_start; + fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start; + } + + regs.ARM_r9 = dma->buf.length; + regs.ARM_r10 = (unsigned long)dma->buf.address; + regs.ARM_fp = FLOPPYDMA_BASE; + + if (claim_fiq(&fh)) { + printk("floppydma: couldn't claim FIQ.\n"); + return; + } + + set_fiq_handler(fiqhandler_start, fiqhandler_length); + set_fiq_regs(®s); + enable_fiq(dma->dma_irq); +} + +static void floppy_disable_dma(dmach_t channel, dma_t *dma) +{ + disable_fiq(dma->dma_irq); + release_fiq(&fh); +} + +static int floppy_get_residue(dmach_t channel, dma_t *dma) +{ + struct pt_regs regs; + get_fiq_regs(®s); + return regs.ARM_r9; +} + +static struct dma_ops floppy_dma_ops = { + type: "FIQDMA", + enable: floppy_enable_dma, + disable: floppy_disable_dma, + residue: floppy_get_residue, +}; + +/* + * This is virtual DMA - we don't need anything here. + */ +static void sound_enable_disable_dma(dmach_t channel, dma_t *dma) +{ +} + +static struct dma_ops sound_dma_ops = { + type: "VIRTUAL", + enable: sound_enable_disable_dma, + disable: sound_enable_disable_dma, +}; + +void __init arch_dma_init(dma_t *dma) +{ + iomd_writeb(0, IOMD_IO0CR); + iomd_writeb(0, IOMD_IO1CR); + iomd_writeb(0, IOMD_IO2CR); + iomd_writeb(0, IOMD_IO3CR); + + iomd_writeb(0xa0, IOMD_DMATCR); + + dma[DMA_0].dma_base = IOMD_IO0CURA; + dma[DMA_0].dma_irq = IRQ_DMA0; + dma[DMA_0].d_ops = &iomd_dma_ops; + dma[DMA_1].dma_base = IOMD_IO1CURA; + dma[DMA_1].dma_irq = IRQ_DMA1; + dma[DMA_1].d_ops = &iomd_dma_ops; + dma[DMA_2].dma_base = IOMD_IO2CURA; + dma[DMA_2].dma_irq = IRQ_DMA2; + dma[DMA_2].d_ops = &iomd_dma_ops; + dma[DMA_3].dma_base = IOMD_IO3CURA; + dma[DMA_3].dma_irq = IRQ_DMA3; + dma[DMA_3].d_ops = &iomd_dma_ops; + dma[DMA_S0].dma_base = IOMD_SD0CURA; + dma[DMA_S0].dma_irq = IRQ_DMAS0; + dma[DMA_S0].d_ops = &iomd_dma_ops; + dma[DMA_S1].dma_base = IOMD_SD1CURA; + dma[DMA_S1].dma_irq = IRQ_DMAS1; + dma[DMA_S1].d_ops = &iomd_dma_ops; + dma[DMA_VIRTUAL_FLOPPY].dma_irq = FIQ_FLOPPYDATA; + dma[DMA_VIRTUAL_FLOPPY].d_ops = &floppy_dma_ops; + dma[DMA_VIRTUAL_SOUND].d_ops = &sound_dma_ops; + + /* + * Setup DMA channels 2,3 to be for podules + * and channels 0,1 for internal devices + */ + iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-rpc/irq.c linux-2.5/arch/arm/mach-rpc/irq.c --- linux-2.5.1/arch/arm/mach-rpc/irq.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-rpc/irq.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,142 @@ +#include <linux/init.h> + +#include <asm/mach/irq.h> +#include <asm/hardware/iomd.h> +#include <asm/irq.h> +#include <asm/io.h> + +static void rpc_mask_irq_ack_a(unsigned int irq) +{ + unsigned int val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + 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 val, mask; + + mask = 1 << (irq & 7); + val = iomd_readb(IOMD_FIQMASK); + iomd_writeb(val | mask, IOMD_FIQMASK); +} + +void __init rpc_init_irq(void) +{ + int irq; + + 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) { + case 0 ... 6: + irq_desc[irq].probe_ok = 1; + case 7: + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = rpc_mask_irq_ack_a; + irq_desc[irq].mask = rpc_mask_irq_a; + irq_desc[irq].unmask = rpc_unmask_irq_a; + break; + + case 9 ... 15: + irq_desc[irq].probe_ok = 1; + case 8: + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = rpc_mask_irq_b; + irq_desc[irq].mask = rpc_mask_irq_b; + irq_desc[irq].unmask = rpc_unmask_irq_b; + break; + + 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 64 ... 71: + irq_desc[irq].valid = 1; + irq_desc[irq].mask_ack = rpc_mask_irq_fiq; + irq_desc[irq].mask = rpc_mask_irq_fiq; + irq_desc[irq].unmask = rpc_unmask_irq_fiq; + break; + } + } + + irq_desc[IRQ_KEYBOARDTX].noautoenable = 1; + + init_FIQ(); +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-rpc/riscpc.c linux-2.5/arch/arm/mach-rpc/riscpc.c --- linux-2.5.1/arch/arm/mach-rpc/riscpc.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-rpc/riscpc.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,94 @@ +/* + * linux/arch/arm/mach-rpc/riscpc.c + * + * Copyright (C) 1998-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. + * + * Architecture specific fixups. + */ +#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/hardware.h> +#include <asm/page.h> +#include <asm/proc/domain.h> +#include <asm/setup.h> + +#include <asm/mach/map.h> +#include <asm/mach/arch.h> + +extern void rpc_init_irq(void); + +extern unsigned int vram_size; + +#if 0 + +unsigned int memc_ctrl_reg; +unsigned int number_mfm_drives; + +static int __init parse_tag_acorn(const struct tag *tag) +{ + memc_ctrl_reg = tag->u.acorn.memc_control_reg; + number_mfm_drives = tag->u.acorn.adfsdrives; + + switch (tag->u.acorn.vram_pages) { + case 512: + vram_size += PAGE_SIZE * 256; + case 256: + vram_size += PAGE_SIZE * 256; + default: + break; + } +#if 0 + if (vram_size) { + desc->video_start = 0x02000000; + desc->video_end = 0x02000000 + vram_size; + } +#endif + return 0; +} + +__tagtable(ATAG_ACORN, parse_tag_acorn); + +#endif + +static void __init +fixup_riscpc(struct machine_desc *desc, struct param_struct *unusd, + char **cmdline, struct meminfo *mi) +{ + /* + * RiscPC can't handle half-word loads and stores + */ + elf_hwcap &= ~HWCAP_HALF; +} + +static struct map_desc rpc_io_desc[] __initdata = { + { SCREEN_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 }, /* VRAM */ + { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, /* IO space */ + { EASI_BASE, EASI_START, EASI_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* EASI space */ + LAST_DESC +}; + +void __init rpc_map_io(void) +{ + iotable_init(rpc_io_desc); +} + +MACHINE_START(RISCPC, "Acorn-RiscPC") + MAINTAINER("Russell King") + BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) + BOOT_PARAMS(0x10000100) + DISABLE_PARPORT(0) + DISABLE_PARPORT(1) + FIXUP(fixup_riscpc) + MAPIO(rpc_map_io) + INITIRQ(rpc_init_irq) +MACHINE_END diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/Makefile linux-2.5/arch/arm/mach-sa1100/Makefile --- linux-2.5.1/arch/arm/mach-sa1100/Makefile Thu Oct 25 20:53:45 2001 +++ linux-2.5/arch/arm/mach-sa1100/Makefile Sun Jan 6 01:38:26 2002 @@ -9,20 +9,15 @@ O_TARGET := sa1100.o -obj-y := +# Common support (must be linked before board specific support) +obj-y := generic.o irq.o dma.o obj-m := obj-n := obj- := -export-objs := assabet.o dma-sa1100.o dma-sa1111.o freebird.o generic.o \ - h3600.o huw_webpanel.o irq.o pcipool.o sa1111-pcibuf.o \ - yopy.o - -# These aren't present yet, and prevents a plain -ac kernel building. -# hwtimer.o usb_ctl.o usb_recv.o usb_send.o - -# Common support (must be linked before board specific support) -obj-y += generic.o irq.o dma-sa1100.o +export-objs := assabet.o dma.o flexanet.o freebird.o generic.o h3600.o \ + huw_webpanel.o irq.o pcipool.o sa1111.o sa1111-pcibuf.o \ + yopy.o usb_ctl.o usb_recv.o usb_send.o # This needs to be cleaned up. We probably need to have SA1100 # and SA1110 config symbols. @@ -31,11 +26,12 @@ ifeq ($(CONFIG_CPU_FREQ),y) obj-$(CONFIG_SA1100_ASSABET) += cpu-sa1110.o obj-$(CONFIG_SA1100_CERF) += cpu-sa1110.o +obj-$(CONFIG_SA1100_PT_SYSTEM3) += cpu-sa1110.o obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o endif # Next, the SA1111 stuff. -obj-$(CONFIG_SA1111) += sa1111.o dma-sa1111.o +obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_USB_OHCI_SA1111) += sa1111-pcibuf.o pcipool.o # Specific board support @@ -59,7 +55,9 @@ obj-$(CONFIG_SA1100_PANGOLIN) += pangolin.o obj-$(CONFIG_SA1100_PFS168) += pfs168.o obj-$(CONFIG_SA1100_PLEB) += pleb.o +obj-$(CONFIG_SA1100_SHANNON) += shannon.o obj-$(CONFIG_SA1100_SHERMAN) += sherman.o +obj-$(CONFIG_SA1100_PT_SYSTEM3) += system3.o obj-$(CONFIG_SA1100_SIMPAD) += simpad.o obj-$(CONFIG_SA1100_VICTOR) += victor.o obj-$(CONFIG_SA1100_XP860) += xp860.o @@ -77,9 +75,21 @@ leds-$(CONFIG_SA1100_LART) += leds-lart.o leds-$(CONFIG_SA1100_PFS168) += leds-pfs168.o leds-$(CONFIG_SA1100_SIMPAD) += leds-simpad.o +leds-$(CONFIG_SA1100_PT_SYSTEM3) += leds-system3.o obj-$(CONFIG_LEDS) += $(leds-y) +# SA1110 USB client support +list-multi += sa1100usb_core.o +sa1100usb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o +obj-$(CONFIG_SA1100_USB) += sa1100usb_core.o +obj-$(CONFIG_SA1100_USB_NETLINK) += usb-eth.o +obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o + # Miscelaneous functions obj-$(CONFIG_PM) += pm.o sleep.o include $(TOPDIR)/Rules.make + +sa1100usb_core.o: $(sa1100usb_core-objs) + $(LD) -r -o $@ $(sa1100usb_core-objs) + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/adsbitsy.c linux-2.5/arch/arm/mach-sa1100/adsbitsy.c --- linux-2.5.1/arch/arm/mach-sa1100/adsbitsy.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-sa1100/adsbitsy.c Sun Jan 6 01:38:26 2002 @@ -14,6 +14,7 @@ #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/ptrace.h> +#include <linux/ioport.h> #include <linux/serial_core.h> #include <asm/hardware.h> @@ -53,7 +54,7 @@ /* * Probe for SA1111. */ - ret = sa1111_probe(); + ret = sa1111_probe(0x18000000); if (ret < 0) return ret; @@ -94,7 +95,7 @@ sa1110_mb_enable(); set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_RISING_EDGE); - sa1111_init_irq(SA1100_GPIO_TO_IRQ(0)); + sa1111_init_irq(IRQ_GPIO0); return 0; } @@ -126,7 +127,6 @@ static struct map_desc adsbitsy_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1111 */ LAST_DESC }; @@ -135,24 +135,15 @@ { if (port->mapbase == _Ser1UTCR0) { Ser1SDCR0 |= SDCR0_UART; - // Set RTS Output and High (should be done in the set_mctrl fn) - GPDR |= GPIO_GPIO15; - GPCR |= GPIO_GPIO15; - // Set CTS Input - GPDR &= ~GPIO_GPIO14; +#error Fixme // Set RTS High (should be done in the set_mctrl fn) + GPCR = GPIO_GPIO15; } else if (port->mapbase == _Ser2UTCR0) { Ser2UTCR4 = Ser2HSCR0 = 0; - // Set RTS Output and High (should be done in the set_mctrl fn) - GPDR |= GPIO_GPIO17; - GPCR |= GPIO_GPIO17; - // Set CTS Input - GPDR &= ~GPIO_GPIO16; +#error Fixme // Set RTS High (should be done in the set_mctrl fn) + GPCR = GPIO_GPIO17; } else if (port->mapbase == _Ser2UTCR0) { - // Set RTS Output and High (should be done in the set_mctrl fn) - GPDR |= GPIO_GPIO19; - GPCR |= GPIO_GPIO19; - // Set CTS Input - GPDR &= ~GPIO_GPIO18; +#error Fixme // Set RTS High (should be done in the set_mctrl fn) + GPCR = GPIO_GPIO19; } return 0; } @@ -166,10 +157,12 @@ sa1100_map_io(); iotable_init(adsbitsy_io_desc); - sa1110_register_uart_fns(&adsbitsy_port_fns); + sa1100_register_uart_fns(&adsbitsy_port_fns); sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); sa1100_register_uart(2, 2); + GPDR |= GPIO_GPIO15 | GPIO_GPIO17 | GPIO_GPIO19; + GPDR &= ~(GPIO_GPIO14 | GPIO_GPIO16 | GPIO_GPIO18); } MACHINE_START(ADSBITSY, "ADS Bitsy") diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/assabet.c linux-2.5/arch/arm/mach-sa1100/assabet.c --- linux-2.5.1/arch/arm/mach-sa1100/assabet.c Thu Oct 25 20:53:45 2001 +++ linux-2.5/arch/arm/mach-sa1100/assabet.c Sun Jan 6 01:38:26 2002 @@ -31,16 +31,70 @@ #include "generic.h" +#define ASSABET_BCR_DB1110 \ + (ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \ + ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \ + ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \ + ASSABET_BCR_IRDA_MD0) + +#define ASSABET_BCR_DB1111 \ + (ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \ + ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \ + ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \ + ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \ + ASSABET_BCR_IRDA_MD0 | ASSABET_BCR_CF_RST) -unsigned long BCR_value = ASSABET_BCR_DB1110; unsigned long SCR_value = ASSABET_SCR_INIT; -EXPORT_SYMBOL(BCR_value); EXPORT_SYMBOL(SCR_value); +static unsigned long BCR_value = ASSABET_BCR_DB1110; + +void ASSABET_BCR_frob(unsigned int mask, unsigned int val) +{ + unsigned long flags; + + local_irq_save(flags); + BCR_value = (BCR_value & ~mask) | val; + ASSABET_BCR = BCR_value; + local_irq_restore(flags); +} + +EXPORT_SYMBOL(ASSABET_BCR_frob); + +static void assabet_backlight_power(int on) +{ +#ifndef ASSABET_PAL_VIDEO + if (on) + ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON); + else +#endif + ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON); +} + +static void assabet_lcd_power(int on) +{ +#ifndef ASSABET_PAL_VIDEO + if (on) + ASSABET_BCR_set(ASSABET_BCR_LCD_ON); + else +#endif + ASSABET_BCR_clear(ASSABET_BCR_LCD_ON); +} static int __init assabet_init(void) { - if (machine_is_assabet() && machine_has_neponset()) { + if (!machine_is_assabet()) + return -EINVAL; + + /* + * Set the IRQ edges + */ + set_GPIO_IRQ_edge(GPIO_GPIO23, GPIO_RISING_EDGE); /* UCB1300 */ + + sa1100fb_lcd_power = assabet_lcd_power; + sa1100fb_backlight_power = assabet_backlight_power; + + if (machine_has_neponset()) { /* * Angel sets this, but other bootloaders may not. * @@ -55,6 +109,7 @@ "hasn't been configured in the kernel\n" ); #endif } + return 0; } @@ -87,18 +142,18 @@ * repeat it here because the kernel may not be loaded as a zImage, and * also because it's a hassle to communicate the SCR value to the kernel * from the decompressor. + * + * Note that IRQs are guaranteed to be disabled. */ static void __init get_assabet_scr(void) { - unsigned long flags, scr, i; + unsigned long scr, i; - local_irq_save(flags); GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */ GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */ GPDR &= ~(0x3fc); /* Configure GPIO 9:2 as inputs */ for(i = 100; i--; scr = GPLR); /* Read GPIO 9:2 */ GPDR |= 0x3fc; /* restore correct pin direction */ - local_irq_restore(flags); scr &= 0x3fc; /* save as system configuration byte. */ SCR_value = scr; } @@ -174,7 +229,6 @@ static struct map_desc assabet_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ /* f3000000 - neponset system registers */ @@ -186,19 +240,18 @@ { if (port->mapbase == _Ser1UTCR0) { if (state) - ASSABET_BCR_clear(ASSABET_BCR_RS232EN); + ASSABET_BCR_clear(ASSABET_BCR_RS232EN | + ASSABET_BCR_COM_RTS | + ASSABET_BCR_COM_DTR); else - ASSABET_BCR_set(ASSABET_BCR_RS232EN); + ASSABET_BCR_set(ASSABET_BCR_RS232EN | + ASSABET_BCR_COM_RTS | + ASSABET_BCR_COM_DTR); } } /* - * Note! this can be called from IRQ context. - * FIXME: You _need_ to handle ASSABET_BCR carefully, which doesn't - * happen at the moment. Suggest putting interrupt save/restore - * in ASSABET_BCR_set/clear. - * - * NB: Assabet uses COM_RTS and COM_DTR for both UART1 (com port) + * Assabet uses COM_RTS and COM_DTR for both UART1 (com port) * and UART3 (radio module). We only handle them for UART1 here. */ static void assabet_set_mctrl(struct uart_port *port, u_int mctrl) @@ -207,21 +260,21 @@ u_int set = 0, clear = 0; if (mctrl & TIOCM_RTS) - set |= ASSABET_BCR_COM_RTS; - else clear |= ASSABET_BCR_COM_RTS; + else + set |= ASSABET_BCR_COM_RTS; if (mctrl & TIOCM_DTR) - set |= ASSABET_BCR_COM_DTR; - else clear |= ASSABET_BCR_COM_DTR; + else + set |= ASSABET_BCR_COM_DTR; ASSABET_BCR_clear(clear); ASSABET_BCR_set(set); } } -static int assabet_get_mctrl(struct uart_port *port) +static u_int assabet_get_mctrl(struct uart_port *port) { u_int ret = 0; u_int bsr = ASSABET_BSR; @@ -312,11 +365,7 @@ PWER = PWER_GPIO0; PGSR = 0; PCFR = 0; - - /* - * Clear all possible wakeup reasons. - */ - RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR; + PSDR = 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/cerf.c linux-2.5/arch/arm/mach-sa1100/cerf.c --- linux-2.5.1/arch/arm/mach-sa1100/cerf.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/cerf.c Sun Jan 6 01:38:26 2002 @@ -16,20 +16,22 @@ #include "generic.h" -static void __init cerf_init_irq (void) +static void __init cerf_init_irq(void) { - sa1100_init_irq(); + sa1100_init_irq(); - /* Need to register these as rising edge interrupts - * For standard 16550 serial driver support - * Basically - I copied it from pfs168.c :) - */ + /* Need to register these as rising edge interrupts + * For standard 16550 serial driver support + * Basically - I copied it from pfs168.c :) + */ #ifdef CONFIG_SA1100_CERF_CPLD - set_GPIO_IRQ_edge(GPIO_GPIO(3), GPIO_RISING_EDGE); /* PDA Full serial port */ - set_GPIO_IRQ_edge(GPIO_GPIO(2), GPIO_RISING_EDGE); /* PDA Bluetooth */ - GPDR &= ~(GPIO_GPIO(3)); /* Set the direction of serial port GPIO pin to in */ - GPDR &= ~(GPIO_GPIO(2)); /* Set the direction of bluetooth GPIO pin to in */ + /* PDA Full serial port */ + set_GPIO_IRQ_edge(GPIO_GPIO3, GPIO_RISING_EDGE); + /* PDA Bluetooth */ + set_GPIO_IRQ_edge(GPIO_GPIO2, GPIO_RISING_EDGE); #endif /* CONFIG_SA1100_CERF_CPLD */ + + set_GPIO_IRQ_edge(GPIO_UCB1200_IRQ, GPIO_RISING_EDGE); } static void __init @@ -37,22 +39,20 @@ char **cmdline, struct meminfo *mi) { #if defined(CONFIG_SA1100_CERF_64MB) - // 64MB RAM - SET_BANK( 0, 0xc0000000, 64*1024*1024 ); - mi->nr_banks = 1; -#elif defined(CONFIG_SA1100_CERF_32MB) // 32MB RAM + SET_BANK( 0, 0xc0000000, 64*1024*1024 ); + mi->nr_banks = 1; +#elif defined(CONFIG_SA1100_CERF_32MB) SET_BANK( 0, 0xc0000000, 32*1024*1024 ); mi->nr_banks = 1; -#elif defined(CONFIG_SA1100_CERF_16MB) // 16Meg Ram. +#elif defined(CONFIG_SA1100_CERF_16MB) SET_BANK( 0, 0xc0000000, 8*1024*1024 ); SET_BANK( 1, 0xc8000000, 8*1024*1024 ); mi->nr_banks = 2; #elif defined(CONFIG_SA1100_CERF_8MB) - // 8Meg Ram. - SET_BANK( 0, 0xc0000000, 8*1024*1024 ); - mi->nr_banks = 1; + SET_BANK( 0, 0xc0000000, 8*1024*1024 ); + mi->nr_banks = 1; #else - #error "Undefined memory size for Cerfboard." +#error "Undefined memory size for Cerfboard." #endif // ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); @@ -62,8 +62,7 @@ } static struct map_desc cerf_io_desc[] __initdata = { - /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + /* virtual physical length domain r w c b */ { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Crystal Ethernet Chip */ #ifdef CONFIG_SA1100_CERF_CPLD { 0xf1000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD Chip */ @@ -78,12 +77,18 @@ sa1100_map_io(); iotable_init(cerf_io_desc); - sa1100_register_uart(0, 3); + sa1100_register_uart(0, 3); #ifdef CONFIG_SA1100_CERF_IRDA_ENABLED sa1100_register_uart(1, 1); #else sa1100_register_uart(1, 2); sa1100_register_uart(2, 1); +#endif + + /* set some GPDR bits here while it's safe */ + GPDR |= GPIO_CF_RESET; +#ifdef CONFIG_SA1100_CERF_CPLD + GPDR |= GPIO_PWR_SHUTDOWN; #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/cpu-sa1100.c linux-2.5/arch/arm/mach-sa1100/cpu-sa1100.c --- linux-2.5.1/arch/arm/mach-sa1100/cpu-sa1100.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-sa1100/cpu-sa1100.c Sun Jan 6 01:38:26 2002 @@ -90,7 +90,8 @@ #include <asm/hardware.h> - +extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz); +extern unsigned int sa11x0_validatespeed(unsigned int khz); typedef struct { @@ -219,14 +220,22 @@ }; - +static void sa1100_setspeed(unsigned int khz) +{ + PPCR = sa11x0_freq_to_ppcr(khz); +} static int __init sa1100_dram_init(void) { - return cpufreq_register_notifier(&sa1100_dram_block); -} + int ret = -ENODEV; + if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) { + ret = cpufreq_register_notifier(&sa1100_dram_block); + cpufreq_setfunctions(sa11x0_validatespeed, sa1100_setspeed); + } + return ret; +} __initcall(sa1100_dram_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/cpu-sa1110.c linux-2.5/arch/arm/mach-sa1100/cpu-sa1110.c --- linux-2.5.1/arch/arm/mach-sa1100/cpu-sa1110.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-sa1100/cpu-sa1110.c Sun Jan 6 01:38:26 2002 @@ -3,7 +3,7 @@ * * Copyright (C) 2001 Russell King * - * $Id: cpu-sa1110.c,v 1.5 2001/09/10 13:25:58 rmk Exp $ + * $Id: cpu-sa1110.c,v 1.6 2001/10/22 11:53:47 rmk Exp $ * * 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,14 +29,8 @@ #undef DEBUG -extern u_int processor_id; - -#define CPU_REVISION (processor_id & 15) -#define CPU_SA1110_A0 (0) -#define CPU_SA1110_B0 (4) -#define CPU_SA1110_B1 (5) -#define CPU_SA1110_B2 (6) -#define CPU_SA1110_B4 (8) +extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz); +extern unsigned int sa11x0_validatespeed(unsigned int khz); struct sdram_params { u_char rows; /* bits */ @@ -48,6 +42,12 @@ u_short refresh; /* refresh time for array (us) */ }; +struct sdram_info { + u_int mdcnfg; + u_int mdrefr; + u_int mdcas[3]; +}; + static struct sdram_params tc59sm716_cl2_params __initdata = { rows: 12, tck: 10, @@ -68,6 +68,16 @@ cas_latency: 3, }; +static struct sdram_params samsung_k4s641632d_tc75 __initdata = { + rows: 14, + tck: 9, + trcd: 27, + trp: 20, + twr: 9, + refresh: 64000, + cas_latency: 3, +}; + static struct sdram_params sdram_params; /* @@ -95,10 +105,11 @@ mdcas[1] = mdcas[2] = 0x55555555 << (shift & 1); } -static void sdram_update_timing(u_int cpu_khz, struct sdram_params *sdram) +static void +sdram_calculate_timing(struct sdram_info *sd, u_int cpu_khz, + struct sdram_params *sdram) { - u_int mdcnfg, mdrefr, mdcas[3], mem_khz, sd_khz, trp, twr; - unsigned long flags; + u_int mem_khz, sd_khz, trp, twr; mem_khz = cpu_khz / 2; sd_khz = mem_khz; @@ -114,7 +125,7 @@ (CPU_REVISION < CPU_SA1110_B2 && sd_khz < 62000)) sd_khz /= 2; - mdcnfg = MDCNFG & 0x007f007f; + sd->mdcnfg = MDCNFG & 0x007f007f; twr = ns_to_cycles(sdram->twr, mem_khz); @@ -123,53 +134,26 @@ if (trp < 1) trp = 1; - mdcnfg |= trp << 8; - mdcnfg |= trp << 24; - mdcnfg |= sdram->cas_latency << 12; - mdcnfg |= sdram->cas_latency << 28; - mdcnfg |= twr << 14; - mdcnfg |= twr << 30; + sd->mdcnfg |= trp << 8; + sd->mdcnfg |= trp << 24; + sd->mdcnfg |= sdram->cas_latency << 12; + sd->mdcnfg |= sdram->cas_latency << 28; + sd->mdcnfg |= twr << 14; + sd->mdcnfg |= twr << 30; - mdrefr = MDREFR & 0xffbffff0; - mdrefr |= 7; + sd->mdrefr = MDREFR & 0xffbffff0; + sd->mdrefr |= 7; if (sd_khz != mem_khz) - mdrefr |= MDREFR_K1DB2; + sd->mdrefr |= MDREFR_K1DB2; /* initial number of '1's in MDCAS + 1 */ - set_mdcas(mdcas, sd_khz >= 62000, ns_to_cycles(sdram->trcd, mem_khz)); + set_mdcas(sd->mdcas, sd_khz >= 62000, ns_to_cycles(sdram->trcd, mem_khz)); #ifdef DEBUG - mdelay(250); printk("MDCNFG: %08x MDREFR: %08x MDCAS0: %08x MDCAS1: %08x MDCAS2: %08x\n", - mdcnfg, mdrefr, mdcas[0], mdcas[1], mdcas[2]); + sd->mdcnfg, sd->mdrefr, sd->mdcas[0], sd->mdcas[1], sd->mdcas[2]); #endif - - /* - * Reprogram the DRAM timings with interrupts disabled, and - * ensure that we are doing this within a complete cache line. - * This means that we won't access SDRAM for the duration of - * the programming. - */ - local_irq_save(flags); - asm("mcr p15, 0, %0, c10, c4" : : "r" (0)); - udelay(10); - __asm__(" - b 1f - .align 5 -1: str %3, [%1, #28] @ MDREFR - str %4, [%1, #4] @ MDCAS0 - str %5, [%1, #8] @ MDCAS1 - str %6, [%1, #12] @ MDCAS2 - str %2, [%1, #0] @ MDCNFG - ldr %0, [%1, #0] - nop - nop" - : "=&r" (mdcnfg) - : "r" (io_p2v(_MDCNFG)), - "0" (mdcnfg), "r" (mdrefr), - "r" (mdcas[0]), "r" (mdcas[1]), "r" (mdcas[2])); - local_irq_restore(flags); } /* @@ -203,65 +187,93 @@ sdram_set_refresh(dri); } -static int -sdram_notifier(struct notifier_block *nb, unsigned long val, void *data) +/* + * Ok, set the CPU frequency. Since we've done the validation + * above, we can match for an exact frequency. If we don't find + * an exact match, we will to set the lowest frequency to be safe. + */ +static void sa1110_setspeed(unsigned int khz) { - struct cpufreq_info *ci = data; struct sdram_params *sdram = &sdram_params; + struct sdram_info sd; + unsigned long flags; + unsigned int ppcr, unused; - /* were we initialised? */ - if (sdram->cas_latency == 0) { - struct cpufreq_minmax *m = data; - m->min_freq = m->max_freq = m->cur_freq; - return 0; - } + ppcr = sa11x0_freq_to_ppcr(khz); + sdram_calculate_timing(&sd, khz, sdram); - switch (val) { - case CPUFREQ_MINMAX: - /* - * until we work out why the assabet - * crashes below 147.5MHz... - */ - cpufreq_updateminmax(data, 147500, -1); - break; - - case CPUFREQ_PRECHANGE: - /* - * The clock could be going away for some time. - * Set the SDRAMs to refresh rapidly (every 64 - * memory clock cycles). To get through the - * whole array, we need to wait 262144 mclk cycles. - * We wait 20ms to be safe. - */ - sdram_set_refresh(2); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(20 * HZ / 1000); - - if (ci->old_freq < ci->new_freq) - sdram_update_timing(ci->new_freq, sdram); - break; - - case CPUFREQ_POSTCHANGE: - if (ci->old_freq > ci->new_freq) - sdram_update_timing(ci->new_freq, sdram); - sdram_update_refresh(ci->new_freq, sdram); - break; +#if 0 + /* + * These values are wrong according to the SA1110 documentation + * and errata, but they seem to work. Need to get a storage + * scope on to the SDRAM signals to work out why. + */ + if (khz < 147500) { + sd.mdrefr |= MDREFR_K1DB2; + sd.mdcas[0] = 0xaaaaaa7f; + } else { + sd.mdrefr &= ~MDREFR_K1DB2; + sd.mdcas[0] = 0xaaaaaa9f; } - return 0; -} + sd.mdcas[1] = 0xaaaaaaaa; + sd.mdcas[2] = 0xaaaaaaaa; +#endif + /* + * The clock could be going away for some time. Set the SDRAMs + * to refresh rapidly (every 64 memory clock cycles). To get + * through the whole array, we need to wait 262144 mclk cycles. + * We wait 20ms to be safe. + */ + sdram_set_refresh(2); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(20 * HZ / 1000); -static struct notifier_block sa1110_clkchg_block = { - notifier_call: sdram_notifier, -}; + /* + * Reprogram the DRAM timings with interrupts disabled, and + * ensure that we are doing this within a complete cache line. + * This means that we won't access SDRAM for the duration of + * the programming. + */ + local_irq_save(flags); + asm("mcr p15, 0, %0, c10, c4" : : "r" (0)); + udelay(10); + __asm__ __volatile__(" + b 2f + .align 5 +1: str %3, [%1, #0] @ MDCNFG + str %4, [%1, #28] @ MDREFR + str %5, [%1, #4] @ MDCAS0 + str %6, [%1, #8] @ MDCAS1 + str %7, [%1, #12] @ MDCAS2 + str %8, [%2, #0] @ PPCR + ldr %0, [%1, #0] + b 3f +2: b 1b +3: nop + nop" + : "=&r" (unused) + : "r" (&MDCNFG), "r" (&PPCR), "0" (sd.mdcnfg), + "r" (sd.mdrefr), "r" (sd.mdcas[0]), + "r" (sd.mdcas[1]), "r" (sd.mdcas[2]), "r" (ppcr)); + local_irq_restore(flags); -static int __init sa1110_sdram_init(void) + /* + * Now, return the SDRAM refresh back to normal. + */ + sdram_update_refresh(khz, sdram); +} + +static int __init sa1110_clk_init(void) { struct sdram_params *sdram = NULL; - unsigned int cur_freq = cpufreq_get(smp_processor_id()); if (machine_is_assabet()) sdram = &tc59sm716_cl3_params; + if (machine_is_pt_system3()) + sdram = &samsung_k4s641632d_tc75; + + if (sdram) { printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d" " twr: %d refresh: %d cas_latency: %d\n", @@ -270,11 +282,11 @@ memcpy(&sdram_params, sdram, sizeof(sdram_params)); - sdram_update_timing(cur_freq, &sdram_params); - sdram_update_refresh(cur_freq, &sdram_params); + sa1110_setspeed(cpufreq_get(0)); + cpufreq_setfunctions(sa11x0_validatespeed, sa1110_setspeed); } - return cpufreq_register_notifier(&sa1110_clkchg_block); + return 0; } -__initcall(sa1110_sdram_init); +__initcall(sa1110_clk_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/dma-sa1100.c linux-2.5/arch/arm/mach-sa1100/dma-sa1100.c --- linux-2.5.1/arch/arm/mach-sa1100/dma-sa1100.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/dma-sa1100.c Thu Jan 1 00:00:00 1970 @@ -1,620 +0,0 @@ -/* - * 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/slab.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 - - -/* - * 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; - -#include "dma.h" - -sa1100_dma_t dma_chan[MAX_SA1100_DMA_CHANNELS]; - -/* - * Maximum physical DMA buffer size - */ -#define MAX_DMA_SIZE 0x1fff -#define MAX_DMA_ORDER 12 - - -/* - * 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; - - status = regs->RdDCSR; - - /* If both DMA buffers are started, there's nothing else we can do. */ - if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) { - DPRINTK("start: st %#x busy\n", status); - return -EBUSY; - } - - if (((status & DCSR_BIU) && (status & DCSR_STRTB)) || - (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) { - if (status & DCSR_DONEA) { - /* give a chance for the interrupt to be processed */ - goto irq_pending; - } - 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 { - if (status & DCSR_DONEB) { - /* give a chance for the interrupt to be processed */ - goto irq_pending; - } - 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; - -irq_pending: - return -EAGAIN; -} - - -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 || dma->stopped) { - /* 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; - 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; - if (dma->callback) { - int size = buf->dma_ptr - buf->dma_start; - dma->callback(buf->id, 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); - - if (status & (DCSR_ERROR)) { - printk(KERN_ERR "DMA on \"%s\" caused an error\n", dma->device_id); - dma->regs->ClrDCSR = DCSR_ERROR; - } - - dma->regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB); - if (status & DCSR_DONEA) - sa1100_dma_done (dma); - if (status & DCSR_DONEB) - sa1100_dma_done (dma); -} - - -/* - * DMA interface functions - */ - -static spinlock_t dma_list_lock; - -int sa1100_request_dma (dmach_t * channel, const char *device_id, - dma_device_t device) -{ - sa1100_dma_t *dma = NULL; - dma_regs_t *regs; - int i, err; - - *channel = -1; /* to be sure we catch the freeing of a misregistered channel */ - - err = 0; - spin_lock(&dma_list_lock); - for (i = 0; i < SA1100_DMA_CHANNELS; i++) { - if (dma_chan[i].in_use) { - if (dma_chan[i].device == device) { - err = -EBUSY; - break; - } - } else if (!dma) { - dma = &dma_chan[i]; - } - } - if (!err) { - if (dma) - dma->in_use = 1; - else - err = -ENOSR; - } - spin_unlock(&dma_list_lock); - if (err) - return err; - - 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\n", - device_id, dma->irq); - return err; - } - - *channel = dma - dma_chan; - dma->device_id = device_id; - dma->device = device; - 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 = device; - DPRINTK("requested\n"); - return 0; -} - - -int sa1100_dma_set_callback(dmach_t channel, dma_callback_t cb) -{ - sa1100_dma_t *dma = &dma_chan[channel]; - - if ((unsigned)channel >= MAX_SA1100_DMA_CHANNELS || !dma->in_use) - return -EINVAL; - - dma->callback = cb; - DPRINTK("cb = %p\n", cb); - 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 ((unsigned)channel >= MAX_SA1100_DMA_CHANNELS || !dma->in_use) - 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 ((unsigned)channel >= MAX_SA1100_DMA_CHANNELS || !dma->in_use) - 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; - int flags, ret; - - if ((unsigned)channel >= MAX_SA1100_DMA_CHANNELS || !dma->in_use) - return -EINVAL; - - if (channel_is_sa1111_sac(channel)) - return sa1111_dma_get_current(channel, buf_id, addr); - - regs = dma->regs; - 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 (dma->tail && dma->stopped) { - dma_buf_t *buf = dma->tail; - if (buf_id) - *buf_id = buf->id; - *addr = buf->dma_ptr; - ret = 0; - } else { - if (buf_id) - *buf_id = NULL; - *addr = 0; - ret = -ENXIO; - } - local_irq_restore(flags); - return ret; -} - - -int sa1100_dma_stop(dmach_t channel) -{ - sa1100_dma_t *dma = &dma_chan[channel]; - int flags; - - if (channel_is_sa1111_sac(channel)) - return sa1111_dma_stop(channel); - - if (dma->stopped) - return 0; - local_irq_save(flags); - dma->stopped = 1; - /* - * Stop DMA and tweak state variables so everything could restart - * from there when resume/wakeup occurs. - */ - dma->regs->ClrDCSR = DCSR_RUN | DCSR_IE; - if (dma->curr) { - dma_buf_t *buf = dma->curr; - if (dma->spin_ref <= 0) { - dma_addr_t curpos; - sa1100_dma_get_current(channel, NULL, &curpos); - buf->size += buf->dma_ptr - curpos; - buf->dma_ptr = curpos; - } - buf->ref = 0; - dma->tail = buf; - dma->curr = NULL; - } - dma->spin_ref = 0; - dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_DONEA|DCSR_DONEB; - process_dma(dma); - local_irq_restore(flags); - return 0; -} - - -int sa1100_dma_resume(dmach_t channel) -{ - sa1100_dma_t *dma = &dma_chan[channel]; - - if ((unsigned)channel >= MAX_SA1100_DMA_CHANNELS || !dma->in_use) - return -EINVAL; - - if (channel_is_sa1111_sac(channel)) - return sa1111_dma_resume(channel); - - if (dma->stopped) { - int flags; - save_flags_cli(flags); - dma->stopped = 0; - dma->spin_ref = 0; - process_dma(dma); - restore_flags(flags); - } - return 0; -} - - -int sa1100_dma_flush_all(dmach_t channel) -{ - sa1100_dma_t *dma = &dma_chan[channel]; - dma_buf_t *buf, *next_buf; - int flags; - - if ((unsigned)channel >= MAX_SA1100_DMA_CHANNELS || !dma->in_use) - return -EINVAL; - - local_irq_save(flags); - if (channel_is_sa1111_sac(channel)) - sa1111_reset_sac_dma(channel); - else - dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_DONEA|DCSR_DONEB|DCSR_RUN|DCSR_IE; - buf = dma->curr; - if (!buf) - buf = dma->tail; - dma->head = dma->tail = dma->curr = NULL; - dma->stopped = 0; - dma->spin_ref = 0; - 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->in_use) { - printk(KERN_ERR "Trying to free free DMA%d\n", channel); - return; - } - - sa1100_dma_set_spin(channel, 0, 0); - sa1100_dma_flush_all(channel); - - if (channel_is_sa1111_sac(channel)) { - sa1111_cleanup_sac_dma(channel); - } else { - free_irq(IRQ_DMA0 + channel, (void *) dma); - } - dma->in_use = 0; - - DPRINTK("freed\n"); -} - - -EXPORT_SYMBOL(sa1100_request_dma); -EXPORT_SYMBOL(sa1100_dma_set_callback); -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); - - -#ifdef CONFIG_PM -/* Drivers should call this from their PM callback function */ - -int sa1100_dma_sleep(dmach_t channel) -{ - sa1100_dma_t *dma = &dma_chan[channel]; - int orig_state; - - if ((unsigned)channel >= MAX_SA1100_DMA_CHANNELS || !dma->in_use) - return -EINVAL; - - if (channel_is_sa1111_sac(channel)) { - /* We'll cheat a little until someone actually - * write the real thing. - */ - sa1111_reset_sac_dma(channel); - return 0; - } - - orig_state = dma->stopped; - sa1100_dma_stop(channel); - dma->regs->ClrDCSR = DCSR_RUN | DCSR_IE | DCSR_STRTA | DCSR_STRTB; - dma->stopped = orig_state; - dma->spin_ref = 0; - return 0; -} - -int sa1100_dma_wakeup(dmach_t channel) -{ - sa1100_dma_t *dma = &dma_chan[channel]; - dma_regs_t *regs; - int flags; - - if ((unsigned)channel >= MAX_SA1100_DMA_CHANNELS || !dma->in_use) - return -EINVAL; - - if (channel_is_sa1111_sac(channel)) { - /* We'll cheat a little until someone actually - * write the real thing. - */ - return 0; - } - - regs = dma->regs; - regs->ClrDCSR = - (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | - DCSR_IE | DCSR_ERROR | DCSR_RUN); - regs->DDAR = dma->device; - local_irq_save(flags); - process_dma(dma); - local_irq_restore(flags); - return 0; -} - -EXPORT_SYMBOL(sa1100_dma_sleep); -EXPORT_SYMBOL(sa1100_dma_wakeup); - -#endif - - -static int __init sa1100_init_dma(void) -{ - int channel; - for (channel = 0; channel < SA1100_DMA_CHANNELS; channel++) { - dma_chan[channel].regs = - (dma_regs_t *) &DDAR(channel); - dma_chan[channel].irq = IRQ_DMA0 + channel; - } - return 0; -} - -__initcall(sa1100_init_dma); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/dma-sa1111.c linux-2.5/arch/arm/mach-sa1100/dma-sa1111.c --- linux-2.5.1/arch/arm/mach-sa1100/dma-sa1111.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/dma-sa1111.c Thu Jan 1 00:00:00 1970 @@ -1,363 +0,0 @@ -/* - * 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->in_use, 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->in_use = 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->in_use = 0; - return err; - } - - *channel = ch; - dma->device_id = device_id; - dma->callback = NULL; - dma->spin_size = 0; - - 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) -{ - sa1100_dma_t *dma = &dma_chan[channel]; - int flags, ret; - - local_irq_save(flags); - if (dma->curr && dma->spin_ref <= 0) { - dma_buf_t *buf = dma->curr; - if (buf_id) - *buf_id = buf->id; - /* not fully accurate but still... */ - *addr = buf->dma_ptr; - ret = 0; - } else { - if (buf_id) - *buf_id = NULL; - *addr = 0; - ret = -ENXIO; - } - local_irq_restore(flags); - return ret; -} - -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), erratum #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() || machine_is_pfs168()) && addr >= 0xc8000000) - 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(SBI_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%lo\n", - __FUNCTION__, FExtr(SBI_SMCR, SMCR_DRAC)); - return -1; - } - - return 0; -} - - -EXPORT_SYMBOL(sa1111_sac_request_dma); -EXPORT_SYMBOL(sa1111_check_dma_bug); - - -static int __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; - return 0; -} - -__initcall(sa1111_init_sac_dma); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/dma.c linux-2.5/arch/arm/mach-sa1100/dma.c --- linux-2.5.1/arch/arm/mach-sa1100/dma.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-sa1100/dma.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,343 @@ +/* + * arch/arm/kernel/dma-sa1100.c + * + * Support functions for the SA11x0 internal DMA channels. + * + * Copyright (C) 2000, 2001 by 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/errno.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/dma.h> + + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK( s, arg... ) printk( "dma<%p>: " s, regs , ##arg ) +#else +#define DPRINTK( x... ) +#endif + + +typedef struct { + const char *device_id; /* device name */ + u_long device; /* this channel device, 0 if unused*/ + dma_callback_t callback; /* to call when DMA completes */ + void *data; /* ... with private data ptr */ +} sa1100_dma_t; + +static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS]; + +static spinlock_t dma_list_lock; + + +static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + dma_regs_t *dma_regs = dev_id; + sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7); + int status = dma_regs->RdDCSR; + + if (status & (DCSR_ERROR)) { + printk(KERN_CRIT "DMA on \"%s\" caused an error\n", dma->device_id); + dma_regs->ClrDCSR = DCSR_ERROR; + } + + dma_regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB); + if (dma->callback) { + if (status & DCSR_DONEA) + dma->callback(dma->data); + if (status & DCSR_DONEB) + dma->callback(dma->data); + } +} + + +/** + * sa1100_request_dma - allocate one of the SA11x0's DMA chanels + * @device: The SA11x0 peripheral targeted by this request + * @device_id: An ascii name for the claiming device + * @callback: Function to be called when the DMA completes + * @data: A cookie passed back to the callback function + * @dma_regs: Pointer to the location of the allocated channel's identifier + * + * This function will search for a free DMA channel and returns the + * address of the hardware registers for that channel as the channel + * identifier. This identifier is written to the location pointed by + * @dma_regs. The list of possible values for @device are listed into + * linux/include/asm-arm/arch-sa1100/dma.h as a dma_device_t enum. + * + * Note that reading from a port and writing to the same port are + * actually considered as two different streams requiring separate + * DMA registrations. + * + * The @callback function is called from interrupt context when one + * of the two possible DMA buffers in flight has terminated. That + * function has to be small and efficient while posponing more complex + * processing to a lower priority execution context. + * + * If no channels are available, or if the desired @device is already in + * use by another DMA channel, then an error code is returned. This + * function must be called before any other DMA calls. + **/ + +int sa1100_request_dma (dma_device_t device, const char *device_id, + dma_callback_t callback, void *data, + dma_regs_t **dma_regs) +{ + sa1100_dma_t *dma = NULL; + dma_regs_t *regs; + int i, err; + + *dma_regs = NULL; + + err = 0; + spin_lock(&dma_list_lock); + for (i = 0; i < SA1100_DMA_CHANNELS; i++) { + if (dma_chan[i].device == device) { + err = -EBUSY; + break; + } else if (!dma_chan[i].device && !dma) { + dma = &dma_chan[i]; + } + } + if (!err) { + if (dma) + dma->device = device; + else + err = -ENOSR; + } + spin_unlock(&dma_list_lock); + if (err) + return err; + + i = dma - dma_chan; + regs = (dma_regs_t *)&DDAR(i); + err = request_irq(IRQ_DMA0 + i, dma_irq_handler, SA_INTERRUPT, + device_id, regs); + if (err) { + printk(KERN_ERR __FUNCTION__ + "unable to request IRQ %d for %s\n", + IRQ_DMA0 + i, device_id); + dma->device = 0; + return err; + } + + *dma_regs = regs; + dma->device_id = device_id; + dma->callback = callback; + dma->data = data; + + regs->ClrDCSR = + (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | + DCSR_IE | DCSR_ERROR | DCSR_RUN); + regs->DDAR = device; + + return 0; +} + + +/** + * sa1100_free_dma - free a SA11x0 DMA channel + * @regs: identifier for the channel to free + * + * This clears all activities on a given DMA channel and releases it + * for future requests. The @regs identifier is provided by a + * successful call to sa1100_request_dma(). + **/ + +void sa1100_free_dma(dma_regs_t *regs) +{ + int i; + + for (i = 0; i < SA1100_DMA_CHANNELS; i++) + if (regs == (dma_regs_t *)&DDAR(i)) + break; + if (i >= SA1100_DMA_CHANNELS) { + printk(KERN_ERR __FUNCTION__ ": bad DMA identifier\n"); + return; + } + + if (!dma_chan[i].device) { + printk(KERN_ERR __FUNCTION__ "Trying to free free DMA\n"); + return; + } + + regs->ClrDCSR = + (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | + DCSR_IE | DCSR_ERROR | DCSR_RUN); + free_irq(IRQ_DMA0 + i, regs); + dma_chan[i].device = 0; +} + + +/** + * sa1100_start_dma - submit a data buffer for DMA + * @regs: identifier for the channel to use + * @dma_ptr: buffer physical (or bus) start address + * @size: buffer size + * + * This function hands the given data buffer to the hardware for DMA + * access. If another buffer is already in flight then this buffer + * will be queued so the DMA engine will switch to it automatically + * when the previous one is done. The DMA engine is actually toggling + * between two buffers so at most 2 successful calls can be made before + * one of them terminates and the callback function is called. + * + * The @regs identifier is provided by a successful call to + * sa1100_request_dma(). + * + * The @size must not be larger than %MAX_DMA_SIZE. If a given buffer + * is larger than that then it's the caller's responsibility to split + * it into smaller chunks and submit them separately. If this is the + * case then a @size of %CUT_DMA_SIZE is recommended to avoid ending + * up with too small chunks. The callback function can be used to chain + * submissions of buffer chunks. + * + * Error return values: + * %-EOVERFLOW: Given buffer size is too big. + * %-EBUSY: Both DMA buffers are already in use. + * %-EAGAIN: Both buffers were busy but one of them just completed + * but the interrupt handler has to execute first. + * + * This function returs 0 on success. + **/ + +int sa1100_start_dma(dma_regs_t *regs, dma_addr_t dma_ptr, u_int size) +{ + long flags; + u_long status; + int ret; + + if (size > MAX_DMA_SIZE) + return -EOVERFLOW; + + local_irq_save(flags); + status = regs->RdDCSR; + + /* If both DMA buffers are started, there's nothing else we can do. */ + if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) { + DPRINTK("start: st %#x busy\n", status); + ret = -EBUSY; + goto out; + } + + if (((status & DCSR_BIU) && (status & DCSR_STRTB)) || + (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) { + if (status & DCSR_DONEA) { + /* give a chance for the interrupt to be processed */ + ret = -EAGAIN; + goto out; + } + 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 { + if (status & DCSR_DONEB) { + /* give a chance for the interrupt to be processed */ + ret = -EAGAIN; + goto out; + } + 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); + } + ret = 0; + +out: + local_irq_restore(flags); + return ret; +} + + +/** + * sa1100_get_dma_pos - return current DMA position + * @regs: identifier for the channel to use + * + * This function returns the current physical (or bus) address for the + * given DMA channel. If the channel is running i.e. not in a stopped + * state then the caller must disable interrupts prior calling this + * function and process the returned value before re-enabling them to + * prevent races with the completion interrupt handler and the callback + * function. The validation of the returned value is the caller's + * responsibility as well -- the hardware seems to return out of range + * values when the DMA engine completes a buffer. + * + * The @regs identifier is provided by a successful call to + * sa1100_request_dma(). + **/ + +dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs) +{ + int status; + + /* + * 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 exact. + */ + status = regs->RdDCSR; + if ((!(status & DCSR_BIU) && (status & DCSR_STRTA)) || + ( (status & DCSR_BIU) && !(status & DCSR_STRTB))) + return regs->DBSA; + else + return regs->DBSB; +} + + +/** + * sa1100_reset_dma - reset a DMA channel + * @regs: identifier for the channel to use + * + * This function resets and reconfigure the given DMA channel. This is + * particularly useful after a sleep/wakeup event. + * + * The @regs identifier is provided by a successful call to + * sa1100_request_dma(). + **/ + +void sa1100_reset_dma(dma_regs_t *regs) +{ + int i; + + for (i = 0; i < SA1100_DMA_CHANNELS; i++) + if (regs == (dma_regs_t *)&DDAR(i)) + break; + if (i >= SA1100_DMA_CHANNELS) { + printk(KERN_ERR __FUNCTION__ ": bad DMA identifier\n"); + return; + } + + regs->ClrDCSR = + (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | + DCSR_IE | DCSR_ERROR | DCSR_RUN); + regs->DDAR = dma_chan[i].device; +} + + +EXPORT_SYMBOL(sa1100_request_dma); +EXPORT_SYMBOL(sa1100_free_dma); +EXPORT_SYMBOL(sa1100_start_dma); +EXPORT_SYMBOL(sa1100_get_dma_pos); +EXPORT_SYMBOL(sa1100_reset_dma); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/dma.h linux-2.5/arch/arm/mach-sa1100/dma.h --- linux-2.5.1/arch/arm/mach-sa1100/dma.h Mon Aug 13 00:36:24 2001 +++ linux-2.5/arch/arm/mach-sa1100/dma.h Thu Jan 1 00:00:00 1970 @@ -1,69 +0,0 @@ -/* - * 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. - */ - -#include <linux/config.h> - -/* - * DMA buffer structure - */ - -typedef struct dma_buf_s { - int size; /* buffer size */ - dma_addr_t dma_start; /* starting DMA address */ - dma_addr_t dma_ptr; /* next DMA pointer to use */ - int ref; /* number of DMA references */ - void *id; /* to identify buffer from outside */ - struct dma_buf_s *next; /* next buffer to process */ -} dma_buf_t; - - -/* - * DMA channel structure. - */ - -typedef struct { - unsigned int in_use; /* Device is allocated */ - const char *device_id; /* Device name */ - dma_device_t device; /* ... to which this channel is attached */ - 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 stopped; /* 1 if DMA is stalled */ - 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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/flexanet.c linux-2.5/arch/arm/mach-sa1100/flexanet.c --- linux-2.5.1/arch/arm/mach-sa1100/flexanet.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-sa1100/flexanet.c Sun Jan 6 01:38:26 2002 @@ -27,22 +27,142 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/serial_sa1100.h> +#include <linux/serial_core.h> #include "generic.h" -unsigned long BCR_value = BCR_POWERUP; -unsigned long flexanet_GUI_type = 0x0000000F; +unsigned long flexanet_BCR = FHH_BCR_POWERUP; -EXPORT_SYMBOL(BCR_value); -EXPORT_SYMBOL(flexanet_GUI_type); +EXPORT_SYMBOL(flexanet_BCR); + +/* physical addresses */ +#define _RCNR 0x90010004 +#define _GPLR 0x90040000 +#define _Ser4SSCR0 0x80070060 + +/* + * Get the modem-control register of the UARTs + * + */ +static int flexanet_get_mctrl(struct uart_port *port) +{ + int stat = 0; + unsigned long bsr; + + /* only DSR and CTS are implemented in UART1 & 3 */ + if (port->membase == (void *)&Ser1UTCR0) + { + bsr = FHH_BSR; + + if ((bsr & FHH_BSR_DSR1) != 0) + stat |= TIOCM_DSR; + if ((bsr & FHH_BSR_CTS1) != 0) + stat |= TIOCM_CTS; + } + else if (port->membase == (void *)&Ser3UTCR0) + { + bsr = FHH_BSR; + + if ((bsr & FHH_BSR_DSR3) != 0) + stat |= TIOCM_DSR; + if ((bsr & FHH_BSR_CTS3) != 0) + stat |= TIOCM_CTS; + } + + return stat; +} + +/* + * Set the modem-control register of the UARTs + * + */ +static void flexanet_set_mctrl(struct uart_port *port, u_int mctrl) +{ + unsigned long flags; + + /* only the RTS signal is implemented in UART1 & 3 */ + if (port->membase == (void *)&Ser1UTCR0) + { + local_irq_save(flags); + + if (mctrl & TIOCM_RTS) + flexanet_BCR |= FHH_BCR_RTS1; + else + flexanet_BCR &= ~FHH_BCR_RTS1; + + FHH_BCR = flexanet_BCR; + local_irq_restore(flags); + } + else if (port->membase == (void *)&Ser3UTCR0) + { + local_irq_save(flags); + + if (mctrl & TIOCM_RTS) + flexanet_BCR |= FHH_BCR_RTS3; + else + flexanet_BCR &= ~FHH_BCR_RTS3; + + FHH_BCR = flexanet_BCR; + local_irq_restore(flags); + } +} + +/* + * machine-specific serial port functions + * + * get_mctrl : set state of modem control lines + * set_mctrl : set the modem control lines + * enable_ms : enable modem-status interrupts + * pm : power-management. Turn device on/off. + * + */ +static struct sa1100_port_fns flexanet_port_fns __initdata = +{ + set_mctrl : flexanet_set_mctrl, + get_mctrl : flexanet_get_mctrl, + enable_ms : NULL, + pm : NULL, +}; + + +/* + * Initialization and serial port mapping + * + */ + +static int flexanet_serial_init(void) +{ + /* register low-level functions */ + sa1100_register_uart_fns(&flexanet_port_fns); + + /* UART port number mapping */ + sa1100_register_uart(0, 1); /* RS232 */ + sa1100_register_uart(1, 3); /* Radio */ + + /* Select UART function in Serial port 1 */ + Ser1SDCR0 |= SDCR0_UART; + + return 0; +} + + +static int __init flexanet_init(void) +{ + return 0; +} + +__initcall(flexanet_init); -static unsigned long probe_gui_board (void); static void __init fixup_flexanet(struct machine_desc *desc, struct param_struct *params, char **cmdline, struct meminfo *mi) { + int status; + unsigned long now; + + /* fixed RAM size, by now (64MB) */ SET_BANK( 0, 0xc0000000, 64*1024*1024 ); mi->nr_banks = 1; @@ -56,8 +176,10 @@ static struct map_desc flexanet_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ + { 0xf1000000, 0x18000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Ethernet controller */ + { 0xD0000000, 0x40000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Instrument boards */ + { 0xD8000000, 0x48000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* External peripherals */ LAST_DESC }; @@ -65,9 +187,27 @@ { sa1100_map_io(); iotable_init(flexanet_io_desc); + flexanet_serial_init(); - sa1100_register_uart(0, 1); - Ser1SDCR0 |= SDCR0_UART; + /* wakeup source is GPIO-0 only */ + PWER = PWER_GPIO0; + + /* GPIOs set to zero during sleep */ + PGSR = 0; + + /* + * stop the 3.68 MHz oscillator and float control busses + * during sleep, since peripherals are powered off. + */ + PCFR = PCFR_OPDE | PCFR_FP | PCFR_FS; + + /* deassert the GUI reset */ + FLEXANET_BCR_set(FHH_BCR_GUI_NRST); + + /* + * Set IRQ edges + */ + set_GPIO_IRQ_edge(GPIO_GUI_IRQ, GPIO_RISING_EDGE); } @@ -78,3 +218,4 @@ MAPIO(flexanet_map_io) INITIRQ(sa1100_init_irq) MACHINE_END + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/freebird.c linux-2.5/arch/arm/mach-sa1100/freebird.c --- linux-2.5.1/arch/arm/mach-sa1100/freebird.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/freebird.c Sun Jan 6 01:38:26 2002 @@ -21,6 +21,35 @@ unsigned long BCR_value = BCR_DB1110; EXPORT_SYMBOL(BCR_value); +static void freebird_backlight_power(int on) +{ +#error FIXME + if (on) { + BCR_set(BCR_FREEBIRD_LCD_PWR | BCR_FREEBIRD_LCD_DISP); + /* Turn on backlight, Chester */ + BCR_set(BCR_FREEBIRD_LCD_BACKLIGHT); + } else { + BCR_clear(BCR_FREEBIRD_LCD_PWR | BCR_FREEBIRD_LCD_DISP + /* | BCR_FREEBIRD_LCD_BACKLIGHT */); + } +} + +static void freebird_lcd_power(int on) +{ +} + +static int __init freebird_init(void) +{ + if (machine_is_freebird()) { + sa1100fb_backlight_power = freebird_backlight_power; + sa1100fb_lcd_power = freebird_lcd_power; + + set_GPIO_IRQ_edge(GPIO_FREEBIRD_UCB1300, GPIO_RISING_EDGE); + } + return 0; +} + +__initcall(freebird_init); static void __init fixup_freebird(struct machine_desc *desc, struct param_struct *params, @@ -37,7 +66,6 @@ static struct map_desc freebird_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ { 0xf0000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ { 0xf2000000, 0x19000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0}, LAST_DESC diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/generic.c linux-2.5/arch/arm/mach-sa1100/generic.c --- linux-2.5.1/arch/arm/mach-sa1100/generic.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-sa1100/generic.c Sun Jan 6 01:38:26 2002 @@ -53,23 +53,8 @@ 2802 /* 280.2 MHz */ }; -/* - * Return the current CPU clock frequency in units of 100kHz - */ -unsigned short get_cclk_frequency(void) -{ - return cclk_frequency_100khz[PPCR & 0xf]; -} - -EXPORT_SYMBOL(get_cclk_frequency); - #ifdef CONFIG_CPU_FREQ - -/* - * Validate the speed in khz. If we can't generate the precise - * frequency requested, round it down (to be on the safe side). - */ -unsigned int sa1100_validatespeed(unsigned int khz) +unsigned int sa11x0_freq_to_ppcr(unsigned int khz) { int i; @@ -79,35 +64,34 @@ if (cclk_frequency_100khz[i] <= khz) break; - return cclk_frequency_100khz[i] * 100; + return i; } /* - * Ok, set the CPU frequency. Since we've done the validation - * above, we can match for an exact frequency. If we don't find - * an exact match, we will to set the lowest frequency to be safe. + * Validate the speed in khz. If we can't generate the precise + * frequency requested, round it down (to be on the safe side). */ -void sa1100_setspeed(unsigned int khz) +unsigned int sa11x0_validatespeed(unsigned int khz) { - int i; - - khz /= 100; - - for (i = NR_FREQS - 1; i > 0; i--) - if (cclk_frequency_100khz[i] == khz) - break; -//printk("setting ppcr to %d\n", i); - PPCR = i; + return cclk_frequency_100khz[sa11x0_freq_to_ppcr(khz)] * 100; } -static int __init sa1100_init_clock(void) +static int __init sa11x0_init_clock(void) { - cpufreq_init(get_cclk_frequency() * 100); - cpufreq_setfunctions(sa1100_validatespeed, sa1100_setspeed); + cpufreq_init(cclk_frequency_100khz[PPCR & 0xf] * 100); return 0; } -__initcall(sa1100_init_clock); +__initcall(sa11x0_init_clock); +#else +/* + * We still need to provide this so building without cpufreq works. + */ +unsigned int cpufreq_get(int cpu) +{ + return cclk_frequency_100khz[PPCR & 0xf] * 100; +} +EXPORT_SYMBOL(cpufreq_get); #endif /* @@ -130,13 +114,19 @@ PMCR = PMCR_SF; } -static int __init sa1100_set_poweroff(void) +static int __init sa1100_init(void) { pm_power_off = sa1100_power_off; return 0; } -__initcall(sa1100_set_poweroff); +__initcall(sa1100_init); + +void (*sa1100fb_backlight_power)(int on); +void (*sa1100fb_lcd_power)(int on); + +EXPORT_SYMBOL(sa1100fb_backlight_power); +EXPORT_SYMBOL(sa1100fb_lcd_power); /* @@ -149,7 +139,9 @@ * 0xf0000000-0xf3ffffff: miscellaneous stuff (CPLDs, etc.) * 0xf4000000-0xf4ffffff: SA-1111 * 0xf5000000-0xf5ffffff: reserved (used by cache flushing area) - * 0xf6000000-0xffffffff: reserved (internal SA1100 IO defined above) + * 0xf6000000-0xfffeffff: reserved (internal SA1100 IO defined above) + * 0xffff0000-0xffff0fff: SA1100 exception vectors + * 0xffff2000-0xffff2fff: Minicache copy_user_page area * * Below 0xe8000000 is reserved for vm allocation. * @@ -159,8 +151,6 @@ static struct map_desc standard_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA0 IO */ - { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA1 IO */ { 0xf8000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */ { 0xfa000000, 0x90000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */ { 0xfc000000, 0xa0000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/generic.h linux-2.5/arch/arm/mach-sa1100/generic.h --- linux-2.5.1/arch/arm/mach-sa1100/generic.h Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-sa1100/generic.h Sun Jan 6 01:38:26 2002 @@ -12,3 +12,6 @@ mi->bank[__nr].size = (__size), \ mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27) +extern void (*sa1100fb_backlight_power)(int on); +extern void (*sa1100fb_lcd_power)(int on); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/graphicsclient.c linux-2.5/arch/arm/mach-sa1100/graphicsclient.c --- linux-2.5.1/arch/arm/mach-sa1100/graphicsclient.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/graphicsclient.c Sun Jan 6 01:38:26 2002 @@ -113,7 +113,6 @@ irq_desc[irq].mask = ADS_mask_irq1; irq_desc[irq].unmask = ADS_unmask_irq1; } - GPDR &= ~GPIO_GPIO0; set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE); setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq ); } @@ -138,7 +137,6 @@ static struct map_desc graphicsclient_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ { 0xf1000000, 0x18000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CAN */ LAST_DESC @@ -193,12 +191,8 @@ if (port->mapbase == _Ser1UTCR0) { Ser1SDCR0 |= SDCR0_UART; /* Set RTS Output */ - GPDR |= GPIO_GC_UART0_RTS; GPSR = GPIO_GC_UART0_RTS; - /* Set CTS Input */ - GPDR &= ~GPIO_GC_UART0_CTS; - gc_uart_ctrl_data[0].cts_prev_state = 0; gc_uart_ctrl_data[0].info = info; gc_uart_ctrl_data[0].port = port; @@ -210,12 +204,8 @@ } else if (port->mapbase == _Ser2UTCR0) { Ser2UTCR4 = Ser2HSCR0 = 0; /* Set RTS Output */ - GPDR |= GPIO_GC_UART1_RTS; GPSR = GPIO_GC_UART1_RTS; - /* Set CTS Input */ - GPDR &= ~GPIO_GC_UART1_RTS; - gc_uart_ctrl_data[1].cts_prev_state = 0; gc_uart_ctrl_data[1].info = info; gc_uart_ctrl_data[1].port = port; @@ -226,12 +216,8 @@ &gc_uart_ctrl_data[1]); } else if (port->mapbase == _Ser3UTCR0) { /* Set RTS Output */ - GPDR |= GPIO_GC_UART2_RTS; GPSR = GPIO_GC_UART2_RTS; - /* Set CTS Input */ - GPDR &= ~GPIO_GC_UART2_RTS; - gc_uart_ctrl_data[2].cts_prev_state = 0; gc_uart_ctrl_data[2].info = info; gc_uart_ctrl_data[2].port = port; @@ -258,9 +244,9 @@ return 0; } -static int graphicsclient_get_mctrl(struct uart_port *port) +static u_int graphicsclient_get_mctrl(struct uart_port *port) { - int result = TIOCM_CD | TIOCM_DSR; + u_int result = TIOCM_CD | TIOCM_DSR; if (port->mapbase == _Ser1UTCR0) { if (!(GPLR & GPIO_GC_UART0_CTS)) @@ -326,6 +312,8 @@ sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); sa1100_register_uart(2, 2); + GPDR |= GPIO_GC_UART0_RTS | GPIO_GC_UART1_RTS | GPIO_GC_UART2_RTS; + GPDR &= ~(GPIO_GC_UART0_CTS | GPIO_GC_UART1_RTS | GPIO_GC_UART2_RTS); } MACHINE_START(GRAPHICSCLIENT, "ADS GraphicsClient") diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/graphicsmaster.c linux-2.5/arch/arm/mach-sa1100/graphicsmaster.c --- linux-2.5.1/arch/arm/mach-sa1100/graphicsmaster.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/graphicsmaster.c Sun Jan 6 01:38:26 2002 @@ -12,6 +12,7 @@ #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/ptrace.h> +#include <linux/ioport.h> #include <asm/hardware.h> #include <asm/setup.h> @@ -43,7 +44,7 @@ /* * Probe for SA1111. */ - ret = sa1111_probe(); + ret = sa1111_probe(0x18000000); if (ret < 0) return ret; @@ -174,7 +175,6 @@ irq_desc[irq].mask = ADS_mask_irq1; irq_desc[irq].unmask = ADS_unmask_irq1; } - GPDR &= ~GPIO_GPIO0; set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE); setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq ); } @@ -200,7 +200,6 @@ static struct map_desc graphicsmaster_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CPLD */ { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* CAN */ { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ @@ -215,31 +214,22 @@ Ser1SDCR0 |= SDCR0_UART; /* Set RTS Output */ GPSR = GPIO_GPIO15; - GPDR |= GPIO_GPIO15; - /* Set CTS Input */ - GPDR &= ~GPIO_GPIO14; } else if (port->mapbase == _Ser2UTCR0) { Ser2UTCR4 = Ser2HSCR0 = 0; /* Set RTS Output */ GPSR = GPIO_GPIO17; - GPDR |= GPIO_GPIO17; - /* Set CTS Input */ - GPDR &= ~GPIO_GPIO16; } else if (port->mapbase == _Ser3UTCR0) { /* Set RTS Output */ GPSR = GPIO_GPIO19; - GPDR |= GPIO_GPIO19; - /* Set CTS Input */ - GPDR &= ~GPIO_GPIO18; } return ret; } -static int graphicsmaster_get_mctrl(struct uart_port *port) +static u_int graphicsmaster_get_mctrl(struct uart_port *port) { - int result = TIOCM_CD | TIOCM_DSR; + u_int result = TIOCM_CD | TIOCM_DSR; if (port->mapbase == _Ser1UTCR0) { if (!(GPLR & GPIO_GPIO14)) @@ -304,6 +294,10 @@ sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); sa1100_register_uart(2, 2); + + /* set GPDR now */ + GPDR |= GPIO_GPIO15 | GPIO_GPIO17 | GPIO_GPIO19; + GPDR &= ~(GPIO_GPIO14 | GPIO_GPIO16 | GPIO_GPIO18); } MACHINE_START(GRAPHICSMASTER, "ADS GraphicsMaster") diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/h3600.c linux-2.5/arch/arm/mach-sa1100/h3600.c --- linux-2.5.1/arch/arm/mach-sa1100/h3600.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/h3600.c Sun Jan 6 01:38:26 2002 @@ -1,5 +1,23 @@ /* - * linux/arch/arm/mach-sa1100/h3600.c + * Hardware definitions for Compaq iPAQ H3xxx Handheld Computers + * + * Copyright 2000,1 Compaq Computer Corporation. + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Author: Jamey Hicks. + * + * History: + * + * 2001-10-?? Andrew Christian Added support for iPAQ H3800 + * and abstracted EGPIO interface. + * */ #include <linux/config.h> @@ -17,84 +35,345 @@ #include <asm/mach/map.h> #include <asm/mach/serial_sa1100.h> #include <linux/serial_core.h> +#include <asm/arch/h3600_gpio.h> #include "generic.h" - /* - * Bitsy has extended, write-only memory-mapped GPIO's + * H3600 has extended, write-only memory-mapped GPIO's + * H3100 has 1/2 extended, write-only GPIO and 1/2 on + * regular GPIO lines. + * H3800 has memory-mapped GPIO through ASIC1 & 2 */ -static int h3600_egpio = EGPIO_H3600_RS232_ON; +#define H3600_EGPIO (*(volatile unsigned int *)H3600_EGPIO_VIRT) + +static unsigned int h3600_egpio; + +/************************* H3100 *************************/ + +#define H3100_DIRECT_EGPIO (GPIO_H3100_BT_ON \ + | GPIO_H3100_GPIO3 \ + | GPIO_H3100_QMUTE \ + | GPIO_H3100_LCD_3V_ON \ + | GPIO_H3100_AUD_ON \ + | GPIO_H3100_AUD_PWR_ON \ + | GPIO_H3100_IR_ON \ + | GPIO_H3100_IR_FSEL) -void init_h3600_egpio(void) +void h3100_init_egpio( void ) { -#ifdef CONFIG_IPAQ_H3100 - int h3100_controls = (GPIO_H3100_BT_ON - | GPIO_H3100_QMUTE - | GPIO_H3100_LCD_3V_ON - | GPIO_H3100_AUD_ON - | GPIO_H3100_AUD_PWR_ON - | GPIO_H3100_IR_ON - | GPIO_H3100_IR_FSEL); - GPDR |= h3100_controls; - GPCR = h3100_controls; - GAFR = GPIO_SSP_CLK; -#endif -} - -void clr_h3600_egpio(unsigned long x) -{ -#ifdef CONFIG_IPAQ_H3100 - unsigned long gpcr = 0; - if (x&EGPIO_H3600_QMUTE) - gpcr |= GPIO_H3100_QMUTE; - if (x&EGPIO_H3600_LCD_ON) - gpcr |= GPIO_H3100_LCD_3V_ON; - if (x&EGPIO_H3600_AUD_AMP_ON) - gpcr |= GPIO_H3100_AUD_ON; - if (x&EGPIO_H3600_AUD_PWR_ON) - gpcr |= GPIO_H3100_AUD_PWR_ON; - if (x&EGPIO_H3600_IR_ON) - gpcr |= GPIO_H3100_IR_ON; - if (x&EGPIO_H3600_IR_FSEL) - gpcr |= GPIO_H3100_IR_FSEL; - GPCR = gpcr; -#endif - h3600_egpio &= ~x; + GPDR |= H3100_DIRECT_EGPIO; + GPCR = H3100_DIRECT_EGPIO; /* Initially all off */ + + /* Older bootldrs put GPIO2-9 in alternate mode on the + assumption that they are used for video */ + GAFR &= ~H3100_DIRECT_EGPIO; + + h3600_egpio = EGPIO_H3600_RS232_ON; H3600_EGPIO = h3600_egpio; } -void set_h3600_egpio(unsigned long x) +void h3100_control_egpio( enum ipaq_egpio_type x, int setp ) { -#ifdef CONFIG_IPAQ_H3100 - unsigned long gpsr = 0; - if (x&EGPIO_H3600_QMUTE) - gpsr |= GPIO_H3100_QMUTE; - if (x&EGPIO_H3600_LCD_ON) - gpsr |= GPIO_H3100_LCD_3V_ON; - if (x&EGPIO_H3600_AUD_AMP_ON) - gpsr |= GPIO_H3100_AUD_ON; - if (x&EGPIO_H3600_AUD_PWR_ON) - gpsr |= GPIO_H3100_AUD_PWR_ON; - if (x&EGPIO_H3600_IR_ON) - gpsr |= GPIO_H3100_IR_ON; - if (x&EGPIO_H3600_IR_FSEL) - gpsr |= GPIO_H3100_IR_FSEL; - GPSR = gpsr; -#endif - h3600_egpio |= x; + unsigned int egpio = 0; + long gpio = 0; + unsigned long flags; + + switch (x) { + case IPAQ_EGPIO_LCD_ON: + egpio |= EGPIO_H3600_LCD_ON; + gpio |= GPIO_H3100_LCD_3V_ON; + break; + case IPAQ_EGPIO_CODEC_NRESET: + egpio |= EGPIO_H3600_CODEC_NRESET; + break; + case IPAQ_EGPIO_AUDIO_ON: + gpio |= GPIO_H3100_AUD_PWR_ON + | GPIO_H3100_AUD_ON; + break; + case IPAQ_EGPIO_QMUTE: + gpio |= GPIO_H3100_QMUTE; + break; + case IPAQ_EGPIO_OPT_NVRAM_ON: + egpio |= EGPIO_H3600_OPT_NVRAM_ON; + break; + case IPAQ_EGPIO_OPT_ON: + egpio |= EGPIO_H3600_OPT_ON; + break; + case IPAQ_EGPIO_CARD_RESET: + egpio |= EGPIO_H3600_CARD_RESET; + break; + case IPAQ_EGPIO_OPT_RESET: + egpio |= EGPIO_H3600_OPT_RESET; + break; + case IPAQ_EGPIO_IR_ON: + gpio |= GPIO_H3100_IR_ON; + break; + case IPAQ_EGPIO_IR_FSEL: + gpio |= GPIO_H3100_IR_FSEL; + break; + case IPAQ_EGPIO_RS232_ON: + egpio |= EGPIO_H3600_RS232_ON; + break; + case IPAQ_EGPIO_VPP_ON: + egpio |= EGPIO_H3600_VPP_ON; + break; + } + + local_irq_save(flags); + if ( setp ) { + h3600_egpio |= egpio; + GPSR = gpio; + } else { + h3600_egpio &= ~egpio; + GPCR = gpio; + } H3600_EGPIO = h3600_egpio; + local_irq_restore(flags); + + /* + if ( x != IPAQ_EGPIO_VPP_ON ) { + printk(__FUNCTION__ " : type=%d (%s) gpio=0x%x (0x%x) egpio=0x%x (0x%x) setp=%d\n", + x, egpio_names[x], GPLR, gpio, h3600_egpio, egpio, setp ); + } + */ +} + +unsigned long h3100_read_egpio( void ) +{ + return h3600_egpio; } -EXPORT_SYMBOL(clr_h3600_egpio); -EXPORT_SYMBOL(set_h3600_egpio); +static struct ipaq_model_ops h3100_model_ops __initdata = { + model : IPAQ_H3100, + generic_name : "3100", + initialize : h3100_init_egpio, + control : h3100_control_egpio, + read : h3100_read_egpio +}; + + +/************************* H3600 *************************/ + +void h3600_init_egpio( void ) +{ + h3600_egpio = EGPIO_H3600_RS232_ON; + H3600_EGPIO = h3600_egpio; +} + +void h3600_control_egpio( enum ipaq_egpio_type x, int setp ) +{ + unsigned int egpio = 0; + unsigned long flags; + + switch (x) { + case IPAQ_EGPIO_LCD_ON: + egpio |= EGPIO_H3600_LCD_ON | + EGPIO_H3600_LCD_PCI | + EGPIO_H3600_LCD_5V_ON | + EGPIO_H3600_LVDD_ON; + break; + case IPAQ_EGPIO_CODEC_NRESET: + egpio |= EGPIO_H3600_CODEC_NRESET; + break; + case IPAQ_EGPIO_AUDIO_ON: + egpio |= EGPIO_H3600_AUD_AMP_ON | + EGPIO_H3600_AUD_PWR_ON; + break; + case IPAQ_EGPIO_QMUTE: + egpio |= EGPIO_H3600_QMUTE; + break; + case IPAQ_EGPIO_OPT_NVRAM_ON: + egpio |= EGPIO_H3600_OPT_NVRAM_ON; + break; + case IPAQ_EGPIO_OPT_ON: + egpio |= EGPIO_H3600_OPT_ON; + break; + case IPAQ_EGPIO_CARD_RESET: + egpio |= EGPIO_H3600_CARD_RESET; + break; + case IPAQ_EGPIO_OPT_RESET: + egpio |= EGPIO_H3600_OPT_RESET; + break; + case IPAQ_EGPIO_IR_ON: + egpio |= EGPIO_H3600_IR_ON; + break; + case IPAQ_EGPIO_IR_FSEL: + egpio |= EGPIO_H3600_IR_FSEL; + break; + case IPAQ_EGPIO_RS232_ON: + egpio |= EGPIO_H3600_RS232_ON; + break; + case IPAQ_EGPIO_VPP_ON: + egpio |= EGPIO_H3600_VPP_ON; + break; + } + + local_irq_save(flags); + if ( setp ) + h3600_egpio |= egpio; + else + h3600_egpio &= ~egpio; + H3600_EGPIO = h3600_egpio; + local_irq_restore(flags); +} + +unsigned long h3600_read_egpio( void ) +{ + return h3600_egpio; +} + +static struct ipaq_model_ops h3600_model_ops __initdata = { + model : IPAQ_H3600, + generic_name : "3600", + initialize : h3600_init_egpio, + control : h3600_control_egpio, + read : h3600_read_egpio +}; + +/************************* H3800 *************************/ + +#define ASIC1_OUTPUTS 0x7fff /* First 15 bits are used */ +static unsigned int h3800_asic1_gpio; +static unsigned int h3800_asic2_gpio; + +void h3800_init_egpio(void) +{ + /* Set up ASIC #1 */ + H3800_ASIC1_GPIO_Direction = ASIC1_OUTPUTS; /* All outputs */ + H3800_ASIC1_GPIO_Mask = ASIC1_OUTPUTS; /* No interrupts */ + H3800_ASIC1_GPIO_SleepMask = ASIC1_OUTPUTS; + H3800_ASIC1_GPIO_SleepDir = ASIC1_OUTPUTS; + H3800_ASIC1_GPIO_SleepOut = GPIO_H3800_ASIC1_EAR_ON_N; + H3800_ASIC1_GPIO_BattFaultDir = ASIC1_OUTPUTS; + H3800_ASIC1_GPIO_BattFaultOut = GPIO_H3800_ASIC1_EAR_ON_N; + + h3800_asic1_gpio = GPIO_H3800_ASIC1_IR_ON_N /* TODO: Check IR level */ + | GPIO_H3800_ASIC1_RS232_ON + | GPIO_H3800_ASIC1_EAR_ON_N; + + H3800_ASIC1_GPIO_Out = h3800_asic1_gpio; + + /* Set up ASIC #2 */ + H3800_ASIC2_GPIO_Direction = GPIO_H3800_ASIC2_PEN_IRQ + | GPIO_H3800_ASIC2_SD_DETECT + | GPIO_H3800_ASIC2_EAR_IN_N + | GPIO_H3800_ASIC2_USB_DETECT_N + | GPIO_H3800_ASIC2_SD_CON_SLT; + + h3800_asic2_gpio = GPIO_H3800_ASIC2_IN_Y1_N | GPIO_H3800_ASIC2_IN_X1_N; + H3800_ASIC2_GPIO_Data = h3800_asic2_gpio; + H3800_ASIC2_GPIO_BattFaultOut = h3800_asic2_gpio; + + /* TODO : Set sleep states & battery fault states */ + + /* Clear VPP Enable */ + H3800_ASIC1_FlashWP_VPP_ON = 0; +} + +void h3800_control_egpio( enum ipaq_egpio_type x, int setp ) +{ + unsigned int set_asic1_egpio = 0; + unsigned int clear_asic1_egpio = 0; + unsigned long flags; + + switch (x) { + case IPAQ_EGPIO_LCD_ON: + set_asic1_egpio |= GPIO_H3800_ASIC1_LCD_5V_ON + | GPIO_H3800_ASIC1_LCD_ON + | GPIO_H3800_ASIC1_LCD_PCI + | GPIO_H3800_ASIC1_VGH_ON + | GPIO_H3800_ASIC1_VGL_ON; + break; + case IPAQ_EGPIO_CODEC_NRESET: + break; + case IPAQ_EGPIO_AUDIO_ON: + break; + case IPAQ_EGPIO_QMUTE: + break; + case IPAQ_EGPIO_OPT_NVRAM_ON: + break; + case IPAQ_EGPIO_OPT_ON: + break; + case IPAQ_EGPIO_CARD_RESET: + break; + case IPAQ_EGPIO_OPT_RESET: + break; + case IPAQ_EGPIO_IR_ON: + clear_asic1_egpio |= GPIO_H3800_ASIC1_IR_ON_N; /* TODO : This is backwards? */ + break; + case IPAQ_EGPIO_IR_FSEL: + break; + case IPAQ_EGPIO_RS232_ON: + set_asic1_egpio |= GPIO_H3800_ASIC1_RS232_ON; + break; + case IPAQ_EGPIO_VPP_ON: + H3800_ASIC1_FlashWP_VPP_ON = setp; + break; + } + + local_irq_save(flags); + if ( setp ) { + h3800_asic1_gpio |= set_asic1_egpio; + h3800_asic1_gpio &= ~clear_asic1_egpio; + } + else { + h3800_asic1_gpio &= ~set_asic1_egpio; + h3800_asic1_gpio |= clear_asic1_egpio; + } + H3800_ASIC1_GPIO_Out = h3800_asic1_gpio; + local_irq_restore(flags); +} + +unsigned long h3800_read_egpio( void ) +{ + return h3800_asic1_gpio | (h3800_asic2_gpio << 16); +} + +static struct ipaq_model_ops h3800_model_ops __initdata = { + model : IPAQ_H3800, + generic_name : "3800", + initialize : h3800_init_egpio, + control : h3800_control_egpio, + read : h3800_read_egpio +}; + + +static void h3600_lcd_power(int on) +{ + if (on) + set_h3600_egpio(IPAQ_EGPIO_LCD_ON); + else + clr_h3600_egpio(IPAQ_EGPIO_LCD_ON); +} + + +struct ipaq_model_ops ipaq_model_ops; +EXPORT_SYMBOL(ipaq_model_ops); + +static int __init h3600_init_model_ops(void) +{ + if (machine_is_h3xxx()) { + sa1100fb_lcd_power = h3600_lcd_power; + + if (machine_is_h3100()) { + ipaq_model_ops = h3100_model_ops; + } else if (machine_is_h3600()) { + ipaq_model_ops = h3600_model_ops; + } else if (machine_is_h3800()) { + ipaq_model_ops = h3800_model_ops; + } + init_h3600_egpio(); + } + return 0; +} + +__initcall(h3600_init_model_ops); /* - * Low-level UART features. - * - * Note that RTS, CTS and DCD are all active low. + * low-level UART features */ static void h3600_uart_set_mctrl(struct uart_port *port, u_int mctrl) @@ -107,9 +386,9 @@ } } -static int h3600_uart_get_mctrl(struct uart_port *port) +static u_int h3600_uart_get_mctrl(struct uart_port *port) { - int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; + u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; if (port->mapbase == _Ser3UTCR0) { int gplr = GPLR; @@ -126,33 +405,47 @@ { struct uart_info *info = dev_id; /* Note: should only call this if something has changed */ + spin_lock_irq(&info->lock); uart_handle_dcd_change(info, !(GPLR & GPIO_H3600_COM_DCD)); + spin_unlock_irq(&info->lock); } static void h3600_cts_intr(int irq, void *dev_id, struct pt_regs *regs) { struct uart_info *info = dev_id; /* Note: should only call this if something has changed */ + spin_lock_irq(&info->lock); uart_handle_cts_change(info, !(GPLR & GPIO_H3600_COM_CTS)); + spin_unlock_irq(&info->lock); } static void h3600_uart_pm(struct uart_port *port, u_int state, u_int oldstate) { if (port->mapbase == _Ser2UTCR0) { - if (state == 0) { - set_h3600_egpio(EGPIO_H3600_IR_ON); - } else { - clr_h3600_egpio(EGPIO_H3600_IR_ON); - } + assign_h3600_egpio( IPAQ_EGPIO_IR_ON, !state ); } else if (port->mapbase == _Ser3UTCR0) { - if (state == 0) { - set_h3600_egpio(EGPIO_H3600_RS232_ON); - } else { - clr_h3600_egpio(EGPIO_H3600_RS232_ON); - } + assign_h3600_egpio( IPAQ_EGPIO_RS232_ON, !state ); } } +/* + * Enable/Disable wake up events for this serial port. + * Obviously, we only support this on the normal COM port. + */ +static int h3600_uart_set_wake(struct uart_port *port, u_int enable) +{ + int err = -EINVAL; + + if (port->mapbase == _Ser3UTCR0) { + if (enable) + PWER |= PWER_GPIO23 | PWER_GPIO25 ; /* DCD and CTS */ + else + PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */ + err = 0; + } + return err; +} + static int h3600_uart_open(struct uart_port *port, struct uart_info *info) { int ret = 0; @@ -163,8 +456,6 @@ Ser2HSSR0 = HSSR0_EIF | HSSR0_TUR | HSSR0_RAB | HSSR0_FRE; } else if (port->mapbase == _Ser3UTCR0) { - GPDR &= ~(GPIO_H3600_COM_DCD|GPIO_H3600_COM_CTS); - GPDR |= GPIO_H3600_COM_RTS; set_GPIO_IRQ_edge(GPIO_H3600_COM_DCD|GPIO_H3600_COM_CTS, GPIO_BOTH_EDGES); @@ -193,16 +484,16 @@ set_mctrl: h3600_uart_set_mctrl, get_mctrl: h3600_uart_get_mctrl, pm: h3600_uart_pm, + set_wake: h3600_uart_set_wake, open: h3600_uart_open, close: h3600_uart_close, }; static struct map_desc h3600_io_desc[] __initdata = { - /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xf0000000, 0x49000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */ - { 0xf1000000, 0x10000000, 0x02800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */ - { 0xf3800000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */ + /* virtual physical length domain r w c b */ + { H3600_EGPIO_VIRT, 0x49000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 CS#5 */ + { H3600_BANK_2_VIRT, 0x10000000, 0x02800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 CS#2 */ + { H3600_BANK_4_VIRT, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 CS#4 */ LAST_DESC }; @@ -214,13 +505,19 @@ sa1100_register_uart_fns(&h3600_port_fns); sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); /* isn't this one driven elsewhere? */ - init_h3600_egpio(); /* - * Default GPIO settings. + * Default GPIO settings. Should be set by machine */ GPCR = 0x0fffffff; - GPDR = 0x0401f3fc; +// GPDR = 0x0401f3fc; + GPDR = GPIO_H3600_COM_RTS | GPIO_H3600_L3_CLOCK | + GPIO_H3600_L3_MODE | GPIO_H3600_L3_DATA | + GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 | + GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | + GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8; + + init_h3600_egpio(); /* * Ensure those pins are outputs and driving low. @@ -230,11 +527,24 @@ /* Configure suspend conditions */ PGSR = 0; - PWER = 0x1 | (1 << 31); - PCFR = PCFR_OPDE | PCFR_FP | PCFR_FS; -} - -MACHINE_START(H3600, "Compaq iPAQ") + PWER = PWER_GPIO0 | PWER_RTC; + PCFR = PCFR_OPDE; + PSDR = 0; +} + +MACHINE_START(H3600, "Compaq iPAQ H3600") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + MAPIO(h3600_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END +MACHINE_START(H3100, "Compaq iPAQ H3100") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + MAPIO(h3600_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END +MACHINE_START(H3800, "Compaq iPAQ H3800") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) BOOT_PARAMS(0xc0000100) MAPIO(h3600_map_io) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/huw_webpanel.c linux-2.5/arch/arm/mach-sa1100/huw_webpanel.c --- linux-2.5.1/arch/arm/mach-sa1100/huw_webpanel.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-sa1100/huw_webpanel.c Sun Jan 6 01:38:26 2002 @@ -22,11 +22,35 @@ unsigned long BCR_value; EXPORT_SYMBOL(BCR_value); +static void huw_lcd_power(int on) +{ + if (on) + BCR_clear(BCR_TFT_NPWR); + else + BCR_set(BCR_TFT_NPWR); +} + +static void huw_backlight_power(int on) +{ +#error FIXME + if (on) { + BCR_set(BCR_CCFL_POW | BCR_PWM_BACKLIGHT); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_task(200 * HZ / 1000); + BCR_set(BCR_TFT_ENA); + } +} -static void __init init_huw_cs3(void) +static int __init init_huw_cs3(void) { // here we can place some initcode // BCR_value = 0x1045bf70; //*((volatile unsigned long*)0xf1fffff0); + if (machine_is_huw_webpanel()) { + sa1100fb_lcd_power = huw_lcd_power; + sa1100fb_backlight_power = huw_backlight_power; + } + + return 0; } __initcall(init_huw_cs3); @@ -55,7 +79,6 @@ **/ static struct map_desc huw_webpanel_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0, neccessary for mtd */ { 0xf0000000, 0xc1fb8000, 0x00048000, DOMAIN_IO, 1, 1, 0, 0 }, /* Parameter */ { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */ LAST_DESC diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/irq.c linux-2.5/arch/arm/mach-sa1100/irq.c --- linux-2.5.1/arch/arm/mach-sa1100/irq.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-sa1100/irq.c Sun Jan 6 01:38:26 2002 @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/sched.h> #include <linux/interrupt.h> +#include <linux/ioport.h> #include <linux/ptrace.h> #include <asm/hardware.h> @@ -37,6 +38,9 @@ void set_GPIO_IRQ_edge( int gpio_mask, int edge ) { + int flags; + + local_irq_save(flags); if (edge & GPIO_FALLING_EDGE) GPIO_IRQ_falling_edge |= gpio_mask; else @@ -45,6 +49,9 @@ GPIO_IRQ_rising_edge |= gpio_mask; else GPIO_IRQ_rising_edge &= ~gpio_mask; + GPDR &= ~gpio_mask; + GAFR &= ~gpio_mask; + restore_flags(flags); } EXPORT_SYMBOL(set_GPIO_IRQ_edge); @@ -121,7 +128,7 @@ for (i = 11; i <= 27; ++i) { if (irq & (1<<i)) { - do_IRQ (IRQ_GPIO_11_27(i), regs); + do_IRQ(IRQ_GPIO11 + i - 11, regs); } } } @@ -175,10 +182,17 @@ GFER = (GFER & ~mask) | (GPIO_IRQ_falling_edge & mask); } +static struct resource irq_resource = { + name: "irqs", + start: 0x90050000, + end: 0x9005ffff, +}; void __init sa1100_init_irq(void) { int irq; + + request_resource(&iomem_resource, &irq_resource); /* disable all IRQs */ ICMR = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/jornada720.c linux-2.5/arch/arm/mach-sa1100/jornada720.c --- linux-2.5.1/arch/arm/mach-sa1100/jornada720.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-sa1100/jornada720.c Sun Jan 6 01:38:26 2002 @@ -6,6 +6,7 @@ #include <linux/kernel.h> #include <linux/tty.h> #include <linux/delay.h> +#include <linux/ioport.h> #include <asm/hardware.h> #include <asm/setup.h> @@ -37,20 +38,17 @@ SKCR = JORSKCR_INIT; /* Turn on the PLL, enable Ready and enable nOE assertion from DC */ mdelay(100); - SKCR = JORSKCR_RCLK; /* turn on the RCLOCK */ - SMCR = 0x35; /* initialize the SMC (debug SA-1111 reset */ - PCCR = 0; /* initialize the S2MC (debug SA-1111 reset) */ + SBI_SKCR = JORSKCR_RCLK;/* turn on the RCLOCK */ + SBI_SMCR = 0x35; /* initialize the SMC (debug SA-1111 reset */ + PCCR = 0; /* initialize the S2MC (debug SA-1111 reset) */ /* LDD4 is speaker, LDD3 is microphone */ PPSR &= ~(PPC_LDD3 | PPC_LDD4); PPDR |= PPC_LDD3 | PPC_LDD4; /* initialize extra IRQs */ - set_GPIO_IRQ_edge(GPIO_GPIO(1), GPIO_RISING_EDGE); - sa1111_init_irq(SA1100_GPIO_TO_IRQ(1)); /* chained on GPIO 1 */ - - sa1100_register_uart(0, 3); - sa1100_register_uart(1, 1); + set_GPIO_IRQ_edge(GPIO_GPIO1, GPIO_RISING_EDGE); + sa1111_init_irq(IRQ_GPIO1)); /* chained on GPIO 1 */ return 0; } @@ -68,7 +66,6 @@ static struct map_desc jornada720_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ { 0xf0000000, 0x48000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Epson registers */ { 0xf1000000, 0x48200000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Epson frame buffer */ { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ @@ -79,6 +76,9 @@ { sa1100_map_io(); iotable_init(jornada720_io_desc); + + sa1100_register_uart(0, 3); + sa1100_register_uart(1, 1); } MACHINE_START(JORNADA720, "HP Jornada 720") diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/lart.c linux-2.5/arch/arm/mach-sa1100/lart.c --- linux-2.5.1/arch/arm/mach-sa1100/lart.c Mon Aug 13 00:36:24 2001 +++ linux-2.5/arch/arm/mach-sa1100/lart.c Sun Jan 6 01:38:26 2002 @@ -31,6 +31,7 @@ sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); sa1100_register_uart(2, 2); + GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD); GPDR |= GPIO_UART_TXD; GPDR &= ~GPIO_UART_RXD; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/leds-assabet.c linux-2.5/arch/arm/mach-sa1100/leds-assabet.c --- linux-2.5.1/arch/arm/mach-sa1100/leds-assabet.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/leds-assabet.c Sun Jan 6 01:38:26 2002 @@ -42,6 +42,8 @@ case led_stop: led_state &= ~LED_STATE_ENABLED; + hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN; + ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state); break; case led_claim: @@ -107,8 +109,7 @@ } if (led_state & LED_STATE_ENABLED) - ASSABET_BCR = BCR_value = (BCR_value & ~ASSABET_BCR_LED_MASK) | - hw_led_state; + ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state); local_irq_restore(flags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/leds-flexanet.c linux-2.5/arch/arm/mach-sa1100/leds-flexanet.c --- linux-2.5.1/arch/arm/mach-sa1100/leds-flexanet.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-sa1100/leds-flexanet.c Sun Jan 6 01:38:26 2002 @@ -35,7 +35,7 @@ switch (evt) { case led_start: /* start using LEDs and enable its hardware */ - hw_led_bcr = BCR_LED_GREEN; + hw_led_bcr = FHH_BCR_LED_GREEN; hw_led_gpio = GPIO_LED_RED; led_state = LED_STATE_ENABLED; break; @@ -71,13 +71,13 @@ case led_idle_start: /* turn off CPU load LED */ if (!(led_state & LED_STATE_CLAIMED)) - hw_led_bcr &= ~BCR_LED_GREEN; + hw_led_bcr &= ~FHH_BCR_LED_GREEN; break; case led_idle_end: /* turn on CPU load LED */ if (!(led_state & LED_STATE_CLAIMED)) - hw_led_bcr |= BCR_LED_GREEN; + hw_led_bcr |= FHH_BCR_LED_GREEN; break; #endif @@ -88,12 +88,12 @@ /* direct LED access (must be previously claimed) */ case led_green_on: if (led_state & LED_STATE_CLAIMED) - hw_led_bcr |= BCR_LED_GREEN; + hw_led_bcr |= FHH_BCR_LED_GREEN; break; case led_green_off: if (led_state & LED_STATE_CLAIMED) - hw_led_bcr &= ~BCR_LED_GREEN; + hw_led_bcr &= ~FHH_BCR_LED_GREEN; break; case led_amber_on: @@ -119,7 +119,7 @@ if (led_state & LED_STATE_ENABLED) { /* update LEDs */ - BCR = BCR_value = (BCR_value & ~BCR_LED_GREEN) | hw_led_bcr; + FHH_BCR = flexanet_BCR = (flexanet_BCR & ~FHH_BCR_LED_GREEN) | hw_led_bcr; GPSR = hw_led_gpio; GPCR = hw_led_gpio ^ GPIO_LED_RED; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/leds-system3.c linux-2.5/arch/arm/mach-sa1100/leds-system3.c --- linux-2.5.1/arch/arm/mach-sa1100/leds-system3.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-sa1100/leds-system3.c Sun Jan 6 13:32:34 2002 @@ -0,0 +1,52 @@ +/* + * linux/arch/arm/mach-sa1100/leds-system3.c + * + * Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@gmx.de> + * + * Original (leds-footbridge.c) by Russell King + * + * $Id: leds-system3.c,v 1.1 2002/01/06 13:32:34 davej Exp $ + * + * 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. + * + * $Log: leds-system3.c,v $ + * Revision 1.1 2002/01/06 13:32:34 davej + * more arm bits + * + * Revision 1.1.6.1 2001/12/04 15:19:26 seletz + * - merged from linux_2_4_13_ac5_rmk2 + * + * Revision 1.1.4.2 2001/11/19 17:58:53 seletz + * - cleanup + * + * Revision 1.1.4.1 2001/11/16 13:49:54 seletz + * - dummy LED support for PT Digital Board + * + * Revision 1.1.2.1 2001/10/15 16:03:39 seletz + * - dummy function + * + * + */ +#include <linux/config.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/leds.h> +#include <asm/system.h> + +#include "leds.h" + + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 + +static unsigned int led_state; +static unsigned int hw_led_state; + +void system3_leds_event(led_event_t evt) +{ + + /* TODO: support LEDs */ +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/leds.c linux-2.5/arch/arm/mach-sa1100/leds.c --- linux-2.5.1/arch/arm/mach-sa1100/leds.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/leds.c Sun Jan 6 01:38:26 2002 @@ -34,6 +34,8 @@ leds_event = graphicsmaster_leds_event; if (machine_is_adsbitsy()) leds_event = adsbitsy_leds_event; + if (machine_is_pt_system3()) + leds_event = system3_leds_event; leds_event(led_start); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/leds.h linux-2.5/arch/arm/mach-sa1100/leds.h --- linux-2.5.1/arch/arm/mach-sa1100/leds.h Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/leds.h Sun Jan 6 01:38:26 2002 @@ -7,3 +7,4 @@ extern void pfs168_leds_event(led_event_t evt); extern void graphicsmaster_leds_event(led_event_t evt); extern void adsbitsy_leds_event(led_event_t evt); +extern void system3_leds_event(led_event_t evt); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/neponset.c linux-2.5/arch/arm/mach-sa1100/neponset.c --- linux-2.5.1/arch/arm/mach-sa1100/neponset.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/neponset.c Sun Jan 6 01:38:26 2002 @@ -7,6 +7,8 @@ #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/ptrace.h> +#include <linux/tty.h> +#include <linux/ioport.h> #include <linux/serial_core.h> #include <asm/hardware.h> @@ -16,6 +18,7 @@ #include <asm/arch/irq.h> #include <asm/mach/serial_sa1100.h> #include <asm/arch/assabet.h> +#include <asm/hardware/sa1111.h> #include "sa1111.h" @@ -40,10 +43,10 @@ if (!irr) break; if( irr & IRR_ETHERNET ) - do_IRQ(NEPONSET_ETHERNET_IRQ, regs); + do_IRQ(IRQ_NEPONSET_SMC9196, regs); if( irr & IRR_USAR ) - do_IRQ(NEPONSET_USAR_IRQ, regs); + do_IRQ(IRQ_NEPONSET_USAR, regs); if( irr & IRR_SA1111 ) sa1111_IRQ_demux(irq, dev_id, regs); @@ -58,19 +61,16 @@ static void __init neponset_init_irq(void) { - int irq; - sa1111_init_irq(-1); /* SA1111 IRQ not routed to a GPIO */ /* setup extra Neponset IRQs */ - irq = NEPONSET_ETHERNET_IRQ; - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq = NEPONSET_USAR_IRQ; - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - set_GPIO_IRQ_edge(ASSABET_GPIO_NEP_IRQ, GPIO_RISING_EDGE); - setup_arm_irq(ASSABET_IRQ_GPIO_NEP_IRQ, &neponset_irq); + irq_desc[IRQ_NEPONSET_SMC9196].valid = 1; + irq_desc[IRQ_NEPONSET_SMC9196].probe_ok = 1; + irq_desc[IRQ_NEPONSET_USAR].valid = 1; + irq_desc[IRQ_NEPONSET_USAR].probe_ok = 1; + + set_GPIO_IRQ_edge(GPIO_GPIO25, GPIO_RISING_EDGE); + setup_arm_irq(IRQ_GPIO25, &neponset_irq); } static int __init neponset_init(void) @@ -102,6 +102,11 @@ } /* + * Disable GPIO 0/1 drivers so the buttons work on the module. + */ + NCR_0 |= NCR_GP01_OFF; + + /* * Neponset has SA1111 connected to CS4. We know that after * reset the chip will be configured for variable latency IO. */ @@ -110,7 +115,7 @@ /* * Probe for a SA1111. */ - ret = sa1111_probe(); + ret = sa1111_probe(0x40000000); if (ret < 0) return ret; @@ -184,7 +189,7 @@ MDM_CTL_0 = mdm_ctl0; } -static int neponset_get_mctrl(struct uart_port *port) +static u_int neponset_get_mctrl(struct uart_port *port) { u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; u_int mdm_ctl1 = MDM_CTL_1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/omnimeter.c linux-2.5/arch/arm/mach-sa1100/omnimeter.c --- linux-2.5.1/arch/arm/mach-sa1100/omnimeter.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-sa1100/omnimeter.c Sun Jan 6 01:38:26 2002 @@ -15,6 +15,30 @@ #include "generic.h" +static void omnimeter_backlight_power(int on) +{ + if (on) + LEDBacklightOn(); + else + LEDBacklightOff(); +} + +static void omnimeter_lcd_power(int on) +{ + if (on) + LCDPowerOn(); +} + +static int __init omnimeter_init(void) +{ + if (machine_is_omnimeter()) { + sa1100fb_backlight_power = omnimeter_backlight_power; + sa1100fb_lcd_power = omnimeter_lcd_power; + } + return 0; +} + +__initcall(omnimeter_init); static void __init fixup_omnimeter(struct machine_desc *desc, struct param_struct *params, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/pangolin.c linux-2.5/arch/arm/mach-sa1100/pangolin.c --- linux-2.5.1/arch/arm/mach-sa1100/pangolin.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-sa1100/pangolin.c Sun Jan 6 01:38:26 2002 @@ -30,7 +30,6 @@ static struct map_desc pangolin_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ LAST_DESC }; @@ -43,6 +42,12 @@ sa1100_register_uart(0, 1); sa1100_register_uart(1, 3); Ser1SDCR0 |= SDCR0_UART; + + /* set some GPDR bits while it's safe */ + GPDR |= GPIO_PCMCIA_RESET; +#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE + GPDR |= GPIO_PCMCIA_BUS_ON; +#endif } MACHINE_START(PANGOLIN, "Dialogue-Pangolin") diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/pfs168.c linux-2.5/arch/arm/mach-sa1100/pfs168.c --- linux-2.5.1/arch/arm/mach-sa1100/pfs168.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-sa1100/pfs168.c Sun Jan 6 01:38:26 2002 @@ -6,6 +6,7 @@ #include <linux/kernel.h> #include <linux/tty.h> #include <linux/errno.h> +#include <linux/ioport.h> #include <asm/hardware.h> #include <asm/setup.h> @@ -34,7 +35,7 @@ /* * Probe for SA1111. */ - ret = sa1111_probe(); + ret = sa1111_probe(0x40000000); if (ret < 0) return ret; @@ -65,8 +66,7 @@ */ sa1110_mb_enable(); - set_GPIO_IRQ_edge(GPIO_GPIO(25), GPIO_RISING_EDGE); - sa1111_init_irq(SA1100_GPIO_TO_IRQ(25)); /* SA1111 IRQ on GPIO 25 */ + sa1111_init_irq(IRQ_GPIO25); /* SA1111 IRQ on GPIO 25 */ return 0; } @@ -84,6 +84,8 @@ */ set_GPIO_IRQ_edge(GPIO_GPIO(19), GPIO_RISING_EDGE); set_GPIO_IRQ_edge(GPIO_GPIO(20), GPIO_RISING_EDGE); + set_GPIO_IRQ_edge(GPIO_GPIO(25), GPIO_RISING_EDGE); + set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ, GPIO_RISING_EDGE); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/pm.c linux-2.5/arch/arm/mach-sa1100/pm.c --- linux-2.5.1/arch/arm/mach-sa1100/pm.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/pm.c Sun Jan 6 01:38:26 2002 @@ -19,30 +19,27 @@ * Cleaned up, pushed platform dependent stuff * in the platform specific files. */ - -/* - * Debug macros - */ -#define DEBUG 1 -#ifdef DEBUG -# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) -#else -# define DPRINTK(fmt, args...) -#endif - - +#include <linux/config.h> #include <linux/init.h> #include <linux/pm.h> #include <linux/slab.h> +#include <linux/sched.h> +#include <linux/interrupt.h> #include <linux/sysctl.h> -#include <linux/acpi.h> +#include <linux/errno.h> #include <asm/hardware.h> #include <asm/memory.h> #include <asm/system.h> +#include <asm/leds.h> #include "sleep.h" +/* + * Debug macros + */ +#undef DEBUG + extern void sa1100_cpu_suspend(void); extern void sa1100_cpu_resume(void); @@ -57,19 +54,16 @@ int retval; /* set up pointer to sleep parameters */ - sleep_save = kmalloc (SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC); + sleep_save = kmalloc(SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC); if (!sleep_save) return -ENOMEM; - sleep_save_p = virt_to_phys(sleep_save); - retval = pm_send_all(PM_SUSPEND, (void *)2); - if (retval) { - kfree(sleep_save); - return retval; - } + sleep_save_p = virt_to_phys(sleep_save); cli(); + leds_event(led_stop); + /* preserve current time */ RCNR = xtime.tv_sec; @@ -112,7 +106,9 @@ /* ensure not to come back here if it wasn't intended */ PSPR = 0; - DPRINTK("*** made it back from resume\n"); +#ifdef DEBUG + printk("*** made it back from resume\n"); +#endif /* restore registers */ RESTORE(GPDR); @@ -146,21 +142,61 @@ /* restore current time */ xtime.tv_sec = RCNR; + leds_event(led_start); + sti(); kfree (sleep_save); - retval = pm_send_all(PM_RESUME, (void *)0); - if (retval) - return retval; + /* + * Restore the CPU frequency settings. + */ +#ifdef CONFIG_CPU_FREQ + cpufreq_restore(); +#endif return 0; } +#ifdef CONFIG_SYSCTL +/* + * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than + * linux/sysctl.h. + * + * This means our interface here won't survive long - it needs a new + * interface. Quick hack to get this working - use sysctl id 9999. + */ +#warning ACPI broke the kernel, this interface needs to be fixed up. +#define CTL_ACPI 9999 +#define ACPI_S1_SLP_TYP 19 + +/* + * Send us to sleep. We must not be called from IRQ context. + */ +static int sysctl_pm_do_suspend(void) +{ + int retval; + + if (in_interrupt()) { + printk(KERN_CRIT "pm_do_suspend() called from IRQ\n"); + return -EINVAL; + } + + retval = pm_send_all(PM_SUSPEND, (void *)3); + + if (retval == 0) { + retval = __pm_do_suspend(); + + pm_send_all(PM_RESUME, (void *)0); + } + + return retval; +} + static struct ctl_table pm_table[] = { - {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&pm_do_suspend}, + {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend}, {0} }; @@ -181,3 +217,4 @@ __initcall(pm_init); +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/sa1111.c linux-2.5/arch/arm/mach-sa1100/sa1111.c --- linux-2.5.1/arch/arm/mach-sa1100/sa1111.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-sa1100/sa1111.c Sun Jan 6 01:38:26 2002 @@ -9,12 +9,12 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * This file contains all generic SA1111 support, except for DMA which is - * provided separately in dma-sa1111.c. + * This file contains all generic SA1111 support. * * All initialization functions provided here are intended to be called * from machine specific code with proper arguments when required. */ +#include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -22,57 +22,80 @@ #include <linux/interrupt.h> #include <linux/ptrace.h> #include <linux/errno.h> +#include <linux/ioport.h> #include <asm/hardware.h> #include <asm/irq.h> #include <asm/mach/irq.h> #include <asm/arch/irq.h> +#include <asm/hardware/sa1111.h> + #include "sa1111.h" +struct resource sa1111_resource = { + name: "SA1111", +}; + +EXPORT_SYMBOL(sa1111_resource); + /* - * SA1111 Interrupt support + * SA1111 interrupt support */ - -void sa1111_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ) +void sa1111_IRQ_demux(int irq, void *dev_id, struct pt_regs *regs) { - int i; unsigned long stat0, stat1; - for(;;) { - stat0 = INTSTATCLR0, stat1 = INTSTATCLR1; - if( !stat0 && !stat1 ) break; - if( stat0 ) - for( i = 0; i < 32; i++ ) - if( stat0 & (1<<i) ) - do_IRQ( SA1111_IRQ(i), regs ); - - if( stat1 ) - for( i = 32; i < 55; i++ ) - if( stat1 & (1<<(i-32)) ) - do_IRQ( SA1111_IRQ(i), regs ); + while (1) { + int i; + + stat0 = INTSTATCLR0; + stat1 = INTSTATCLR1; + + if (stat0 == 0 && stat1 == 0) + break; + + for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1) + if (stat0 & 1) + do_IRQ(i, regs); + + for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) + if (stat1 & 1) + do_IRQ(i, regs); } } -static struct irqaction sa1111_irq = { - name: "SA1111", - handler: sa1111_IRQ_demux, - flags: SA_INTERRUPT -}; +#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) +#define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) +/* + * A note about masking IRQs: + * + * The GPIO IRQ edge detection only functions while the IRQ itself is + * enabled; edges are not detected while the IRQ is disabled. + * + * This is especially important for the PCMCIA signals, where we must + * pick up every transition. We therefore do not disable the IRQs + * while processing them. + * + * However, since we are changed to a GPIO on the host processor, + * all SA1111 IRQs will be disabled while we're processing any SA1111 + * IRQ. + * + * Note also that changing INTPOL while an IRQ is enabled will itself + * trigger an IRQ. + */ static void sa1111_mask_and_ack_lowirq(unsigned int irq) { - unsigned int mask = 1 << (irq - SA1111_IRQ(0)); + unsigned int mask = SA1111_IRQMASK_LO(irq); - // broken hardware: interrupt events are lost if they occur - // while the interrupts are disabled. //INTEN0 &= ~mask; INTSTATCLR0 = mask; } static void sa1111_mask_and_ack_highirq(unsigned int irq) { - unsigned int mask = 1 << (irq - SA1111_IRQ(32)); + unsigned int mask = SA1111_IRQMASK_HI(irq); //INTEN1 &= ~mask; INTSTATCLR1 = mask; @@ -80,27 +103,29 @@ static void sa1111_mask_lowirq(unsigned int irq) { - //INTEN0 &= ~(1 << (irq - SA1111_IRQ(0))); + INTEN0 &= ~SA1111_IRQMASK_LO(irq); } static void sa1111_mask_highirq(unsigned int irq) { - //INTEN1 &= ~(1 << (irq - SA1111_IRQ(32))); + INTEN1 &= ~SA1111_IRQMASK_HI(irq); } static void sa1111_unmask_lowirq(unsigned int irq) { - INTEN0 |= 1 << (irq - SA1111_IRQ(0)); + INTEN0 |= SA1111_IRQMASK_LO(irq); } static void sa1111_unmask_highirq(unsigned int irq) { - INTEN1 |= 1 << ((irq - SA1111_IRQ(32))); + INTEN1 |= SA1111_IRQMASK_HI(irq); } void __init sa1111_init_irq(int irq_nr) { - int irq; + int irq, ret; + + request_mem_region(_INTTEST0, 512, "irqs"); /* disable all IRQs */ INTEN0 = 0; @@ -111,21 +136,21 @@ * specifies that S0ReadyInt and S1ReadyInt should be '1'. */ INTPOL0 = 0; - INTPOL1 = 1 << (S0_READY_NINT - SA1111_IRQ(32)) | - 1 << (S1_READY_NINT - SA1111_IRQ(32)); + INTPOL1 = SA1111_IRQMASK_HI(S0_READY_NINT) | + SA1111_IRQMASK_HI(S1_READY_NINT); /* clear all IRQs */ INTSTATCLR0 = -1; INTSTATCLR1 = -1; - for (irq = SA1111_IRQ(0); irq <= SA1111_IRQ(26); irq++) { + for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { irq_desc[irq].valid = 1; irq_desc[irq].probe_ok = 0; irq_desc[irq].mask_ack = sa1111_mask_and_ack_lowirq; irq_desc[irq].mask = sa1111_mask_lowirq; irq_desc[irq].unmask = sa1111_unmask_lowirq; } - for (irq = SA1111_IRQ(32); irq <= SA1111_IRQ(54); irq++) { + for (irq = AUDXMTDMADONEA; irq <= S1_BVD1_STSCHG; irq++) { irq_desc[irq].valid = 1; irq_desc[irq].probe_ok = 0; irq_desc[irq].mask_ack = sa1111_mask_and_ack_highirq; @@ -134,28 +159,60 @@ } /* Register SA1111 interrupt */ - if (irq_nr >= 0) - setup_arm_irq(irq_nr, &sa1111_irq); + if (irq_nr < 0) + return; + + ret = request_irq(irq_nr, sa1111_IRQ_demux, SA_INTERRUPT, + "SA1111", NULL); + if (ret < 0) + printk(KERN_ERR "SA1111: unable to claim IRQ%d: %d\n", + irq_nr, ret); } -/* - * Probe for a SA1111 chip. +/** + * sa1111_probe - probe for a single SA1111 chip. + * @phys_addr: physical address of device. + * + * Probe for a SA1111 chip. This must be called + * before any other SA1111-specific code. + * + * Returns: + * %-ENODEV device not found. + * %-EBUSY physical address already marked in-use. + * %0 successful. */ - -int __init sa1111_probe(void) +int __init sa1111_probe(unsigned long phys_addr) { - unsigned long id = SBI_SKID; + unsigned long id; int ret = -ENODEV; - if ((id & SKID_ID_MASK) == SKID_SA1111_ID) { - printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: " - "silicon revision %lx, metal revision %lx\n", - (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); - ret = 0; - } else { + sa1111_resource.start = phys_addr; + sa1111_resource.end = phys_addr + 0x2000; + + if (request_resource(&iomem_resource, &sa1111_resource)) { + ret = -EBUSY; + goto out; + } + + /* + * Probe for the chip. Only touch the SBI registers. + */ + id = SBI_SKID; + if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { printk(KERN_DEBUG "SA-1111 not detected: ID = %08lx\n", id); + ret = -ENODEV; + goto release; } + printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: " + "silicon revision %lx, metal revision %lx\n", + (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); + + return 0; + + release: + release_resource(&sa1111_resource); + out: return ret; } @@ -175,6 +232,10 @@ */ void sa1111_wake(void) { + unsigned long flags; + + local_irq_save(flags); + /* * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: * (SA-1110 Developer's Manual, section 9.1.2.1) @@ -210,6 +271,8 @@ * Ensure all clocks are initially off. */ SKPCR = 0; + + local_irq_restore(flags); } void sa1111_doze(void) @@ -242,12 +305,17 @@ */ void __init sa1110_mb_disable(void) { + unsigned long flags; + + local_irq_save(flags); + PGSR &= ~GPIO_MBGNT; GPCR = GPIO_MBGNT; GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT; GAFR &= ~(GPIO_MBGNT | GPIO_MBREQ); + local_irq_restore(flags); } /* @@ -256,10 +324,85 @@ */ void __init sa1110_mb_enable(void) { + unsigned long flags; + + local_irq_save(flags); + PGSR &= ~GPIO_MBGNT; GPCR = GPIO_MBGNT; GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT; GAFR |= (GPIO_MBGNT | GPIO_MBREQ); TUCR |= TUCR_MR; + + local_irq_restore(flags); +} + +EXPORT_SYMBOL(sa1111_wake); +EXPORT_SYMBOL(sa1111_doze); + +/* According to the "Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update" (June 2000), erratum #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() || machine_is_pfs168()) && addr >= 0xc8000000) + 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(SBI_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%lo\n", + __FUNCTION__, FExtr(SBI_SMCR, SMCR_DRAC)); + return -1; + } + + return 0; } + +EXPORT_SYMBOL(sa1111_check_dma_bug); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/sa1111.h linux-2.5/arch/arm/mach-sa1100/sa1111.h --- linux-2.5.1/arch/arm/mach-sa1100/sa1111.h Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-sa1100/sa1111.h Sun Jan 6 01:38:26 2002 @@ -11,7 +11,7 @@ /* * Probe for a SA1111 chip. */ -extern int sa1111_probe(void); +extern int sa1111_probe(unsigned long phys); /* * Wake up a SA1111 chip. @@ -30,5 +30,5 @@ extern void sa1111_init_irq(int irq_nr); -extern void sa1111_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ); +extern void sa1111_IRQ_demux(int irq, void *dev_id, struct pt_regs *regs); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/shannon.c linux-2.5/arch/arm/mach-sa1100/shannon.c --- linux-2.5.1/arch/arm/mach-sa1100/shannon.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-sa1100/shannon.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,40 @@ +/* + * linux/arch/arm/mach-sa1100/shannon.c + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/tty.h> + +#include <asm/hardware.h> +#include <asm/setup.h> +#include <asm/irq.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/serial_sa1100.h> + +#include "generic.h" + + +static void __init shannon_map_io(void) +{ + sa1100_map_io(); + + sa1100_register_uart(0, 3); + sa1100_register_uart(1, 1); + Ser1SDCR0 |= SDCR0_SUS; + GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD); + GPDR |= GPIO_UART_TXD; + GPDR &= ~GPIO_UART_RXD; + PPAR |= PPAR_UPR; + + set_GPIO_IRQ_edge(SHANNON_GPIO_IRQ_CODEC); +} + +MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + MAPIO(shannon_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/sherman.c linux-2.5/arch/arm/mach-sa1100/sherman.c --- linux-2.5.1/arch/arm/mach-sa1100/sherman.c Mon Aug 13 00:36:24 2001 +++ linux-2.5/arch/arm/mach-sa1100/sherman.c Sun Jan 6 01:38:26 2002 @@ -29,16 +29,9 @@ // setup_initrd( 0xc0400000, 8*1024*1024 ); } -static struct map_desc sherman_io_desc[] __initdata = { - /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash*/ - LAST_DESC -}; - static void __init sherman_map_io(void) { sa1100_map_io(); - iotable_init(sherman_io_desc); sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/simpad.c linux-2.5/arch/arm/mach-sa1100/simpad.c --- linux-2.5.1/arch/arm/mach-sa1100/simpad.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/simpad.c Sun Jan 6 01:38:26 2002 @@ -23,18 +23,6 @@ long cs3_shadow; -static int __init simpad_init(void) -{ - PSPR = 0xc0008000; - GPDR &= ~GPIO_GPIO0; - cs3_shadow = (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON | - ENABLE_5V | RESET_SIMCARD); - *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow; - return 0; -} - -__initcall(simpad_init); - long get_cs3_shadow() { return cs3_shadow; @@ -70,7 +58,6 @@ static struct map_desc simpad_io_desc[] __initdata = { /* virtual physical length domain r w c b */ - { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */ LAST_DESC @@ -96,11 +83,17 @@ sa1100_map_io(); iotable_init(simpad_io_desc); -#ifndef CONFIG_SERIAL_SA1100_OLD + PSPR = 0xc0008000; + GPDR &= ~GPIO_GPIO0; + cs3_shadow = (EN1 | EN0 | LED2_ON | DISPLAY_ON | RS232_ON | + ENABLE_5V | RESET_SIMCARD); + *(CS3BUSTYPE *)(CS3_BASE) = cs3_shadow; + //It is only possible to register 3 UART in serial_sa1100.c sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); -#endif + + set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ); } #ifdef CONFIG_PROC_FS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/sleep.S linux-2.5/arch/arm/mach-sa1100/sleep.S --- linux-2.5.1/arch/arm/mach-sa1100/sleep.S Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-sa1100/sleep.S Sun Jan 6 01:38:26 2002 @@ -176,7 +176,7 @@ ENTRY(sa1100_cpu_resume) @ set SVC, irqs off - mov r0, #I_BIT | MODE_SVC + mov r0, #PSR_F_BIT | PSR_I_BIT | MODE_SVC msr cpsr_c, r0 @ load physical address of sleep_save diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/system3.c linux-2.5/arch/arm/mach-sa1100/system3.c --- linux-2.5.1/arch/arm/mach-sa1100/system3.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-sa1100/system3.c Sun Jan 6 13:32:34 2002 @@ -0,0 +1,482 @@ +/* + * linux/arch/arm/mach-sa1100/system3.c + * + * Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de> + * + * $Id: system3.c,v 1.1 2002/01/06 13:32:34 davej Exp $ + * + * This file contains all PT Sytsem 3 tweaks. Based on original work from + * Nicolas Pitre's assabet fixes + * + * 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. + * + * $Log: system3.c,v $ + * Revision 1.1 2002/01/06 13:32:34 davej + * more arm bits + * + * Revision 1.1.6.1 2001/12/04 17:28:06 seletz + * - merged from previous branch + * + * Revision 1.1.4.3 2001/12/04 15:16:31 seletz + * - merged from linux_2_4_13_ac5_rmk2 + * + * Revision 1.1.4.2 2001/11/19 17:18:57 seletz + * - more code cleanups + * + * Revision 1.1.4.1 2001/11/16 13:52:05 seletz + * - PT Digital Board Support Code + * + * Revision 1.1.2.2 2001/11/05 16:46:18 seletz + * - cleanups + * + * Revision 1.1.2.1 2001/10/15 16:00:43 seletz + * - first revision working with new board + * + * + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/cpufreq.h> + +#include <asm/hardware.h> +#include <asm/setup.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/irq.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> +#include <asm/mach/serial_sa1100.h> + +#include <asm/arch/irq.h> + +#include <linux/serial_core.h> + +#include "generic.h" +#include "sa1111.h" + +#define DEBUG 1 + +#ifdef DEBUG +# define DPRINTK( x, args... ) printk( "%s: line %d: "x, __FUNCTION__, __LINE__, ## args ); +#else +# define DPRINTK( x, args... ) /* nix */ +#endif + +/********************************************************************** + * prototypes + */ + +/* init funcs */ +static void __init fixup_system3(struct machine_desc *desc, + struct param_struct *params, char **cmdline, struct meminfo *mi); +static void __init get_system3_scr(void); +static int __init system3_init(void); +static void __init system3_init_irq(void); +static void __init system3_map_io(void); + +static void system3_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ); +static int system3_get_mctrl(struct uart_port *port); +static void system3_set_mctrl(struct uart_port *port, u_int mctrl); +static void system3_uart_pm(struct uart_port *port, u_int state, u_int oldstate); +static int sdram_notifier(struct notifier_block *nb, unsigned long event, void *data); + +static int system3_lcd_power(int on); +static int system3_backlight_power(int on); + +extern void convert_to_tag_list(struct param_struct *params, int mem_init); + + +/********************************************************************** + * global data + */ + +/********************************************************************** + * static data + */ + +static struct map_desc system3_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ + { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + LAST_DESC +}; + +static struct sa1100_port_fns system3_port_fns __initdata = { + set_mctrl: system3_set_mctrl, + get_mctrl: system3_get_mctrl, + pm: system3_uart_pm, +}; + +static struct irqaction system3_irq = { + name: "PT Digital Board SA1111 IRQ", + handler: system3_IRQ_demux, + flags: SA_INTERRUPT +}; + +static struct notifier_block system3_clkchg_block = { + notifier_call: sdram_notifier, +}; + +/********************************************************************** + * Static functions + */ + +static void __init system3_map_io(void) +{ + DPRINTK( "%s\n", "START" ); + sa1100_map_io(); + iotable_init(system3_io_desc); + + sa1100_register_uart_fns(&system3_port_fns); + sa1100_register_uart(0, 1); /* com port */ + sa1100_register_uart(1, 2); + sa1100_register_uart(2, 3); /* radio module */ + + Ser1SDCR0 |= SDCR0_SUS; +} + + +/********************************************************************* + * Install IRQ handler + */ +static void system3_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ) +{ + u_char irr; + + for(;;){ + //irr = PTCPLD_REG_IRQSR & (PT_IRQ_LAN | PT_IRQ_USAR | PT_IRQ_SA1111); + irr = PT_IRQSR & (PT_IRQ_LAN | PT_IRQ_SA1111); + + irr ^= (PT_IRQ_LAN); + if (!irr) break; + + if( irr & PT_IRQ_LAN ) + do_IRQ(IRQ_SYSTEM3_SMC9196, regs); + +#if 0 + /* Highspeed Serial Bus not yet used */ + if( irr & PT_IRQ_USAR ) + do_IRQ(PT_USAR_IRQ, regs); +#endif + + if( irr & PT_IRQ_SA1111 ) + sa1111_IRQ_demux(irq, dev_id, regs); + } +} + + +static void __init system3_init_irq(void) +{ + int irq; + + DPRINTK( "%s\n", "START" ); + + /* SA1111 IRQ not routed to a GPIO. */ + sa1111_init_irq(-1); + + /* setup extra IRQs */ + irq = IRQ_SYSTEM3_SMC9196; + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + +#if 0 + /* Highspeed Serial Bus not yet used */ + irq = PT_USAR_IRQ; + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; +#endif + + /* IRQ by CPLD */ + set_GPIO_IRQ_edge( GPIO_GPIO(25), GPIO_RISING_EDGE ); + setup_arm_irq( IRQ_GPIO25, &system3_irq ); +} + +/********************************************************************** + * On system 3 limit cpu frequency to 206 Mhz + */ +static int sdram_notifier(struct notifier_block *nb, unsigned long event, + void *data) +{ + switch (event) { + case CPUFREQ_MINMAX: + cpufreq_updateminmax(data, 147500, 206000); + break; + + } + return 0; +} + +/** + * fixup_system3 - fixup function for system 3 board + * @desc: machine description + * @param: kernel params + * @cmdline: kernel cmdline + * @mi: memory info struct + * + */ +static void __init fixup_system3(struct machine_desc *desc, + struct param_struct *params, char **cmdline, struct meminfo *mi) +{ + DPRINTK( "%s\n", "START" ); + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( 0xc0800000, 8*1024*1024 ); +} + + +/** + * system3_uart_pm - powermgmt callback function for system 3 UART + * @port: uart port structure + * @state: pm state + * @oldstate: old pm state + * + */ +static void system3_uart_pm(struct uart_port *port, u_int state, u_int oldstate) +{ + /* TODO: switch on/off uart in powersave mode */ +} + +/* + * Note! this can be called from IRQ context. + * FIXME: Handle PT Digital Board CTRL regs irq-safe. + * + * NB: system3 uses COM_RTS and COM_DTR for both UART1 (com port) + * and UART3 (radio module). We only handle them for UART1 here. + */ +static void system3_set_mctrl(struct uart_port *port, u_int mctrl) +{ + if (port->mapbase == _Ser1UTCR0) { + u_int set = 0, clear = 0; + + if (mctrl & TIOCM_RTS) + set |= PT_CTRL2_RS1_RTS; + else + clear |= PT_CTRL2_RS1_RTS; + + if (mctrl & TIOCM_DTR) + set |= PT_CTRL2_RS1_DTR; + else + clear |= PT_CTRL2_RS1_DTR; + + PTCTRL2_clear(clear); + PTCTRL2_set(set); + } +} + +static int system3_get_mctrl(struct uart_port *port) +{ + u_int ret = 0; + u_int irqsr = PT_IRQSR; + + /* need 2 reads to read current value */ + irqsr = PT_IRQSR; + + /* TODO: check IRQ source register for modem/com + status lines and set them correctly. */ + + ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; + + return ret; +} + +/** + * system3_lcd_backlight_on - switch system 3 lcd backlight on + * + */ +int system3_lcd_backlight_on( void ) +{ + PTCTRL0_set( PT_CTRL0_LCD_BL ); + return 0; +} + +/** + * system3_lcd_backlight_off - switch system 3 lcd backlight off + * + */ +static void system3_lcd_backlight_off(void) +{ + PTCTRL0_clear( PT_CTRL0_LCD_BL ); +} + +/** + * system3_lcd_on - switch system 3 lcd on + * + */ +static void system3_lcd_on(void) +{ + DPRINTK( "%s\n", "START" ); + PTCTRL0_set( PT_CTRL0_LCD_EN ); + + /* brightness / contrast */ + SKPCR |= SKPCR_PWMCLKEN; + PB_DDR = 0xFFFFFFFF; + SKPEN0 = 1; + SKPEN1 = 1; +} + +/** + * system3_lcd_off - switch system 3 lcd off + * + */ +static void system3_lcd_off(void) +{ + DPRINTK( "%s\n", "START" ); + PTCTRL0_clear( PT_CTRL0_LCD_EN ); + SKPEN0 = 0; + SKPEN1 = 0; + SKPCR &= ~SKPCR_PWMCLKEN; +} + +/** + * system3_lcd_contrast - set system 3 contrast + * @value: the new contrast + * + */ +static void system3_lcd_contrast(unsigned char value) +{ + DPRINTK( "value=0x%02x\n", value ); + SYS3LCDCONTR = value; +} + +/** + * system3_lcd_brightness - set system 3 brightness + * @value: the new brightness + * + */ +static void system3_lcd_brightness(unsigned char value) +{ + DPRINTK( "value=0x%02x\n", value ); + SYS3LCDBRIGHT = value; +} + +static void system3_lcd_power(int on) +{ +#error why is backlight stuff here??? + if (on) { + system3_lcd_on(); + system3_lcd_backlight_on(); + system3_lcd_contrast(0x95); + system3_lcd_brightness(240); + } else { + system3_lcd_off(); + } +} + +static void system3_backlight_power(int on) +{ + if (on) { + system3_lcd_backlight_on(); + system3_lcd_contrast(0x95); + system3_lcd_brightness(240); + } else { + system3_lcd_backlight_off(); + } +} + +static int __init system3_init(void) +{ + int ret = 0; + DPRINTK( "%s\n", "START" ); + + if ( !machine_is_pt_system3() ) { + ret = -EINVAL; + goto DONE; + } + + sa1100fb_lcd_power = system3_lcd_power; + sa1100fb_backlight_power = system3_backlight_power; + + /* init control register */ + PT_CTRL0 = PT_CTRL0_INIT; + PT_CTRL1 = 0x02; + PT_CTRL2 = 0x00; + DPRINTK( "CTRL[0]=0x%02x\n", PT_CTRL0 ); + DPRINTK( "CTRL[1]=0x%02x\n", PT_CTRL1 ); + DPRINTK( "CTRL[2]=0x%02x\n", PT_CTRL2 ); + + /* + * Ensure that the memory bus request/grant signals are setup, + * and the grant is held in its inactive state. + */ + sa1110_mb_disable(); + + /* + * Probe for a SA1111. + */ + ret = sa1111_probe(0x40000000); + if (ret < 0) { + printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" ); + goto DONE; + } + + /* + * We found it. Wake the chip up. + */ + sa1111_wake(); + + /* + * The SDRAM configuration of the SA1110 and the SA1111 must + * match. This is very important to ensure that SA1111 accesses + * don't corrupt the SDRAM. Note that this ungates the SA1111's + * MBGNT signal, so we must have called sa1110_mb_disable() + * beforehand. + */ + sa1111_configure_smc(1, + FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), + FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); + + /* + * We only need to turn on DCLK whenever we want to use the + * DMA. It can otherwise be held firmly in the off position. + */ + SKPCR |= SKPCR_DCLKEN; + + /* + * Enable the SA1110 memory bus request and grant signals. + */ + sa1110_mb_enable(); + + system3_init_irq(); + +#if defined( CONFIG_CPU_FREQ ) + ret = cpufreq_register_notifier(&system3_clkchg_block); + if ( ret != 0 ) { + printk( KERN_WARNING"PT Digital Board: could not register clock scale callback\n" ); + goto DONE; + } +#endif + + ret = 0; +DONE: + DPRINTK( "ret=%d\n", ret ); + return ret; +} + +/********************************************************************** + * Exported Functions + */ + +/********************************************************************** + * kernel magic macros + */ +__initcall(system3_init); + +MACHINE_START(PT_SYSTEM3, "PT System 3") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_system3) + MAPIO(system3_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/xp860.c linux-2.5/arch/arm/mach-sa1100/xp860.c --- linux-2.5.1/arch/arm/mach-sa1100/xp860.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mach-sa1100/xp860.c Sun Jan 6 01:38:26 2002 @@ -7,6 +7,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/tty.h> +#include <linux/ioport.h> #include <asm/hardware.h> #include <asm/setup.h> @@ -21,6 +22,7 @@ static void xp860_power_off(void) { + cli(); GPDR |= GPIO_GPIO20; GPSR = GPIO_GPIO20; mdelay(1000); @@ -40,7 +42,7 @@ /* * Probe for SA1111. */ - ret = sa1111_probe(); + ret = sa1111_probe(0x40000000); if (ret < 0) return ret; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-sa1100/yopy.c linux-2.5/arch/arm/mach-sa1100/yopy.c --- linux-2.5.1/arch/arm/mach-sa1100/yopy.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-sa1100/yopy.c Sun Jan 6 01:38:26 2002 @@ -52,14 +52,16 @@ static int __init yopy_hw_init(void) { - YOPY_EGPIO = yopy_egpio; + if (machine_is_yopy()) { + YOPY_EGPIO = yopy_egpio; - /* Enable Output */ - PPDR |= PPC_L_BIAS; - PSDR &= ~PPC_L_BIAS; - PPSR |= PPC_L_BIAS; + /* Enable Output */ + PPDR |= PPC_L_BIAS; + PSDR &= ~PPC_L_BIAS; + PPSR |= PPC_L_BIAS; - YOPY_EGPIO = yopy_egpio; + YOPY_EGPIO = yopy_egpio; + } return 0; } @@ -82,6 +84,8 @@ iotable_init(yopy_io_desc); sa1100_register_uart(0, 3); + + set_GPIO_IRQ_edge(GPIO_UCB1200_IRQ, GPIO_RISING_EDGE); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-shark/Makefile linux-2.5/arch/arm/mach-shark/Makefile --- linux-2.5.1/arch/arm/mach-shark/Makefile Thu Apr 12 19:20:31 2001 +++ linux-2.5/arch/arm/mach-shark/Makefile Sun Jan 6 01:38:26 2002 @@ -11,7 +11,7 @@ # Object file lists. -obj-y := arch.o dma.o mm.o pci.o +obj-y := core.o dma.o irq.o pci.o obj-m := obj-n := obj- := diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-shark/arch.c linux-2.5/arch/arm/mach-shark/arch.c --- linux-2.5.1/arch/arm/mach-shark/arch.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mach-shark/arch.c Thu Jan 1 00:00:00 1970 @@ -1,27 +0,0 @@ -/* - * linux/arch/arm/mach-shark/arch.c - * - * Architecture specific stuff. - */ -#include <linux/tty.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/init.h> - -#include <asm/hardware/dec21285.h> -#include <asm/elf.h> -#include <asm/setup.h> -#include <asm/mach-types.h> - -#include <asm/mach/arch.h> - -extern void shark_map_io(void); -extern void genarch_init_irq(void); - -MACHINE_START(SHARK, "Shark") - MAINTAINER("Alexander Schulz") - BOOT_MEM(0x08000000, 0x40000000, 0xe0000000) - BOOT_PARAMS(0x08003000) - MAPIO(shark_map_io) - INITIRQ(genarch_init_irq) -MACHINE_END diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-shark/core.c linux-2.5/arch/arm/mach-shark/core.c --- linux-2.5.1/arch/arm/mach-shark/core.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-shark/core.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,41 @@ +/* + * linux/arch/arm/mach-shark/arch.c + * + * Architecture specific stuff. + */ +#include <linux/tty.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/elf.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/io.h> + +#include <asm/mach/map.h> +#include <asm/mach/arch.h> + +extern void shark_init_irq(void); + +static struct map_desc shark_io_desc[] __initdata = { + { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +static void __init shark_map_io(void) +{ + iotable_init(shark_io_desc); +} + +MACHINE_START(SHARK, "Shark") + MAINTAINER("Alexander Schulz") + BOOT_MEM(0x08000000, 0x40000000, 0xe0000000) + BOOT_PARAMS(0x08003000) + MAPIO(shark_map_io) + INITIRQ(shark_init_irq) +MACHINE_END diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-shark/irq.c linux-2.5/arch/arm/mach-shark/irq.c --- linux-2.5.1/arch/arm/mach-shark/irq.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-shark/irq.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,124 @@ +/* + * linux/arch/arm/mach-shark/irq.c + * + * by Alexander Schulz + * + * derived from linux/arch/ppc/kernel/i8259.c and: + * include/asm-arm/arch-ebsa110/irq.h + * Copyright (C) 1996-1998 Russell King + */ +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/mach/irq.h> + +/* + * 8259A PIC functions to handle ISA devices: + */ + +/* + * This contains the irq mask for both 8259A irq controllers, + * Let through the cascade-interrupt no. 2 (ff-(1<<2)==fb) + */ +static unsigned char cached_irq_mask[2] = { 0xfb, 0xff }; + +/* + * These have to be protected by the irq controller spinlock + * before being called. + */ +static void shark_disable_8259A_irq(unsigned int irq) +{ + unsigned int mask; + if (irq<8) { + mask = 1 << irq; + cached_irq_mask[0] |= mask; + } else { + mask = 1 << (irq-8); + cached_irq_mask[1] |= mask; + } + outb(cached_irq_mask[1],0xA1); + outb(cached_irq_mask[0],0x21); +} + +static void shark_enable_8259A_irq(unsigned int irq) +{ + unsigned int mask; + if (irq<8) { + mask = ~(1 << irq); + cached_irq_mask[0] &= mask; + } else { + mask = ~(1 << (irq-8)); + cached_irq_mask[1] &= mask; + } + outb(cached_irq_mask[1],0xA1); + outb(cached_irq_mask[0],0x21); +} + +/* + * Careful! The 8259A is a fragile beast, it pretty + * much _has_ to be done exactly like this (mask it + * first, _then_ send the EOI, and the order of EOI + * to the two 8259s is important! + */ +static void shark_mask_and_ack_8259A_irq(unsigned int irq) +{ + if (irq & 8) { + cached_irq_mask[1] |= 1 << (irq-8); + inb(0xA1); /* DUMMY */ + outb(cached_irq_mask[1],0xA1); + } else { + cached_irq_mask[0] |= 1 << irq; + outb(cached_irq_mask[0],0x21); + } +} + +static void bogus_int(int irq, void *dev_id, struct pt_regs *regs) +{ + printk("Got interrupt %i!\n",irq); +} + +static struct irqaction cascade; + +void __init shark_init_irq(void) +{ + int irq; + + for (irq = 0; irq < NR_IRQS; irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = shark_mask_and_ack_8259A_irq; + irq_desc[irq].mask = shark_disable_8259A_irq; + irq_desc[irq].unmask = shark_enable_8259A_irq; + } + + /* The PICs are initialized to level triggered and auto eoi! + * If they are set to edge triggered they lose some IRQs, + * if they are set to manual eoi they get locked up after + * a short time + */ + + /* init master interrupt controller */ + outb(0x19, 0x20); /* Start init sequence, level triggered */ + outb(0x00, 0x21); /* Vector base */ + outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */ + outb(0x03, 0x21); /* Select 8086 mode , auto eoi*/ + outb(0x0A, 0x20); + /* init slave interrupt controller */ + outb(0x19, 0xA0); /* Start init sequence, level triggered */ + outb(0x08, 0xA1); /* Vector base */ + outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */ + outb(0x03, 0xA1); /* Select 8086 mode, auto eoi */ + outb(0x0A, 0xA0); + outb(cached_irq_mask[1],0xA1); + outb(cached_irq_mask[0],0x21); + //request_region(0x20,0x2,"pic1"); + //request_region(0xA0,0x2,"pic2"); + + cascade.handler = bogus_int; + cascade.flags = 0; + cascade.mask = 0; + cascade.name = "cascade"; + cascade.next = NULL; + cascade.dev_id = NULL; + setup_arm_irq(2,&cascade); +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-shark/mm.c linux-2.5/arch/arm/mach-shark/mm.c --- linux-2.5.1/arch/arm/mach-shark/mm.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mach-shark/mm.c Thu Jan 1 00:00:00 1970 @@ -1,28 +0,0 @@ -/* - * linux/arch/arm/mach-shark/mm.c - * - * by Alexander Schulz - * - * 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/mm.h> -#include <linux/init.h> - -#include <asm/pgtable.h> -#include <asm/page.h> -#include <asm/io.h> - -#include <asm/mach/map.h> - -static struct map_desc shark_io_desc[] __initdata = { - { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, - LAST_DESC -}; - -void __init shark_map_io(void) -{ - iotable_init(shark_io_desc); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-tbox/Makefile linux-2.5/arch/arm/mach-tbox/Makefile --- linux-2.5.1/arch/arm/mach-tbox/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-tbox/Makefile Sun Jan 6 01:38:26 2002 @@ -0,0 +1,21 @@ +# +# 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 := tbox.o + +# Object file lists. + +obj-y := core.o +obj-m := +obj-n := +obj- := + +export-objs := + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mach-tbox/core.c linux-2.5/arch/arm/mach-tbox/core.c --- linux-2.5.1/arch/arm/mach-tbox/core.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-tbox/core.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,75 @@ +/* + * linux/arch/arm/mm/mm-tbox.c + * + * Copyright (C) 1998, 1999, 2000 Phil Blundell + * Copyright (C) 1998-1999 Russell King + * + * Extra MM routines for the Tbox architecture + */ +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/elf.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +extern unsigned long soft_irq_mask; + +static void tbox_mask_irq(unsigned int irq) +{ + __raw_writel(0, INTCONT + (irq << 2)); + soft_irq_mask &= ~(1<<irq); +} + +static void tbox_unmask_irq(unsigned int irq) +{ + soft_irq_mask |= (1<<irq); + __raw_writel(1, INTCONT + (irq << 2)); +} + +static void tbox_init_irq(void) +{ + unsigned int i; + + /* Disable all interrupts initially. */ + for (i = 0; i < NR_IRQS; i++) { + if (i <= 10 || (i >= 12 && i <= 13)) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 0; + irq_desc[i].mask_ack = tbox_mask_irq; + irq_desc[i].mask = tbox_mask_irq; + irq_desc[i].unmask = tbox_unmask_irq; + tbox_mask_irq(i); + } else { + irq_desc[i].valid = 0; + irq_desc[i].probe_ok = 0; + } + } +} + +static struct map_desc tbox_io_desc[] __initdata = { + /* See hardware.h for details */ + { IO_BASE, IO_START, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +static void __init tbox_map_io(void) +{ + iotable_init(tbox_io_desc); +} + +MACHINE_START(TBOX, "unknown-TBOX") + MAINTAINER("Philip Blundell") + BOOT_MEM(0x80000000, 0x00400000, 0xe0000000) + MAPIO(tbox_map_io) + INITIRQ(tbox_init_irq) +MACHINE_END + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/Makefile linux-2.5/arch/arm/mm/Makefile --- linux-2.5.1/arch/arm/mm/Makefile Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/arm/mm/Makefile Sun Jan 6 01:38:26 2002 @@ -13,38 +13,32 @@ # Object file lists. -obj-y := init.o +obj-y := init.o extable.o fault-common.o obj-m := obj-n := obj- := export-objs := proc-syms.o discontig.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) +ifeq ($(CONFIG_CPU_32),y) +obj-y += consistent.o fault-armv.o ioremap.o mm-armv.o +obj-$(CONFIG_MODULES) += proc-syms.o +endif +obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o 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 -p-$(CONFIG_CPU_ARM720T) += proc-arm720.o -p-$(CONFIG_CPU_ARM920T) += proc-arm920.o -p-$(CONFIG_CPU_ARM926T) += proc-arm926.o -p-$(CONFIG_CPU_ARM1020) += proc-arm1020.o -p-$(CONFIG_CPU_SA110) += proc-sa110.o -p-$(CONFIG_CPU_SA1100) += proc-sa110.o - -# Integrator follows "new style" -# Soon, others will do too, and we can get rid of this -MMMACH := mm-$(MACHINE).c -ifeq ($(MMMACH),$(wildcard $(MMMACH))) -obj-$(CONFIG_CPU_32) += $(MMMACH:.c=.o) -endif +p-$(CONFIG_CPU_ARM720T) += proc-arm720.o armv4t-late-abort.o +p-$(CONFIG_CPU_ARM920T) += proc-arm920.o armv4t-early-abort.o +p-$(CONFIG_CPU_ARM922T) += proc-arm922.o armv4t-early-abort.o +p-$(CONFIG_CPU_ARM926T) += proc-arm926.o armv5ej-early-abort.o +p-$(CONFIG_CPU_ARM1020) += proc-arm1020.o armv4t-early-abort.o +p-$(CONFIG_CPU_SA110) += proc-sa110.o armv4-early-abort.o +p-$(CONFIG_CPU_SA1100) += proc-sa110.o armv4-early-abort.o minicache.o +p-$(CONFIG_CPU_XSCALE) += proc-xscale.o armv4t-early-abort.o minicache.o obj-y += $(sort $(p-y)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/alignment.c linux-2.5/arch/arm/mm/alignment.c --- linux-2.5.1/arch/arm/mm/alignment.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/alignment.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,578 @@ +/* + * linux/arch/arm/mm/alignment.c + * + * Copyright (C) 1995 Linus Torvalds + * 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 + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/compiler.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/proc_fs.h> +#include <linux/bitops.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/pgalloc.h> +#include <asm/pgtable.h> +#include <asm/unaligned.h> + +/* + * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998 + * /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 code is not portable to processors with late data abort handling. + */ +#define CODING_BITS(i) (i & 0x0e000000) + +#define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */ +#define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */ +#define LDST_U_BIT(i) (i & (1 << 23)) /* Add offset */ +#define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */ +#define LDST_L_BIT(i) (i & (1 << 20)) /* Load */ + +#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0) + +#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */ +#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */ + +#define RN_BITS(i) ((i >> 16) & 15) /* Rn */ +#define RD_BITS(i) ((i >> 12) & 15) /* Rd */ +#define RM_BITS(i) (i & 15) /* Rm */ + +#define REGMASK_BITS(i) (i & 0xffff) +#define OFFSET_BITS(i) (i & 0x0fff) + +#define IS_SHIFT(i) (i & 0x0ff0) +#define SHIFT_BITS(i) ((i >> 7) & 0x1f) +#define SHIFT_TYPE(i) (i & 0x60) +#define SHIFT_LSL 0x00 +#define SHIFT_LSR 0x20 +#define SHIFT_ASR 0x40 +#define SHIFT_RORRRX 0x60 + +static unsigned long ai_user; +static unsigned long ai_sys; +static unsigned long ai_skipped; +static unsigned long ai_half; +static unsigned long ai_word; +static unsigned long ai_multi; +static int ai_usermode; + +#ifdef CONFIG_PROC_FS +static const char *usermode_action[] = { + "ignored", + "warn", + "fixup", + "fixup+warn", + "signal", + "signal+warn" +}; + +static int +proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + char *p = page; + int len; + + p += sprintf(p, "User:\t\t%lu\n", ai_user); + p += sprintf(p, "System:\t\t%lu\n", ai_sys); + p += sprintf(p, "Skipped:\t%lu\n", ai_skipped); + p += sprintf(p, "Half:\t\t%lu\n", ai_half); + p += sprintf(p, "Word:\t\t%lu\n", ai_word); + p += sprintf(p, "Multi:\t\t%lu\n", ai_multi); + p += sprintf(p, "User faults:\t%i (%s)\n", ai_usermode, + usermode_action[ai_usermode]); + + len = (p - page) - off; + if (len < 0) + len = 0; + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + return len; +} + +static int proc_alignment_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int mode; + + if (count > 0) { + if (get_user(mode, buffer)) + return -EFAULT; + if (mode >= '0' && mode <= '5') + ai_usermode = mode - '0'; + } + return count; +} + +/* + * This needs to be done after sysctl_init, otherwise sys/ will be + * overwritten. Actually, this shouldn't be in sys/ at all since + * it isn't a sysctl, and it doesn't contain sysctl information. + * We now locate it in /proc/cpu/alignment instead. + */ +static int __init alignment_init(void) +{ + struct proc_dir_entry *res; + + res = proc_mkdir("cpu", NULL); + if (!res) + return -ENOMEM; + + res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res); + if (!res) + return -ENOMEM; + + res->read_proc = proc_alignment_read; + res->write_proc = proc_alignment_write; + + return 0; +} + +__initcall(alignment_init); +#endif /* CONFIG_PROC_FS */ + +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], #1\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], #1\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_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs) +{ + unsigned int rd = RD_BITS(instr); + + if ((instr & 0x01f00ff0) == 0x01000090) + goto swp; + + 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; +} + +/* + * LDM/STM alignment handler. + * + * There are 4 variants of this instruction: + * + * B = rn pointer before instruction, A = rn pointer after instruction + * ------ increasing address -----> + * | | r0 | r1 | ... | rx | | + * PU = 01 B A + * PU = 11 B A + * PU = 00 A B + * PU = 10 A B + */ +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, newaddr; + + if (LDM_S_BIT(instr)) + goto bad; + + correction = 4; /* processor implementation defined */ + regs->ARM_pc += correction; + + ai_multi += 1; + + /* count the number of registers in the mask to be transferred */ + nr_regs = hweight16(REGMASK_BITS(instr)) * 4; + + rn = RN_BITS(instr); + newaddr = eaddr = regs->uregs[rn]; + + if (!LDST_U_BIT(instr)) + nr_regs = -nr_regs; + newaddr += nr_regs; + if (!LDST_U_BIT(instr)) + eaddr = newaddr; + + if (LDST_P_EQ_U(instr)) /* U = P */ + eaddr += 4; + + /* + * For alignment faults on the ARM922T the MMU makes + * the FSR (and hence addr) equal to the updated base address + * of the multiple access rather than the restored value. + * Switch this messsage off if we've got a ARM922, otherwise + * [ls]dm alignment faults are noisy! + */ +#if !(defined CONFIG_CPU_ARM922T) + /* + * 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); + show_regs(regs); + } +#endif + + 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); + else + put32_unaligned_check(regs->uregs[rd], eaddr); + eaddr += 4; + } + + if (LDST_W_BIT(instr)) + regs->uregs[rn] = newaddr; + if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15))) + regs->ARM_pc -= correction; + return TYPE_DONE; + +fault: + regs->ARM_pc -= correction; + return TYPE_FAULT; + +bad: + printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n"); + return TYPE_ERROR; +} + +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; + + instrptr = instruction_pointer(regs); + instr = *(unsigned long *)instrptr; + + if (user_mode(regs)) + goto user; + + ai_sys += 1; + + fixup: + + 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: /* ldr or str immediate */ + offset.un = OFFSET_BITS(instr); + handler = do_alignment_ldrstr; + break; + + case 0x06000000: /* ldr or str register */ + offset.un = regs->uregs[RM_BITS(instr)]; + + if (IS_SHIFT(instr)) { + unsigned int shiftval = SHIFT_BITS(instr); + + switch(SHIFT_TYPE(instr)) { + case SHIFT_LSL: + offset.un <<= shiftval; + break; + + case SHIFT_LSR: + offset.un >>= shiftval; + break; + + case SHIFT_ASR: + offset.sn >>= shiftval; + break; + + case SHIFT_RORRRX: + if (shiftval == 0) { + offset.un >>= 1; + if (regs->ARM_cpsr & PSR_C_BIT) + offset.un |= 1 << 31; + } else + offset.un = offset.un >> shiftval | + offset.un << (32 - shiftval); + break; + } + } + handler = do_alignment_ldrstr; + break; + + case 0x08000000: /* ldm or stm */ + handler = do_alignment_ldmstm; + break; + + default: + goto bad; + } + + type = handler(addr, instr, regs); + + if (type == TYPE_ERROR || type == TYPE_FAULT) + goto bad_or_fault; + + if (type == TYPE_LDST) + do_alignment_finish_ldst(addr, instr, regs, offset); + + return 0; + +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>]\n", instr, instrptr); + ai_skipped += 1; + return 1; + + user: + ai_user += 1; + + if (ai_usermode & 1) + printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%08lx " + "Address=0x%08lx Code 0x%02x\n", current->comm, + current->pid, instrptr, instr, addr, error_code); + + if (ai_usermode & 2) + goto fixup; + + if (ai_usermode & 4) + force_sig(SIGBUS, current); + else + set_cr(cr_no_alignment); + + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/armv4-early-abort.S linux-2.5/arch/arm/mm/armv4-early-abort.S --- linux-2.5.1/arch/arm/mm/armv4-early-abort.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/armv4-early-abort.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,29 @@ +#include <linux/linkage.h> +#include <asm/assembler.h> +/* + * Function: armv4_early_abort + * + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR + * + * Returns : r0 = address of abort + * : r1 = FSR, bit 8 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + */ + .align 5 +ENTRY(armv4_early_abort) + mrc p15, 0, r1, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + ldr r3, [r2] @ read aborted ARM instruction + tst r3, #1 << 20 @ L = 1 -> write? + orreq r1, r1, #1 << 8 @ yes. + mov pc, lr + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/armv4t-early-abort.S linux-2.5/arch/arm/mm/armv4t-early-abort.S --- linux-2.5.1/arch/arm/mm/armv4t-early-abort.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/armv4t-early-abort.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,31 @@ +#include <linux/linkage.h> +#include <asm/assembler.h> +/* + * Function: armv4t_early_abort + * + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR + * + * Returns : r0 = address of abort + * : r1 = FSR, bit 8 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + */ + .align 5 +ENTRY(armv4t_early_abort) + mrc p15, 0, r1, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + tst r3, #PSR_T_BIT + ldrneh r3, [r2] @ read aborted thumb instruction + ldreq r3, [r2] @ read aborted ARM instruction + bic r1, r1, #1 << 8 + movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 + tst r3, #1 << 20 @ check write + orreq r1, r1, #1 << 8 + mov pc, lr diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/armv4t-late-abort.S linux-2.5/arch/arm/mm/armv4t-late-abort.S --- linux-2.5.1/arch/arm/mm/armv4t-late-abort.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/armv4t-late-abort.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,224 @@ +#include <linux/linkage.h> +#include <asm/assembler.h> +/* + * Function: armv4t_late_abort + * + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR + * + * Returns : r0 = address of abort + * : r1 = FSR, bit 8 = writing + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + */ +ENTRY(armv4t_late_abort) + tst r3, #PSR_T_BIT @ check for thumb mode + mrc p15, 0, r1, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + ldreq r8, [r2] @ read arm instruction + bne .data_thumb_abort + tst r8, #1 << 20 @ L = 1 -> write? + orreq r1, r1, #1 << 8 @ yes. + and r7, r8, #15 << 24 + add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine + nop + +/* 0 */ b .data_arm_lateldrhpost @ ldrh rd, [rn], #m/rm +/* 1 */ b .data_arm_lateldrhpre @ ldrh rd, [rn, #m/rm] +/* 2 */ b .data_unknown +/* 3 */ b .data_unknown +/* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m +/* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m] +/* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm +/* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm] +/* 8 */ b .data_arm_ldmstm @ ldm*a rn, <rlist> +/* 9 */ b .data_arm_ldmstm @ ldm*b rn, <rlist> +/* a */ b .data_unknown +/* b */ b .data_unknown +/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ mov pc, lr @ ldc rd, [rn, #m] +/* e */ b .data_unknown +/* f */ +.data_unknown: @ Part of jumptable + mov r0, r2 + mov r1, r8 + mov r2, sp + bl baddataabort + b ret_from_exception + +.data_arm_ldmstm: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup + mov r7, #0x11 + orr r7, r7, #0x1100 + and r6, r8, r7 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 + add r6, r6, r6, lsr #8 + add r6, r6, r6, lsr #4 + and r6, r6, #15 @ r7 = no. of registers to transfer. + and r5, r8, #15 << 16 @ Extract 'n' form instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6, lsl #2 @ Undo increment + addeq r7, r7, r6, lsl #2 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrhpre: + tst r8, #1 << 21 @ Check writeback bit + moveq pc, lr @ No writeback -> no fixup +.data_arm_lateldrhpost: + and r5, r8, #0x00f @ get Rm / low nibble of immediate value + tst r8, #1 << 22 @ if (immediate offset) + andne r6, r8, #0xf00 @ { immediate high nibble + orrne r6, r5, r6, lsr #4 @ combine nibbles } else + ldreq r6, [sp, r5, lsl #2] @ { load Rm value } +.data_arm_apply_r6_and_rn: + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6 @ Undo incrmenet + addeq r7, r7, r6 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrpreconst: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostconst: + movs r2, r8, lsl #20 @ Get offset + moveq pc, lr @ zero -> no fixup + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r2, lsr #20 @ Undo increment + addeq r7, r7, r2, lsr #20 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrprereg: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostreg: + and r7, r8, #15 @ Extract 'm' from instruction + ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' + mov r5, r8, lsr #7 @ get shift count + ands r5, r5, #31 + and r7, r8, #0x70 @ get shift type + orreq r7, r7, #8 @ shift count = 0 + add pc, pc, r7 + nop + + mov r6, r6, lsl r5 @ 0: LSL #!0 + b .data_arm_apply_r6_and_rn + b .data_arm_apply_r6_and_rn @ 1: LSL #0 + nop + b .data_unknown @ 2: MUL? + nop + b .data_unknown @ 3: MUL? + nop + mov r6, r6, lsr r5 @ 4: LSR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, lsr #32 @ 5: LSR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ 6: MUL? + nop + b .data_unknown @ 7: MUL? + nop + mov r6, r6, asr r5 @ 8: ASR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, asr #32 @ 9: ASR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ A: MUL? + nop + b .data_unknown @ B: MUL? + nop + mov r6, r6, ror r5 @ C: ROR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, rrx @ D: RRX + b .data_arm_apply_r6_and_rn + b .data_unknown @ E: MUL? + nop + b .data_unknown @ F: MUL? + +.data_thumb_abort: + ldrh r8, [r2] @ read instruction + tst r8, #1 << 11 @ L = 1 -> write? + orreq r1, r1, #1 << 8 @ yes + and r7, r8, #15 << 12 + add pc, pc, r7, lsr #10 @ lookup in table + nop + +/* 0 */ b .data_unknown +/* 1 */ b .data_unknown +/* 2 */ b .data_unknown +/* 3 */ b .data_unknown +/* 4 */ b .data_unknown +/* 5 */ b .data_thumb_reg +/* 6 */ mov pc, lr +/* 7 */ mov pc, lr +/* 8 */ mov pc, lr +/* 9 */ mov pc, lr +/* A */ b .data_unknown +/* B */ b .data_thumb_pushpop +/* C */ b .data_thumb_ldmstm +/* D */ b .data_unknown +/* E */ b .data_unknown +/* F */ b .data_unknown + +.data_thumb_reg: + tst r8, #1 << 9 + moveq pc, lr + tst r8, #1 << 10 @ If 'S' (signed) bit is set + movne r1, #0 @ it must be a load instr + mov pc, lr + +.data_thumb_pushpop: + tst r8, #1 << 10 + beq .data_unknown + mov r7, #0x11 + and r6, r8, r7 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 + add r6, r6, r6, lsr #4 + and r2, r8, #0x0100 @ catch 'R' bit for push/pop + add r6, r6, r2, lsr #8 + and r6, r6, #15 @ number of regs to transfer + ldr r7, [sp, #13 << 2] + tst r8, #1 << 11 + addne r7, r7, r6, lsl #2 @ increment SP if PUSH + subeq r7, r7, r6, lsr #2 @ decrement SP if POP + str r7, [sp, #13 << 2] + mov pc, lr + +.data_thumb_ldmstm: + mov r7, #0x11 + and r6, r8, r7 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 + add r6, r6, r6, lsr #4 + and r6, r6, #15 @ number of regs to transfer + and r5, r8, #7 << 8 + ldr r7, [sp, r5, lsr #6] + sub r7, r7, r6, lsr #2 @ always decrement + str r7, [sp, r5, lsr #6] + mov pc, lr diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/armv5ej-early-abort.S linux-2.5/arch/arm/mm/armv5ej-early-abort.S --- linux-2.5.1/arch/arm/mm/armv5ej-early-abort.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/armv5ej-early-abort.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,35 @@ +#include <linux/linkage.h> +#include <asm/assembler.h> +/* + * Function: armv5ej_early_abort + * + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR + * + * Returns : r0 = address of abort + * : r1 = FSR, bit 8 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + */ + .align 5 +ENTRY(armv5ej_early_abort) + mrc p15, 0, r1, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + tst r3, #PSR_J_BIT + orrne r1, r1, #1 << 8 @ always assume write + bne 1f + tst r3, #PSR_T_BIT + ldrneh r3, [r2] @ read aborted thumb instruction + ldreq r3, [r2] @ read aborted ARM instruction + movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 + tst r2, #1 << 20 @ L = 1 -> write + orreq r1, r1, #1 << 8 @ yes. +1: mov pc, lr + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/fault-armo.c linux-2.5/arch/arm/mm/fault-armo.c --- linux-2.5.1/arch/arm/mm/fault-armo.c Fri Feb 9 00:32:44 2001 +++ linux-2.5/arch/arm/mm/fault-armo.c Thu Jan 1 00:00:00 1970 @@ -1,66 +0,0 @@ -/* - * linux/arch/arm/mm/fault-armo.c - * - * Copyright (C) 1995 Linus Torvalds - * Modifications for ARM processor (c) 1995-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. - */ -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> -#include <linux/mm.h> -#include <linux/interrupt.h> - -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/pgtable.h> - -#define FAULT_CODE_LDRSTRPOST 0x80 -#define FAULT_CODE_LDRSTRPRE 0x40 -#define FAULT_CODE_LDRSTRREG 0x20 -#define FAULT_CODE_LDMSTM 0x10 -#define FAULT_CODE_LDCSTC 0x08 -#define FAULT_CODE_PREFETCH 0x04 -#define FAULT_CODE_WRITE 0x02 -#define FAULT_CODE_FORCECOW 0x01 - -#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) -#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) - -extern int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs); -extern void show_pte(struct mm_struct *mm, unsigned long addr); - -/* - * Handle a data abort. Note that we have to handle a range of addresses - * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force - * a copy-on-write. However, on the second page, we always force COW. - */ -asmlinkage void -do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs) -{ - do_page_fault(min_addr, mode, regs); - - if ((min_addr ^ max_addr) >> PAGE_SHIFT) - do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs); -} - -asmlinkage int -do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) -{ -#if 0 - if (the memc mapping for this page exists) { - printk ("Page in, but got abort (undefined instruction?)\n"); - return 0; - } -#endif - do_page_fault(addr, FAULT_CODE_PREFETCH, regs); - return 1; -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/fault-armv.c linux-2.5/arch/arm/mm/fault-armv.c --- linux-2.5.1/arch/arm/mm/fault-armv.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mm/fault-armv.c Sun Jan 6 01:38:26 2002 @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ #include <linux/config.h> +#include <linux/compiler.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -27,7 +28,6 @@ #include <asm/uaccess.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> -#include <asm/unaligned.h> 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); @@ -40,499 +40,15 @@ struct pt_regs *regs); #ifdef CONFIG_ALIGNMENT_TRAP -/* - * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998 - * /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 code is not portable to processors with late data abort handling. - */ -#define CODING_BITS(i) (i & 0x0e000000) - -#define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */ -#define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */ -#define LDST_U_BIT(i) (i & (1 << 23)) /* Add offset */ -#define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */ -#define LDST_L_BIT(i) (i & (1 << 20)) /* Load */ - -#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0) - -#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */ -#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */ - -#define RN_BITS(i) ((i >> 16) & 15) /* Rn */ -#define RD_BITS(i) ((i >> 12) & 15) /* Rd */ -#define RM_BITS(i) (i & 15) /* Rm */ - -#define REGMASK_BITS(i) (i & 0xffff) -#define OFFSET_BITS(i) (i & 0x0fff) - -#define IS_SHIFT(i) (i & 0x0ff0) -#define SHIFT_BITS(i) ((i >> 7) & 0x1f) -#define SHIFT_TYPE(i) (i & 0x60) -#define SHIFT_LSL 0x00 -#define SHIFT_LSR 0x20 -#define SHIFT_ASR 0x40 -#define SHIFT_RORRRX 0x60 - -static unsigned long ai_user; -static unsigned long ai_sys; -static unsigned long ai_skipped; -static unsigned long ai_half; -static unsigned long ai_word; -static unsigned long ai_multi; - -#ifdef CONFIG_SYSCTL -static int proc_alignment_read(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - char *p = page; - int len; - - p += sprintf(p, "User:\t\t%li\n", ai_user); - p += sprintf(p, "System:\t\t%li\n", ai_sys); - p += sprintf(p, "Skipped:\t%li\n", ai_skipped); - p += sprintf(p, "Half:\t\t%li\n", ai_half); - p += sprintf(p, "Word:\t\t%li\n", ai_word); - p += sprintf(p, "Multi:\t\t%li\n", ai_multi); - - len = (p - page) - off; - if (len < 0) - len = 0; - - *eof = (len <= count) ? 1 : 0; - *start = page + off; - - return len; -} - -/* - * This needs to be done after sysctl_init, otherwise sys/ - * will be overwritten. - */ -static int __init alignment_init(void) -{ - create_proc_read_entry("sys/debug/alignment", 0, NULL, - proc_alignment_read, NULL); - return 0; -} - -__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], #1\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], #1\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_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs) -{ - unsigned int rd = RD_BITS(instr); - - if ((instr & 0x01f00ff0) == 0x01000090) - goto swp; - - 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; -} - -/* - * LDM/STM alignment handler. - * - * There are 4 variants of this instruction: - * - * B = rn pointer before instruction, A = rn pointer after instruction - * ------ increasing address -----> - * | | r0 | r1 | ... | rx | | - * PU = 01 B A - * PU = 11 B A - * PU = 00 A B - * PU = 10 A B - */ -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, newaddr; - - if (LDM_S_BIT(instr)) - goto bad; - - correction = 4; /* processor implementation defined */ - regs->ARM_pc += correction; - - ai_multi += 1; - - /* count the number of registers in the mask to be transferred */ - nr_regs = hweight16(REGMASK_BITS(instr)) * 4; - - rn = RN_BITS(instr); - newaddr = eaddr = regs->uregs[rn]; - - if (!LDST_U_BIT(instr)) - nr_regs = -nr_regs; - newaddr += nr_regs; - if (!LDST_U_BIT(instr)) - eaddr = newaddr; - - if (LDST_P_EQ_U(instr)) /* U = P */ - eaddr += 4; - - /* - * 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); - show_regs(regs); - } - - 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); - else - put32_unaligned_check(regs->uregs[rd], eaddr); - eaddr += 4; - } - - if (LDST_W_BIT(instr)) - regs->uregs[rn] = newaddr; - if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15))) - regs->ARM_pc -= correction; - return TYPE_DONE; - -fault: - regs->ARM_pc -= correction; - 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: /* ldr or str immediate */ - offset.un = OFFSET_BITS(instr); - handler = do_alignment_ldrstr; - break; - - case 0x06000000: /* ldr or str register */ - offset.un = regs->uregs[RM_BITS(instr)]; - - if (IS_SHIFT(instr)) { - unsigned int shiftval = SHIFT_BITS(instr); - - switch(SHIFT_TYPE(instr)) { - case SHIFT_LSL: - offset.un <<= shiftval; - break; - - case SHIFT_LSR: - offset.un >>= shiftval; - break; - - case SHIFT_ASR: - offset.sn >>= shiftval; - break; - - case SHIFT_RORRRX: - if (shiftval == 0) { - offset.un >>= 1; - if (regs->ARM_cpsr & CC_C_BIT) - offset.un |= 1 << 31; - } else - offset.un = offset.un >> shiftval | - offset.un << (32 - shiftval); - break; - } - } - handler = do_alignment_ldrstr; - break; - - case 0x08000000: /* ldm or stm */ - handler = do_alignment_ldmstm; - break; - - default: - goto bad; - } - - type = handler(addr, instr, regs); - - if (type == TYPE_ERROR || type == TYPE_FAULT) - goto bad_or_fault; - - if (type == TYPE_LDST) - do_alignment_finish_ldst(addr, instr, regs, offset); - - return 0; - -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>]\n", instr, instrptr); - ai_skipped += 1; - return 1; - -user: - set_cr(cr_no_alignment); - ai_user += 1; - return 0; -} - +extern int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs); #else - -#define do_alignment NULL - +#define do_alignment do_bad #endif + /* - * Some section permission faults need to be handled gracefully, for - * instance, when they happen due to a __{get,put}_user during an oops). + * Some section permission faults need to be handled gracefully. + * They can happen due to a __{get,put}_user during an oops. */ static int do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs) @@ -557,73 +73,54 @@ return 1; } +/* + * This abort handler always returns "fault". + */ +static int +do_bad(unsigned long addr, int error_code, struct pt_regs *regs) +{ + return 1; +} + static const struct fsr_info { int (*fn)(unsigned long addr, int error_code, struct pt_regs *regs); int sig; - char *name; + const char *name; } fsr_info[] = { - { NULL, SIGSEGV, "vector exception" }, + { do_bad, SIGSEGV, "vector exception" }, { do_alignment, SIGILL, "alignment exception" }, - { NULL, SIGKILL, "terminal exception" }, + { do_bad, SIGKILL, "terminal exception" }, { do_alignment, SIGILL, "alignment exception" }, { do_external_fault, SIGBUS, "external abort on linefetch" }, { do_translation_fault, SIGSEGV, "section translation fault" }, { do_external_fault, SIGBUS, "external abort on linefetch" }, { do_page_fault, SIGSEGV, "page translation fault" }, { do_external_fault, SIGBUS, "external abort on non-linefetch" }, - { NULL, SIGSEGV, "section domain fault" }, + { do_bad, SIGSEGV, "section domain fault" }, { do_external_fault, SIGBUS, "external abort on non-linefetch" }, - { NULL, SIGSEGV, "page domain fault" }, - { NULL, SIGBUS, "external abort on translation" }, + { do_bad, SIGSEGV, "page domain fault" }, + { do_bad, SIGBUS, "external abort on translation" }, { do_sect_fault, SIGSEGV, "section permission fault" }, - { NULL, SIGBUS, "external abort on translation" }, + { do_bad, SIGBUS, "external abort on translation" }, { do_page_fault, SIGSEGV, "page permission fault" } }; /* - * Currently dropped down to debug level + * Dispatch a data abort to the relevant handler. */ asmlinkage void -do_DataAbort(unsigned long addr, int error_code, struct pt_regs *regs, int fsr) +do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { const struct fsr_info *inf = fsr_info + (fsr & 15); -#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) || defined(CONFIG_DEBUG_ERRORS) - if (addr == regs->ARM_pc) - goto sa1_weirdness; -#endif - - if (!inf->fn) - goto bad; - - if (!inf->fn(addr, error_code, regs)) + if (!inf->fn(addr, fsr, regs)) return; -bad: + printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n", inf->name, fsr, addr); - show_pte(current->mm, addr); force_sig(inf->sig, current); + show_pte(current->mm, addr); die_if_kernel("Oops", regs, 0); - return; - -#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) || defined(CONFIG_DEBUG_ERRORS) -sa1_weirdness: - if (user_mode(regs)) { - static int first = 1; - if (first) { - printk(KERN_DEBUG "Fixing up bad data abort at %08lx\n", addr); -#ifdef CONFIG_DEBUG_ERRORS - show_pte(current->mm, addr); -#endif - } - first = 0; - return; - } - - if (!inf->fn || inf->fn(addr, error_code, regs)) - goto bad; - return; -#endif } asmlinkage void @@ -727,7 +224,7 @@ * Note that we intentionally don't mask out the VMA * that we are fixing up. */ - if (mpnt->vm_mm != mm && mpnt != vma) + if (mpnt->vm_mm != mm || mpnt == vma) continue; /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/fault-common.c linux-2.5/arch/arm/mm/fault-common.c --- linux-2.5.1/arch/arm/mm/fault-common.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mm/fault-common.c Sun Jan 6 01:38:26 2002 @@ -39,8 +39,8 @@ * of the 26-bit machines, and also means that we avoid the horrible * gcc code for "int val = !other_val;". */ -#define DO_COW(m) (m) -#define READ_FAULT(m) (!(m)) +#define DO_COW(code) ((code) & (1 << 8)) +#define READ_FAULT(code) (!DO_COW(code)) #endif NORET_TYPE void die(const char *msg, struct pt_regs *regs, int err) ATTRIB_NORET; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/minicache.c linux-2.5/arch/arm/mm/minicache.c --- linux-2.5.1/arch/arm/mm/minicache.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/minicache.c Sun Jan 6 01:38:26 2002 @@ -0,0 +1,63 @@ +/* + * linux/arch/arm/mm/minicache.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. + * + * This handles the mini data cache, as found on SA11x0 and XScale + * processors. When we copy a user page page, we map it in such a way + * that accesses to this page will not touch the main data cache, but + * will be cached in the mini data cache. This prevents us thrashing + * the main data cache on page faults. + */ +#include <linux/init.h> +#include <linux/mm.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +#define minicache_address (0xffff2000) +#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ + L_PTE_CACHEABLE) + +static pte_t *minicache_pte; + +/* + * Note that this is intended to be called only from the copy_user_page + * asm code; anything else will require special locking to prevent the + * mini-cache space being re-used. (Note: probably preempt unsafe). + * + * We rely on the fact that the minicache is 2K, and we'll be pushing + * 4K of data through it, so we don't actually have to specifically + * flush the minicache when we change the mapping. + * + * Note also: assert(PAGE_OFFSET <= virt < high_memory). + * Unsafe: preempt, kmap. + */ +unsigned long map_page_minicache(unsigned long virt) +{ + set_pte(minicache_pte, mk_pte_phys(__pa(virt), minicache_pgprot)); + cpu_tlb_invalidate_page(minicache_address, 0); + + return minicache_address; +} + +static int __init minicache_init(void) +{ + pgd_t *pgd; + pmd_t *pmd; + + pgd = pgd_offset_k(minicache_address); + pmd = pmd_alloc(&init_mm, pgd, minicache_address); + if (!pmd) + BUG(); + minicache_pte = pte_alloc(&init_mm, pmd, minicache_address); + if (!minicache_pte) + BUG(); + + return 0; +} + +__initcall(minicache_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/mm-armo.c linux-2.5/arch/arm/mm/mm-armo.c --- linux-2.5.1/arch/arm/mm/mm-armo.c Thu Apr 12 19:20:31 2001 +++ linux-2.5/arch/arm/mm/mm-armo.c Thu Jan 1 00:00:00 1970 @@ -1,184 +0,0 @@ -/* - * linux/arch/arm/mm/mm-armo.c - * - * Copyright (C) 1998-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. - * - * Page table sludge for older ARM processor architectures. - */ -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/bootmem.h> - -#include <asm/pgtable.h> -#include <asm/pgalloc.h> -#include <asm/page.h> -#include <asm/arch/memory.h> - -#include <asm/mach/map.h> - -#define MEMC_TABLE_SIZE (256*sizeof(unsigned long)) - -kmem_cache_t *pte_cache, *pgd_cache; -int page_nr; - -/* - * 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. - */ -static inline pgd_t *alloc_pgd_table(int priority) -{ - void *pg2k = kmem_cache_alloc(pgd_cache, GFP_KERNEL); - - if (pg2k) - pg2k += MEMC_TABLE_SIZE; - - 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; - - kmem_cache_free(pgd_cache, (void *)tbl); -} - -pgd_t *get_pgd_slow(struct mm_struct *mm) -{ - 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; - - 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); - free_pgd_slow(new_pgd); - return NULL; - -no_pmd: - spin_unlock(&mm->page_table_lock); - free_pgd_slow(new_pgd); - return NULL; - -no_pgd: - return NULL; -} - -/* - * No special code is required here. - */ -void setup_mm_for_reboot(char mode) -{ -} - -/* - * This contains the code to setup the memory map on an ARM2/ARM250/ARM3 - * machine. This is both processor & architecture specific, and requires - * some more work to get it to fit into our separate processor and - * architecture structure. - */ -void __init memtable_init(struct meminfo *mi) -{ - pte_t *pte; - int i; - - page_nr = max_low_pfn; - - pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t)); - pte[0] = mk_pte_phys(PAGE_OFFSET + 491520, PAGE_READONLY); - 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; -} - -void __init iotable_init(struct map_desc *io_desc) -{ - /* nothing to do */ -} - -/* - * We never have holes in the memmap - */ -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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/mm-armv.c linux-2.5/arch/arm/mm/mm-armv.c --- linux-2.5.1/arch/arm/mm/mm-armv.c Wed Jun 27 21:12:04 2001 +++ linux-2.5/arch/arm/mm/mm-armv.c Sun Jan 6 01:38:26 2002 @@ -30,8 +30,8 @@ */ static int __init nocache_setup(char *__unused) { - cr_alignment &= ~4; - cr_no_alignment &= ~4; + cr_alignment &= ~CR1_C; + cr_no_alignment &= ~CR1_C; flush_cache_all(); set_cr(cr_alignment); return 1; @@ -39,8 +39,8 @@ static int __init nowrite_setup(char *__unused) { - cr_alignment &= ~(8|4); - cr_no_alignment &= ~(8|4); + cr_alignment &= ~(CR1_W|CR1_C); + cr_no_alignment &= ~(CR1_W|CR1_C); flush_cache_all(); set_cr(cr_alignment); return 1; @@ -48,8 +48,8 @@ static int __init noalign_setup(char *__unused) { - cr_alignment &= ~2; - cr_no_alignment &= ~2; + cr_alignment &= ~CR1_A; + cr_no_alignment &= ~CR1_A; set_cr(cr_alignment); return 1; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/mm-clps7500.c linux-2.5/arch/arm/mm/mm-clps7500.c --- linux-2.5.1/arch/arm/mm/mm-clps7500.c Thu Apr 12 19:20:31 2001 +++ linux-2.5/arch/arm/mm/mm-clps7500.c Thu Jan 1 00:00:00 1970 @@ -1,30 +0,0 @@ -/* - * linux/arch/arm/mm/mm-cl7500.c - * - * Copyright (C) 1998 Russell King - * Copyright (C) 1999 Nexus Electronics Ltd - * - * Extra MM routines for CL7500 architecture - */ -#include <linux/types.h> -#include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/page.h> -#include <asm/proc/domain.h> -#include <asm/setup.h> - -#include <asm/mach/map.h> - -static struct map_desc cl7500_io_desc[] __initdata = { - { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1 }, /* IO space */ - { ISA_BASE, ISA_START, ISA_SIZE , DOMAIN_IO, 0, 1 }, /* ISA space */ - { FLASH_BASE, FLASH_START, FLASH_SIZE, DOMAIN_IO, 0, 1 }, /* Flash */ - { LED_BASE, LED_START, LED_SIZE , DOMAIN_IO, 0, 1 }, /* LED */ - LAST_DESC -}; - -void __init clps7500_map_io(void) -{ - iotable_init(cl7500_io_desc); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/mm-ftvpci.c linux-2.5/arch/arm/mm/mm-ftvpci.c --- linux-2.5.1/arch/arm/mm/mm-ftvpci.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mm/mm-ftvpci.c Thu Jan 1 00:00:00 1970 @@ -1,32 +0,0 @@ -/* - * linux/arch/arm/mm/mm-nexuspci.c - * from linux/arch/arm/mm/mm-ebsa110.c - * - * Copyright (C) 1998-1999 Phil Blundell - * Copyright (C) 1998-1999 Russell King - * - * Extra MM routines for the FTV/PCI architecture - */ -#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/mach/map.h> - -static struct map_desc nexuspci_io_desc[] __initdata = { - { INTCONT_BASE, INTCONT_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { PLX_BASE, PLX_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { PCIO_BASE, PLX_IO_START, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, - { DUART_BASE, DUART_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { STATUS_BASE, STATUS_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - LAST_DESC -}; - -void __init nexuspci_map_io(void) -{ - iotable_init(nexuspci_io_desc); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/mm-l7200.c linux-2.5/arch/arm/mm/mm-l7200.c --- linux-2.5.1/arch/arm/mm/mm-l7200.c Wed Jun 27 21:12:04 2001 +++ linux-2.5/arch/arm/mm/mm-l7200.c Thu Jan 1 00:00:00 1970 @@ -1,28 +0,0 @@ -/* - * linux/arch/arm/mm/mm-lusl7200.c - * - * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) - * - * Extra MM routines for L7200 architecture - */ -#include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/page.h> -#include <asm/proc/domain.h> - -#include <asm/mach/map.h> - -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 -}; - -void __init l7200_map_io(void) -{ - iotable_init(l7200_io_desc); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/mm-rpc.c linux-2.5/arch/arm/mm/mm-rpc.c --- linux-2.5.1/arch/arm/mm/mm-rpc.c Wed Mar 7 03:44:35 2001 +++ linux-2.5/arch/arm/mm/mm-rpc.c Thu Jan 1 00:00:00 1970 @@ -1,32 +0,0 @@ -/* - * linux/arch/arm/mm/mm-rpc.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 RiscPC architecture - */ -#include <linux/types.h> -#include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/page.h> -#include <asm/proc/domain.h> -#include <asm/setup.h> - -#include <asm/mach/map.h> - -static struct map_desc rpc_io_desc[] __initdata = { - { SCREEN_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 }, /* VRAM */ - { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, /* IO space */ - { EASI_BASE, EASI_START, EASI_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* EASI space */ - LAST_DESC -}; - -void __init rpc_map_io(void) -{ - iotable_init(rpc_io_desc); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/mm-tbox.c linux-2.5/arch/arm/mm/mm-tbox.c --- linux-2.5.1/arch/arm/mm/mm-tbox.c Mon Sep 18 22:15:25 2000 +++ linux-2.5/arch/arm/mm/mm-tbox.c Thu Jan 1 00:00:00 1970 @@ -1,28 +0,0 @@ -/* - * linux/arch/arm/mm/mm-tbox.c - * - * Copyright (C) 1998, 1999, 2000 Phil Blundell - * Copyright (C) 1998-1999 Russell King - * - * Extra MM routines for the Tbox architecture - */ -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/init.h> - -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/page.h> - -#include <asm/mach/map.h> - -static struct map_desc tbox_io_desc[] __initdata = { - /* See hardware.h for details */ - { IO_BASE, IO_START, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, - LAST_DESC -}; - -void __init tbox_map_io(void) -{ - iotable_init(tbox_io_desc); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/proc-arm1020.S linux-2.5/arch/arm/mm/proc-arm1020.S --- linux-2.5.1/arch/arm/mm/proc-arm1020.S Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/arm/mm/proc-arm1020.S Sun Jan 6 01:38:26 2002 @@ -51,35 +51,12 @@ #define PAGESIZE 4096 .text - -/* - * cpu_arm1020_data_abort() - * - * obtain information about current aborted instruction - * - * r0 = address of aborted instruction - * - * Returns: - * r0 = address of abort - * r1 != 0 if writing - * r3 = FSR - */ - .align 5 -ENTRY(cpu_arm1020_data_abort) - ldr r1, [r0] @ read aborted instruction - mrc p15, 0, r0, c6, c0, 0 @ get FAR - tst r1, r1, lsr #21 @ C = bit 20 - mrc p15, 0, r3, c5, c0, 0 @ get FSR - sbc r1, r1, r1 @ r1 = C - 1 - and r3, r3, #255 - mov pc, lr - /* * cpu_arm1020_check_bugs() */ ENTRY(cpu_arm1020_check_bugs) mrs ip, cpsr - bic ip, ip, #F_BIT + bic ip, ip, #PSR_F_BIT msr cpsr, ip mov pc, lr @@ -94,7 +71,7 @@ */ ENTRY(cpu_arm1020_proc_fin) stmfd sp!, {lr} - mov ip, #F_BIT | I_BIT | SVC_MODE + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, ip bl cpu_arm1020_cache_clean_invalidate_all mrc p15, 0, r0, c1, c0, 0 @ ctrl register @@ -696,7 +673,7 @@ */ .type arm1020_processor_functions, #object arm1020_processor_functions: - .word cpu_arm1020_data_abort + .word armv4t_early_abort .word cpu_arm1020_check_bugs .word cpu_arm1020_proc_init .word cpu_arm1020_proc_fin @@ -727,6 +704,11 @@ .word cpu_arm1020_set_pgd .word cpu_arm1020_set_pmd .word cpu_arm1020_set_pte + + /* misc */ + .word armv4_clear_user_page + .word armv4_copy_user_page + .size arm1020_processor_functions, . - arm1020_processor_functions .type cpu_arm1020_info, #object diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/proc-arm2,3.S linux-2.5/arch/arm/mm/proc-arm2,3.S --- linux-2.5.1/arch/arm/mm/proc-arm2,3.S Wed Mar 7 03:44:35 2001 +++ linux-2.5/arch/arm/mm/proc-arm2,3.S Sun Jan 6 01:38:26 2002 @@ -234,7 +234,7 @@ */ _arm3_proc_fin: mov r0, #2 mcr p15, 0, r0, c2, c0 -_arm2_proc_fin: orrs pc, lr, #I_BIT|F_BIT +_arm2_proc_fin: orrs pc, lr, #PSR_I_BIT|PSR_F_BIT /* * Function: *_xchg_1 (int new, volatile void *ptr) @@ -244,7 +244,7 @@ * Returns : Original byte data at 'ptr' */ _arm2_xchg_1: mov r2, pc - orr r2, r2, #I_BIT + orr r2, r2, #PSR_I_BIT teqp r2, #0 ldrb r2, [r1] strb r0, [r1] @@ -262,7 +262,7 @@ * Returns : Original word data at 'ptr' */ _arm2_xchg_4: mov r2, pc - orr r2, r2, #I_BIT + orr r2, r2, #PSR_I_BIT teqp r2, #0 ldr r2, [r1] str r0, [r1] diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/proc-arm6,7.S linux-2.5/arch/arm/mm/proc-arm6,7.S --- linux-2.5.1/arch/arm/mm/proc-arm6,7.S Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/mm/proc-arm6,7.S Sun Jan 6 01:38:26 2002 @@ -240,7 +240,7 @@ ENTRY(cpu_arm6_check_bugs) ENTRY(cpu_arm7_check_bugs) mrs ip, cpsr - bic ip, ip, #F_BIT + bic ip, ip, #PSR_F_BIT msr cpsr, ip mov pc, lr @@ -250,7 +250,7 @@ ENTRY(cpu_arm6_proc_fin) ENTRY(cpu_arm7_proc_fin) - mov r0, #F_BIT | I_BIT | SVC_MODE + mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, r0 mov r0, #0x31 @ ....S..DP...M mcr p15, 0, r0, c1, c0, 0 @ disable caches @@ -418,6 +418,11 @@ .word cpu_arm6_set_pgd .word cpu_arm6_set_pmd .word cpu_arm6_set_pte + + /* other */ + .word armv3_clear_user_page + .word armv3_copy_user_page + .size arm6_processor_functions, . - arm6_processor_functions /* @@ -457,6 +462,11 @@ .word cpu_arm7_set_pgd .word cpu_arm7_set_pmd .word cpu_arm7_set_pte + + /* other */ + .word armv3_clear_user_page + .word armv3_copy_user_page + .size arm7_processor_functions, . - arm7_processor_functions .type cpu_arm6_info, #object diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/proc-arm720.S linux-2.5/arch/arm/mm/proc-arm720.S --- linux-2.5.1/arch/arm/mm/proc-arm720.S Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/mm/proc-arm720.S Sun Jan 6 01:38:26 2002 @@ -105,231 +105,6 @@ mov pc, lr /* - * Function: arm720_data_abort () - * - * Params : r0 = address of aborted instruction - * : r3 = saved SPSR - * - * Purpose : obtain information about current aborted instruction - * - * Returns : r0 = address of abort - * : r1 != 0 if writing - * : r3 = FSR - * : sp = pointer to registers - */ - -Ldata_ldmstm: tst r4, #1 << 21 @ check writeback bit - beq Ldata_simple - mov r7, #0x11 - orr r7, r7, r7, lsl #8 - and r0, r4, r7 - and r2, r4, r7, lsl #1 - add r0, r0, r2, lsr #1 - and r2, r4, r7, lsl #2 - add r0, r0, r2, lsr #2 - and r2, r4, r7, lsl #3 - add r0, r0, r2, lsr #3 - add r0, r0, r0, lsr #8 - add r0, r0, r0, lsr #4 - and r7, r0, #15 @ r7 = no. of registers to transfer. - and r5, r4, #15 << 16 @ Get Rn - ldr r0, [sp, r5, lsr #14] @ Get register - tst r4, #1 << 23 @ U bit - subne r7, r0, r7, lsl #2 - addeq r7, r0, r7, lsl #2 @ Do correction (signed) -Ldata_saver7: str r7, [sp, r5, lsr #14] @ Put register -Ldata_simple: mrc p15, 0, r0, c6, c0, 0 @ get FAR - mrc p15, 0, r3, c5, c0, 0 @ get FSR - and r3, r3, #255 - mov pc, lr - -ENTRY(cpu_arm720_data_abort) - tst r3, #T_BIT - bne .data_thumb_abort - ldr r4, [r0] @ read instruction causing problem - tst r4, r4, lsr #21 @ C = bit 20 - sbc r1, r1, r1 @ r1 = C - 1 - and r2, r4, #15 << 24 - add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine - movs pc, lr - - b Ldata_lateldrhpost @ ldrh rd, [rn], #m/rm - b Ldata_lateldrhpre @ ldrh rd, [rn, #m/rm] - b Ldata_unknown - b Ldata_unknown - b Ldata_lateldrpostconst @ ldr rd, [rn], #m - b Ldata_lateldrpreconst @ ldr rd, [rn, #m] - b Ldata_lateldrpostreg @ ldr rd, [rn], rm - b Ldata_lateldrprereg @ ldr rd, [rn, rm] - b Ldata_ldmstm @ ldm*a rn, <rlist> - b Ldata_ldmstm @ ldm*b rn, <rlist> - b Ldata_unknown - b Ldata_unknown - b Ldata_simple @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m - b Ldata_simple @ ldc rd, [rn, #m] - b Ldata_unknown - -Ldata_unknown: @ Part of jumptable - mov r0, r2 - mov r1, r4 - mov r2, sp - bl baddataabort - b ret_from_exception - -Ldata_lateldrhpre: - tst r4, #1 << 21 @ check writeback bit - beq Ldata_simple -Ldata_lateldrhpost: - and r5, r4, #0x00f @ get Rm / low nibble of immediate value - tst r4, #1 << 22 @ if (immediate offset) - andne r2, r4, #0xf00 @ { immediate high nibble - orrne r2, r5, r2, lsr #4 @ combine nibbles } else - ldreq r2, [sp, r5, lsl #2] @ { load Rm value } - and r5, r4, #15 << 16 @ get Rn - ldr r0, [sp, r5, lsr #14] @ load Rn value - tst r4, #1 << 23 @ U bit - subne r7, r0, r2 - addeq r7, r0, r2 - b Ldata_saver7 - -Ldata_lateldrpreconst: - tst r4, #1 << 21 @ check writeback bit - beq Ldata_simple -Ldata_lateldrpostconst: - movs r2, r4, lsl #20 @ Get offset - beq Ldata_simple - and r5, r4, #15 << 16 @ Get Rn - ldr r0, [sp, r5, lsr #14] - tst r4, #1 << 23 @ U bit - subne r7, r0, r2, lsr #20 - addeq r7, r0, r2, lsr #20 - b Ldata_saver7 - -Ldata_lateldrprereg: - tst r4, #1 << 21 @ check writeback bit - beq Ldata_simple -Ldata_lateldrpostreg: - and r5, r4, #15 - ldr r2, [sp, r5, lsl #2] @ Get Rm - mov r3, r4, lsr #7 - ands r3, r3, #31 - and r6, r4, #0x70 - orreq r6, r6, #8 - add pc, pc, r6 - mov r0, r0 - - mov r2, r2, lsl r3 @ 0: LSL #!0 - b 1f - b 1f @ 1: LSL #0 - mov r0, r0 - b 1f @ 2: MUL? - mov r0, r0 - b 1f @ 3: MUL? - mov r0, r0 - mov r2, r2, lsr r3 @ 4: LSR #!0 - b 1f - mov r2, r2, lsr #32 @ 5: LSR #32 - b 1f - b 1f @ 6: MUL? - mov r0, r0 - b 1f @ 7: MUL? - mov r0, r0 - mov r2, r2, asr r3 @ 8: ASR #!0 - b 1f - mov r2, r2, asr #32 @ 9: ASR #32 - b 1f - b 1f @ A: MUL? - mov r0, r0 - b 1f @ B: MUL? - mov r0, r0 - mov r2, r2, ror r3 @ C: ROR #!0 - b 1f - mov r2, r2, rrx @ D: RRX - b 1f - mov r0, r0 @ E: MUL? - mov r0, r0 - mov r0, r0 @ F: MUL? - - -1: and r5, r4, #15 << 16 @ Get Rn - ldr r0, [sp, r5, lsr #14] - tst r4, #1 << 23 @ U bit - subne r7, r0, r2 - addeq r7, r0, r2 - b Ldata_saver7 - -.data_thumb_abort: - ldrh r4, [r0] @ read instruction - tst r4, r4, lsr #12 @ C = bit 11 - sbc r1, r1, r1 @ r1 = C - 1 - and r2, r4, #15 << 12 - add pc, pc, r2, lsr #10 @ lookup in table - nop - -/* 0 */ b Ldata_unknown -/* 1 */ b Ldata_unknown -/* 2 */ b Ldata_unknown -/* 3 */ b Ldata_unknown -/* 4 */ b Ldata_unknown -/* 5 */ b .data_thumb_reg -/* 6 */ b Ldata_simple -/* 7 */ b Ldata_simple -/* 8 */ b Ldata_simple -/* 9 */ b Ldata_simple -/* A */ b Ldata_unknown -/* B */ b .data_thumb_pushpop -/* C */ b .data_thumb_ldmstm -/* D */ b Ldata_unknown -/* E */ b Ldata_unknown -/* F */ b Ldata_unknown - -.data_thumb_reg: - tst r4, #1 << 9 - beq Ldata_simple - tst r4, #1 << 10 @ If 'S' (signed) bit is set - movne r1, #0 @ it must be a load instr - b Ldata_simple - -.data_thumb_pushpop: - tst r4, #1 << 10 - beq Ldata_unknown - mov r7, #0x11 - and r0, r4, r7 - and r2, r4, r7, lsl #1 - add r0, r0, r2, lsr #1 - and r2, r4, r7, lsl #2 - add r0, r0, r2, lsr #2 - and r2, r4, r7, lsl #3 - add r0, r0, r2, lsr #3 - add r0, r0, r0, lsr #4 - and r2, r4, #0x0100 @ catch 'R' bit for push/pop - add r0, r0, r2, lsr #8 - and r0, r0, #15 @ number of regs to transfer - ldr r7, [sp, #13 << 2] - tst r4, #1 << 11 - addne r7, r7, r0, lsl #2 @ increment SP if PUSH - subeq r7, r7, r0, lsr #2 @ decrement SP if POP - str r7, [sp, #13 << 2] - b Ldata_simple - -.data_thumb_ldmstm: - mov r7, #0x11 - and r0, r4, r7 - and r2, r4, r7, lsl #1 - add r0, r0, r2, lsr #1 - and r2, r4, r7, lsl #2 - add r0, r0, r2, lsr #2 - and r2, r4, r7, lsl #3 - add r0, r0, r2, lsr #3 - add r0, r0, r0, lsr #4 - and r0, r0, #15 @ number of regs to transfer - and r5, r4, #7 << 8 - ldr r7, [sp, r5, lsr #6] - sub r7, r7, r0, lsr #2 @ always decrement - str r7, [sp, r5, lsr #6] - b Ldata_simple - -/* * Function: arm720_check_bugs (void) * : arm720_proc_init (void) * : arm720_proc_fin (void) @@ -338,7 +113,7 @@ */ ENTRY(cpu_arm720_check_bugs) mrs ip, cpsr - bic ip, ip, #F_BIT + bic ip, ip, #PSR_F_BIT msr cpsr, ip mov pc, lr @@ -347,7 +122,7 @@ ENTRY(cpu_arm720_proc_fin) stmfd sp!, {lr} - mov ip, #F_BIT | I_BIT | SVC_MODE + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, ip mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x1000 @ ...i............ @@ -462,7 +237,7 @@ */ .type arm720_processor_functions, #object ENTRY(arm720_processor_functions) - .word cpu_arm720_data_abort + .word armv4t_late_abort .word cpu_arm720_check_bugs .word cpu_arm720_proc_init .word cpu_arm720_proc_fin @@ -493,6 +268,11 @@ .word cpu_arm720_set_pgd .word cpu_arm720_set_pmd .word cpu_arm720_set_pte + + /* misc */ + .word armv4_clear_user_page + .word armv4_copy_user_page + .size arm720_processor_functions, . - arm720_processor_functions .type cpu_arm720_info, #object diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/proc-arm920.S linux-2.5/arch/arm/mm/proc-arm920.S --- linux-2.5.1/arch/arm/mm/proc-arm920.S Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mm/proc-arm920.S Sun Jan 6 01:38:26 2002 @@ -51,35 +51,12 @@ #define PAGESIZE 4096 .text - -/* - * cpu_arm920_data_abort() - * - * obtain information about current aborted instruction - * - * r0 = address of aborted instruction - * - * Returns: - * r0 = address of abort - * r1 != 0 if writing - * r3 = FSR - */ - .align 5 -ENTRY(cpu_arm920_data_abort) - ldr r1, [r0] @ read aborted instruction - mrc p15, 0, r0, c6, c0, 0 @ get FAR - tst r1, r1, lsr #21 @ C = bit 20 - mrc p15, 0, r3, c5, c0, 0 @ get FSR - sbc r1, r1, r1 @ r1 = C - 1 - and r3, r3, #255 - mov pc, lr - /* * cpu_arm920_check_bugs() */ ENTRY(cpu_arm920_check_bugs) mrs ip, cpsr - bic ip, ip, #F_BIT + bic ip, ip, #PSR_F_BIT msr cpsr, ip mov pc, lr @@ -94,7 +71,7 @@ */ ENTRY(cpu_arm920_proc_fin) stmfd sp!, {lr} - mov ip, #F_BIT | I_BIT | SVC_MODE + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, ip bl cpu_arm920_cache_clean_invalidate_all mrc p15, 0, r0, c1, c0, 0 @ ctrl register @@ -590,7 +567,7 @@ */ .type arm920_processor_functions, #object arm920_processor_functions: - .word cpu_arm920_data_abort + .word armv4t_early_abort .word cpu_arm920_check_bugs .word cpu_arm920_proc_init .word cpu_arm920_proc_fin @@ -621,6 +598,11 @@ .word cpu_arm920_set_pgd .word cpu_arm920_set_pmd .word cpu_arm920_set_pte + + /* misc */ + .word armv4_clear_user_page + .word armv4_copy_user_page + .size arm920_processor_functions, . - arm920_processor_functions .type cpu_arm920_info, #object diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/proc-arm922.S linux-2.5/arch/arm/mm/proc-arm922.S --- linux-2.5.1/arch/arm/mm/proc-arm922.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/proc-arm922.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,639 @@ +/* + * linux/arch/arm/mm/arm922.S: MMU functions for ARM922 + * + * Copyright (C) 1999,2000 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * Copyright (C) 2001 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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 + * + * + * These are the low level assembler for performing cache and TLB + * functions on the arm922. + */ +#include <linux/linkage.h> +#include <linux/config.h> +#include <asm/assembler.h> +#include <asm/constants.h> +#include <asm/procinfo.h> +#include <asm/hardware.h> + +/* + * This is the maximum size of an area which will be invalidated + * using the single invalidate entry instructions. Anything larger + * than this, and we go for the whole cache. + * + * This value should be chosen such that we choose the cheapest + * alternative. + */ +#define MAX_AREA_SIZE 8192 + +/* + * the cache line size of the I and D cache + */ +#define DCACHELINESIZE 32 +#define ICACHELINESIZE 32 + +/* + * and the page size + */ +#define PAGESIZE 4096 + + .text +/* + * cpu_arm922_check_bugs() + */ +ENTRY(cpu_arm922_check_bugs) + mrs ip, cpsr + bic ip, ip, #PSR_F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_arm922_proc_init() + */ +ENTRY(cpu_arm922_proc_init) + mov pc, lr + +/* + * cpu_arm922_proc_fin() + */ +ENTRY(cpu_arm922_proc_fin) + stmfd sp!, {lr} + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE + msr cpsr_c, ip + bl cpu_arm922_cache_clean_invalidate_all + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} + +/* + * cpu_arm922_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_arm922_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 + +/* + * cpu_arm922_do_idle() + */ + .align 5 +ENTRY(cpu_arm922_do_idle) +#if defined(CONFIG_CPU_ARM922_CPU_IDLE) + mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt +#endif + mov pc, lr + +/* ================================= CACHE ================================ */ + + +/* + * cpu_arm922_cache_clean_invalidate_all() + * + * clean and invalidate all cache lines + * + * Note: + * 1. we should preserve r0 at all times + */ + .align 5 +ENTRY(cpu_arm922_cache_clean_invalidate_all) + mov r2, #1 +cpu_arm922_cache_clean_invalidate_all_r2: + mov ip, #0 +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else +/* + * 'Clean & Invalidate whole DCache' + * Re-written to use Index Ops. + * Uses registers r1, r3 and ip + */ + mov r1, #3 << 5 @ 4 segments +1: orr r3, r1, #63 << 26 @ 64 entries +2: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index + subs r3, r3, #1 << 26 + bcs 2b @ entries 63 to 0 + subs r1, r1, #1 << 5 + bcs 1b @ segments 7 to 0 +#endif + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm922_cache_clean_invalidate_range(start, end, flags) + * + * clean and invalidate all cache lines associated with this area of memory + * + * start: Area start address + * end: Area end address + * flags: nonzero for I cache as well + */ + .align 5 +ENTRY(cpu_arm922_cache_clean_invalidate_range) + bic r0, r0, #DCACHELINESIZE - 1 @ && added by PGM + bic r1, r1, #DCACHELINESIZE - 1 @ && added by DHM + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_arm922_cache_clean_invalidate_all_r2 +1: teq r2, #0 +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE +#else + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE +#endif + cmp r0, r1 + blt 1b + + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm922_flush_ram_page(page) + * + * clean and invalidate all cache lines associated with this area of memory + * + * page: page to clean and invalidate + */ + .align 5 +ENTRY(cpu_arm922_flush_ram_page) + mov r1, #PAGESIZE +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE +#else +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE +#endif + subs r1, r1, #2 * DCACHELINESIZE + bne 1b + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ D-CACHE =============================== */ + +/* + * cpu_arm922_dcache_invalidate_range(start, end) + * + * throw away all D-cached data in specified region without an obligation + * to write them back. Note however that we must clean the D-cached entries + * around the boundaries if the start and/or end address are not cache + * aligned. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm922_dcache_invalidate_range) +#ifndef CONFIG_CPU_ARM922_WRITETHROUGH + tst r0, #DCACHELINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 1 @ clean D entry + tst r1, #DCACHELINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 1 @ clean D entry +#endif @ clean D entry + bic r0, r0, #DCACHELINESIZE - 1 + bic r1, r1, #DCACHELINESIZE - 1 +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm922_dcache_clean_range(start, end) + * + * For the specified virtual address range, ensure that all caches contain + * clean data, such that peripheral accesses to the physical RAM fetch + * correct data. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm922_dcache_clean_range) +#ifndef CONFIG_CPU_ARM922_WRITETHROUGH + bic r0, r0, #DCACHELINESIZE - 1 + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + mov r2, #0 + bgt cpu_arm922_cache_clean_invalidate_all_r2 + + bic r1, r1, #DCACHELINESIZE -1 + add r1, r1, #DCACHELINESIZE + +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #DCACHELINESIZE + bpl 1b +#endif + mcr p15, 0, r2, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm922_dcache_clean_page(page) + * + * Cleans a single page of dcache so that if we have any future aliased + * mappings, they will be consistent at the time that they are created. + * + * page: virtual address of page to clean from dcache + * + * Note: + * 1. we don't need to flush the write buffer in this case. + * 2. we don't invalidate the entries since when we write the page + * out to disk, the entries may get reloaded into the cache. + */ + .align 5 +ENTRY(cpu_arm922_dcache_clean_page) +#ifndef CONFIG_CPU_ARM922_WRITETHROUGH + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bne 1b +#endif + mov pc, lr + +/* + * cpu_arm922_dcache_clean_entry(addr) + * + * Clean the specified entry of any caches such that the MMU + * translation fetches will obtain correct data. + * + * addr: cache-unaligned virtual address + */ + .align 5 +ENTRY(cpu_arm922_dcache_clean_entry) +#ifndef CONFIG_CPU_ARM922_WRITETHROUGH + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ I-CACHE =============================== */ + +/* + * cpu_arm922_icache_invalidate_range(start, end) + * + * invalidate a range of virtual addresses from the Icache + * + * This is a little misleading, it is not intended to clean out + * the i-cache but to make sure that any data written to the + * range is made consistant. This means that when we execute code + * in that region, everything works as we expect. + * + * This generally means writing back data in the Dcache and + * write buffer and flushing the Icache over that region + * + * start: virtual start address + * end: virtual end address + * + * NOTE: ICACHELINESIZE == DCACHELINESIZE (so we don't need to + * loop twice, once for i-cache, once for d-cache) + */ + .align 5 +ENTRY(cpu_arm922_icache_invalidate_range) + bic r0, r0, #ICACHELINESIZE - 1 @ Safety check + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + bgt cpu_arm922_cache_clean_invalidate_all_r2 + + bic r1, r1, #ICACHELINESIZE - 1 + add r1, r1, #ICACHELINESIZE + +1: mcr p15, 0, r0, c7, c5, 1 @ Clean I entry + mcr p15, 0, r0, c7, c10, 1 @ Clean D entry + add r0, r0, #ICACHELINESIZE + subs r1, r1, #ICACHELINESIZE + bne 1b + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +ENTRY(cpu_arm922_icache_invalidate_page) + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mov pc, lr + +/* ================================== TLB ================================= */ + +/* + * cpu_arm922_tlb_invalidate_all() + * + * Invalidate all TLB entries + */ + .align 5 +ENTRY(cpu_arm922_tlb_invalidate_all) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_arm922_tlb_invalidate_range(start, end) + * + * invalidate TLB entries covering the specified range + * + * start: range start address + * end: range end address + */ + .align 5 +ENTRY(cpu_arm922_tlb_invalidate_range) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + + mov r3, #PAGESIZE + sub r3, r3, #1 + bic r0, r0, r3 + bic r1, r1, r3 + +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + add r0, r0, #PAGESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm922_tlb_invalidate_page(page, flags) + * + * invalidate the TLB entries for the specified page. + * + * page: page to invalidate + * flags: non-zero if we include the I TLB + */ + .align 5 +ENTRY(cpu_arm922_tlb_invalidate_page) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + teq r1, #0 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + mov pc, lr + +/* =============================== PageTable ============================== */ + +/* + * cpu_arm922_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_arm922_set_pgd) + mov ip, #0 +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH + /* Any reason why we don't use mcr p15, 0, r0, c7, c7, 0 here? --rmk */ + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else +@ && 'Clean & Invalidate whole DCache' +@ && Re-written to use Index Ops. +@ && Uses registers r1, r3 and ip + + mov r1, #3 << 5 @ 4 segments +1: orr r3, r1, #63 << 26 @ 64 entries +2: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index + subs r3, r3, #1 << 26 + bcs 2b @ entries 63 to 0 + subs r1, r1, #1 << 5 + bcs 1b @ segments 7 to 0 +#endif + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_arm922_set_pmd(pmdp, pmd) + * + * Set a level 1 translation table entry, and clean it out of + * any caches such that the MMUs can load it correctly. + * + * pmdp: pointer to PMD entry + * pmd: PMD value to store + */ + .align 5 +ENTRY(cpu_arm922_set_pmd) +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH + eor r2, r1, #0x0a @ C & Section + tst r2, #0x0b + biceq r1, r1, #4 @ clear bufferable bit +#endif + str r1, [r0] + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm922_set_pte(ptep, pte) + * + * Set a PTE and flush it out + */ + .align 5 +ENTRY(cpu_arm922_set_pte) + str r1, [r0], #-1024 @ linux version + + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? + movne r2, #0 + +#ifdef CONFIG_CPU_ARM922_WRITETHROUGH + eor r3, r2, #0x0a @ C & small page? + tst r3, #0x0b + biceq r2, r2, #4 +#endif + str r2, [r0] @ hardware version + mov r0, r0 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + + +cpu_manu_name: + .asciz "ARM/ALTERA" +ENTRY(cpu_arm922_name) + .ascii "Arm922T" +#if defined(CONFIG_CPU_ARM922_CPU_IDLE) + .ascii "s" +#endif +#if defined(CONFIG_CPU_ARM922_I_CACHE_ON) + .ascii "i" +#endif +#if defined(CONFIG_CPU_ARM922_D_CACHE_ON) + .ascii "d" +#if defined(CONFIG_CPU_ARM922_WRITETHROUGH) + .ascii "(wt)" +#else + .ascii "(wb)" +#endif +#endif + .ascii "\0" + .align + + .section ".text.init", #alloc, #execinstr + +__arm922_setup: + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 +/* + * Clear out 'unwanted' bits (then put them in if we need them) + */ + @ VI ZFRS BLDP WCAM + bic r0, r0, #0x0e00 + bic r0, r0, #0x0002 + bic r0, r0, #0x000c + bic r0, r0, #0x1000 @ ...0 000. .... 000. +/* + * Turn on what we want + */ + orr r0, r0, #0x0031 + orr r0, r0, #0x2100 @ ..1. ...1 ..11 ...1 + +#ifdef CONFIG_CPU_ARM922_D_CACHE_ON + orr r0, r0, #0x0004 @ .... .... .... .1.. +#endif +#ifdef CONFIG_CPU_ARM922_I_CACHE_ON + orr r0, r0, #0x1000 @ ...1 .... .... .... +#endif + mov pc, lr + + .text + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm922_processor_functions, #object +arm922_processor_functions: + .word armv4t_early_abort + .word cpu_arm922_check_bugs + .word cpu_arm922_proc_init + .word cpu_arm922_proc_fin + .word cpu_arm922_reset + .word cpu_arm922_do_idle + + /* cache */ + .word cpu_arm922_cache_clean_invalidate_all + .word cpu_arm922_cache_clean_invalidate_range + .word cpu_arm922_flush_ram_page + + /* dcache */ + .word cpu_arm922_dcache_invalidate_range + .word cpu_arm922_dcache_clean_range + .word cpu_arm922_dcache_clean_page + .word cpu_arm922_dcache_clean_entry + + /* icache */ + .word cpu_arm922_icache_invalidate_range + .word cpu_arm922_icache_invalidate_page + + /* tlb */ + .word cpu_arm922_tlb_invalidate_all + .word cpu_arm922_tlb_invalidate_range + .word cpu_arm922_tlb_invalidate_page + + /* pgtable */ + .word cpu_arm922_set_pgd + .word cpu_arm922_set_pmd + .word cpu_arm922_set_pte + + /* misc */ + .word armv4_clear_user_page + .word armv4_copy_user_page + + .size arm922_processor_functions, . - arm922_processor_functions + + .type cpu_arm922_info, #object +cpu_arm922_info: + .long cpu_manu_name + .long cpu_arm922_name + .size cpu_arm922_info, . - cpu_arm922_info + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __arm922_proc_info,#object +__arm922_proc_info: + .long 0x41009220 + .long 0xff00fff0 + .long 0x00000c1e @ mmuflags + b __arm922_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_arm922_info + .long arm922_processor_functions + .size __arm922_proc_info, . - __arm922_proc_info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/proc-arm926.S linux-2.5/arch/arm/mm/proc-arm926.S --- linux-2.5.1/arch/arm/mm/proc-arm926.S Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/arm/mm/proc-arm926.S Sun Jan 6 01:38:26 2002 @@ -56,35 +56,39 @@ * cpu_arm926_data_abort() * * obtain information about current aborted instruction + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. * * Inputs: - * r0 = address of abort - * r1 = cpsr of abort + * r2 = address of abort + * r3 = cpsr of abort * * Returns: * r0 = address of abort * r1 != 0 if writing * r3 = FSR + * r4 = corrupted */ .align 5 ENTRY(cpu_arm926_data_abort) + mrc p15, 0, r0, c6, c0, 0 @ get FAR + mrc p15, 0, r4, c5, c0, 0 @ get FSR + tst r1, #1<<24 @ Check for Jbit (NE -> found) movne r1, #-1 @ Mark as writing bne 2f - tst r1, #1<<5 @ Check for Thumb-bit (NE -> found) - ldrneh r1, [r0] @ Read aborted Thumb instruction + tst r3, #1<<5 @ Check for Thumb-bit (NE -> found) + ldrneh r1, [r2] @ Read aborted Thumb instruction tstne r1, r1, lsr #12 @ C = bit 11 - ldreq r1, [r0] @ Read aborted ARM instruction + ldreq r1, [r2] @ Read aborted ARM instruction tsteq r1, r1, lsr #21 @ C = bit 20 sbc r1, r1, r1 @ r1 = C - 1 2: - mrc p15, 0, r3, c5, c0, 0 @ get FSR - and r3, r3, #255 - mrc p15, 0, r0, c6, c0, 0 @ get FAR - + and r3, r4, #255 mov pc, lr /* @@ -92,7 +96,7 @@ */ ENTRY(cpu_arm926_check_bugs) mrs ip, cpsr - bic ip, ip, #F_BIT + bic ip, ip, #PSR_F_BIT msr cpsr, ip mov pc, lr @@ -107,7 +111,7 @@ */ ENTRY(cpu_arm926_proc_fin) stmfd sp!, {lr} - mov ip, #F_BIT | I_BIT | SVC_MODE + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, ip bl cpu_arm926_cache_clean_invalidate_all mrc p15, 0, r0, c1, c0, 0 @ ctrl register @@ -601,7 +605,7 @@ */ .type arm926_processor_functions, #object arm926_processor_functions: - .word cpu_arm926_data_abort + .word armv5ej_early_abort .word cpu_arm926_check_bugs .word cpu_arm926_proc_init .word cpu_arm926_proc_fin @@ -632,6 +636,11 @@ .word cpu_arm926_set_pgd .word cpu_arm926_set_pmd .word cpu_arm926_set_pte + + /* misc */ + .word armv4_clear_user_page + .word armv4_copy_user_page + .size arm926_processor_functions, . - arm926_processor_functions .type cpu_arm926_info, #object diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/proc-sa110.S linux-2.5/arch/arm/mm/proc-sa110.S --- linux-2.5.1/arch/arm/mm/proc-sa110.S Thu Oct 25 20:53:46 2001 +++ linux-2.5/arch/arm/mm/proc-sa110.S Sun Jan 6 01:38:26 2002 @@ -22,6 +22,7 @@ #include <asm/constants.h> #include <asm/procinfo.h> #include <asm/hardware.h> +#include <asm/proc/pgtable.h> /* This is the maximum size of an area which will be flushed. If the area * is larger than this, then we flush the whole cache @@ -41,6 +42,10 @@ #define FLUSH_OFFSET 32768 .macro flush_110_dcache rd, ra, re + ldr \rd, =flush_base + ldr \ra, [\rd] + eor \ra, \ra, #FLUSH_OFFSET + str \ra, [\rd] add \re, \ra, #16384 @ only necessary for 16k 1001: ldr \rd, [\ra], #DCACHELINESIZE teq \re, \ra @@ -48,6 +53,10 @@ .endm .macro flush_1100_dcache rd, ra, re + ldr \rd, =flush_base + ldr \ra, [\rd] + eor \ra, \ra, #FLUSH_OFFSET + str \ra, [\rd] add \re, \ra, #8192 @ only necessary for 8k 1001: ldr \rd, [\ra], #DCACHELINESIZE teq \re, \ra @@ -62,40 +71,16 @@ .endm .data -Lclean_switch: .long 0 +flush_base: .long FLUSH_BASE .text - -/* - * cpu_sa110_data_abort() - * - * obtain information about current aborted instruction - * - * r0 = address of aborted instruction - * - * Returns: - * r0 = address of abort - * r1 != 0 if writing - * r3 = FSR - */ - .align 5 -ENTRY(cpu_sa110_data_abort) -ENTRY(cpu_sa1100_data_abort) - ldr r1, [r0] @ read aborted instruction - mrc p15, 0, r0, c6, c0, 0 @ get FAR - tst r1, r1, lsr #21 @ C = bit 20 - mrc p15, 0, r3, c5, c0, 0 @ get FSR - sbc r1, r1, r1 @ r1 = C - 1 - and r3, r3, #255 - mov pc, lr - /* * cpu_sa110_check_bugs() */ ENTRY(cpu_sa110_check_bugs) ENTRY(cpu_sa1100_check_bugs) mrs ip, cpsr - bic ip, ip, #F_BIT + bic ip, ip, #PSR_F_BIT msr cpsr, ip mov pc, lr @@ -113,7 +98,7 @@ */ ENTRY(cpu_sa110_proc_fin) stmfd sp!, {lr} - mov ip, #F_BIT | I_BIT | SVC_MODE + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, ip bl cpu_sa110_cache_clean_invalidate_all @ clean caches 1: mov r0, #0 @@ -126,7 +111,7 @@ ENTRY(cpu_sa1100_proc_fin) stmfd sp!, {lr} - mov ip, #F_BIT | I_BIT | SVC_MODE + mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, ip bl cpu_sa1100_cache_clean_invalidate_all @ clean caches b 1b @@ -224,13 +209,6 @@ ENTRY(cpu_sa110_cache_clean_invalidate_all) mov r2, #1 cpu_sa110_cache_clean_invalidate_all_r2: - ldr r3, =Lclean_switch - ldr ip, =FLUSH_BASE - ldr r1, [r3] - ands r1, r1, #1 - eor r1, r1, #1 - str r1, [r3] - addne ip, ip, #FLUSH_OFFSET flush_110_dcache r3, ip, r1 mov ip, #0 teq r2, #0 @@ -242,13 +220,6 @@ ENTRY(cpu_sa1100_cache_clean_invalidate_all) mov r2, #1 cpu_sa1100_cache_clean_invalidate_all_r2: - ldr r3, =Lclean_switch - ldr ip, =FLUSH_BASE - ldr r1, [r3] - ands r1, r1, #1 - eor r1, r1, #1 - str r1, [r3] - addne ip, ip, #FLUSH_OFFSET flush_1100_dcache r3, ip, r1 mov ip, #0 teq r2, #0 @@ -501,13 +472,6 @@ */ .align 5 ENTRY(cpu_sa110_set_pgd) - ldr r3, =Lclean_switch - ldr ip, =FLUSH_BASE - ldr r2, [r3] - ands r2, r2, #1 - eor r2, r2, #1 - str r2, [r3] - addne ip, ip, #FLUSH_OFFSET flush_110_dcache r3, ip, r1 mov r1, #0 mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache @@ -525,13 +489,6 @@ */ .align 5 ENTRY(cpu_sa1100_set_pgd) - ldr r3, =Lclean_switch - ldr ip, =FLUSH_BASE - ldr r2, [r3] - ands r2, r2, #1 - eor r2, r2, #1 - str r2, [r3] - addne ip, ip, #FLUSH_OFFSET flush_1100_dcache r3, ip, r1 mov ip, #0 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache @@ -568,19 +525,19 @@ ENTRY(cpu_sa1100_set_pte) str r1, [r0], #-1024 @ linux version - eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY bic r2, r1, #0xff0 bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL + orr r2, r2, #PTE_TYPE_SMALL - tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? - orrne r2, r2, #HPTE_AP_READ + tst r1, #L_PTE_USER | L_PTE_EXEC @ User or Exec? + orrne r2, r2, #PTE_SMALL_AP_URO_SRW - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? - orreq r2, r2, #HPTE_AP_WRITE + tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? + orreq r2, r2, #PTE_SMALL_AP_UNO_SRW - tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? + tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? movne r2, #0 str r2, [r0] @ hardware version @@ -636,7 +593,7 @@ .type sa110_processor_functions, #object ENTRY(sa110_processor_functions) - .word cpu_sa110_data_abort + .word armv4_early_abort .word cpu_sa110_check_bugs .word cpu_sa110_proc_init .word cpu_sa110_proc_fin @@ -667,6 +624,11 @@ .word cpu_sa110_set_pgd .word cpu_sa110_set_pmd .word cpu_sa110_set_pte + + /* misc */ + .word armv4_clear_user_page + .word armv4_copy_user_page + .size sa110_processor_functions, . - sa110_processor_functions .type cpu_sa110_info, #object @@ -681,7 +643,7 @@ */ .type sa1100_processor_functions, #object ENTRY(sa1100_processor_functions) - .word cpu_sa1100_data_abort + .word armv4_early_abort .word cpu_sa1100_check_bugs .word cpu_sa1100_proc_init .word cpu_sa1100_proc_fin @@ -712,6 +674,11 @@ .word cpu_sa1100_set_pgd .word cpu_sa1100_set_pmd .word cpu_sa1100_set_pte + + /* misc */ + .word armv4_clear_user_page + .word armv4_copy_user_page + .size sa1100_processor_functions, . - sa1100_processor_functions cpu_sa1100_info: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/proc-xscale.S linux-2.5/arch/arm/mm/proc-xscale.S --- linux-2.5.1/arch/arm/mm/proc-xscale.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/proc-xscale.S Sun Jan 6 01:38:26 2002 @@ -0,0 +1,812 @@ +/* + * linux/arch/arm/mm/proc-xscale.S + * + * Author: Nicolas Pitre + * Created: November 2000 + * Copyright: (C) 2000, 2001 MontaVista Software Inc. + * + * 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. + * + * MMU functions for the Intel XScale CPUs + * + * 2001 Aug 21: + * some contributions by Brett Gaines <brett.w.gaines@intel.com> + * Copyright 2001 by Intel Corp. + * + * 2001 Sep 08: + * Completely revisited, many important fixes + * Nicolas Pitre <nico@cam.org> + */ + +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/constants.h> +#include <asm/procinfo.h> +#include <asm/hardware.h> +#include <asm/proc/pgtable.h> + +/* + * This is the maximum size of an area which will be flushed. If the area + * is larger than this, then we flush the whole cache + */ +#define MAX_AREA_SIZE 32768 + +/* + * the cache line size of the I and D cache + */ +#define CACHELINESIZE 32 + +/* + * the size of the data cache + */ +#define CACHESIZE 32768 + +/* + * and the page size + */ +#define PAGESIZE 4096 + +/* + * Virtual address used to allocate the cache when flushed + * + * This must be an address range which is _never_ used. It should + * apparently have a mapping in the corresponding page table for + * compatibility with future CPUs that _could_ require it. For instance we + * don't care. + * + * This must be aligned on a 2*CACHESIZE boundary. The code selects one of + * the 2 areas in alternance each time the clean_d_cache macro is used. + * Without this the XScale core exhibits cache eviction problems and no one + * knows why. + * + * Reminder: the vector table is located at 0xffff0000-0xffff0fff. + */ +#define CLEAN_ADDR 0xfffe0000 + +/* + * This macro is used to wait for a CP15 write and is needed + * when we have to ensure that the last operation to the co-pro + * was completed before continuing with operation. + */ + .macro cpwait, rd + mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 + mov \rd, \rd @ wait for completion + sub pc, pc, #4 @ flush instruction pipeline + .endm + + .macro cpwait_ret, lr, rd + mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 + sub pc, \lr, \rd, LSR #32 @ wait for completion and + @ flush instruction pipeline + .endm + +/* + * This macro cleans the entire dcache using line allocate. + * The main loop has been unrolled to reduce loop overhead. + * rd and rs are two scratch registers. + */ + .macro clean_d_cache, rd, rs + ldr \rs, =clean_addr + ldr \rd, [\rs] + eor \rd, \rd, #CACHESIZE + str \rd, [\rs] + add \rs, \rd, #CACHESIZE +1: mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line + add \rd, \rd, #CACHELINESIZE + mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line + add \rd, \rd, #CACHELINESIZE + mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line + add \rd, \rd, #CACHELINESIZE + mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line + add \rd, \rd, #CACHELINESIZE + teq \rd, \rs + bne 1b + .endm + + .data +clean_addr: .word CLEAN_ADDR + + .text + +/* + * cpu_xscale_check_bugs() + */ +ENTRY(cpu_xscale_check_bugs) + mrs ip, cpsr + bic ip, ip, #PSR_F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_xscale_proc_init() + * + * Nothing too exciting at the moment + */ +ENTRY(cpu_xscale_proc_init) + mov pc, lr + +/* + * cpu_xscale_proc_fin() + */ +ENTRY(cpu_xscale_proc_fin) + str lr, [sp, #-4]! + mov r0, #PSR_F_BIT|PSR_I_BIT|SVC_MODE + msr cpsr_c, r0 + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1800 @ ...IZ........... + bic r0, r0, #0x0006 @ .............CA. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + bl cpu_xscale_cache_clean_invalidate_all @ clean caches + ldr pc, [sp], #4 + +/* + * cpu_xscale_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_xscale_reset) + mov r1, #PSR_F_BIT|PSR_I_BIT|SVC_MODE + msr cpsr_c, r1 @ reset CPSR + mrc p15, 0, r1, c1, c0, 0 @ ctrl register + bic r1, r1, #0x0086 @ ........B....CA. + bic r1, r1, #0x1900 @ ...IZ..S........ + mcr p15, 0, r1, c1, c0, 0 @ ctrl register + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches & BTB + bic r1, r1, #0x0001 @ ...............M + mcr p15, 0, r1, c1, c0, 0 @ ctrl register + @ CAUTION: MMU turned off from this point. We count on the pipeline + @ already containing those two last instructions to survive. + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mov pc, r0 + +/* + * cpu_xscale_do_idle(type) + * + * Cause the processor to idle + * + * type: + * 0 = slow idle + * 1 = fast idle + * 2 = switch to slow processor clock + * 3 = switch to fast processor clock + * + * For now we do nothing but go to idle mode for every case + * + * XScale supports clock switching, but using idle mode support + * allows external hardware to react to system state changes. + */ + .align 5 + +ENTRY(cpu_xscale_do_idle) + mov r0, #1 + mcr p14, 0, r0, c7, c0, 0 @ Go to IDLE + mov pc, lr + +/* ================================= CACHE ================================ */ + +/* + * cpu_xscale_cache_clean_invalidate_all (void) + * + * clean and invalidate all cache lines + * + * Note: + * 1. We should preserve r0 at all times. + * 2. Even if this function implies cache "invalidation" by its name, + * we don't need to actually use explicit invalidation operations + * since the goal is to discard all valid references from the cache + * and the cleaning of it already has that effect. + * 3. Because of 2 above and the fact that kernel space memory is always + * coherent across task switches there is no need to worry about + * inconsistencies due to interrupts, ence no irq disabling. + */ + .align 5 +ENTRY(cpu_xscale_cache_clean_invalidate_all) + mov r2, #1 +cpu_xscale_cache_clean_invalidate_all_r2: + clean_d_cache r0, r1 + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* + * cpu_xscale_cache_clean_invalidate_range(start, end, flags) + * + * clean and invalidate all cache lines associated with this area of memory + * + * start: Area start address + * end: Area end address + * flags: nonzero for I cache as well + */ + .align 5 +ENTRY(cpu_xscale_cache_clean_invalidate_range) + bic r0, r0, #CACHELINESIZE - 1 @ round down to cache line + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bhi cpu_xscale_cache_clean_invalidate_all_r2 +1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line + add r0, r0, #CACHELINESIZE + cmp r0, r1 + blo 1b + teq r2, #0 + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + moveq pc, lr + sub r0, r0, r3 +1: mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + cmp r0, r1 + blo 1b + mcr p15, 0, ip, c7, c5, 6 @ Invalidate BTB + mov pc, lr + +/* + * cpu_xscale_flush_ram_page(page) + * + * clean all cache lines associated with this memory page + * + * page: page to clean + */ + .align 5 +ENTRY(cpu_xscale_flush_ram_page) + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + subs r1, r1, #2 * CACHELINESIZE + bne 1b + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* ================================ D-CACHE =============================== */ + +/* + * cpu_xscale_dcache_invalidate_range(start, end) + * + * throw away all D-cached data in specified region without an obligation + * to write them back. Note however that on XScale we must clean all + * entries also due to hardware errata (80200 A0 & A1 only). + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_xscale_dcache_invalidate_range) + mrc p15, 0, r2, c0, c0, 0 @ Read part no. + eor r2, r2, #0x69000000 + eor r2, r2, #0x00052000 @ 80200 XX part no. + bics r2, r2, #0x1 @ Clear LSB in revision field + moveq r2, #0 + beq cpu_xscale_cache_clean_invalidate_range @ An 80200 A0 or A1 + + tst r0, #CACHELINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 1 @ Clean D cache line + tst r1, #CACHELINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 1 @ Clean D cache line + bic r0, r0, #CACHELINESIZE - 1 @ round down to cache line +1: mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line + add r0, r0, #CACHELINESIZE + cmp r0, r1 + blo 1b + mov pc, lr + +/* + * cpu_xscale_dcache_clean_range(start, end) + * + * For the specified virtual address range, ensure that all caches contain + * clean data, such that peripheral accesses to the physical RAM fetch + * correct data. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_xscale_dcache_clean_range) + bic r0, r0, #CACHELINESIZE - 1 + sub r2, r1, r0 + cmp r2, #MAX_AREA_SIZE + movhi r2, #0 + bhi cpu_xscale_cache_clean_invalidate_all_r2 + +1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + cmp r0, r1 + blo 1b + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* + * cpu_xscale_clean_dcache_page(page) + * + * Cleans a single page of dcache so that if we have any future aliased + * mappings, they will be consistent at the time that they are created. + * + * Note: + * 1. we don't need to flush the write buffer in this case. [really? -Nico] + * 2. we don't invalidate the entries since when we write the page + * out to disk, the entries may get reloaded into the cache. + */ + .align 5 +ENTRY(cpu_xscale_dcache_clean_page) + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + add r0, r0, #CACHELINESIZE + subs r1, r1, #4 * CACHELINESIZE + bne 1b + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* + * cpu_xscale_dcache_clean_entry(addr) + * + * Clean the specified entry of any caches such that the MMU + * translation fetches will obtain correct data. + * + * addr: cache-unaligned virtual address + */ + .align 5 +ENTRY(cpu_xscale_dcache_clean_entry) + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* ================================ I-CACHE =============================== */ + +/* + * cpu_xscale_icache_invalidate_range(start, end) + * + * invalidate a range of virtual addresses from the Icache + * + * start: virtual start address + * end: virtual end address + * + * Note: This is vaguely defined as supposed to bring the dcache and the + * icache in sync by the way this function is used. + */ + .align 5 +ENTRY(cpu_xscale_icache_invalidate_range) + bic r0, r0, #CACHELINESIZE - 1 +1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + cmp r0, r1 + blo 1b + mcr p15, 0, ip, c7, c5, 6 @ Invalidate BTB + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* + * cpu_xscale_icache_invalidate_page(page) + * + * invalidate all Icache lines associated with this area of memory + * + * page: page to invalidate + */ + .align 5 +ENTRY(cpu_xscale_icache_invalidate_page) + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line + add r0, r0, #CACHELINESIZE + subs r1, r1, #4 * CACHELINESIZE + bne 1b + mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB + mov pc, lr + +/* ================================ CACHE LOCKING============================ + * + * The XScale MicroArchitecture implements support for locking entries into + * the data and instruction cache. The following functions implement the core + * low level instructions needed to accomplish the locking. The developer's + * manual states that the code that performs the locking must be in non-cached + * memory. To accomplish this, the code in xscale-cache-lock.c copies the + * following functions from the cache into a non-cached memory region that + * is allocated through consistent_alloc(). + * + */ + .align 5 +/* + * xscale_icache_lock + * + * r0: starting address to lock + * r1: end address to lock + */ +ENTRY(xscale_icache_lock) + +iLockLoop: + bic r0, r0, #CACHELINESIZE - 1 + mcr p15, 0, r0, c9, c1, 0 @ lock into cache + cmp r0, r1 @ are we done? + add r0, r0, #CACHELINESIZE @ advance to next cache line + bls iLockLoop + mov pc, lr + +/* + * xscale_icache_unlock + */ +ENTRY(xscale_icache_unlock) + mcr p15, 0, r0, c9, c1, 1 @ Unlock icache + mov pc, lr + +/* + * xscale_dcache_lock + * + * r0: starting address to lock + * r1: end address to lock + */ +ENTRY(xscale_dcache_lock) + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov r2, #1 + mcr p15, 0, r2, c9, c2, 0 @ Put dcache in lock mode + cpwait ip @ Wait for completion + + mrs r2, cpsr + orr r3, r2, #PSR_F_BIT | PSR_I_BIT +dLockLoop: + msr cpsr_c, r3 + mcr p15, 0, r0, c7, c10, 1 @ Write back line if it is dirty + mcr p15, 0, r0, c7, c6, 1 @ Flush/invalidate line + msr cpsr_c, r2 + ldr ip, [r0], #CACHELINESIZE @ Preload 32 bytes into cache from + @ location [r0]. Post-increment + @ r3 to next cache line + cmp r0, r1 @ Are we done? + bls dLockLoop + + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov r2, #0 + mcr p15, 0, r2, c9, c2, 0 @ Get out of lock mode + cpwait_ret lr, ip + +/* + * xscale_dcache_unlock + */ +ENTRY(xscale_dcache_unlock) + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mcr p15, 0, ip, c9, c2, 1 @ Unlock cache + mov pc, lr + +/* + * Needed to determine the length of the code that needs to be copied. + */ + .align 5 +ENTRY(xscale_cache_dummy) + mov pc, lr + +/* ================================== TLB ================================= */ + +/* + * cpu_xscale_tlb_invalidate_all() + * + * Invalidate all TLB entries + */ + .align 5 +ENTRY(cpu_xscale_tlb_invalidate_all) + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + cpwait_ret lr, ip + +/* + * cpu_xscale_tlb_invalidate_range(start, end) + * + * invalidate TLB entries covering the specified range + * + * start: range start address + * end: range end address + */ + .align 5 +ENTRY(cpu_xscale_tlb_invalidate_range) + bic r0, r0, #(PAGESIZE - 1) & 0x00ff + bic r0, r0, #(PAGESIZE - 1) & 0xff00 + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + add r0, r0, #PAGESIZE + cmp r0, r1 + blo 1b + cpwait_ret lr, ip + +/* + * cpu_xscale_tlb_invalidate_page(page, flags) + * + * invalidate the TLB entries for the specified page. + * + * page: page to invalidate + * flags: non-zero if we include the I TLB + */ + .align 5 +ENTRY(cpu_xscale_tlb_invalidate_page) + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + teq r1, #0 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcrne p15, 0, r3, c8, c5, 1 @ invalidate I TLB entry + cpwait_ret lr, ip + +/* ================================ TLB LOCKING============================== + * + * The XScale MicroArchitecture implements support for locking entries into + * the Instruction and Data TLBs. The following functions provide the + * low level support for supporting these under Linux. xscale-lock.c + * implements some higher level management code. Most of the following + * is taken straight out of the Developer's Manual. + */ + +/* + * Lock I-TLB entry + * + * r0: Virtual address to translate and lock + */ + .align 5 +ENTRY(xscale_itlb_lock) + mrs r2, cpsr + orr r3, r2, #PSR_F_BIT | PSR_I_BIT + msr cpsr_c, r3 @ Disable interrupts + mcr p15, 0, r0, c8, c5, 1 @ Invalidate I-TLB entry + mcr p15, 0, r0, c10, c4, 0 @ Translate and lock + msr cpsr_c, r2 @ Restore interrupts + cpwait_ret lr, ip + +/* + * Lock D-TLB entry + * + * r0: Virtual address to translate and lock + */ + .align 5 +ENTRY(xscale_dtlb_lock) + mrs r2, cpsr + orr r3, r2, #PSR_F_BIT | PSR_I_BIT + msr cpsr_c, r3 @ Disable interrupts + mcr p15, 0, r0, c8, c6, 1 @ Invalidate D-TLB entry + mcr p15, 0, r0, c10, c8, 0 @ Translate and lock + msr cpsr_c, r2 @ Restore interrupts + cpwait_ret lr, ip + +/* + * Unlock all I-TLB entries + */ + .align 5 +ENTRY(xscale_itlb_unlock) + mcr p15, 0, ip, c10, c4, 1 @ Unlock I-TLB + mcr p15, 0, ip, c8, c5, 0 @ Invalidate I-TLB + cpwait_ret lr, ip + +/* + * Unlock all D-TLB entries + */ +ENTRY(xscale_dtlb_unlock) + mcr p15, 0, ip, c10, c8, 1 @ Unlock D-TBL + mcr p15, 0, ip, c8, c6, 0 @ Invalidate D-TLB + cpwait_ret lr, ip + +/* =============================== PageTable ============================== */ + +#define PMD_CACHE_WRITE_ALLOCATE 0 +#define PTE_CACHE_WRITE_ALLOCATE 0 + +/* + * cpu_xscale_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_xscale_set_pgd) + clean_d_cache r1, r2 + mcr p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + cpwait_ret lr, ip + +/* + * cpu_xscale_set_pmd(pmdp, pmd) + * + * Set a level 1 translation table entry, and clean it out of + * any caches such that the MMUs can load it correctly. + * + * pmdp: pointer to PMD entry + * pmd: PMD value to store + */ + .align 5 +ENTRY(cpu_xscale_set_pmd) +#if PMD_CACHE_WRITE_ALLOCATE + and r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE + cmp r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE + orreq r1, r1, #PMD_SECT_TEX(1) +#endif + str r1, [r0] + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + +/* + * cpu_xscale_set_pte(ptep, pte) + * + * Set a PTE and flush it out + */ + .align 5 +ENTRY(cpu_xscale_set_pte) + str r1, [r0], #-1024 @ linux version + + bic r2, r1, #0xff0 + orr r2, r2, #PTE_TYPE_EXT @ extended page + + eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY + + tst r1, #L_PTE_USER | L_PTE_EXEC @ User or Exec? + orrne r2, r2, #PTE_EXT_AP_URO_SRW @ yes -> user r/o, system r/w + + tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? + orreq r2, r2, #PTE_EXT_AP_UNO_SRW @ yes -> user n/a, system r/w + @ combined with user -> user r/w + +#if PTE_CACHE_WRITE_ALLOCATE + tst r1, #L_PTE_CACHEABLE @ cacheable? + orrne r2, r2, #PTE_EXT_TEX(1) +#else + eor r1, r1, #L_PTE_CACHEABLE + tst r1, #L_PTE_CACHEABLE | L_PTE_BUFFERABLE @ C = 1 B = 0? + orreq r2, r2, #PTE_EXT_TEX(1) @ yes -> set X (minicache) +#endif + + tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? + movne r2, #0 @ no -> fault + + str r2, [r0] @ hardware version + mov r0, r0 + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + + + .ltorg + +cpu_manu_name: + .asciz "Intel" + +cpu_80200_name: + .asciz "XScale-80200" + +cpu_cotulla_name: + .asciz "XScale-Cotulla" + + .align + + .section ".text.init", #alloc, #execinstr + +__xscale_setup: + mov r0, #PSR_F_BIT|PSR_I_BIT|SVC_MODE + msr cpsr_c, r0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs + mcr p15, 0, r4, c2, c0, 0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0, 0 @ load domain access register + mrc p15, 0, r0, c1, c0, 0 @ get control register + bic r0, r0, #0x0200 @ .... ..R. .... .... + bic r0, r0, #0x0082 @ .... .... B... ..A. + orr r0, r0, #0x0005 @ .... .... .... .C.M + orr r0, r0, #0x3900 @ ..VI Z..S .... .... + mov pc, lr + + .text + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + + .type xscale_processor_functions, #object +ENTRY(xscale_processor_functions) + .word armv4t_early_abort + .word cpu_xscale_check_bugs + .word cpu_xscale_proc_init + .word cpu_xscale_proc_fin + .word cpu_xscale_reset + .word cpu_xscale_do_idle + + /* cache */ + .word cpu_xscale_cache_clean_invalidate_all + .word cpu_xscale_cache_clean_invalidate_range + .word cpu_xscale_flush_ram_page + + /* dcache */ + .word cpu_xscale_dcache_invalidate_range + .word cpu_xscale_dcache_clean_range + .word cpu_xscale_dcache_clean_page + .word cpu_xscale_dcache_clean_entry + + /* icache */ + .word cpu_xscale_icache_invalidate_range + .word cpu_xscale_icache_invalidate_page + + /* tlb */ + .word cpu_xscale_tlb_invalidate_all + .word cpu_xscale_tlb_invalidate_range + .word cpu_xscale_tlb_invalidate_page + + /* pgtable */ + .word cpu_xscale_set_pgd + .word cpu_xscale_set_pmd + .word cpu_xscale_set_pte + + /* misc */ + .word armv5te_clear_user_page + .word armv5te_copy_user_page + + .size xscale_processor_functions, . - xscale_processor_functions + + .type cpu_80200_info, #object +cpu_80200_info: + .long cpu_manu_name + .long cpu_80200_name + .size cpu_80200_info, . - cpu_80200_info + + .type cpu_cotulla_info, #object +cpu_cotulla_info: + .long cpu_manu_name + .long cpu_cotulla_name + .size cpu_cotulla_info, . - cpu_cotulla_info + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __80200_proc_info,#object +__80200_proc_info: + .long 0x69052000 + .long 0xfffffff0 + .long 0x00000c0e + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_80200_info + .long xscale_processor_functions + .size __80200_proc_info, . - __80200_proc_info + + .type __cotulla_proc_info,#object +__cotulla_proc_info: + .long 0x69052100 + .long 0xfffffff0 + .long 0x00000c0e + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_cotulla_info + .long xscale_processor_functions + .size __cotulla_proc_info, . - __cotulla_proc_info + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/mm/small_page.c linux-2.5/arch/arm/mm/small_page.c --- linux-2.5.1/arch/arm/mm/small_page.c Thu Apr 12 19:20:31 2001 +++ linux-2.5/arch/arm/mm/small_page.c Thu Jan 1 00:00:00 1970 @@ -1,213 +0,0 @@ -/* - * linux/arch/arm/mm/small_page.c - * - * Copyright (C) 1996 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: - * 26/01/1996 RMK Cleaned up various areas to make little more generic - * 07/02/1999 RMK Support added for 16K and 32K page sizes - * containing 8K blocks - */ -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> -#include <linux/mm.h> -#include <linux/swap.h> -#include <linux/smp.h> - -#include <asm/bitops.h> -#include <asm/pgtable.h> - -#define PEDANTIC - -/* - * Requirement: - * We need to be able to allocate naturally aligned memory of finer - * granularity than the page size. This is typically used for the - * second level page tables on 32-bit ARMs. - * - * Theory: - * We "misuse" the Linux memory management system. We use alloc_page - * to allocate a page and then mark it as reserved. The Linux memory - * management system will then ignore the "offset", "next_hash" and - * "pprev_hash" entries in the mem_map for this page. - * - * We then use a bitstring in the "offset" field to mark which segments - * of the page are in use, and manipulate this as required during the - * allocation and freeing of these small pages. - * - * We also maintain a queue of pages being used for this purpose using - * the "next_hash" and "pprev_hash" entries of mem_map; - */ - -struct order { - struct page *queue; - unsigned int mask; /* (1 << shift) - 1 */ - unsigned int shift; /* (1 << shift) size of page */ - unsigned int block_mask; /* nr_blocks - 1 */ - unsigned int all_used; /* (1 << nr_blocks) - 1 */ -}; - - -static struct order orders[] = { -#if PAGE_SIZE == 4096 - { NULL, 2047, 11, 1, 0x00000003 } -#elif PAGE_SIZE == 32768 - { NULL, 2047, 11, 15, 0x0000ffff }, - { NULL, 8191, 13, 3, 0x0000000f } -#else -#error unsupported page size -#endif -}; - -#define USED_MAP(pg) ((pg)->index) -#define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &USED_MAP(pg))) -#define SET_USED(pg,off) (set_bit(off, &USED_MAP(pg))) - -static spinlock_t small_page_lock = SPIN_LOCK_UNLOCKED; - -static void add_page_to_queue(struct page *page, struct page **p) -{ -#ifdef PEDANTIC - if (page->pprev_hash) - PAGE_BUG(page); -#endif - page->next_hash = *p; - if (*p) - (*p)->pprev_hash = &page->next_hash; - *p = page; - page->pprev_hash = p; -} - -static void remove_page_from_queue(struct page *page) -{ - if (page->pprev_hash) { - if (page->next_hash) - page->next_hash->pprev_hash = page->pprev_hash; - *page->pprev_hash = page->next_hash; - page->pprev_hash = NULL; - } -} - -static unsigned long __get_small_page(int priority, struct order *order) -{ - unsigned long flags; - struct page *page; - int offset; - - if (!order->queue) - goto need_new_page; - - spin_lock_irqsave(&small_page_lock, flags); - page = order->queue; -again: -#ifdef PEDANTIC - if (USED_MAP(page) & ~order->all_used) - PAGE_BUG(page); -#endif - offset = ffz(USED_MAP(page)); - SET_USED(page, offset); - if (USED_MAP(page) == order->all_used) - remove_page_from_queue(page); - spin_unlock_irqrestore(&small_page_lock, flags); - - return (unsigned long) page_address(page) + (offset << order->shift); - -need_new_page: - page = alloc_page(priority); - - spin_lock_irqsave(&small_page_lock, flags); - if (!order->queue) { - if (!page) - goto no_page; - SetPageReserved(page); - USED_MAP(page) = 0; - cli(); - add_page_to_queue(page, &order->queue); - } else { - __free_page(page); - cli(); - page = order->queue; - } - goto again; - -no_page: - spin_unlock_irqrestore(&small_page_lock, flags); - return 0; -} - -static void __free_small_page(unsigned long spage, struct order *order) -{ - unsigned long flags; - struct page *page; - - page = virt_to_page(spage); - if (VALID_PAGE(page)) { - - /* - * The container-page must be marked Reserved - */ - if (!PageReserved(page) || spage & order->mask) - goto non_small; - -#ifdef PEDANTIC - if (USED_MAP(page) & ~order->all_used) - PAGE_BUG(page); -#endif - - spage = spage >> order->shift; - spage &= order->block_mask; - - /* - * the following must be atomic wrt get_page - */ - spin_lock_irqsave(&small_page_lock, flags); - - if (USED_MAP(page) == order->all_used) - add_page_to_queue(page, &order->queue); - - if (!TEST_AND_CLEAR_USED(page, spage)) - goto already_free; - - if (USED_MAP(page) == 0) - goto free_page; - - spin_unlock_irqrestore(&small_page_lock, flags); - } - return; - -free_page: - /* - * unlink the page from the small page queue and free it - */ - remove_page_from_queue(page); - spin_unlock_irqrestore(&small_page_lock, flags); - ClearPageReserved(page); - __free_page(page); - return; - -non_small: - printk("Trying to free non-small page from %p\n", __builtin_return_address(0)); - return; -already_free: - printk("Trying to free free small page from %p\n", __builtin_return_address(0)); -} - -unsigned long get_page_8k(int priority) -{ - return __get_small_page(priority, orders+1); -} - -void free_page_8k(unsigned long spage) -{ - __free_small_page(spage, orders+1); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/nwfpe/ARM-gcc.h linux-2.5/arch/arm/nwfpe/ARM-gcc.h --- linux-2.5.1/arch/arm/nwfpe/ARM-gcc.h Thu Jun 17 08:11:35 1999 +++ linux-2.5/arch/arm/nwfpe/ARM-gcc.h Thu Dec 27 22:10:28 2001 @@ -1,11 +1,3 @@ - -/* -------------------------------------------------------------------------------- -One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined. -------------------------------------------------------------------------------- -*/ -#define LITTLEENDIAN - /* ------------------------------------------------------------------------------- The macro `BITS64' can be defined to indicate that 64-bit integer types are diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/nwfpe/entry.S linux-2.5/arch/arm/nwfpe/entry.S --- linux-2.5.1/arch/arm/nwfpe/entry.S Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/nwfpe/entry.S Thu Dec 27 22:10:28 2001 @@ -50,11 +50,10 @@ This routine does three things: -1) It saves SP into a variable called userRegisters. The kernel has -created a struct pt_regs on the stack and saved the user registers -into it. See /usr/include/asm/proc/ptrace.h for details. The -emulator code uses userRegisters as the base of an array of words from -which the contents of the registers can be extracted. +1) The kernel has created a struct pt_regs on the stack and saved the +user registers into it. See /usr/include/asm/proc/ptrace.h for details. +The emulator code uses userRegisters as the base of an array of words +from which the contents of the registers can be extracted. 2) It calls EmulateAll to emulate a floating point instruction. EmulateAll returns 1 if the emulation was successful, or 0 if not. @@ -78,16 +77,18 @@ of stealing two regs from the register allocator. Not sure if it's worth it. */ str sp, [r10] @ Store the user registers pointer in the fpa11 structure. - mov r4, sp @ use r4 for local pointer - mov r10, lr @ save the failure-return addresses + mov r4, lr @ save the failure-return addresses - ldr r5, [r4, #60] @ get contents of PC; + mov r0, r10 + bl FPA11_CheckInit @ check to see if we are initialised + + ldr r5, [sp, #60] @ get contents of PC; sub r8, r5, #4 .Lx2: ldrt r0, [r8] @ get actual instruction into r0 emulate: bl EmulateAll @ emulate the instruction cmp r0, #0 @ was emulation successful - moveq pc, r10 @ no, return failure + moveq pc, r4 @ no, return failure next: .Lx1: ldrt r6, [r5], #4 @ get the next instruction and @@ -99,10 +100,10 @@ teqne r2, #0x0E000000 movne pc, r9 @ return ok if not a fp insn - str r5, [r4, #60] @ update PC copy in regs + str r5, [sp, #60] @ update PC copy in regs mov r0, r6 @ save a copy - ldr r1, [r4, #64] @ fetch the condition codes + ldr r1, [sp, #64] @ fetch the condition codes bl checkCondition @ check the condition cmp r0, #0 @ r0 = 0 ==> condition failed diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/nwfpe/entry26.S linux-2.5/arch/arm/nwfpe/entry26.S --- linux-2.5.1/arch/arm/nwfpe/entry26.S Thu Apr 12 02:02:27 2001 +++ linux-2.5/arch/arm/nwfpe/entry26.S Sun Jan 6 01:38:26 2002 @@ -26,7 +26,7 @@ It is called from the kernel with code similar to this: mov fp, #0 - teqp pc, #I_BIT | MODE_SVC + teqp pc, #PSR_I_BIT | MODE_SVC ldr r4, .LC2 ldr pc, [r4] @ Call FP module USR entry point diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/nwfpe/fpa11.c linux-2.5/arch/arm/nwfpe/fpa11.c --- linux-2.5.1/arch/arm/nwfpe/fpa11.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/nwfpe/fpa11.c Sun Jan 6 01:38:26 2002 @@ -18,7 +18,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - +#include <linux/compiler.h> #include <asm/system.h> #include "fpa11.h" @@ -123,47 +123,57 @@ } } -/* Emulate the instruction in the opcode. */ -unsigned int EmulateAll(unsigned int opcode) +void FPA11_CheckInit(FPA11 *fpa11) { - unsigned int nRc = 0; - unsigned long flags; - FPA11 *fpa11; - save_flags(flags); sti(); - - fpa11 = GET_FPA11(); - - if (fpa11->initflag == 0) /* good place for __builtin_expect */ + if (unlikely(fpa11->initflag == 0)) { resetFPA11(); SetRoundingMode(ROUND_TO_NEAREST); SetRoundingPrecision(ROUND_EXTENDED); fpa11->initflag = 1; } +} - if (TEST_OPCODE(opcode,MASK_CPRT)) - { - /* Emulate conversion opcodes. */ - /* Emulate register transfer opcodes. */ - /* Emulate comparison opcodes. */ - nRc = EmulateCPRT(opcode); - } - else if (TEST_OPCODE(opcode,MASK_CPDO)) - { - /* Emulate monadic arithmetic opcodes. */ - /* Emulate dyadic arithmetic opcodes. */ - nRc = EmulateCPDO(opcode); - } - else if (TEST_OPCODE(opcode,MASK_CPDT)) - { - /* Emulate load/store opcodes. */ - /* Emulate load/store multiple opcodes. */ - nRc = EmulateCPDT(opcode); - } - else +/* Emulate the instruction in the opcode. */ +unsigned int EmulateAll(unsigned int opcode) +{ + unsigned int nRc = 1, code; + unsigned long flags; + + save_flags(flags); sti(); + + code = opcode & 0x00000f00; + if (code == 0x00000100 || code == 0x00000200) { - /* Invalid instruction detected. Return FALSE. */ - nRc = 0; + /* For coprocessor 1 or 2 (FPA11) */ + code = opcode & 0x0e000000; + if (code == 0x0e000000) + { + if (opcode & 0x00000010) + { + /* Emulate conversion opcodes. */ + /* Emulate register transfer opcodes. */ + /* Emulate comparison opcodes. */ + nRc = EmulateCPRT(opcode); + } + else + { + /* Emulate monadic arithmetic opcodes. */ + /* Emulate dyadic arithmetic opcodes. */ + nRc = EmulateCPDO(opcode); + } + } + else if (code == 0x0c000000) + { + /* Emulate load/store opcodes. */ + /* Emulate load/store multiple opcodes. */ + nRc = EmulateCPDT(opcode); + } + else + { + /* Invalid instruction detected. Return FALSE. */ + nRc = 0; + } } restore_flags(flags); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/nwfpe/fpa11_cpdt.c linux-2.5/arch/arm/nwfpe/fpa11_cpdt.c --- linux-2.5.1/arch/arm/nwfpe/fpa11_cpdt.c Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/nwfpe/fpa11_cpdt.c Thu Dec 27 22:10:28 2001 @@ -45,7 +45,7 @@ fpa11->fType[Fn] = typeDouble; get_user(p[0], &pMem[1]); get_user(p[1], &pMem[0]); /* sign & exponent */ -} +} static inline void loadExtended(const unsigned int Fn,const unsigned int *pMem) @@ -57,7 +57,7 @@ get_user(p[0], &pMem[0]); /* sign & exponent */ get_user(p[1], &pMem[2]); /* ls bits */ get_user(p[2], &pMem[1]); /* ms bits */ -} +} static inline void loadMultiple(const unsigned int Fn,const unsigned int *pMem) @@ -69,7 +69,7 @@ p = (unsigned int*)&(fpa11->fpreg[Fn]); get_user(x, &pMem[0]); fpa11->fType[Fn] = (x >> 14) & 0x00000003; - + switch (fpa11->fType[Fn]) { case typeSingle: @@ -79,13 +79,13 @@ get_user(p[1], &pMem[1]); /* double msw */ p[2] = 0; /* empty */ } - break; - + break; + case typeExtended: { get_user(p[1], &pMem[2]); get_user(p[2], &pMem[1]); /* msw */ - p[0] = (x & 0x80003fff); + p[0] = (x & 0x80003fff); } break; } @@ -95,82 +95,92 @@ void storeSingle(const unsigned int Fn,unsigned int *pMem) { FPA11 *fpa11 = GET_FPA11(); - float32 val; - register unsigned int *p = (unsigned int*)&val; - + union + { + float32 f; + unsigned int i[1]; + } val; + switch (fpa11->fType[Fn]) { - case typeDouble: - val = float64_to_float32(fpa11->fpreg[Fn].fDouble); + case typeDouble: + val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble); break; - case typeExtended: - val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); + case typeExtended: + val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); break; - default: val = fpa11->fpreg[Fn].fSingle; + default: val.f = fpa11->fpreg[Fn].fSingle; } - - put_user(p[0], pMem); -} + + put_user(val.i[0], pMem); +} static inline void storeDouble(const unsigned int Fn,unsigned int *pMem) { FPA11 *fpa11 = GET_FPA11(); - float64 val; - register unsigned int *p = (unsigned int*)&val; + union + { + float64 f; + unsigned int i[2]; + } val; switch (fpa11->fType[Fn]) { - case typeSingle: - val = float32_to_float64(fpa11->fpreg[Fn].fSingle); + case typeSingle: + val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle); break; case typeExtended: - val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); + val.f = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); break; - default: val = fpa11->fpreg[Fn].fDouble; + default: val.f = fpa11->fpreg[Fn].fDouble; } - put_user(p[1], &pMem[0]); /* msw */ - put_user(p[0], &pMem[1]); /* lsw */ -} + + put_user(val.i[1], &pMem[0]); /* msw */ + put_user(val.i[0], &pMem[1]); /* lsw */ +} static inline void storeExtended(const unsigned int Fn,unsigned int *pMem) { FPA11 *fpa11 = GET_FPA11(); - floatx80 val; - register unsigned int *p = (unsigned int*)&val; - + union + { + floatx80 f; + unsigned int i[3]; + } val; + switch (fpa11->fType[Fn]) { - case typeSingle: - val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + case typeSingle: + val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); break; - case typeDouble: - val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + case typeDouble: + val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); break; - default: val = fpa11->fpreg[Fn].fExtended; + default: val.f = fpa11->fpreg[Fn].fExtended; } - - put_user(p[0], &pMem[0]); /* sign & exp */ - put_user(p[1], &pMem[2]); - put_user(p[2], &pMem[1]); /* msw */ -} + + put_user(val.i[0], &pMem[0]); /* sign & exp */ + put_user(val.i[1], &pMem[2]); + put_user(val.i[2], &pMem[1]); /* msw */ +} static inline void storeMultiple(const unsigned int Fn,unsigned int *pMem) { FPA11 *fpa11 = GET_FPA11(); register unsigned int nType, *p; - + p = (unsigned int*)&(fpa11->fpreg[Fn]); nType = fpa11->fType[Fn]; - + switch (nType) { case typeSingle: @@ -180,8 +190,8 @@ put_user(p[1], &pMem[1]); /* double msw */ put_user(nType << 14, &pMem[0]); } - break; - + break; + case typeExtended: { put_user(p[2], &pMem[1]); /* msw */ @@ -221,7 +231,7 @@ case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; default: nRc = 0; } - + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); return nRc; } @@ -230,10 +240,10 @@ { unsigned int *pBase, *pAddress, *pFinal, nRc = 1, write_back = WRITE_BACK(opcode); - + //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); SetRoundingMode(ROUND_TO_NEAREST); - + pBase = (unsigned int*)readRegister(getRn(opcode)); if (REG_PC == getRn(opcode)) { @@ -256,7 +266,7 @@ case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; default: nRc = 0; } - + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); return nRc; } @@ -297,14 +307,14 @@ { unsigned int i, Fd, *pBase, *pAddress, *pFinal, write_back = WRITE_BACK(opcode); - + pBase = (unsigned int*)readRegister(getRn(opcode)); if (REG_PC == getRn(opcode)) { pBase += 2; write_back = 0; } - + pFinal = pBase; if (BIT_UP_SET(opcode)) pFinal += getOffset(opcode); @@ -331,7 +341,7 @@ unsigned int nRc = 0; //printk("EmulateCPDT(0x%08x)\n",opcode); - + if (LDF_OP(opcode)) { nRc = PerformLDF(opcode); @@ -343,7 +353,7 @@ else if (STF_OP(opcode)) { nRc = PerformSTF(opcode); - } + } else if (SFM_OP(opcode)) { nRc = PerformSFM(opcode); @@ -352,7 +362,7 @@ { nRc = 0; } - + return nRc; } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/tools/Makefile linux-2.5/arch/arm/tools/Makefile --- linux-2.5.1/arch/arm/tools/Makefile Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/tools/Makefile Sun Jan 6 01:38:26 2002 @@ -15,13 +15,17 @@ # what we want. We do this in several stages so make picks up on # any errors that occur along the way. -$(TOPDIR)/include/asm-arm/constants.h: constants-hdr getconstants.c - $(CC) $(CFLAGS) -S -o - getconstants.c > $@.tmp.1 +constants.h: constants-hdr getconstants.c + $(CC) $(CFLAGS) -S -o $@.tmp.1 getconstants.c sed 's/^\(#define .* \)[#$$]\(.*\)/\1\2/;/^#define/!d' $@.tmp.1 > $@.tmp.2 - cat constants-hdr $@.tmp.2 > $@.tmp - cmp $@.tmp $@ >/dev/null 2>&1 || mv $@.tmp $@ + cat constants-hdr $@.tmp.2 > $@ $(RM) $@.tmp* +# Only update include/asm-arm/constants.h when it has actually changed. + +$(TOPDIR)/include/asm-arm/constants.h: constants.h + cmp constants.h $@ >/dev/null 2>&1 || cp -p constants.h $@ + # Build our dependencies, and then generate the constants and # mach-types header files. If we do it now, mkdep will pick # the dependencies up later on when it runs through the other @@ -29,7 +33,7 @@ dep: $(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS) -- getconstants.c |\ - sed s,getconstants.o,$(TOPDIR)/include/asm-arm/constants.h, > .depend + sed s,getconstants.o,constants.h, > .depend $(MAKE) all .PHONY: all dep diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/tools/getconstants.c linux-2.5/arch/arm/tools/getconstants.c --- linux-2.5.1/arch/arm/tools/getconstants.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/arm/tools/getconstants.c Sun Jan 6 01:38:26 2002 @@ -18,10 +18,17 @@ * 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 +#error Sorry, 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 +#error Sorry, your compiler targets APCS-26 but this kernel requires APCS-32 +#endif +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95) +#error Sorry, your compiler is known to miscompile kernels. Only use gcc 2.95.3 and later. +#endif +#if __GNUC__ == 2 && __GNUC_MINOR__ == 95 +/* shame we can't detect the .1 or .2 releases */ +#warning GCC 2.95.2 and earlier miscompiles kernels. #endif #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/tools/mach-types linux-2.5/arch/arm/tools/mach-types --- linux-2.5.1/arch/arm/tools/mach-types Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/arm/tools/mach-types Sun Jan 6 01:38:26 2002 @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Fri Oct 26 17:37:13 2001 +# Last update: Fri Jan 4 10:27:21 2002 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -137,3 +137,28 @@ elroy SA1100_ELROY ELROY 126 gms720 ARCH_GMS720 GMS720 127 s24x ARCH_S24X S24X 128 +jtel_clep7312 ARCH_JTEL_CLEP7312 JTEL_CLEP7312 129 +cx821xx ARCH_CX821XX CX821XX 130 +edb7312 ARCH_EDB7312 EDB7312 131 +bsa1110 SA1100_BSA1110 BSA1110 132 +powerpin ARCH_POWERPIN POWERPIN 133 +openarm ARCH_OPENARM OPENARM 134 +whitechapel SA1100_WHITECHAPEL WHITECHAPEL 135 +h3100 SA1100_H3100 H3100 136 +h3800 SA1100_H3800 H3800 137 +blue_v1 ARCH_BLUE_V1 BLUE_V1 138 +xscale_cerf ARCH_XSCALE_CERF XSCALE_CERF 139 +arm7tevb ARCH_ARM7TEVB ARM7TEVB 140 +d7400 ARCH_D7400 D7400 141 +piranha ARCH_PIRANHA PIRANHA 142 +sbcamelot SA1100_SBCAMELOT SBCAMELOT 143 +kings SA1100_KINGS KINGS 144 +smdk2400 ARCH_SMDK2400 SMDK2400 145 +collie ARCH_COLLIE COLLIE 146 +idr ARCH_IDR IDR 147 +badge4 SA1100_BADGE4 BADGE4 148 +webnet ARCH_WEBNET WEBNET 149 +d7300 SA1100_D7300 D7300 150 +cep SA1100_CEP CEP 151 +fortunet ARCH_FORTUNET FORTUNET 152 +vc547x ARCH_VC547X VC547X 153 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/vmlinux-armo.lds.in linux-2.5/arch/arm/vmlinux-armo.lds.in --- linux-2.5.1/arch/arm/vmlinux-armo.lds.in Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/vmlinux-armo.lds.in Sat Dec 29 11:10:40 2001 @@ -48,7 +48,6 @@ *(.text) *(.fixup) *(.gnu.warning) - *(.text.lock) /* out-of-line lock text */ *(.rodata) *(.rodata.*) *(.glue_7) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/arm/vmlinux-armv.lds.in linux-2.5/arch/arm/vmlinux-armv.lds.in --- linux-2.5.1/arch/arm/vmlinux-armv.lds.in Sun Aug 12 18:13:59 2001 +++ linux-2.5/arch/arm/vmlinux-armv.lds.in Sat Dec 29 11:10:40 2001 @@ -43,7 +43,6 @@ *(.text) *(.fixup) *(.gnu.warning) - *(.text.lock) /* out-of-line lock text */ *(.rodata) *(.rodata.*) *(.glue_7) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/Makefile linux-2.5/arch/cris/Makefile --- linux-2.5.1/arch/cris/Makefile Mon Oct 8 18:43:54 2001 +++ linux-2.5/arch/cris/Makefile Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.22 2001/10/01 14:42:38 bjornw Exp $ +# $Id: Makefile,v 1.26 2001/11/16 17:42:17 pkj Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own @@ -37,10 +37,9 @@ OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S -# normally, gcc on a linux box adds __linux__ but we do it "manually" -# -mlinux enables -march=v10, -fno-underscores among others +# -mlinux enables -march=v10, -fno-underscores, -D__linux__ among others -CFLAGS := $(CFLAGS) -mlinux -fno-strict-aliasing -pipe -D__linux__ +CFLAGS := $(CFLAGS) -mlinux -pipe ifdef CONFIG_ETRAX_KGDB CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/boot/rescue/head.S linux-2.5/arch/cris/boot/rescue/head.S --- linux-2.5.1/arch/cris/boot/rescue/head.S Mon Oct 8 18:43:54 2001 +++ linux-2.5/arch/cris/boot/rescue/head.S Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.8 2001/10/03 17:15:15 bjornw Exp $ +/* $Id: head.S,v 1.10 2001/11/08 15:10:16 starvik Exp $ * * Rescue code, made to reside at the beginning of the * flash-memory. when it starts, it checks a partition @@ -114,7 +114,7 @@ #define NOP_DI 0xf025050f #define RAM_INIT_MAGIC 0x56902387 - + .text ;; This is the entry point of the rescue code @@ -144,7 +144,13 @@ jumptarget: .dword 0xffffffff ; can be overwritten later to insert new code -no_newjump: +no_newjump: +#ifdef CONFIG_ETRAX_ETHERNET + ;; Start MII clock to make sure it is running when tranceiver is reset + move.d 0x3, $r0 ; enable = on, phy = mii_clk + move.d $r0, [R_NETWORK_GEN_CONFIG] +#endif + ;; We need to setup the bus registers before we start using the DRAM #include "../../lib/dram_init.S" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/config.in linux-2.5/arch/cris/config.in --- linux-2.5.1/arch/cris/config.in Mon Oct 15 20:42:14 2001 +++ linux-2.5/arch/cris/config.in Thu Jan 10 22:41:07 2002 @@ -35,6 +35,9 @@ bool 'Use kernel gdb debugger' CONFIG_ETRAX_KGDB bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG +if [ "$CONFIG_ETRAX_WATCHDOG" = "y" ]; then + bool 'Disable watchdog during Oops printouts' CONFIG_ETRAX_WATCHDOG_NICE_DOGGY +fi endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/cris.ld linux-2.5/arch/cris/cris.ld --- linux-2.5.1/arch/cris/cris.ld Mon Oct 8 18:43:54 2001 +++ linux-2.5/arch/cris/cris.ld Sat Dec 29 11:10:40 2001 @@ -24,7 +24,6 @@ *(.fixup) *(.text.__*) } - .text.lock : { *(.text.lock) } /* out-of-line lock text */ _etext = . ; /* End of text section */ __etext = .; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/drivers/axisflashmap.c linux-2.5/arch/cris/drivers/axisflashmap.c --- linux-2.5.1/arch/cris/drivers/axisflashmap.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/drivers/axisflashmap.c Thu Jan 10 22:41:07 2002 @@ -11,6 +11,14 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * Revision 1.17 2001/11/12 19:42:38 pkj + * Fixed compiler warnings. + * + * Revision 1.16 2001/11/08 11:18:58 jonashg + * Always read from uncached address to avoid problems with flushing + * cachelines after write and MTD-erase. No performance loss have been + * seen yet. + * * Revision 1.15 2001/10/19 12:41:04 jonashg * Name of probe has changed in MTD. * @@ -121,7 +129,7 @@ static void flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { - memcpy(to, (void *)(FLASH_CACHED_ADDR + from), len); + memcpy(to, (void *)(FLASH_UNCACHED_ADDR + from), len); } static void flash_write8(struct map_info *map, __u8 d, unsigned long adr) @@ -237,7 +245,7 @@ int use_default_ptable = 1; /* Until proven otherwise */ const char *pmsg = " /dev/flash%d at 0x%x, size 0x%x\n"; - printk(KERN_NOTICE "Axis flash mapping: %x at %x\n", + printk(KERN_NOTICE "Axis flash mapping: %x at %lx\n", WINDOW_SIZE, FLASH_CACHED_ADDR); #ifdef CONFIG_MTD_CFI diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/drivers/ethernet.c linux-2.5/arch/cris/drivers/ethernet.c --- linux-2.5.1/arch/cris/drivers/ethernet.c Mon Oct 8 18:43:54 2001 +++ linux-2.5/arch/cris/drivers/ethernet.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: ethernet.c,v 1.18 2001/10/03 14:40:43 jonashg Exp $ +/* $Id: ethernet.c,v 1.21 2001/11/23 11:54:49 starvik Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * @@ -7,6 +7,21 @@ * The outline of this driver comes from skeleton.c. * * $Log: ethernet.c,v $ + * Revision 1.21 2001/11/23 11:54:49 starvik + * Added IFF_PROMISC and IFF_ALLMULTI handling in set_multicast_list + * Removed compiler warnings + * + * Revision 1.20 2001/11/12 19:26:00 pkj + * * Corrected e100_negotiate() to not assign half to current_duplex when + * it was supposed to compare them... + * * Cleaned up failure handling in e100_open(). + * * Fixed compiler warnings. + * + * Revision 1.19 2001/11/09 07:43:09 starvik + * Added full duplex support + * Added ioctl to set speed and duplex + * Clear LED timer only runs when LED is lit + * * Revision 1.18 2001/10/03 14:40:43 jonashg * Update rx_bytes counter. * @@ -104,6 +119,7 @@ #include <asm/dma.h> #include <asm/system.h> #include <asm/bitops.h> +#include <asm/ethernet.h> //#define ETHDEBUG #define D(x) @@ -120,7 +136,7 @@ static struct sockaddr default_mac = { 0, - { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 } + { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 } }; /* Information that need to be kept for each board. */ @@ -136,6 +152,14 @@ }; +/* Duplex settings */ +enum duplex +{ + half, + full, + autoneg +}; + /* Dma descriptors etc. */ #define RX_BUF_SIZE 32768 @@ -148,9 +172,18 @@ /* ** MDIO constants. */ -#define MDIO_BASE_STATUS_REG 0x1 -#define MDIO_BASE_CONTROL_REG 0x0 -#define MDIO_LINK_UP_MASK 0x4 +#define MDIO_BASE_STATUS_REG 0x1 +#define MDIO_BASE_CONTROL_REG 0x0 +#define MDIO_BC_NEGOTIATE 0x0200 +#define MDIO_BC_FULL_DUPLEX_MASK 0x0100 +#define MDIO_BC_AUTO_NEG_MASK 0x1000 +#define MDIO_BC_SPEED_SELECT_MASK 0x2000 +#define MDIO_ADVERTISMENT_REG 0x4 +#define MDIO_ADVERT_100_FD 0x100 +#define MDIO_ADVERT_100_HD 0x080 +#define MDIO_ADVERT_10_FD 0x040 +#define MDIO_ADVERT_10_HD 0x020 +#define MDIO_LINK_UP_MASK 0x4 #define MDIO_START 0x1 #define MDIO_READ 0x2 #define MDIO_WRITE 0x1 @@ -158,6 +191,7 @@ /* Broadcom specific */ #define MDIO_AUX_CTRL_STATUS_REG 0x18 +#define MDIO_FULL_DUPLEX_IND 0x1 #define MDIO_SPEED 0x2 #define MDIO_PHYS_ADDR 0x0 @@ -165,18 +199,25 @@ #define NET_FLASH_TIME (HZ/50) /* 20 ms */ #define NET_FLASH_PAUSE (HZ/100) /* 10 ms */ #define NET_LINK_UP_CHECK_INTERVAL (2*HZ) /* 2 s */ +#define NET_DUPLEX_CHECK_INTERVAL (2*HZ) /* 2 s */ #define NO_NETWORK_ACTIVITY 0 #define NETWORK_ACTIVITY 1 #define RX_DESC_BUF_SIZE 256 #define NBR_OF_RX_DESC (RX_BUF_SIZE / \ - RX_DESC_BUF_SIZE) + RX_DESC_BUF_SIZE) #define GET_BIT(bit,val) (((val) >> (bit)) & 0x01) +/* 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) + static etrax_dma_descr *myNextRxDesc; /* Points to the next descriptor to - to be processed */ + to be processed */ static etrax_dma_descr *myLastRxDesc; /* The last processed descriptor */ static etrax_dma_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */ @@ -187,13 +228,21 @@ static struct sk_buff *tx_skb; +static unsigned int network_rec_config_shadow = 0; + /* Network speed indication. */ static struct timer_list speed_timer; static struct timer_list clear_led_timer; -static int current_speed; +static int current_speed; /* Speed read from tranceiver */ +static int current_speed_selection; /* Speed selected by user */ static int led_next_time; static int led_active; +/* Duplex */ +static struct timer_list duplex_timer; +static int full_duplex; +static enum duplex current_duplex; + /* Index to functions, as function prototypes. */ static int etrax_ethernet_init(struct net_device *dev); @@ -206,6 +255,8 @@ static void e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void e100_rx(struct net_device *dev); static int e100_close(struct net_device *dev); +static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static void e100_tx_timeout(struct net_device *dev); static struct net_device_stats *e100_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void e100_hardware_send_packet(char *buf, int length); @@ -213,6 +264,11 @@ static void update_tx_stats(struct net_device_stats *); static void e100_check_speed(unsigned long dummy); +static void e100_set_speed(unsigned long speed); +static void e100_check_duplex(unsigned long dummy); +static void e100_set_duplex(enum duplex); +static void e100_negotiate(void); + static unsigned short e100_get_mdio_reg(unsigned char reg_num); static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd); static void e100_send_mdio_bit(unsigned char bit); @@ -278,6 +334,8 @@ dev->get_stats = e100_get_stats; dev->set_multicast_list = set_multicast_list; dev->set_mac_address = e100_set_mac_address; + dev->do_ioctl = e100_ioctl; + dev->tx_timeout = e100_tx_timeout; /* set the default MAC address */ @@ -287,7 +345,7 @@ /* Initialise receive descriptors */ - for(i = 0; i < (NBR_OF_RX_DESC - 1); i++) { + for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) { RxDescList[i].ctrl = 0; RxDescList[i].sw_len = RX_DESC_BUF_SIZE; RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); @@ -313,12 +371,18 @@ /* Initialize speed indicator stuff. */ current_speed = 10; + current_speed_selection = 0; /* Auto */ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; speed_timer.function = e100_check_speed; add_timer(&speed_timer); + clear_led_timer.function = e100_clear_network_leds; - clear_led_timer.expires = jiffies + HZ/10; - add_timer(&clear_led_timer); + + full_duplex = 0; + current_duplex = autoneg; + duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; + duplex_timer.function = e100_check_duplex; + add_timer(&duplex_timer); return 0; } @@ -335,7 +399,7 @@ /* remember it */ - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); /* Write it to the hardware. * Note the way the address is wrapped: @@ -409,21 +473,21 @@ if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0, cardname, (void *)dev)) { - goto grace_exit; + goto grace_exit0; } /* allocate the irq corresponding to the transmitting DMA */ if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0, cardname, (void *)dev)) { - goto grace_exit; + goto grace_exit1; } /* allocate the irq corresponding to the network errors etc */ if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0, cardname, (void *)dev)) { - goto grace_exit; + goto grace_exit2; } /* @@ -431,18 +495,12 @@ * and clean up on failure. */ - if(request_dma(NETWORK_TX_DMA_NBR, cardname)) { - goto grace_exit; + if (request_dma(NETWORK_TX_DMA_NBR, cardname)) { + goto grace_exit3; } - if(request_dma(NETWORK_RX_DMA_NBR, cardname)) { - grace_exit: - /* this will cause some 'trying to free free irq' but what the heck... */ - free_dma(NETWORK_TX_DMA_NBR); - free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev); - free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); - free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); - return -EAGAIN; + if (request_dma(NETWORK_RX_DMA_NBR, cardname)) { + goto grace_exit4; } /* give the HW an idea of what MAC address we want */ @@ -459,9 +517,10 @@ *R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */ #else - *R_NETWORK_REC_CONFIG = - IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | - IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable); + SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive); + SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable); + SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); + *R_NETWORK_REC_CONFIG = network_rec_config_shadow; #endif *R_NETWORK_GEN_CONFIG = @@ -507,6 +566,17 @@ netif_start_queue(dev); return 0; + +grace_exit4: + free_dma(NETWORK_TX_DMA_NBR); +grace_exit3: + free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); +grace_exit2: + free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); +grace_exit1: + free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev); +grace_exit0: + return -EAGAIN; } @@ -532,10 +602,119 @@ add_timer(&speed_timer); } +static void +e100_negotiate(void) +{ + unsigned short cmd; + unsigned short data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG); + int bitCounter; + + /* Discard old speed and duplex settings */ + data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | + MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD); + + switch (current_speed_selection) { + case 10 : + if (current_duplex == full) + data |= MDIO_ADVERT_10_FD; + else if (current_duplex == half) + data |= MDIO_ADVERT_10_HD; + else + data |= MDIO_ADVERT_10_HD | MDIO_ADVERT_10_FD; + break; + + case 100 : + if (current_duplex == full) + data |= MDIO_ADVERT_100_FD; + else if (current_duplex == half) + data |= MDIO_ADVERT_100_HD; + else + data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD; + break; + + case 0 : /* Auto */ + if (current_duplex == full) + data |= MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD; + else if (current_duplex == half) + data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_10_HD; + else + data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD; + break; + + default : /* assume autoneg speed and duplex */ + data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | + MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD; + } + + cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | + (MDIO_ADVERTISMENT_REG<< 2); + + e100_send_mdio_cmd(cmd, 1); + + /* Data... */ + for (bitCounter=15; bitCounter>=0 ; bitCounter--) { + e100_send_mdio_bit(GET_BIT(bitCounter, data)); + } + + /* Renegotiate with link partner */ + data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG); + data |= MDIO_BC_NEGOTIATE; + + cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | + (MDIO_BASE_CONTROL_REG<< 2); + + e100_send_mdio_cmd(cmd, 1); + + /* Data... */ + for (bitCounter=15; bitCounter>=0 ; bitCounter--) { + e100_send_mdio_bit(GET_BIT(bitCounter, data)); + } +} + +static void +e100_set_speed(unsigned long speed) +{ + current_speed_selection = speed; + e100_negotiate(); +} + +static void +e100_check_duplex(unsigned long dummy) +{ + unsigned long data; + + data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); + + if (data & MDIO_FULL_DUPLEX_IND) { + if (!full_duplex) { /* Duplex changed to full? */ + full_duplex = 1; + SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); + *R_NETWORK_REC_CONFIG = network_rec_config_shadow; + } + } else { /* half */ + if (full_duplex) { /* Duplex changed to half? */ + full_duplex = 0; + SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); + *R_NETWORK_REC_CONFIG = network_rec_config_shadow; + } + } + + /* Reinitialize the timer. */ + duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; + add_timer(&duplex_timer); +} + +static void +e100_set_duplex(enum duplex new_duplex) +{ + current_duplex = new_duplex; + e100_negotiate(); +} + + static unsigned short e100_get_mdio_reg(unsigned char reg_num) { - unsigned long flags; unsigned short cmd; /* Data to be sent on MDIO port */ unsigned short data; /* Data read from MDIO */ int bitCounter; @@ -549,7 +728,7 @@ data = 0; /* Data... */ - for(bitCounter=15; bitCounter>=0 ; bitCounter--) { + for (bitCounter=15; bitCounter>=0 ; bitCounter--) { data |= (e100_receive_mdio_bit() << bitCounter); } @@ -563,14 +742,14 @@ unsigned char data = 0x2; /* Preamble */ - for(bitCounter = 31; bitCounter>= 0; bitCounter--) + for (bitCounter = 31; bitCounter>= 0; bitCounter--) e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE)); - for(bitCounter = 15; bitCounter >= 2; bitCounter--) + for (bitCounter = 15; bitCounter >= 2; bitCounter--) e100_send_mdio_bit(GET_BIT(bitCounter, cmd)); /* Turnaround */ - for(bitCounter = 1; bitCounter >= 0 ; bitCounter--) + for (bitCounter = 1; bitCounter >= 0 ; bitCounter--) if (write_cmd) e100_send_mdio_bit(GET_BIT(bitCounter, data)); else @@ -606,7 +785,6 @@ static void e100_reset_tranceiver(void) { - unsigned long flags; unsigned short cmd; unsigned short data; int bitCounter; @@ -619,7 +797,7 @@ data |= 0x8000; - for(bitCounter = 15; bitCounter >= 0 ; bitCounter--) { + for (bitCounter = 15; bitCounter >= 0 ; bitCounter--) { e100_send_mdio_bit(GET_BIT(bitCounter, data)); } } @@ -706,15 +884,14 @@ struct net_device *dev = (struct net_device *)dev_id; unsigned long irqbits = *R_IRQ_MASK2_RD; - if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { - + if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { /* acknowledge the eop interrupt */ *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do); /* check if one or more complete packets were indeed received */ - while(*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) { + while (*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) { /* Take out the buffer and give it to the OS, then * allocate a new buffer to put a packet in. */ @@ -747,8 +924,7 @@ struct net_local *np = (struct net_local *)dev->priv; /* check for a dma0_eop interrupt */ - if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { - + if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { /* This protects us from concurrent execution of * our dev->hard_start_xmit function above. */ @@ -759,7 +935,7 @@ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); - if(*R_DMA_CH0_FIRST == 0 && tx_skb) { + if (*R_DMA_CH0_FIRST == 0 && tx_skb) { np->stats.tx_bytes += tx_skb->len; np->stats.tx_packets++; /* dma is ready with the transmission of the data in tx_skb, so now @@ -784,19 +960,19 @@ unsigned long irqbits = *R_IRQ_MASK0_RD; /* check for underrun irq */ - if(irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { + if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); np->stats.tx_errors++; D(printk("ethernet receiver underrun!\n")); } /* check for overrun irq */ - if(irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { + if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { update_rx_stats(&np->stats); /* this will ack the irq */ D(printk("ethernet receiver overrun!\n")); } /* check for excessive collision irq */ - if(irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { + if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); np->stats.tx_errors++; D(printk("ethernet excessive collisions!\n")); @@ -809,11 +985,13 @@ e100_rx(struct net_device *dev) { struct sk_buff *skb; - int length=0; - int i; + int length = 0; struct net_local *np = (struct net_local *)dev->priv; struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; unsigned char *skb_data_ptr; +#ifdef ETHDEBUG + int i; +#endif if (!led_active && jiffies > led_next_time) { /* light the network leds depending on the current speed. */ @@ -822,6 +1000,7 @@ /* Set the earliest time we may clear the LED */ led_next_time = jiffies + NET_FLASH_TIME; led_active = 1; + mod_timer(&clear_led_timer, jiffies + HZ/10); } /* If the packet is broken down in many small packages then merge @@ -842,7 +1021,7 @@ printk("Got a packet of length %d:\n", length); /* dump the first bytes in the packet */ skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf); - for(i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3], skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]); @@ -869,7 +1048,7 @@ /* this loop can be made using max two memcpy's if optimized */ - while(mySaveRxDesc != myNextRxDesc) { + while (mySaveRxDesc != myNextRxDesc) { memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), mySaveRxDesc->sw_len); skb_data_ptr += mySaveRxDesc->sw_len; @@ -946,6 +1125,37 @@ return 0; } +static int +e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + /* Maybe default should return -EINVAL instead? */ + switch (cmd) { + case SET_ETH_SPEED_10: /* 10 Mbps */ + e100_set_speed(10); + break; + case SET_ETH_SPEED_100: /* 100 Mbps */ + e100_set_speed(100); + break; + case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */ + e100_set_speed(0); + break; + case SET_ETH_DUPLEX_HALF: /* Hhalf duplex. */ + e100_set_duplex(half); + break; + case SET_ETH_DUPLEX_FULL: /* Full duplex. */ + e100_set_duplex(full); + break; + case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex*/ + e100_set_duplex(autoneg); + break; + default: /* Auto neg */ + e100_set_speed(0); + e100_set_duplex(autoneg); + break; + } + return 0; +} + static void update_rx_stats(struct net_device_stats *es) { @@ -996,26 +1206,31 @@ int num_addr = dev->mc_count; unsigned long int lo_bits; unsigned long int hi_bits; - if (num_addr == -1) + if (dev->flags & IFF_PROMISC) { /* 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); + /* Enable individual receive */ + SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, receive); + *R_NETWORK_REC_CONFIG = network_rec_config_shadow; + } else if (dev->flags & IFF_ALLMULTI) { + /* enable all multicasts */ + lo_bits = 0xfffffffful; + hi_bits = 0xfffffffful; + + /* Disable individual receive */ + SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); + *R_NETWORK_REC_CONFIG = network_rec_config_shadow; } 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); + /* Disable individual receive */ + SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); + *R_NETWORK_REC_CONFIG = network_rec_config_shadow; } else { /* MC mode, receive normal and MC packets */ char hash_ix; @@ -1057,10 +1272,9 @@ } 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); + /* Disable individual receive */ + SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); + *R_NETWORK_REC_CONFIG = network_rec_config_shadow; } *R_NETWORK_GA_0 = lo_bits; *R_NETWORK_GA_1 = hi_bits; @@ -1078,6 +1292,7 @@ /* Set the earliest time we may clear the LED */ led_next_time = jiffies + NET_FLASH_TIME; led_active = 1; + mod_timer(&clear_led_timer, jiffies + HZ/10); } /* configure the tx dma descriptor */ @@ -1095,16 +1310,13 @@ static void e100_clear_network_leds(unsigned long dummy) { - if (led_active && jiffies > led_next_time) { + if (led_active && jiffies > led_next_time) { e100_set_network_leds(NO_NETWORK_ACTIVITY); /* Set the earliest time we may set the LED */ led_next_time = jiffies + NET_FLASH_PAUSE; led_active = 0; } - - clear_led_timer.expires = jiffies + HZ/10; - add_timer(&clear_led_timer); } static void @@ -1143,7 +1355,7 @@ d->init = etrax_ethernet_init; - if(register_netdev(d) == 0) + if (register_netdev(d) == 0) return 0; else return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/drivers/gpio.c linux-2.5/arch/cris/drivers/gpio.c --- linux-2.5.1/arch/cris/drivers/gpio.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/drivers/gpio.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: gpio.c,v 1.11 2001/10/30 14:39:12 johana Exp $ +/* $Id: gpio.c,v 1.12 2001/11/12 19:42:15 pkj Exp $ * * Etrax general port I/O device * @@ -9,6 +9,10 @@ * Johan Adolfsson (read/set directions, write) * * $Log: gpio.c,v $ + * Revision 1.12 2001/11/12 19:42:15 pkj + * * Corrected return values from gpio_leds_ioctl(). + * * Fixed compiler warnings. + * * Revision 1.11 2001/10/30 14:39:12 johana * Added D() around gpio_write printk. * @@ -74,7 +78,9 @@ static char gpio_name[] = "etrax gpio"; +#if 0 static wait_queue_head_t *gpio_wq; +#endif static int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); @@ -143,7 +149,7 @@ { /* TODO poll on alarms! */ #if 0 - if(!ANYTHING_WANTED) { + if (!ANYTHING_WANTED) { D(printk("gpio_select sleeping task\n")); select_wait(&gpio_wq, table); return 0; @@ -160,16 +166,14 @@ unsigned char data, clk_mask, data_mask, write_msb; unsigned long flags; ssize_t retval = count; - if (verify_area(VERIFY_READ, buf, count)) - { + if (verify_area(VERIFY_READ, buf, count)) { return -EFAULT; } clk_mask = priv->clk_mask; data_mask = priv->data_mask; /* It must have been configured using the IO_CFG_WRITE_MODE */ /* Perhaps a better error code? */ - if (clk_mask == 0 || data_mask == 0) - { + if (clk_mask == 0 || data_mask == 0) { return -EPERM; } write_msb = priv->write_msb; @@ -178,7 +182,7 @@ int i; data = *buf++; if (priv->write_msb) { - for (i = 7; i>=0;i--) { + for (i = 7; i >= 0;i--) { save_flags(flags); cli(); *priv->port = *priv->shadow &= ~clk_mask; if (data & 1<<i) @@ -190,7 +194,7 @@ restore_flags(flags); } } else { - for (i = 0; i<=7;i++) { + for (i = 0; i <= 7;i++) { save_flags(flags); cli(); *priv->port = *priv->shadow &= ~clk_mask; if (data & 1<<i) @@ -212,13 +216,13 @@ struct gpio_private *priv; int p = MINOR(inode->i_rdev); - if(p >= NUM_PORTS && p != LEDS) + if (p >= NUM_PORTS && p != LEDS) return -EINVAL; priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), GFP_KERNEL); - if(!priv) + if (!priv) return -ENOMEM; priv->minor = p; @@ -254,10 +258,10 @@ /* unlink from alarmlist and free the private structure */ - if(p == todel) { + if (p == todel) { alarmlist = todel->next; } else { - while(p->next != todel) + while (p->next != todel) p = p->next; p->next = todel->next; } @@ -280,7 +284,7 @@ { unsigned long flags; struct gpio_private *priv = (struct gpio_private *)file->private_data; - if(_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { + if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { return -EINVAL; } @@ -353,7 +357,7 @@ if (!((priv->clk_mask & priv->changeable_bits) && (priv->data_mask & priv->changeable_bits) && (priv->clk_mask & *priv->dir_shadow) && - (priv->data_mask & *priv->dir_shadow)) ) + (priv->data_mask & *priv->dir_shadow))) { priv->clk_mask = 0; priv->data_mask = 0; @@ -361,7 +365,7 @@ } break; default: - if(priv->minor == LEDS) + if (priv->minor == LEDS) return gpio_leds_ioctl(cmd, arg); else return -EINVAL; @@ -375,6 +379,7 @@ { unsigned char green; unsigned char red; + switch (_IOC_NR(cmd)) { case IO_LEDACTIVE_SET: green = ((unsigned char) arg) & 1; @@ -382,14 +387,20 @@ LED_ACTIVE_SET_G(green); LED_ACTIVE_SET_R(red); break; - case IO_LED_SETBIT: - LED_BIT_SET(arg); - break; - case IO_LED_CLRBIT: - LED_BIT_CLR(arg); + + case IO_LED_SETBIT: + LED_BIT_SET(arg); + break; + + case IO_LED_CLRBIT: + LED_BIT_CLR(arg); + break; + default: return -EINVAL; } + + return 0; } struct file_operations gpio_fops = { @@ -406,30 +417,32 @@ static __init int gpio_init(void) { - int res,i; + extern void init_ioremap(void); + int res; +#if defined (CONFIG_ETRAX_CSP0_LEDS) + int i; +#endif /* do the formalities */ res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); - if(res < 0) { + if (res < 0) { printk(KERN_ERR "gpio: couldn't get a major number.\n"); return res; } /* Clear all leds */ -#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) - - init_ioremap(); - LED_NETWORK_SET(0); - LED_ACTIVE_SET(0); - LED_DISK_READ(0); - LED_DISK_WRITE(0); +#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) + init_ioremap(); + LED_NETWORK_SET(0); + LED_ACTIVE_SET(0); + LED_DISK_READ(0); + LED_DISK_WRITE(0); #if defined (CONFIG_ETRAX_CSP0_LEDS) - for( i = 0; i < 32; i ++) - { - LED_BIT_SET(i); - } + for (i = 0; i < 32; i++) { + LED_BIT_SET(i); + } #endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/drivers/serial.c linux-2.5/arch/cris/drivers/serial.c --- linux-2.5.1/arch/cris/drivers/serial.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/drivers/serial.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: serial.c,v 1.23 2001/10/30 17:53:26 pkj Exp $ +/* $Id: serial.c,v 1.28 2001/12/18 15:04:53 johana Exp $ * * Serial port driver for the ETRAX 100LX chip * @@ -7,6 +7,34 @@ * Many, many authors. Based once upon a time on serial.c for 16x50. * * $Log: serial.c,v $ + * Revision 1.28 2001/12/18 15:04:53 johana + * Cleaned up write_rs485() - now it works correctly without padding extra + * char. + * Added sane default initialisation of rs485. + * Added #ifdef around dummy variables. + * + * Revision 1.27 2001/11/29 17:00:41 pkj + * 2kB seems to be too small a buffer when using 921600 bps, + * so increase it to 4kB (this was already done for the elinux + * version of the serial driver). + * + * Revision 1.26 2001/11/19 14:20:41 pkj + * Minor changes to comments and unused code. + * + * Revision 1.25 2001/11/12 20:03:43 pkj + * Fixed compiler warnings. + * + * Revision 1.24 2001/11/12 15:10:05 pkj + * Total redesign of the receiving part of the serial driver. + * Uses eight chained descriptors to write to a 4kB buffer. + * This data is then serialised into a 2kB buffer. From there it + * is copied into the TTY's flip buffers when they become available. + * A lot of copying, and the sizes of the buffers might need to be + * tweaked, but all in all it should work better than the previous + * version, without the need to modify the TTY code in any way. + * Also note that erroneous bytes are now correctly marked in the + * flag buffers (instead of always marking the first byte). + * * Revision 1.23 2001/10/30 17:53:26 pkj * * Set info->uses_dma to 0 when a port is closed. * * Mark the timer1 interrupt as a fast one (SA_INTERRUPT). @@ -123,12 +151,12 @@ * Changed %ul to %lu in printf's * * Revision 1.47 2000/10/18 15:06:53 pkj - * Compile correctly with CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST and - * CONFIG_SERIAL_PROC_ENTRY together. + * Compile correctly with CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST and + * CONFIG_ETRAX_SERIAL_PROC_ENTRY together. * Some clean-up of the /proc/serial file. * * Revision 1.46 2000/10/16 12:59:40 johana - * Added CONFIG_SERIAL_PROC_ENTRY for statistics and debug info. + * Added CONFIG_ETRAX_SERIAL_PROC_ENTRY for statistics and debug info. * * Revision 1.45 2000/10/13 17:10:59 pkj * Do not flush DMAs while flipping TTY buffers. @@ -171,7 +199,7 @@ * Uncomment definition of SERIAL_HANDLE_EARLY_ERRORS. * * Revision 1.36 2000/09/20 13:12:52 johana - * Support for CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS: + * Support for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS: * Number of timer ticks between flush of receive fifo (1 tick = 10ms). * Try 0-3 for low latency applications. Approx 5 for high load * applications (e.g. PPP). Maybe this should be more adaptive some day... @@ -255,7 +283,7 @@ * */ -static char *serial_version = "$Revision: 1.23 $"; +static char *serial_version = "$Revision: 1.28 $"; #include <linux/config.h> #include <linux/version.h> @@ -272,6 +300,7 @@ #include <linux/string.h> #include <linux/fcntl.h> #include <linux/mm.h> +#include <linux/slab.h> #if (LINUX_VERSION_CODE >= 131343) #include <linux/init.h> #endif @@ -302,6 +331,8 @@ #include "serial_compat.h" #endif +#define _INLINE_ inline + static DECLARE_TASK_QUEUE(tq_serial); struct tty_driver serial_driver, callout_driver; @@ -313,11 +344,6 @@ #define SERIAL_TYPE_CALLOUT 2 #endif -#define DEBUG_LOG(line, string, value) - -/* Add an x here to log a lot of timer stuff */ -#define TIMERD(x) - /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 @@ -337,6 +363,14 @@ #define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10) +#define SERIAL_RECV_SIZE 4096 +#define SERIAL_DESCR_BUF_SIZE 512 + +/* Add an x here to log a lot of timer stuff */ +#define TIMERD(x) + +#define DEBUG_LOG(line, string, value) + #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 @@ -345,8 +379,6 @@ #define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 #endif -#define _INLINE_ inline - static void change_speed(struct e100_serial *info); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); static int rs_write(struct tty_struct * tty, int from_user, @@ -403,9 +435,9 @@ static struct e100_serial rs_table[] = { { DEF_BAUD, (unsigned char *)R_SERIAL0_CTRL, 1U << 12, /* uses DMA 6 and 7 */ R_DMA_CH6_CLR_INTR, R_DMA_CH6_FIRST, R_DMA_CH6_CMD, - R_DMA_CH6_STATUS, R_DMA_CH6_HWSW, + R_DMA_CH6_STATUS, R_DMA_CH6_HWSW, R_DMA_CH6_DESCR, R_DMA_CH7_CLR_INTR, R_DMA_CH7_FIRST, R_DMA_CH7_CMD, - R_DMA_CH7_STATUS, R_DMA_CH7_HWSW, + R_DMA_CH7_STATUS, R_DMA_CH7_HWSW, R_DMA_CH7_DESCR, STD_FLAGS, DEF_RX, DEF_TX, 2, #ifdef CONFIG_ETRAX_SERIAL_PORT0 1 @@ -416,9 +448,9 @@ #ifndef CONFIG_SVINTO_SIM { DEF_BAUD, (unsigned char *)R_SERIAL1_CTRL, 1U << 16, /* uses DMA 8 and 9 */ R_DMA_CH8_CLR_INTR, R_DMA_CH8_FIRST, R_DMA_CH8_CMD, - R_DMA_CH8_STATUS, R_DMA_CH8_HWSW, + R_DMA_CH8_STATUS, R_DMA_CH8_HWSW, R_DMA_CH8_DESCR, R_DMA_CH9_CLR_INTR, R_DMA_CH9_FIRST, R_DMA_CH9_CMD, - R_DMA_CH9_STATUS, R_DMA_CH9_HWSW, + R_DMA_CH9_STATUS, R_DMA_CH9_HWSW, R_DMA_CH9_DESCR, STD_FLAGS, DEF_RX, DEF_TX, 3 , #ifdef CONFIG_ETRAX_SERIAL_PORT1 1 @@ -429,9 +461,9 @@ { DEF_BAUD, (unsigned char *)R_SERIAL2_CTRL, 1U << 4, /* uses DMA 2 and 3 */ R_DMA_CH2_CLR_INTR, R_DMA_CH2_FIRST, R_DMA_CH2_CMD, - R_DMA_CH2_STATUS, R_DMA_CH2_HWSW, + R_DMA_CH2_STATUS, R_DMA_CH2_HWSW, R_DMA_CH2_DESCR, R_DMA_CH3_CLR_INTR, R_DMA_CH3_FIRST, R_DMA_CH3_CMD, - R_DMA_CH3_STATUS, R_DMA_CH3_HWSW, + R_DMA_CH3_STATUS, R_DMA_CH3_HWSW, R_DMA_CH3_DESCR, STD_FLAGS, DEF_RX, DEF_TX, 0, #ifdef CONFIG_ETRAX_SERIAL_PORT2 1 @@ -442,9 +474,9 @@ { DEF_BAUD, (unsigned char *)R_SERIAL3_CTRL, 1U << 8, /* uses DMA 4 and 5 */ R_DMA_CH4_CLR_INTR, R_DMA_CH4_FIRST, R_DMA_CH4_CMD, - R_DMA_CH4_STATUS, R_DMA_CH4_HWSW, + R_DMA_CH4_STATUS, R_DMA_CH4_HWSW, R_DMA_CH4_DESCR, R_DMA_CH5_CLR_INTR, R_DMA_CH5_FIRST, R_DMA_CH5_CMD, - R_DMA_CH5_STATUS, R_DMA_CH5_HWSW, + R_DMA_CH5_STATUS, R_DMA_CH5_HWSW, R_DMA_CH5_DESCR, STD_FLAGS, DEF_RX, DEF_TX, 1, #ifdef CONFIG_ETRAX_SERIAL_PORT3 1 @@ -462,9 +494,9 @@ static struct termios *serial_termios[NR_PORTS]; static struct termios *serial_termios_locked[NR_PORTS]; -#ifdef CONFIG_SERIAL_PROC_ENTRY +#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY #define PROCSTAT(x) x -struct ser_statistics_type{ +struct ser_statistics_type { int overrun_cnt; int early_errors_cnt; int ser_ints_ok_cnt; @@ -484,7 +516,7 @@ #define PROCSTAT(x) -#endif /* CONFIG_SERIAL_PROC_ENTRY */ +#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */ /* RS-485 */ #if defined(CONFIG_ETRAX_RS485) @@ -497,14 +529,20 @@ /* For now we assume that all bits are on the same port for each serial port */ /* Dummy shadow variables */ +#if !defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB) static unsigned char dummy_ser0 = 0x00; -static unsigned char dummy_ser1 = 0x00; -static unsigned char dummy_ser2 = 0x00; -static unsigned char dummy_ser3 = 0x00; - static unsigned char dummy_dir_ser0 = 0x00; +#endif +#if !defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB) +static unsigned char dummy_ser1 = 0x00; static unsigned char dummy_dir_ser1 = 0x00; +#endif +#if !defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA) +static unsigned char dummy_ser2 = 0x00; static unsigned char dummy_dir_ser2 = 0x00; +#endif + +static unsigned char dummy_ser3 = 0x00; static unsigned char dummy_dir_ser3 = 0x00; /* Info needed for each ports extra control/status signals. @@ -523,52 +561,56 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = { -/* Ser 0 */ - { + /* Ser 0 */ + { #if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB) - R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, - 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 + R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, + 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 */ - { + &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3 +#endif + }, + + /* Ser 1 */ + { #if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB) - R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, - 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 + R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, + 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 */ - { + &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3 +#endif + }, + + /* Ser 2 */ + { #if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA) - R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow, - 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 + R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow, + 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 - }, -/* Ser 3 */ - { - &dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3 - } + &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3 +#endif + }, + + /* Ser 3 */ + { + &dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3 + } }; #if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA) unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif + #define E100_RTS_MASK 0x20 #define E100_CTS_MASK 0x40 @@ -840,8 +882,8 @@ { #ifndef CONFIG_SVINTO_SIM /* disable the receiver */ - info->port[REG_REC_CTRL] = info->rx_ctrl &= - ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable); + info->port[REG_REC_CTRL] = + (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); #endif } @@ -850,8 +892,8 @@ { #ifndef CONFIG_SVINTO_SIM /* enable the receiver */ - info->port[REG_REC_CTRL] = info->rx_ctrl |= - IO_MASK(R_SERIAL0_REC_CTRL, rec_enable); + info->port[REG_REC_CTRL] = + (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); #endif } @@ -943,13 +985,8 @@ static int e100_write_rs485(struct tty_struct *tty,struct rs485_write *r) { - int stop_delay; - int total, i; - int max_j, delay_ms, bits; - tcflag_t cflags; - int size = (*r).outc_size; + int total; struct e100_serial * info = (struct e100_serial *)tty->driver_data; - struct wait_queue wait = { current, NULL }; /* If we are in RS-485 mode, we need to toggle RTS and disable * the receiver before initiating a DMA transfer @@ -975,44 +1012,20 @@ * enable the receiver */ - /* wait on transmit shift register */ - /* All is sent, check if we should wait more before toggling rts */ - - /* calc. number of bits / data byte */ - cflags = info->tty->termios->c_cflag; - - /* databits + startbit and 1 stopbit */ - if ((cflags & CSIZE) == CS7) - bits = 9; - else - bits = 10; - - if (cflags & CSTOPB) /* 2 stopbits ? */ - bits++; - - if (cflags & PARENB) /* parity bit ? */ - bits++; - - /* calc timeout */ - delay_ms = ((bits * size * 1000) / info->baud) + 1; - max_j = jiffies + (delay_ms * HZ)/1000 + 10; - - while (jiffies < max_j) { - if (info->port[REG_STATUS] & - IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { - for (i = 0; i < 100; i++) - ; - if (info->port[REG_STATUS] & - IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { - /* ~25 for loops per usec */ - stop_delay = 1000000 / info->baud; - if (cflags & CSTOPB) - stop_delay *= 2; - udelay(stop_delay); - break; - } - } + /* Sleep until all sent */ + tty_wait_until_sent(tty, 0); +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER + /* Now sleep a little more so that shift register is empty */ + schedule_usleep(info->char_time_usec * 2); +#else + { + unsigned int val; + /* wait on transmit shift register */ + do{ + get_lsr_info(info, &val); + }while (!(val & TIOCSER_TEMT)); } +#endif e100_rts(info, info->rs485.rts_after_sent); @@ -1118,7 +1131,7 @@ } return; #endif - /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ + /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ *info->oclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); @@ -1168,14 +1181,14 @@ #if defined(CONFIG_ETRAX_RS485) /* Check if we should toggle RTS now */ - if (info->rs485.enabled) - { + if (info->rs485.enabled) { /* Make sure fifo is empty */ - int in_fifo = 0 ; - do{ + int in_fifo = 0; + + do { in_fifo = IO_EXTRACT(R_DMA_CH6_STATUS, avail, - *info->ostatusadr); - } while (in_fifo > 0) ; + *info->ostatusadr); + } while (in_fifo > 0); /* Any way to really check transmitter empty? (TEMT) */ /* Control RTS to set to RX mode */ e100_rts(info, info->rs485.rts_after_sent); @@ -1201,7 +1214,6 @@ *info->ocmdadr = 1; /* dma command start -> R_DMAx_CMD */ /* DMA is now running (hopefully) */ - } static void @@ -1220,13 +1232,122 @@ transmit_chars(info); } +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +static int serial_fast_timer_started = 0; +static int serial_fast_timer_expired = 0; +static void flush_timeout_function(unsigned long data); +#define START_FLUSH_FAST_TIMER(info, string) {\ + unsigned long timer_flags; \ + save_flags(timer_flags); \ + cli(); \ + if (fast_timers[info->line].function == NULL) { \ + serial_fast_timer_started++; \ + TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \ + TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \ + start_one_shot_timer(&fast_timers[info->line], \ + flush_timeout_function, \ + (unsigned long)info, \ + info->char_time_usec*4, \ + string); \ + } \ + else { \ + TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \ + } \ + restore_flags(timer_flags); \ +} + +#else +#define START_FLUSH_FAST_TIMER(info, string) +#endif + +static int +add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag) +{ + if (!CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE)) + return 0; + + info->recv.buf[info->recv.head] = data; + info->flag_buf[info->recv.head] = flag; + info->recv.head = (info->recv.head + 1) & (SERIAL_RECV_SIZE - 1); + + info->icount.rx++; + + return 1; +} + +static _INLINE_ unsigned int +copy_descr_data(struct e100_serial *info, unsigned int recvl, unsigned char *buf) +{ + unsigned int count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); + unsigned int length = 0; + + while (length < recvl && count) { + if (length + count > recvl) + count = recvl - length; + + memcpy(info->recv.buf + info->recv.head, buf + length, count); + memset(info->flag_buf + info->recv.head, '\0', count); + info->recv.head = (info->recv.head + count) & (SERIAL_RECV_SIZE - 1); + length += count; + + count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); + } + + if (length != recvl) { + printk(__FUNCTION__ ": Buffer overflow! %d byte(s) did not fit.\n", recvl - length); + PROCSTAT(ser_stat[info->line].overrun_cnt += recvl - length); + } + + return length; +} + +static _INLINE_ unsigned int +copy_all_descr_data(struct e100_serial *info) +{ + struct etrax_dma_descr *descr; + unsigned int recvl; + unsigned int ret = 0; + + while (1) + { + descr = &info->rec_descr[info->cur_rec_descr]; + + if (descr == phys_to_virt(*info->idescradr)) + break; + + if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS) + info->cur_rec_descr = 0; + + /* find out how many bytes were read */ + + /* if the eop bit was not set, all data has been received */ + if (!(descr->status & d_eop)) { + recvl = descr->sw_len; + } else { + /* otherwise we find the amount of data received here */ + recvl = descr->hw_len; + } + + /* Reset the status information */ + descr->status = 0; + + DEBUG_LOG(info->line, "recvl %lu\n", recvl); + + /* update stats */ + info->icount.rx += recvl; + + ret += copy_descr_data(info, recvl, phys_to_virt(descr->buf)); + } + + return ret; +} + static _INLINE_ void receive_chars(struct e100_serial *info) { struct tty_struct *tty; unsigned char rstat; - unsigned int recvl; - struct etrax_dma_descr *descr; + unsigned int old_head; #ifdef CONFIG_SVINTO_SIM /* No receive in the simulator. Will probably be when the rest of @@ -1235,168 +1356,96 @@ return; #endif - tty = info->tty; - - /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ - - // ? + /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ *info->iclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); - if (!tty) /* something wrong... */ + tty = info->tty; + if (!tty) /* Something wrong... */ return; - descr = &info->rec_descr; +#ifdef SERIAL_HANDLE_EARLY_ERRORS + e100_enable_serial_data_irq(info); +#endif - /* find out how many bytes were read */ + if (info->errorcode == ERRCODE_INSERT_BREAK) + add_char_and_flag(info, '\0', TTY_BREAK); - /* if the eop bit was not set, all data has been received */ - if (!(descr->status & d_eop)) { - recvl = descr->sw_len; - } else { - /* otherwise we find the amount of data received here */ - recvl = descr->hw_len; - } + old_head = info->recv.head; + + if (copy_all_descr_data(info) && info->errorcode == ERRCODE_SET_BREAK) + info->flag_buf[old_head] = TTY_BREAK; - /* read the status register so we can detect errors, - * but we can't really do anything about those errors - * anyway, since we have the DMA in "force eop at error" mode - * the fault characters are not in the buffer anyway. - */ + info->errorcode = 0; + /* Read the status register to detect errors */ rstat = info->port[REG_STATUS]; - if ((rstat & SER_ERROR_MASK) != 0) { - unsigned char data; - /* if we got an error, we must reset it by reading the + if (rstat & SER_ERROR_MASK) { + /* If we got an error, we must reset it by reading the * data_in field */ - data = info->port[REG_DATA]; + unsigned char data = info->port[REG_DATA]; + PROCSTAT(ser_stat[info->line].errors_cnt++); - DEBUG_LOG(info->line, " #dERR: s d 0x%04X\n", + DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n", ((rstat & SER_ERROR_MASK) << 8) | data); - /* Only handle the saved error code, that indicates that we got - * the last character of a break that looks like it's ok, but - * is not - */ - if (info->errorcode == 0) { - *tty->flip.flag_buf_ptr = TTY_NORMAL; - } else { - unsigned char data; - data = info->port[REG_DATA]; - if (info->errorcode & ERRCODE_INSERT) { - unsigned char *currbuf; - /* Get the current buffer */ - if (tty->flip.buf_num) { - currbuf = tty->flip.char_buf + TTY_FLIPBUF_SIZE; - } else { - currbuf = tty->flip.char_buf; - } - /* We should insert a character in the buffer! */ - if (recvl == 0) { - recvl = 1; - DEBUG_LOG(info->line, "insert to %lu\n", recvl); - } else { - /* Move stuff around.. */ - DEBUG_LOG(info->line, "#insert to %lu!\n", recvl); - if (recvl < TTY_FLIPBUF_SIZE) { - int i; - /* Move the data 1 step right */ - i = recvl; - while (i) { - currbuf[i] = currbuf[i-1]; - i--; - } - recvl++; - } else { - /* We can't move it all! Skip break! */ - /* TODO: Handle full buffer? */ - DEBUG_LOG(info->line, "#BRK skipped! %lu!\n", recvl); - info->errorcode = 0; - } - } - } - - PROCSTAT(ser_stat[info->line].errors_cnt++); - DEBUG_LOG(info->line, " #bERR: s d 0x%04X\n", - ((rstat & SER_ERROR_MASK) << 8) | data); - *tty->flip.flag_buf_ptr = (info->errorcode & 0xFF); - info->errorcode = 0; -#if 0 - printk("SERERR: 0x%02X data: 0x%02X\n", rstat & SER_ERROR_MASK, data); -#endif - /* we only ever write errors into the first byte in - * the flip flag buffer, so we dont have to clear it - * all every time - */ - } + if (rstat & SER_PAR_ERR_MASK) + add_char_and_flag(info, data, TTY_PARITY); + else if (rstat & SER_OVERRUN_MASK) + add_char_and_flag(info, data, TTY_OVERRUN); + else if (rstat & SER_FRAMING_ERR_MASK) + add_char_and_flag(info, data, TTY_FRAME); } - DEBUG_LOG(info->line, "recvl %lu\n", recvl); - - if (recvl) { - unsigned char *buf; - struct async_icount *icount = &info->icount; - - /* update stats */ - icount->rx += recvl; - - /* use the flip buffer next in turn to restart DMA into */ - - if (tty->flip.buf_num) { - buf = tty->flip.char_buf; - } else { - buf = tty->flip.char_buf + TTY_FLIPBUF_SIZE; - } + if (!E100_RTS_GET(info) && + CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) < TTY_THROTTLE_LIMIT) + info->tty->driver.throttle(info->tty); + + START_FLUSH_FAST_TIMER(info, "receive_chars"); - if (buf == phys_to_virt(descr->buf)) { - printk("ttyS%d flip-buffer overrun!\n", info->line); - icount->overrun++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - /* restart old buffer */ - } else { - descr->buf = virt_to_phys(buf); + /* Restart the receiving DMA */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); +} - /* schedule or push a flip of the buffer */ +static _INLINE_ int +start_recv_dma(struct e100_serial *info) +{ + struct etrax_dma_descr *descr = info->rec_descr; + unsigned char *buf = info->recv.buf + 2*SERIAL_RECV_SIZE; + int i; - info->tty->flip.count = recvl; + /* Set up the receiving descriptors */ + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { + descr[i].ctrl = d_int; + descr[i].buf = virt_to_phys(buf); + descr[i].sw_len = SERIAL_DESCR_BUF_SIZE; + descr[i].hw_len = 0; + descr[i].status = 0; + descr[i].next = virt_to_phys(&descr[i+1]); -#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ - /* this includes a check for low-latency */ - tty_flip_buffer_push(tty); -#else - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); -#endif - } + buf += SERIAL_DESCR_BUF_SIZE; } - /* restart the receiving dma */ + /* Link the last descriptor to the first */ + descr[i-1].next = virt_to_phys(&descr[0]); - descr->sw_len = TTY_FLIPBUF_SIZE; - descr->ctrl = d_int | d_eol | d_eop; - descr->hw_len = 0; - descr->status = 0; + /* Start with the first descriptor in the list */ + info->cur_rec_descr = 0; - *info->ifirstadr = virt_to_phys(descr); + /* Start the DMA */ + *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]); *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); -#ifdef SERIAL_HANDLE_EARLY_ERRORS - e100_enable_serial_data_irq(info); -#endif - /* input dma should be running now */ - - /* unthrottle if we have throttled */ - if (E100_RTS_GET(info)) - tty->driver.unthrottle(info->tty); + /* Input DMA should be running now */ + return 1; } static void start_receive(struct e100_serial *info) { - struct etrax_dma_descr *descr; - #ifdef CONFIG_SVINTO_SIM /* No receive in the simulator. Will probably be when the rest of * the serial interface works, and this piece will just be removed. @@ -1410,21 +1459,10 @@ while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); - descr = &info->rec_descr; - - /* start the receiving dma into the flip buffer */ - - descr->ctrl = d_int | d_eol | d_eop; - descr->sw_len = TTY_FLIPBUF_SIZE; - descr->buf = virt_to_phys(info->tty->flip.char_buf_ptr); - descr->hw_len = 0; - descr->status = 0; - info->tty->flip.count = 0; - *info->ifirstadr = virt_to_phys(descr); - *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); - + start_recv_dma(info); + #ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST start_flush_timer(); #endif @@ -1474,9 +1512,16 @@ info = rs_table + i; if (!info->uses_dma) continue; - /* check for dma_descr (dont need to check for dma_eop in output dma for serial */ + /* check for dma_descr (don't need to check for dma_eop in output dma for serial */ if (ireg & info->irq) { /* we can send a new dma bunch. make it so. */ + DEBUG_LOG(info->line, "tr_interrupt %i\n", i); + /* Read jiffies_usec first, + * we want this time to be as late as possible + */ + PROCSTAT(ser_stat[info->line].tx_dma_ints++); + info->last_tx_active_usec = GET_JIFFIES_USEC(); + info->last_tx_active = jiffies; transmit_chars(info); } @@ -1524,77 +1569,26 @@ } } -#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -static int serial_fast_timer_started = 0; -static int serial_fast_timer_expired = 0; -static void flush_timeout_function(unsigned long data); -#define START_FLUSH_FAST_TIMER(info, string) {\ - unsigned long timer_flags; \ - save_flags(timer_flags); \ - cli(); \ - TIMERD(DEBUG_LOG(info->line, "start_timer? %i ", info->line)); \ - if (fast_timers[info->line].function == NULL) { \ - serial_fast_timer_started++; \ - TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \ - TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \ - start_one_shot_timer(&fast_timers[info->line], \ - flush_timeout_function, \ - (unsigned long)info, \ - info->char_time_usec*4, \ - string); \ - } \ - else { \ - /* DEBUG_LOG(info->line, " ## timer %i running ##\n", info->line); */ \ - } \ - restore_flags(timer_flags); \ -} - -#else -#define START_FLUSH_FAST_TIMER(info, string) -#endif - -void _INLINE_ check_flush_timeout(struct e100_serial *info) +static _INLINE_ int +force_eop_if_needed(struct e100_serial *info) { - unsigned char rstat; - unsigned int magic; - - if (0 /*info->tty->processing_flip*/) { - if (!E100_RTS_GET(info)) { - int left = (*info->ihwswadr >> 16) - (*info->istatusadr & 0x3F); - - if (left < TTY_THROTTLE_LIMIT) - info->tty->driver.throttle(info->tty); - } - - PROCSTAT(ser_stat[info->line].processing_flip++); - START_FLUSH_FAST_TIMER(info, "flip"); - return; - } - /* We check data_avail bit to determine if data has * arrived since last time */ - magic = info->fifo_magic; -#ifdef SERIAL_DEBUG_DATA - if (info->fifo_magic || info->fifo_didmagic) { - DEBUG_LOG(info->line, "timeout_int: did fifo_magic %03X\n", - (info->fifo_didmagic << 8) | info->fifo_magic); - } -#endif - rstat = info->port[REG_STATUS]; + unsigned char rstat = info->port[REG_STATUS]; + /* error or datavail? */ if (rstat & SER_ERROR_MASK) { - /* Some error has occured */ - /* If there has been valid data, - * an EOP interrupt will be made automatically. - * If no data, the normal ser_interrupt should be enabled - * and handle it. + /* Some error has occurred. If there has been valid data, an + * EOP interrupt will be made automatically. If no data, the + * normal ser_interrupt should be enabled and handle it. * So do nothing! */ DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n", rstat | (info->line << 8)); - return; + return 0; } + if (rstat & SER_DATA_AVAIL_MASK) { /* Ok data, no error, count it */ TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n", @@ -1602,32 +1596,87 @@ /* Read data to clear status flags */ (void)info->port[REG_DATA]; - magic++; + info->forced_eop = 0; + START_FLUSH_FAST_TIMER(info, "magic"); + return 0; } - if (magic != info->fifo_magic) { - info->fifo_magic = magic; - info->fifo_didmagic = 0; - START_FLUSH_FAST_TIMER(info, "magic"); - } else { - /* hit the timeout, force an EOP for the input - * dma channel if we haven't already - */ - if (!info->fifo_didmagic && magic) { - info->fifo_didmagic = 1; - info->fifo_magic = 0; - PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); - DEBUG_LOG(info->line, "timeout EOP %i\n", info->line); - TIMERD(DEBUG_LOG(info->line, "timeout magic %i\n", magic)); - FORCE_EOP(info); - } + /* hit the timeout, force an EOP for the input + * dma channel if we haven't already + */ + if (!info->forced_eop) { + info->forced_eop = 1; + PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); + DEBUG_LOG(info->line, "timeout EOP %i\n", info->line); + FORCE_EOP(info); } -} /* check_flush_timeout */ + + return 1; +} + +static _INLINE_ void +flush_to_flip_buffer(struct e100_serial *info) +{ + struct tty_struct *tty = info->tty; + unsigned int count = CIRC_CNT_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); + unsigned int length; + unsigned long flags; + + if (!count) + return; + + save_flags(flags); + cli(); + + length = tty->flip.count; + + do { + if (length + count > TTY_FLIPBUF_SIZE) + count = TTY_FLIPBUF_SIZE - length; + + memcpy(tty->flip.char_buf_ptr + length, info->recv.buf + info->recv.tail, count); + memcpy(tty->flip.flag_buf_ptr + length, info->flag_buf + info->recv.tail, count); + info->recv.tail = ((info->recv.tail + count) & (SERIAL_RECV_SIZE-1)); + length += count; + + count = CIRC_CNT_TO_END(info->recv.head, + info->recv.tail, + SERIAL_RECV_SIZE); + } while (length < TTY_FLIPBUF_SIZE && count); + + tty->flip.count = length; + + restore_flags(flags); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,66) + /* this includes a check for low-latency */ + tty_flip_buffer_push(tty); +#else + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); +#endif + + /* unthrottle if we have throttled */ + if (E100_RTS_GET(info) && + CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) > TTY_THROTTLE_LIMIT) + tty->driver.unthrottle(info->tty); +} + +static _INLINE_ void +check_flush_timeout(struct e100_serial *info) +{ + force_eop_if_needed(info); + + flush_to_flip_buffer(info); + + if (CIRC_CNT(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE)) + START_FLUSH_FAST_TIMER(info, "flip"); +} #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER static void flush_timeout_function(unsigned long data) { struct e100_serial *info = (struct e100_serial *)data; + fast_timers[info->line].function = NULL; serial_fast_timer_expired++; TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line)); @@ -1681,7 +1730,6 @@ { struct e100_serial *info; int i; - unsigned int magic; #ifdef CONFIG_SVINTO_SIM return; @@ -1689,35 +1737,8 @@ for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; - if (!info->enabled || !(info->flags & ASYNC_INITIALIZED)) - continue; - - /* istatusadr (bit 6-0) hold number of bytes in fifo - * ihwswadr (bit 31-16) holds number of bytes in dma buffer - * ihwswadr (bit 15-0) specifies size of dma buffer - */ - - magic = (*info->istatusadr & 0x3f); - magic += ((*info->ihwswadr & 0xffff) - (*info->ihwswadr >> 16)); - - /* if magic is equal to fifo_magic (magic in previous - * timeout_interrupt) then no new data has arrived since last - * interrupt and we'll force eop to flush fifo+dma buffers - */ - - if (magic != info->fifo_magic) { - info->fifo_magic = magic; - info->fifo_didmagic = 0; - } else { - /* hit the timeout, force an EOP for the input - * dma channel if we haven't already - */ - if (!info->fifo_didmagic && magic) { - info->fifo_didmagic = 1; - info->fifo_magic = 0; - FORCE_EOP(info); - } - } + if (info->uses_dma) + check_flush_timeout(info); } /* restart flush timer */ @@ -1770,7 +1791,7 @@ Multiple frame errors with data == 0x00 (B), but the part of the break trigs is interpreted as a start bit (and possibly -som 0 bits followed by a number of 1 bits and a stop bit). +some 0 bits followed by a number of 1 bits and a stop bit). Depending on parity settings etc. this last character can be either a fake "valid" char (F) or have a parity error (E). @@ -1805,19 +1826,20 @@ /* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */ if (rstat & SER_ERROR_MASK) { unsigned char data; + info->last_rx_active_usec = GET_JIFFIES_USEC(); info->last_rx_active = jiffies; - /* if we got an error, we must reset it by - * reading the data_in field + /* If we got an error, we must reset it by reading the + * data_in field */ data = info->port[REG_DATA]; - if ((data == 0x00) && (rstat & SER_FRAMING_ERR_MASK)) { - /* Most likely a break, but we get - * interrupts over and over again. + if (!data && (rstat & SER_FRAMING_ERR_MASK)) { + /* Most likely a break, but we get interrupts over and + * over again. */ - if (info->break_detected_cnt == 0) { + if (!info->break_detected_cnt) { DEBUG_LOG(info->line, "#BRK start\n", 0); } if (rstat & SER_RXD_MASK) { @@ -1833,46 +1855,46 @@ } info->break_detected_cnt++; } else { - /* Error doesn't look like a break, - * but could be end of a break + /* The error does not look like a break, but could be + * the end of one */ if (info->break_detected_cnt) { DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); info->errorcode = ERRCODE_INSERT_BREAK; + } else { + if (info->errorcode == ERRCODE_INSERT_BREAK) + add_char_and_flag(info, '\0', TTY_BREAK); + + if (rstat & SER_PAR_ERR_MASK) + add_char_and_flag(info, data, TTY_PARITY); + else if (rstat & SER_OVERRUN_MASK) + add_char_and_flag(info, data, TTY_OVERRUN); + else if (rstat & SER_FRAMING_ERR_MASK) + add_char_and_flag(info, data, TTY_FRAME); + info->errorcode = 0; } info->break_detected_cnt = 0; DEBUG_LOG(info->line, "#iERR s d %04X\n", ((rstat & SER_ERROR_MASK) << 8) | data); } PROCSTAT(ser_stat[info->line].early_errors_cnt++); - -#if 0 - /* Reset DMA before starting */ - *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); - while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); -#endif - } else { /* it was a valid byte, now let the dma do the rest */ - unsigned char data; + } else { /* It was a valid byte, now let the DMA do the rest */ unsigned long curr_time_u = GET_JIFFIES_USEC(); unsigned long curr_time = jiffies; if (info->break_detected_cnt) { - /* Detect if this character is a new - * valid char or the last char in a - * break sequence: - * If LSBits are 0 and MSBits are high - * AND the time is close to the - * previous interrupt we should discard - * it. + /* Detect if this character is a new valid char or the + * last char in a break sequence: If LSBits are 0 and + * MSBits are high AND the time is close to the + * previous interrupt we should discard it. */ long elapsed_usec = - (curr_time - info->last_rx_active) * (1000000/HZ) + - curr_time_u - info->last_rx_active_usec; - if (elapsed_usec<2*info->char_time_usec) { + (curr_time - info->last_rx_active) * (1000000/HZ) + + curr_time_u - info->last_rx_active_usec; + if (elapsed_usec < 2*info->char_time_usec) { DEBUG_LOG(info->line, "FBRK %i\n", info->line); - /* Report as BREAK (error) and - * let receive_chars handle it + /* Report as BREAK (error) and let + * receive_chars() handle it */ info->errorcode = ERRCODE_SET_BREAK; } else { @@ -1880,22 +1902,19 @@ } DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt); } - /* Reset data_avail by - * reading the data_in field - */ - data = info->port[REG_DATA]; - info->break_detected_cnt = 0; - info->fifo_magic++; /* Count received chars */ + #ifdef SERIAL_DEBUG_INTR printk("** OK, disabling ser_interupts\n"); #endif - PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); - DEBUG_LOG(info->line, " ser_int OK %03X\n", - (info->line << 8) | data); e100_disable_serial_data_irq(info); + + info->break_detected_cnt = 0; + + PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); + DEBUG_LOG(info->line, "ser_int OK %d\n", info->line); } - /* restart the DMA never hurts */ + /* Restarting the DMA never hurts */ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); START_FLUSH_FAST_TIMER(info, "ser_int"); } /* handle_ser_interrupt */ @@ -1973,7 +1992,7 @@ { struct e100_serial *info = (struct e100_serial *) private_; struct tty_struct *tty; - + tty = info->tty; if (!tty) return; @@ -1985,43 +2004,46 @@ startup(struct e100_serial * info) { unsigned long flags; - unsigned long page; + unsigned long xmit_page; + unsigned char *recv_page; + + xmit_page = get_zeroed_page(GFP_KERNEL); + if (!xmit_page) + return -ENOMEM; - page = get_zeroed_page(GFP_KERNEL); - if (!page) + recv_page = kmalloc(2 * SERIAL_RECV_SIZE + SERIAL_RECV_DESCRIPTORS * SERIAL_DESCR_BUF_SIZE, GFP_KERNEL); + if (!recv_page) { + free_page(xmit_page); return -ENOMEM; + } save_flags(flags); cli(); /* if it was already initialized, skip this */ - + if (info->flags & ASYNC_INITIALIZED) { - free_page(page); restore_flags(flags); + free_page(xmit_page); + kfree(recv_page); return 0; } - + if (info->xmit.buf) - free_page(page); + free_page(xmit_page); else - 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); -#endif - - if (info->tty) { - - /* clear the tty flip flag buffer since we will not - * be using it (we only use the first byte..) - */ + info->xmit.buf = (unsigned char *) xmit_page; - memset(info->tty->flip.flag_buf, 0, TTY_FLIPBUF_SIZE * 2); + if (info->recv.buf) + kfree(recv_page); + else { + info->recv.buf = (unsigned char *) recv_page; + info->flag_buf = info->recv.buf + SERIAL_RECV_SIZE; } - save_flags(flags); - cli(); - +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttyS%d (xmit_buf 0x%p, recv_buf 0x%p)...\n", info->line, info->xmit.buf, info->recv.buf); +#endif + #ifdef CONFIG_SVINTO_SIM /* Bits and pieces collected from below. Better to have them in one ifdef:ed clause than to mix in a lot of ifdefs, @@ -2029,7 +2051,8 @@ if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit.head = info->xmit.tail = 0; - + info->recv.head = info->recv.tail = 0; + /* No real action in the simulator, but may set info important to ioctl. */ change_speed(info); @@ -2039,33 +2062,35 @@ * Clear the FIFO buffers and disable them * (they will be reenabled in change_speed()) */ - + /* * Reset the DMA channels and make sure their interrupts are cleared */ - + info->uses_dma = 1; *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); - /* wait until reset cycle is complete */ + /* Wait until reset cycle is complete */ while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); - + + /* Make sure the irqs are cleared */ *info->iclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); *info->oclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); - + if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); - info->xmit.head = info->xmit.tail = 0; + info->xmit.head = info->xmit.tail = 0; + info->recv.head = info->recv.tail = 0; /* * and set the speed and other flags of the serial port @@ -2085,7 +2110,7 @@ e100_enable_txdma_irq(info); e100_enable_rxdma_irq(info); - info->tr_running = 0; /* to be sure we dont lock up the transmitter */ + info->tr_running = 0; /* to be sure we don't lock up the transmitter */ /* setup the dma input descriptor and start dma */ @@ -2120,7 +2145,7 @@ unsigned long flags; #ifndef CONFIG_SVINTO_SIM - /* shut down the transmitter and receiver */ + /* shut down the transmitter and receiver */ e100_disable_rx(info); info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); @@ -2150,9 +2175,14 @@ cli(); /* Disable interrupts */ if (info->xmit.buf) { - unsigned long pg = (unsigned long) info->xmit.buf; - info->xmit.buf = 0; - free_page(pg); + free_page((unsigned long)info->xmit.buf); + info->xmit.buf = NULL; + } + + if (info->recv.buf) { + kfree(info->recv.buf); + info->recv.buf = NULL; + info->flag_buf = NULL; } if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { @@ -2258,11 +2288,11 @@ struct e100_serial *info = (struct e100_serial *)tty->driver_data; unsigned long flags; - if (info->tr_running - || info->xmit.head == info->xmit.tail - || tty->stopped - || tty->hw_stopped - || !info->xmit.buf) + if (info->tr_running || + info->xmit.head == info->xmit.tail || + tty->stopped || + tty->hw_stopped || + !info->xmit.buf) return; #ifdef SERIAL_DEBUG_FLOW @@ -2299,7 +2329,7 @@ #ifdef CONFIG_SVINTO_SIM /* Really simple. The output is here and now. */ SIMCOUT(buf, count); - return; + return count; #endif save_flags(flags); @@ -2370,8 +2400,8 @@ * the IRQ's are not running anyway for this port. */ - if (info->xmit.head != info->xmit.tail - && !tty->stopped && + if (info->xmit.head != info->xmit.tail && + !tty->stopped && !tty->hw_stopped && !info->tr_running) { start_transmit(info); @@ -2528,20 +2558,20 @@ tmp.flags = info->flags; tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; - if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0; } static int -set_serial_info(struct e100_serial * info, - struct serial_struct * new_info) +set_serial_info(struct e100_serial *info, + struct serial_struct *new_info) { struct serial_struct new_serial; struct e100_serial old_info; - int retval = 0; + int retval = 0; - if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) return -EFAULT; old_info = *info; @@ -2636,6 +2666,7 @@ char *get_control_state_str(int MLines, char *s) { int i = 0; + s[0]='\0'; while (control_state_str[i].str != NULL) { if (MLines & control_state_str[i].state) { @@ -2805,9 +2836,13 @@ rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - int error; struct e100_serial * info = (struct e100_serial *)tty->driver_data; +#if defined(CONFIG_ETRAX_RS485) || (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ + int error; +#endif +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ int retval; +#endif if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && @@ -3108,7 +3143,7 @@ struct e100_serial *info) { DECLARE_WAITQUEUE(wait, current); - unsigned long flags; + unsigned long flags; int retval; int do_clocal = 0, extra_count = 0; @@ -3292,7 +3327,7 @@ } /* - * If the port is the middle of closing, bail out now + * If the port is in the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { @@ -3346,12 +3381,11 @@ static inline int line_info(char *buf, struct e100_serial *info) { - char stat_buf[30], control, status; + char stat_buf[30]; int ret; - unsigned long flags; ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d", - info->line, info->port, info->irq); + info->line, (unsigned long)info->port, info->irq); if (!info->port || (info->type == PORT_UNKNOWN)) { ret += sprintf(buf+ret, "\n"); @@ -3376,19 +3410,24 @@ ret += sprintf(buf+ret, " baud:%d", info->baud); ret += sprintf(buf+ret, " tx:%lu rx:%lu", - info->icount.tx, info->icount.rx); + (unsigned long)info->icount.tx, + (unsigned long)info->icount.rx); if (info->icount.frame) - ret += sprintf(buf+ret, " fe:%lu", info->icount.frame); + ret += sprintf(buf+ret, " fe:%lu", + (unsigned long)info->icount.frame); if (info->icount.parity) - ret += sprintf(buf+ret, " pe:%lu", info->icount.parity); + ret += sprintf(buf+ret, " pe:%lu", + (unsigned long)info->icount.parity); if (info->icount.brk) - ret += sprintf(buf+ret, " brk:%lu", info->icount.brk); + ret += sprintf(buf+ret, " brk:%lu", + (unsigned long)info->icount.brk); if (info->icount.overrun) - ret += sprintf(buf+ret, " oe:%lu", info->icount.overrun); + ret += sprintf(buf+ret, " oe:%lu", + (unsigned long)info->icount.overrun); /* * Last thing is the RS-232 status lines @@ -3526,8 +3565,7 @@ info->tty = 0; info->type = PORT_ETRAX; info->tr_running = 0; - info->fifo_magic = 0; - info->fifo_didmagic = 0; + info->forced_eop = 0; info->flags = 0; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; @@ -3541,8 +3579,21 @@ info->normal_termios = serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); - info->xmit.buf = 0; + info->xmit.buf = NULL; info->xmit.tail = info->xmit.head = 0; + info->recv.buf = NULL; + info->recv.tail = info->recv.head = 0; + info->flag_buf = NULL; + info->last_tx_active_usec = 0; + info->last_tx_active = 0; + +#if defined(CONFIG_ETRAX_RS485) + /* Set sane defaults */ + info->rs485.rts_on_send = 0; + info->rs485.rts_after_sent = 1; + info->rs485.delay_rts_before_send = 0; + info->rs485.enabled = 0; +#endif if (info->enabled) { printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/drivers/serial.h linux-2.5/arch/cris/drivers/serial.h --- linux-2.5.1/arch/cris/drivers/serial.h Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/drivers/serial.h Thu Jan 10 22:41:07 2002 @@ -23,81 +23,90 @@ * For definitions of the flags field, see tty.h */ +#define SERIAL_RECV_DESCRIPTORS 8 + struct e100_serial { - int baud; - volatile u8 *port; /* R_SERIALx_CTRL */ - u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ - - volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ - volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ - volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ - const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */ - volatile u32 *ohwswadr; /* adr to R_DMA_CHx_HWSW, output */ - - volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ - volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ - volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD, input */ - const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ - volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ - - int flags; /* defined in tty.h */ - - u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ - u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ - u8 iseteop; /* bit number for R_SET_EOP for the input dma */ - int enabled; /* Set to 1 if the port is enabled in HW config */ - + int baud; + volatile u8 *port; /* R_SERIALx_CTRL */ + u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ + + /* Output registers */ + volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */ + volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST */ + volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD */ + const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS */ + volatile u32 *ohwswadr; /* adr to R_DMA_CHx_HWSW */ + volatile u32 *odescradr; /* adr to R_DMA_CHx_DESCR */ + + /* Input registers */ + volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */ + volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST */ + volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */ + const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS */ + volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW */ + volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */ + + int flags; /* defined in tty.h */ + + u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ + u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ + u8 iseteop; /* bit number for R_SET_EOP for the input dma */ + + int enabled; /* Set to 1 if the port is enabled in HW config */ -/* end of fields defined in rs_table[] in .c-file */ - int uses_dma; /* Set to 1 if DMA should be used */ - unsigned char fifo_didmagic; /* a fifo eop has been forced */ + /* end of fields defined in rs_table[] in .c-file */ - struct etrax_dma_descr tr_descr, rec_descr; + int uses_dma; /* Set to 1 if DMA should be used */ + unsigned char forced_eop; /* a fifo eop has been forced */ - int fifo_magic; /* fifo amount - bytes left in dma buffer */ + struct etrax_dma_descr tr_descr; + struct etrax_dma_descr rec_descr[SERIAL_RECV_DESCRIPTORS]; + int cur_rec_descr; - volatile int tr_running; /* 1 if output is running */ + volatile int tr_running; /* 1 if output is running */ - struct tty_struct *tty; + struct tty_struct *tty; int read_status_mask; int ignore_status_mask; int x_char; /* xon/xoff character */ int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; + unsigned short closing_wait; + unsigned short closing_wait2; unsigned long event; unsigned long last_active; int line; - int type; /* PORT_ETRAX */ + int type; /* PORT_ETRAX */ int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ long session; /* Session of opening process */ long pgrp; /* pgrp of opening process */ - struct circ_buf xmit; + struct circ_buf xmit; + struct circ_buf recv; + unsigned char *flag_buf; struct tq_struct tqueue; - struct async_icount icount; /* error-statistics etc.*/ - struct termios normal_termios; - struct termios callout_termios; + struct async_icount icount; /* error-statistics etc.*/ + struct termios normal_termios; + struct termios callout_termios; #ifdef DECLARE_WAITQUEUE - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; -#else - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; +#else + struct wait_queue *open_wait; + struct wait_queue *close_wait; #endif - unsigned long char_time_usec; /* The time for 1 char, in usecs */ - unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */ - unsigned long last_tx_active; /* Last tx time in jiffies */ - unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */ - unsigned long last_rx_active; /* Last rx time in jiffies */ + unsigned long char_time_usec; /* The time for 1 char, in usecs */ + unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */ + unsigned long last_tx_active; /* Last tx time in jiffies */ + unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */ + unsigned long last_rx_active; /* Last rx time in jiffies */ - int break_detected_cnt; - int errorcode; + int break_detected_cnt; + int errorcode; #ifdef CONFIG_RS485 - struct rs485_control rs485; /* RS-485 support */ + struct rs485_control rs485; /* RS-485 support */ #endif }; @@ -116,4 +125,4 @@ #endif /* __KERNEL__ */ -#endif /* !(_ETRAX_SERIAL_H) */ +#endif /* !_ETRAX_SERIAL_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/drivers/sync_serial.c linux-2.5/arch/cris/drivers/sync_serial.c --- linux-2.5.1/arch/cris/drivers/sync_serial.c Tue May 1 23:04:56 2001 +++ linux-2.5/arch/cris/drivers/sync_serial.c Thu Jan 10 22:41:07 2002 @@ -711,7 +711,7 @@ { port->out_descr.hw_len = 0; port->out_descr.next = 0; - port->out_descr.ctrl = d_int | d_eol | d_eop; + port->out_descr.ctrl = d_int | d_eol | d_eop | d_wait; port->out_descr.sw_len = count; port->out_descr.buf = virt_to_phys(port->out_buffer); port->out_descr.status = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/drivers/usb-host.c linux-2.5/arch/cris/drivers/usb-host.c --- linux-2.5.1/arch/cris/drivers/usb-host.c Mon Oct 8 18:43:54 2001 +++ linux-2.5/arch/cris/drivers/usb-host.c Thu Jan 10 22:41:07 2002 @@ -3,7 +3,7 @@ * * Copyright (c) 2001 Axis Communications AB. * - * $Id: usb-host.c,v 1.11 2001/09/26 11:52:16 bjornw Exp $ + * $Id: usb-host.c,v 1.13 2001/11/13 12:06:17 pkj Exp $ * */ @@ -34,7 +34,7 @@ #define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR #define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR -static const char *usb_hcd_version = "$Revision: 1.11 $"; +static const char *usb_hcd_version = "$Revision: 1.13 $"; #undef KERN_DEBUG #define KERN_DEBUG "" @@ -78,11 +78,11 @@ #endif #ifdef USB_DEBUG_TRACE -#define DBFENTER (printk(KERN_DEBUG __FILE__ ": Entering : " __FUNCTION__ "\n")) -#define DBFEXIT (printk(KERN_DEBUG __FILE__ ": Exiting : " __FUNCTION__ "\n")) +#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) +#define DBFENTER do {} while (0) +#define DBFEXIT do {} while (0) #endif /*------------------------------------------------------------------- @@ -163,7 +163,7 @@ #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; +static unsigned long submit_urb_count = 0; //#define ETRAX_USB_INTR_IRQ //#define ETRAX_USB_INTR_ERROR_FATAL @@ -178,6 +178,7 @@ static __u32 ep_usage_bitmask; static __u32 ep_really_active; +static __u32 ep_out_traffic; static unsigned char RxBuf[RX_BUF_SIZE]; static USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4))); @@ -196,22 +197,25 @@ static kmem_cache_t *usb_desc_cache; static struct usb_bus *etrax_usb_bus; -static void dump_urb (purb_t purb); +#ifdef USB_DEBUG_DESC +static void dump_urb (struct urb *urb); +#endif 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 void etrax_usb_setup_epid(int epid, char devnum, char endpoint, + char packsize, char slow, char out_traffic); +static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, + char slow, int maxp, char out_traffic); static int etrax_usb_allocate_epid(void); -static void etrax_usb_free_epid(char epid); +static void etrax_usb_free_epid(int 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 void etrax_usb_do_ctrl_hw_add(urb_t *urb, int epid, char maxlen); +static void etrax_usb_do_bulk_hw_add(urb_t *urb, int epid, char maxlen); static int etrax_usb_submit_ctrl_urb(urb_t *urb); @@ -240,24 +244,24 @@ }; #ifdef USB_DEBUG_DESC -static void dump_urb(purb_t purb) +static void dump_urb(struct urb *urb) { - 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); + printk("\nurb :0x%08X\n", urb); + printk("next :0x%08X\n", urb->next); + printk("dev :0x%08X\n", urb->dev); + printk("pipe :0x%08X\n", urb->pipe); + printk("status :%d\n", urb->status); + printk("transfer_flags :0x%08X\n", urb->transfer_flags); + printk("transfer_buffer :0x%08X\n", urb->transfer_buffer); + printk("transfer_buffer_length:%d\n", urb->transfer_buffer_length); + printk("actual_length :%d\n", urb->actual_length); + printk("setup_packet :0x%08X\n", urb->setup_packet); + printk("start_frame :%d\n", urb->start_frame); + printk("number_of_packets :%d\n", urb->number_of_packets); + printk("interval :%d\n", urb->interval); + printk("error_count :%d\n", urb->error_count); + printk("context :0x%08X\n", urb->context); + printk("complete :0x%08X\n\n", urb->complete); } static void dump_in_desc(USB_IN_Desc_t *in) @@ -292,10 +296,10 @@ #else -#define dump_urb(...) (NULL) -#define dump_ep_desc(...) (NULL) -#define dump_sb_desc(...) (NULL) -#define dump_in_desc(...) (NULL) +#define dump_urb(...) do {} while (0) +#define dump_in_desc(...) do {} while (0) +#define dump_sb_desc(...) do {} while (0) +#define dump_ep_desc(...) do {} while (0) #endif static void init_rx_buffers(void) @@ -423,25 +427,19 @@ 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; + int epid; char devnum; char endpoint; char slow; int maxlen; + char out_traffic; int i; - etrax_urb_priv_t *urb_priv; - unsigned long flags; - DBFENTER; devnum = usb_pipedevice(urb->pipe); @@ -449,8 +447,9 @@ slow = usb_pipeslow(urb->pipe); maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + out_traffic = usb_pipeout(urb->pipe); - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen, out_traffic); if (epid == -1) { err("Trying to unlink urb that is not in traffic queue!!"); return -1; /* fix this */ @@ -517,18 +516,16 @@ USB_EP_Desc_t *tmp_ep; USB_EP_Desc_t *first_ep; - USB_SB_Desc_t *sb_desc; - - char epid; + int epid; char devnum; char endpoint; char maxlen; + char out_traffic; char slow; int interval; int i; etrax_urb_priv_t *urb_priv; - unsigned long flags; DBFENTER; @@ -536,6 +533,7 @@ endpoint = usb_pipeendpoint(urb->pipe); maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + out_traffic = usb_pipeout(urb->pipe); slow = usb_pipeslow(urb->pipe); interval = urb->interval; @@ -543,7 +541,7 @@ 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); + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen, out_traffic); if (epid == -1) { epid = etrax_usb_allocate_epid(); if (epid == -1) { @@ -552,7 +550,7 @@ return -ENOMEM; } /* Now we have to fill in this ep */ - etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); + etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow, out_traffic); } /* Ok, now we got valid endpoint, lets insert some traffic */ @@ -641,7 +639,7 @@ } -static int handle_intr_transfer_attn(char epid, int status) +static void handle_intr_transfer_attn(int epid, int status) { urb_t *old_urb; @@ -782,7 +780,7 @@ /* DBFEXIT; */ } -static void etrax_usb_setup_epid(char epid, char devnum, char endpoint, char packsize, char slow) +static void etrax_usb_setup_epid(int epid, char devnum, char endpoint, char packsize, char slow, char out_traffic) { unsigned long flags; @@ -800,8 +798,6 @@ } 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(); @@ -811,12 +807,20 @@ IO_FIELD(R_USB_EPT_DATA, max_len, packsize) | IO_FIELD(R_USB_EPT_DATA, low_speed, slow); + if (out_traffic) + set_bit(epid, (void *)&ep_out_traffic); + else + clear_bit(epid, (void *)&ep_out_traffic); + restore_flags(flags); + dbg_ep("Setting up ep_id %d with devnum %d, endpoint %d and max_len %d (%s)", + epid, devnum, endpoint, packsize, out_traffic ? "OUT" : "IN"); + DBFEXIT; } -static void etrax_usb_free_epid(char epid) +static void etrax_usb_free_epid(int epid) { unsigned long flags; @@ -846,7 +850,7 @@ } -static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp) +static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp, char out_traffic) { int i; unsigned long flags; @@ -855,10 +859,12 @@ DBFENTER; save_flags(flags); - + cli(); + /* 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)) { + if (test_bit(i, (void *)&ep_usage_bitmask) && + test_bit(i, (void *)&ep_out_traffic) == out_traffic) { *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i); nop(); data = *R_USB_EPT_DATA; @@ -869,8 +875,8 @@ (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxp)) { restore_flags(flags); - dbg_ep("Found ep_id %d for devnum %d, endpoint %d", - i, devnum, endpoint); + dbg_ep("Found ep_id %d for devnum %d, endpoint %d (%s)", + i, devnum, endpoint, out_traffic ? "OUT" : "IN"); DBFEXIT; return i; } @@ -879,8 +885,8 @@ restore_flags(flags); - dbg_ep("Found no ep_id for devnum %d, endpoint %d", - devnum, endpoint); + dbg_ep("Found no ep_id for devnum %d, endpoint %d (%s)", + devnum, endpoint, out_traffic ? "OUT" : "IN"); DBFEXIT; return -1; } @@ -906,15 +912,15 @@ static int etrax_usb_submit_bulk_urb(urb_t *urb) { - char epid; + int epid; char devnum; char endpoint; char maxlen; + char out_traffic; char slow; urb_t *tmp_urb; - etrax_urb_priv_t *urb_priv; unsigned long flags; DBFENTER; @@ -923,9 +929,10 @@ endpoint = usb_pipeendpoint(urb->pipe); maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + out_traffic = usb_pipeout(urb->pipe); slow = usb_pipeslow(urb->pipe); - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen, out_traffic); if (epid == -1) { epid = etrax_usb_allocate_epid(); if (epid == -1) { @@ -934,7 +941,7 @@ return -ENOMEM; } /* Now we have to fill in this ep */ - etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); + etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow, out_traffic); } /* Ok, now we got valid endpoint, lets insert some traffic */ @@ -962,14 +969,13 @@ return 0; } -static int etrax_usb_do_bulk_hw_add(urb_t *urb, char epid, char maxlen) +static void etrax_usb_do_bulk_hw_add(urb_t *urb, int 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; @@ -1078,7 +1084,7 @@ DBFEXIT; } -static int handle_bulk_transfer_attn(char epid, int status) +static void handle_bulk_transfer_attn(int epid, int status) { urb_t *old_urb; etrax_urb_priv_t *hc_priv; @@ -1129,8 +1135,9 @@ 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, @@ -1161,15 +1168,15 @@ static int etrax_usb_submit_ctrl_urb(urb_t *urb) { - char epid; + int epid; char devnum; char endpoint; char maxlen; + char out_traffic; char slow; urb_t *tmp_urb; - etrax_urb_priv_t *urb_priv; unsigned long flags; DBFENTER; @@ -1178,9 +1185,10 @@ endpoint = usb_pipeendpoint(urb->pipe); maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + out_traffic = usb_pipeout(urb->pipe); slow = usb_pipeslow(urb->pipe); - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen, out_traffic); if (epid == -1) { epid = etrax_usb_allocate_epid(); if (epid == -1) { @@ -1189,7 +1197,7 @@ return -ENOMEM; } /* Now we have to fill in this ep */ - etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); + etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow, out_traffic); } /* Ok, now we got valid endpoint, lets insert some traffic */ @@ -1217,7 +1225,7 @@ return 0; } -static int etrax_usb_do_ctrl_hw_add(urb_t *urb, char epid, char maxlen) +static void etrax_usb_do_ctrl_hw_add(urb_t *urb, int epid, char maxlen) { USB_SB_Desc_t *sb_desc_1; USB_SB_Desc_t *sb_desc_2; @@ -1226,8 +1234,6 @@ etrax_urb_priv_t *urb_priv; unsigned long flags; - __u32 r_usb_ept_data; - DBFENTER; @@ -1365,6 +1371,8 @@ DBFENTER; + urb->next = NULL; + dump_urb(urb); submit_urb_count++; @@ -1407,8 +1415,7 @@ { etrax_hc_t *hc = urb->dev->bus->hcpriv; int epid; - int pos; - int devnum, endpoint, slow, maxlen; + int devnum, endpoint, slow, maxlen, out_traffic; etrax_urb_priv_t *hc_priv; unsigned long flags; @@ -1419,13 +1426,13 @@ slow = usb_pipeslow(urb->pipe); maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + out_traffic = usb_pipeout(urb->pipe); - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); + epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen, out_traffic); if (epid == -1) return 0; - if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { int ret; ret = etrax_rh_unlink_urb(urb); @@ -1449,35 +1456,37 @@ for (epid = 0; epid < 32; epid++) { urb_t *u = URB_List[epid]; - pos = 0; + urb_t *prev = NULL; + int pos = 0; for (; u; u = u->next) { pos++; if (u == urb) { - info("Found urb at epid %d, pos %d", epid, pos); + if (!prev) { + URB_List[epid] = u->next; + } else { + prev->next = u->next; + } - if (pos == 1) { + restore_flags(flags); + + if (!prev) { 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; } + + info("Found urb at epid %d, pos %d", epid, pos); + u->status = -ENOENT; if (u->complete) { u->complete(u); @@ -1486,7 +1495,11 @@ hc_priv = (etrax_urb_priv_t *)u->hcpriv; cleanup_sb(hc_priv->first_sb); kfree(hc_priv); + + DBFEXIT; + return 0; } + prev = u; } } @@ -1519,13 +1532,6 @@ 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)) { @@ -1589,8 +1595,8 @@ } 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); + err("Packet (epid: %d) in RX buffer (%d) was bigger " + "than the URB has room for (%d)!!!", epid, urb_priv->rx_offset + myNextRxDesc->hw_len, urb->transfer_buffer_length); goto skip_out; } @@ -1606,7 +1612,7 @@ } else { err("This is almost fatal, inpacket for epid %d which does not exist " - " or is out !!!\nURB was at 0x%08X", epid, urb); + " or is out!!!\nURB was at 0x%08lX", epid, (unsigned long)urb); goto skip_out; } @@ -1647,7 +1653,7 @@ } -static int handle_control_transfer_attn(char epid, int status) +static void handle_control_transfer_attn(int epid, int status) { urb_t *old_urb; etrax_urb_priv_t *hc_priv; @@ -1710,7 +1716,6 @@ 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; @@ -1804,7 +1809,7 @@ 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("submit urb has been called %lu times..", submit_urb_count); err("EPID_ATTN for epid %d, with NULL entry in list", epid); return; } @@ -1822,7 +1827,7 @@ 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); + warn("Undefined error for epid %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) { @@ -1861,7 +1866,7 @@ } } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) { - warn("Stall for endpoint %d", epid); + warn("Stall for epid %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) { @@ -1872,10 +1877,10 @@ } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) { - panic("USB bus error for endpoint %d\n", epid); + panic("USB bus error for epid %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); + warn("Buffer error for epid %d", epid); if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { handle_control_transfer_attn(epid, -EPROTO); @@ -1981,15 +1986,11 @@ 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; + struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) 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; @@ -2009,10 +2010,10 @@ 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); + bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8; + wValue = le16_to_cpu(cmd->wValue); + wIndex = le16_to_cpu(cmd->wIndex); + wLength = le16_to_cpu(cmd->wLength); dbg_rh("bmRType_bReq : 0x%04X (%d)", bmRType_bReq, bmRType_bReq); dbg_rh("wValue : 0x%04X (%d)", wValue, wValue); @@ -2281,7 +2282,7 @@ 0xff, "ETRAX 100LX", data, wLength); if (len > 0) { - OK(min_t(int, leni, len)); + OK(min(leni, len)); } else stat = -EPIPE; } @@ -2306,7 +2307,7 @@ urb->actual_length = len; urb->status = stat; - urb->dev=NULL; + urb->dev = NULL; if (urb->complete) { urb->complete (urb); } @@ -2356,6 +2357,7 @@ ep_usage_bitmask = 0; set_bit(0, (void *)&ep_usage_bitmask); ep_really_active = 0; + ep_out_traffic = 0; memset(URB_List, 0, sizeof(URB_List)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/kernel/entry.S linux-2.5/arch/cris/kernel/entry.S --- linux-2.5.1/arch/cris/kernel/entry.S Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/kernel/entry.S Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.35 2001/10/30 17:10:15 bjornw Exp $ +/* $Id: entry.S,v 1.37 2001/12/07 17:03:55 bjornw Exp $ * * linux/arch/cris/entry.S * @@ -7,6 +7,15 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.37 2001/12/07 17:03:55 bjornw + * Call a c-hook called watchdog_bite_hook instead of show_registers directly + * + * Revision 1.36 2001/11/22 13:36:36 bjornw + * * In ret_from_intr, check regs->dccr for usermode reentrance instead of + * DCCR explicitely (because the latter might not reflect current reality) + * * In mmu_bus_fault, set $r9 _after_ calling the C-code instead of before + * since $r9 is call-clobbered and is potentially needed afterwards + * * Revision 1.35 2001/10/30 17:10:15 bjornw * Add some syscalls * @@ -217,8 +226,11 @@ ret_from_intr: ;; check for resched only if we're going back to user-mode - - move $ccr, $r0 + ;; this test matches the user_regs(regs) macro + ;; we cannot simply test $dccr, because that does not necessarily + ;; reflect what mode we'll return into. + + move.d [$sp + LDCCR], $r0; regs->dccr btstq 8, $r0 ; U-flag bpl _Rexit ; go back directly nop @@ -468,8 +480,6 @@ moveq 1, $r10 push $r10 ; frametype == 1, BUSFAULT frame type - moveq 0, $r9 ; busfault is equivalent to an irq - move.d $sp, $r10 ; pt_regs argument to handle_mmu_bus_fault jsr handle_mmu_bus_fault ; in arch/cris/mm/fault.c @@ -479,6 +489,8 @@ ;; process due to a SEGV, scheduled due to a page blocking or ;; whatever. + moveq 0, $r9 ; busfault is equivalent to an irq + ba ret_from_intr nop @@ -585,7 +597,7 @@ jsr printk move.d $sp, $r10 - jsr show_registers + jsr watchdog_bite_hook ;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps ;; rather than "spurious_interrupt". diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/kernel/head.S linux-2.5/arch/cris/kernel/head.S --- linux-2.5.1/arch/cris/kernel/head.S Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/kernel/head.S Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.41 2001/10/29 14:55:58 pkj Exp $ +/* $Id: head.S,v 1.43 2001/11/08 15:09:43 starvik Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,12 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.43 2001/11/08 15:09:43 starvik + * Only start MII clock if Ethernet is configured + * + * Revision 1.42 2001/11/08 14:37:34 starvik + * Start MII clock early to make sure that it is running at tranceiver reset + * * Revision 1.41 2001/10/29 14:55:58 pkj * Corrected pa$r0 to par0. * @@ -156,7 +162,10 @@ #define CRAMFS_MAGIC 0x28cd3d45 #define RAM_INIT_MAGIC 0x56902387 - + +#define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\ + IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) + ;; exported symbols .globl etrax_irv @@ -301,6 +310,12 @@ ;; after init. .section ".text.init" _inflash: +#ifdef CONFIG_ETRAX_ETHERNET + ;; Start MII clock to make sure it is running when tranceiver is reset + move.d START_ETHERNET_CLOCK, $r0 + move.d $r0, [R_NETWORK_GEN_CONFIG] +#endif + ;; We need to initialze DRAM registers before we start using the DRAM cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/kernel/irq.c linux-2.5/arch/cris/kernel/irq.c --- linux-2.5.1/arch/cris/kernel/irq.c Wed Nov 28 21:22:25 2001 +++ linux-2.5/arch/cris/kernel/irq.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.17 2001/07/25 16:08:01 bjornw Exp $ +/* $Id: irq.c,v 1.18 2001/11/21 13:40:18 bjornw Exp $ * * linux/arch/cris/kernel/irq.c * @@ -138,7 +138,7 @@ /* IRQ0 and 1 are special traps */ void hwbreakpoint(void); void IRQ1_interrupt(void); -BUILD_IRQ(2, 0x04) /* the timer interrupt */ +BUILD_TIMER_IRQ(2, 0x04) /* the timer interrupt is somewhat special */ BUILD_IRQ(3, 0x08) BUILD_IRQ(4, 0x10) BUILD_IRQ(5, 0x20) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/kernel/ksyms.c linux-2.5/arch/cris/kernel/ksyms.c --- linux-2.5.1/arch/cris/kernel/ksyms.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/kernel/ksyms.c Thu Jan 10 22:41:07 2002 @@ -23,34 +23,45 @@ extern void dump_thread(struct pt_regs *, struct user *); extern unsigned long get_cmos_time(void); +extern void __Udiv(void); extern void __ashrdi3(void); extern void iounmap(void *addr); -/* platform dependent support */ - +/* Platform dependent support */ EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(get_cmos_time); +EXPORT_SYMBOL(loops_per_usec); +/* String functions */ +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(simple_strtol); EXPORT_SYMBOL(strstr); - +EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strncmp); + +/* Math functions */ +EXPORT_SYMBOL(__Udiv); EXPORT_SYMBOL(__ashrdi3); +/* Memory functions */ EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); -/* export shadow registers for the CPU I/O pins */ +/* Semaphore functions */ +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__down); +/* Export shadow registers for the CPU I/O pins */ EXPORT_SYMBOL(genconfig_shadow); EXPORT_SYMBOL(port_pa_data_shadow); EXPORT_SYMBOL(port_pa_dir_shadow); @@ -59,8 +70,7 @@ EXPORT_SYMBOL(port_pb_config_shadow); EXPORT_SYMBOL(port_g_data_shadow); -/* other stuff */ - +/* Userspace access functions */ EXPORT_SYMBOL(strncpy_from_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__generic_copy_from_user); @@ -71,8 +81,8 @@ #undef memcpy #undef memset -extern void * memset(void *,int,__kernel_size_t); -extern void * memcpy(void *,const void *,__kernel_size_t); +extern void * memset(void *, int, __kernel_size_t); +extern void * memcpy(void *, const void *, __kernel_size_t); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/kernel/process.c linux-2.5/arch/cris/kernel/process.c --- linux-2.5.1/arch/cris/kernel/process.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/kernel/process.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.20 2001/10/03 08:21:39 jonashg Exp $ +/* $Id: process.c,v 1.22 2001/11/13 09:40:43 orjanf Exp $ * * linux/arch/cris/kernel/process.c * @@ -8,6 +8,12 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: process.c,v $ + * Revision 1.22 2001/11/13 09:40:43 orjanf + * Added dump_fpu (needed for core dumps). + * + * Revision 1.21 2001/11/12 18:26:21 pkj + * Fixed compiler warnings. + * * Revision 1.20 2001/10/03 08:21:39 jonashg * cause_of_death does not exist if CONFIG_SVINTO_SIM is defined. * @@ -57,6 +63,7 @@ #include <linux/slab.h> #include <linux/user.h> #include <linux/a.out.h> +#include <linux/elfcore.h> #include <linux/interrupt.h> #include <linux/delay.h> @@ -77,7 +84,6 @@ * setup. */ -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; @@ -119,7 +125,6 @@ int cpu_idle(void *unused) { while(1) { - current->counter = -100; schedule(); } } @@ -136,14 +141,15 @@ * code to know about it than the watchdog handler in entry.S and * this code, implementing hard reset through the watchdog. */ +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) extern int cause_of_death; +#endif printk("*** HARD RESET ***\n"); cli(); #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) cause_of_death = 0xbedead; - #else /* Since we dont plan to keep on reseting the watchdog, the key can be arbitrary hence three */ @@ -244,9 +250,10 @@ */ void dump_thread(struct pt_regs * regs, struct user * dump) { - int i; #if 0 -/* changed the size calculations - should hopefully work better. lbt */ + int i; + + /* changed the size calculations - should hopefully work better. lbt */ dump->magic = CMAGIC; dump->start_code = 0; dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); @@ -264,6 +271,12 @@ dump->u_fpvalid = dump_fpu (regs, &dump->i387); #endif +} + +/* Fill in the fpu structure for a core dump. */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) +{ + return 0; } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/kernel/ptrace.c linux-2.5/arch/cris/kernel/ptrace.c --- linux-2.5.1/arch/cris/kernel/ptrace.c Mon Oct 8 18:43:54 2001 +++ linux-2.5/arch/cris/kernel/ptrace.c Thu Jan 10 22:41:07 2002 @@ -8,6 +8,9 @@ * Authors: Bjorn Wesen * * $Log: ptrace.c,v $ + * Revision 1.8 2001/11/12 18:26:21 pkj + * Fixed compiler warnings. + * * Revision 1.7 2001/09/26 11:53:49 bjornw * PTRACE_DETACH works more simple in 2.4.10 * @@ -74,8 +77,6 @@ static inline int put_reg(struct task_struct *task, unsigned int regno, unsigned long data) { - unsigned long *addr; - if (regno == PT_USP) task->thread.usp = data; else if (regno < PT_MAX) @@ -207,9 +208,7 @@ break; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - long tmp; - + case PTRACE_CONT: /* restart after signal. */ ret = -EIO; if ((unsigned long) data > _NSIG) break; @@ -222,16 +221,13 @@ wake_up_process(child); ret = 0; break; - } /* * make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ - case PTRACE_KILL: { - long tmp; - + case PTRACE_KILL: ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ break; @@ -239,11 +235,8 @@ /* TODO: make sure any pending breakpoint is killed */ wake_up_process(child); break; - } - - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - long tmp; + case PTRACE_SINGLESTEP: /* set the trap flag. */ ret = -EIO; if ((unsigned long) data > _NSIG) break; @@ -256,7 +249,6 @@ wake_up_process(child); ret = 0; break; - } case PTRACE_DETACH: ret = ptrace_detach(child, data); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/kernel/setup.c linux-2.5/arch/cris/kernel/setup.c --- linux-2.5.1/arch/cris/kernel/setup.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/kernel/setup.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.22 2001/10/23 17:42:58 pkj Exp $ +/* $Id: setup.c,v 1.24 2001/12/07 17:03:19 bjornw Exp $ * * linux/arch/cris/kernel/setup.c * @@ -26,10 +26,12 @@ #include <linux/config.h> #include <linux/init.h> #include <linux/bootmem.h> +#include <linux/seq_file.h> #include <asm/segment.h> #include <asm/system.h> #include <asm/smp.h> +#include <asm/pgtable.h> #include <asm/types.h> #include <asm/svinto.h> @@ -72,10 +74,10 @@ void __init setup_arch(char **cmdline_p) { - unsigned long bootmap_size; + extern void init_etrax_debug(void); + unsigned long bootmap_size; unsigned long start_pfn, max_pfn; unsigned long memory_start; - extern void console_print_etrax(const char *b); /* register an initial console printing routine for printk's */ @@ -87,12 +89,12 @@ if(romfs_in_flash || !romfs_length) { /* if we have the romfs in flash, or if there is no rom filesystem, - * our free area starts directly after the BSS + * our free area starts directly after the BSS */ memory_start = (unsigned long) &_end; } else { /* otherwise the free area starts after the ROM filesystem */ - printk("ROM fs in RAM, size %d bytes\n", romfs_length); + printk("ROM fs in RAM, size %lu bytes\n", romfs_length); memory_start = romfs_start + romfs_length; } @@ -193,7 +195,7 @@ #define HAS_ATA 0x0020 #define HAS_USB 0x0040 #define HAS_IRQ_BUG 0x0080 -#define HAS_MMU_BUG 0x0100 +#define HAS_MMU_BUG 0x0100 static struct cpu_info { char *model; @@ -213,50 +215,27 @@ { "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 | HAS_MMU_BUG }, - { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, + { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, { "Unknown", 0, 0 } /* This entry MUST be the last */ }; -/* - * get_cpuinfo - Get information on one CPU for use by the procfs. - * - * Prints info on the next CPU into buffer. Beware, doesn't check for - * buffer overflow. Current implementation of procfs assumes that the - * resulting data is <= 1K. - * - * BUFFER is PAGE_SIZE - 1K bytes long. - * - * Args: - * buffer -- you guessed it, the data buffer - * cpu_np -- Input: next cpu to get (start at 0). Output: Updated. - * - * Returns number of bytes written to buffer. - */ -int get_cpuinfo(char *buffer, unsigned *cpu_np) +static int show_cpuinfo(struct seq_file *m, void *v) { - int revision; - struct cpu_info *info; - unsigned n; + unsigned long revision; + struct cpu_info *info; /* read the version register in the CPU and print some stuff */ revision = rdvr(); - if (revision < 0 || revision >= sizeof cpu_info/sizeof *cpu_info) { + if (revision >= sizeof cpu_info/sizeof *cpu_info) info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1]; - } else + else info = &cpu_info[revision]; - /* No SMP at the moment, so just toggle 0/1 */ - n = *cpu_np; - *cpu_np = 1; - if (n != 0) { - return (0); - } - - return sprintf(buffer, + return seq_printf(m, "cpu\t\t: CRIS\n" - "cpu revision\t: %d\n" + "cpu revision\t: %lu\n" "cpu model\t: %s\n" "cache size\t: %d kB\n" "fpu\t\t: %s\n" @@ -283,4 +262,28 @@ (loops_per_jiffy * HZ + 500) / 500000, ((loops_per_jiffy * HZ + 500) / 5000) % 100); } + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + /* We only got one CPU... */ + return *pos < 1 ? (void *)1 : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + start: c_start, + next: c_next, + stop: c_stop, + show: show_cpuinfo, +}; + #endif /* CONFIG_PROC_FS */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/kernel/time.c linux-2.5/arch/cris/kernel/time.c --- linux-2.5.1/arch/cris/kernel/time.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/kernel/time.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.9 2001/10/25 10:26:37 johana Exp $ +/* $Id: time.c,v 1.11 2001/11/12 18:26:22 pkj Exp $ * * linux/arch/cris/kernel/time.c * @@ -18,6 +18,7 @@ * Linux/CRIS specific code: * * Authors: Bjorn Wesen + * Johan Adolfsson * */ @@ -61,6 +62,7 @@ static unsigned long do_slow_gettimeoffset(void) { unsigned long count; + unsigned long usec_count = 0; static unsigned long count_p = LATCH; /* for the first call after boot */ static unsigned long jiffies_p = 0; @@ -93,16 +95,20 @@ */ if( jiffies_t == jiffies_p ) { if( count > count_p ) { + /* Timer wrapped */ + count = count_p; + usec_count = 1000000/CLOCK_TICK_RATE/2; } } else jiffies_p = jiffies_t; - count_p = count; - + /* Convert timer value to usec using table lookup */ + usec_count += cris_timer0_value_us[count]; +#if 0 count = ((LATCH-1) - count) * TICK_SIZE; count = (count + LATCH/2) / LATCH; - - return count; +#endif + return usec_count; } static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; @@ -160,9 +166,8 @@ { int retval = 0; int real_seconds, real_minutes, cmos_minutes; - unsigned char save_control, save_freq_select; - printk("set_rtc_mmss(%d)\n", nowtime); + printk("set_rtc_mmss(%lu)\n", nowtime); if(!have_rtc) return 0; @@ -225,7 +230,9 @@ /* right now, starting the watchdog is the same as resetting it */ #define start_watchdog reset_watchdog +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) static int watchdog_key = 0; /* arbitrary number */ +#endif /* number of pages to consider "out of memory". it is normal that the memory * is used though, so put this really low. @@ -306,12 +313,12 @@ 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)) + xtime.tv_usec < 500000 + (tick >> 1)) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; - + } } #if 0 @@ -322,6 +329,7 @@ { unsigned long flags; unsigned int newjiff; + save_flags(flags); cli(); newjiff = (myjiff << 16) | (unsigned short)(-*R_TIMER01_DATA); @@ -337,7 +345,6 @@ get_cmos_time(void) { unsigned int year, mon, day, hour, min, sec; - int i; sec = CMOS_READ(RTC_SECONDS); min = CMOS_READ(RTC_MINUTES); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/kernel/traps.c linux-2.5/arch/cris/kernel/traps.c --- linux-2.5.1/arch/cris/kernel/traps.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/cris/kernel/traps.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.15 2001/07/18 14:02:37 bjornw Exp $ +/* $Id: traps.c,v 1.17 2001/12/07 17:02:34 bjornw Exp $ * * linux/arch/cris/traps.c * @@ -30,6 +30,55 @@ int kstack_depth_to_print = 24; +void show_trace(unsigned long * stack) +{ + unsigned long addr, module_start, module_end; + extern char _stext, _etext; + int i; + + printk("\nCall Trace: "); + + i = 1; + module_start = VMALLOC_START; + module_end = VMALLOC_END; + + while (((long) stack & (THREAD_SIZE-1)) != 0) { + if (__get_user (addr, stack)) { + /* This message matches "failing address" marked + s390 in ksymoops, so lines containing it will + not be filtered out by ksymoops. */ + printk ("Failing address 0x%lx\n", (unsigned long)stack); + break; + } + stack++; + + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_stext) && + (addr <= (unsigned long) &_etext)) || + ((addr >= module_start) && (addr <= module_end))) { + if (i && ((i % 8) == 0)) + printk("\n "); + printk("[<%08lx>] ", addr); + i++; + } + } +} + +void show_trace_task(struct task_struct *tsk) +{ + /* TODO, this is not really useful since its called from + * SysRq-T and we don't have a keyboard.. :) + */ +} + + /* * These constants are for searching for possible module text * segments. MODULE_RANGE is a guess of how much space is likely @@ -48,9 +97,8 @@ void show_stack(unsigned long *sp) { - unsigned long *stack, addr, module_start, module_end; + unsigned long *stack, addr; int i; - extern char _stext, _etext; /* * debugging aid: "show_stack(NULL);" prints a @@ -62,7 +110,7 @@ stack = sp; - printk("\nStack from %08lx:\n ", stack); + printk("\nStack from %08lx:\n ", (unsigned long)stack); for(i = 0; i < kstack_depth_to_print; i++) { if (((long) stack & (THREAD_SIZE-1)) == 0) break; @@ -72,45 +120,13 @@ /* This message matches "failing address" marked s390 in ksymoops, so lines containing it will not be filtered out by ksymoops. */ - printk ("Failing address 0x%lx\n", stack); + printk ("Failing address 0x%lx\n", (unsigned long)stack); break; } stack++; printk("%08lx ", addr); } - - printk("\nCall Trace: "); - stack = sp; - i = 1; - module_start = VMALLOC_START; - module_end = VMALLOC_END; - while (((long) stack & (THREAD_SIZE-1)) != 0) { - if (__get_user (addr, stack)) { - /* This message matches "failing address" marked - s390 in ksymoops, so lines containing it will - not be filtered out by ksymoops. */ - printk ("Failing address 0x%lx\n", stack); - break; - } - stack++; - - /* - * If the address is either in the text segment of the - * kernel, or in the region which contains vmalloc'ed - * memory, it *may* be the address of a calling - * routine; if so, print it so that someone tracing - * down the cause of the crash will be able to figure - * out the call path that was taken. - */ - if (((addr >= (unsigned long) &_stext) && - (addr <= (unsigned long) &_etext)) || - ((addr >= module_start) && (addr <= module_end))) { - if (i && ((i % 8) == 0)) - printk("\n "); - printk("[<%08lx>] ", addr); - i++; - } - } + show_trace(sp); } #if 0 @@ -148,7 +164,7 @@ regs->r8, regs->r9, regs->r10, regs->r11); printk("r12: %08lx r13: %08lx oR10: %08lx\n", regs->r12, regs->r13, regs->orig_r10); - printk("R_MMU_CAUSE: %08lx\n", *R_MMU_CAUSE); + printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE); printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current); @@ -195,25 +211,56 @@ } } +/* Called from entry.S when the watchdog has bitten + * We print out something resembling an oops dump, and if + * we have the nice doggy development flag set, we halt here + * instead of rebooting. + */ + +void +watchdog_bite_hook(struct pt_regs *regs) +{ +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + cli(); + stop_watchdog(); + show_registers(regs); + while(1) /* nothing */; +#else + show_registers(regs); +#endif +} + +/* This is normally the 'Oops' routine */ + void die_if_kernel(const char * str, struct pt_regs * regs, long err) { + extern void reset_watchdog(void); + extern void stop_watchdog(void); + if(user_mode(regs)) return; +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + /* This printout might take too long and trigger the + * watchdog normally. If we're in the nice doggy + * development mode, stop the watchdog during printout. + */ stop_watchdog(); +#endif printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY reset_watchdog(); - +#endif do_exit(SIGSEGV); } void __init trap_init(void) { - /* Nothing needs to be done */ + /* Nothing needs to be done */ } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/mm/fault.c linux-2.5/arch/cris/mm/fault.c --- linux-2.5.1/arch/cris/mm/fault.c Thu Jul 26 22:10:06 2001 +++ linux-2.5/arch/cris/mm/fault.c Thu Jan 10 22:41:07 2002 @@ -6,6 +6,17 @@ * Authors: Bjorn Wesen * * $Log: fault.c,v $ + * Revision 1.20 2001/11/22 13:34:06 bjornw + * * Bug workaround (LX TR89): force a rerun of the whole of an interrupted + * unaligned write, because the second half of the write will be corrupted + * otherwise. Affected unaligned writes spanning not-yet mapped pages. + * * Optimization: use the wr_rd bit in R_MMU_CAUSE to know whether a miss + * was due to a read or a write (before we didn't know this until the next + * restart of the interrupted instruction, thus wasting one fault-irq) + * + * Revision 1.19 2001/11/12 19:02:10 pkj + * Fixed compiler warnings. + * * Revision 1.18 2001/07/18 22:14:32 bjornw * Enable interrupts in the bulk of do_page_fault * @@ -78,7 +89,14 @@ int error_code); /* debug of low-level TLB reload */ +#undef DEBUG + +#ifdef DEBUG +#define D(x) x +#else #define D(x) +#endif + /* debug of higher-level faults */ #define DPG(x) @@ -94,9 +112,12 @@ handle_mmu_bus_fault(struct pt_regs *regs) { int cause, select; +#ifdef DEBUG int index; int page_id; - int miss, we, acc, inv; + int acc, inv; +#endif + int miss, we, writeac; pmd_t *pmd; pte_t pte; int errcode; @@ -106,75 +127,83 @@ select = *R_TLB_SELECT; address = cause & PAGE_MASK; /* get faulting address */ - - D(page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause)); - D(acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause)); - D(inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause)); - D(index = IO_EXTRACT(R_TLB_SELECT, index, select)); + +#ifdef DEBUG + page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); + acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); + inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); + index = IO_EXTRACT(R_TLB_SELECT, index, select); +#endif miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); + writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause); + + /* ETRAX 100LX TR89 bugfix: if the second half of an unaligned + * write causes a MMU-fault, it will not be restarted correctly. + * This could happen if a write crosses a page-boundary and the + * second page is not yet COW'ed or even loaded. The workaround + * is to clear the unaligned bit in the CPU status record, so + * that the CPU will rerun both the first and second halves of + * the instruction. This will not have any sideeffects unless + * the first half goes to any device or memory that can't be + * written twice, and which is mapped through the MMU. + * + * We only need to do this for writes. + */ + + if(writeac) + regs->csrinstr &= ~(1 << 5); - /* Note: the reason we don't set errcode's r/w flag here - * using the 'we' flag, is because the latter is only given - * if there is a write-protection exception, not given as a - * general r/w access mode flag. It is currently not possible - * to get this from the MMU (TODO: check if this is the case - * for LXv2). - * - * The page-fault code won't care, but there will be two page- - * faults instead of one for the case of a write to a non-tabled - * page (miss, then write-protection). + /* Set errcode's R/W flag according to the mode which caused the + * fault */ - errcode = 0; + errcode = writeac << 1; - D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, " - "idx %d pid %d\n", + D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n", regs->irp, address, miss, inv, we, acc, index, page_id)); /* for a miss, we need to reload the TLB entry */ - if(miss) { - + if (miss) { /* see if the pte exists at all * refer through current_pgd, dont use mm->pgd */ - + pmd = (pmd_t *)(current_pgd + pgd_index(address)); - if(pmd_none(*pmd)) + if (pmd_none(*pmd)) goto dofault; - if(pmd_bad(*pmd)) { - printk("bad pgdir entry 0x%x at 0x%x\n", *pmd, pmd); + if (pmd_bad(*pmd)) { + printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd); pmd_clear(pmd); return; } pte = *pte_offset(pmd, address); - if(!pte_present(pte)) + if (!pte_present(pte)) goto dofault; - - D(printk(" found pte %x pg %x ", pte_val(pte), pte_page(pte))); - D( - { - if(pte_val(pte) & _PAGE_SILENT_WRITE) - printk("Silent-W "); - if(pte_val(pte) & _PAGE_KERNEL) - printk("Kernel "); - if(pte_val(pte) & _PAGE_SILENT_READ) - printk("Silent-R "); - if(pte_val(pte) & _PAGE_GLOBAL) - printk("Global "); - if(pte_val(pte) & _PAGE_PRESENT) - printk("Present "); - if(pte_val(pte) & _PAGE_ACCESSED) - printk("Accessed "); - if(pte_val(pte) & _PAGE_MODIFIED) - printk("Modified "); - if(pte_val(pte) & _PAGE_READ) - printk("Readable "); - if(pte_val(pte) & _PAGE_WRITE) - printk("Writeable "); - printk("\n"); - }); + +#ifdef DEBUG + printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte)); + if (pte_val(pte) & _PAGE_SILENT_WRITE) + printk("Silent-W "); + if (pte_val(pte) & _PAGE_KERNEL) + printk("Kernel "); + if (pte_val(pte) & _PAGE_SILENT_READ) + printk("Silent-R "); + if (pte_val(pte) & _PAGE_GLOBAL) + printk("Global "); + if (pte_val(pte) & _PAGE_PRESENT) + printk("Present "); + if (pte_val(pte) & _PAGE_ACCESSED) + printk("Accessed "); + if (pte_val(pte) & _PAGE_MODIFIED) + printk("Modified "); + if (pte_val(pte) & _PAGE_READ) + printk("Readable "); + if (pte_val(pte) & _PAGE_WRITE) + printk("Writeable "); + printk("\n"); +#endif /* load up the chosen TLB entry * this assumes the pte format is the same as the TLB_LO layout. @@ -189,10 +218,10 @@ } errcode = 1 | (we << 1); - + dofault: /* leave it to the MM system fault handler below */ - D(printk("do_page_fault %p errcode %d\n", address, errcode)); + D(printk("do_page_fault %lx errcode %d\n", address, errcode)); do_page_fault(address, regs, errcode); } @@ -221,20 +250,19 @@ struct mm_struct *mm; struct vm_area_struct * vma; int writeaccess; - int fault; unsigned long fixup; siginfo_t info; tsk = current; - /* - * 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. + /* + * 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. * * NOTE2: This is done so that, when updating the vmalloc * mappings we don't have to walk all processes pgdirs and @@ -243,13 +271,13 @@ * bit set so sometimes the TLB can use a lingering entry. * * This verifies that the fault happens in kernel space - * and that the fault was not a protection error (error_code & 1). - */ + * and that the fault was not a protection error (error_code & 1). + */ - if (address >= VMALLOC_START && + if (address >= VMALLOC_START && !(error_code & 1) && !user_mode(regs)) - goto vmalloc_fault; + goto vmalloc_fault; /* we can and should enable interrupts at this point */ sti(); @@ -312,28 +340,27 @@ */ switch (handle_mm_fault(mm, vma, address, writeaccess)) { - case 1: - tsk->min_flt++; - break; - case 2: - tsk->maj_flt++; - break; - case 0: - goto do_sigbus; - default: - goto out_of_memory; + case 1: + tsk->min_flt++; + break; + case 2: + tsk->maj_flt++; + break; + case 0: + goto do_sigbus; + default: + goto out_of_memory; } up_read(&mm->mmap_sem); return; - + /* * Something tried to access memory that isn't in our memory map.. * Fix it, but check if it's kernel or user first.. */ bad_area: - up_read(&mm->mmap_sem); bad_area_nosemaphore: @@ -361,10 +388,10 @@ * code) */ - if ((fixup = search_exception_table(regs->irp)) != 0) { + if ((fixup = search_exception_table(regs->irp)) != 0) { /* Adjust the instruction pointer in the stackframe */ - regs->irp = fixup; + regs->irp = fixup; /* We do not want to return by restoring the CPU-state * anymore, so switch frame-types (see ptrace.h) @@ -372,9 +399,9 @@ regs->frametype = CRIS_FRAME_NORMAL; - D(printk("doing fixup to 0x%x\n", fixup)); - return; - } + D(printk("doing fixup to 0x%lx\n", fixup)); + return; + } /* * Oops. The kernel tried to access some bad page. We'll have to @@ -397,9 +424,9 @@ */ out_of_memory: - up_read(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); - if(user_mode(regs)) + if (user_mode(regs)) do_exit(SIGKILL); goto no_context; @@ -407,40 +434,40 @@ up_read(&mm->mmap_sem); /* - * Send a sigbus, regardless of whether we were in kernel - * or user mode. - */ + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ info.si_code = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; info.si_addr = (void *)address; force_sig_info(SIGBUS, &info, tsk); - - /* Kernel mode? Handle exceptions or die */ - if (!user_mode(regs)) - goto no_context; - return; + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + goto no_context; + return; vmalloc_fault: - { - /* - * Synchronize this task's top level page-table - * with the 'reference' page table. + { + /* + * Synchronize this task's top level page-table + * with the 'reference' page table. * * Use current_pgd instead of tsk->active_mm->pgd * since the latter might be unavailable if this * code is executed in a misfortunately run irq * (like inside schedule() between switch_mm and * switch_to...). - */ + */ - int offset = pgd_index(address); - pgd_t *pgd, *pgd_k; - pmd_t *pmd, *pmd_k; + int offset = pgd_index(address); + pgd_t *pgd, *pgd_k; + pmd_t *pmd, *pmd_k; pte_t *pte_k; - pgd = current_pgd + offset; - pgd_k = init_mm.pgd + offset; + pgd = (pgd_t *)current_pgd + offset; + pgd_k = init_mm.pgd + offset; /* Since we're two-level, we don't need to do both * set_pgd and set_pmd (they do the same thing). If @@ -454,13 +481,13 @@ * it exists. */ - pmd = pmd_offset(pgd, address); - pmd_k = pmd_offset(pgd_k, address); + pmd = pmd_offset(pgd, address); + pmd_k = pmd_offset(pgd_k, address); - if (!pmd_present(*pmd_k)) - goto bad_area_nosemaphore; + if (!pmd_present(*pmd_k)) + goto bad_area_nosemaphore; - set_pmd(pmd, *pmd_k); + set_pmd(pmd, *pmd_k); /* Make sure the actual PTE exists as well to * catch kernel vmalloc-area accesses to non-mapped @@ -468,10 +495,10 @@ * silently loop forever. */ - pte_k = pte_offset(pmd_k, address); - if (!pte_present(*pte_k)) - goto no_context; + pte_k = pte_offset(pmd_k, address); + if (!pte_present(*pte_k)) + goto no_context; - return; - } + return; + } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/cris/mm/init.c linux-2.5/arch/cris/mm/init.c --- linux-2.5.1/arch/cris/mm/init.c Thu Jul 26 22:10:06 2001 +++ linux-2.5/arch/cris/mm/init.c Thu Jan 10 22:41:07 2002 @@ -7,6 +7,12 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: init.c,v $ + * Revision 1.31 2001/11/13 16:22:00 bjornw + * Skip calculating totalram and sharedram in si_meminfo + * + * Revision 1.30 2001/11/12 19:02:10 pkj + * Fixed compiler warnings. + * * Revision 1.29 2001/07/25 16:09:50 bjornw * val->sharedram will stay 0 * @@ -459,29 +465,18 @@ free_page(addr); totalram_pages++; } - printk ("Freeing unused kernel memory: %dk freed\n", + printk ("Freeing unused kernel memory: %luk freed\n", (&__init_end - &__init_begin) >> 10); } void si_meminfo(struct sysinfo *val) { - int i; - - i = max_mapnr; - val->totalram = 0; - 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 (!atomic_read(&mem_map[i].count)) - continue; - val->sharedram += atomic_read(&mem_map[i].count) - 1; - } - val->mem_unit = PAGE_SIZE; - val->totalhigh = 0; - val->freehigh = 0; + 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; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/boot/compressed/Makefile linux-2.5/arch/i386/boot/compressed/Makefile --- linux-2.5.1/arch/i386/boot/compressed/Makefile Wed Sep 12 06:08:12 2001 +++ linux-2.5/arch/i386/boot/compressed/Makefile Sat Dec 29 11:10:40 2001 @@ -32,8 +32,10 @@ head.o: head.S $(CC) $(AFLAGS) -traditional -c head.S +comma := , + misc.o: misc.c - $(CC) $(CFLAGS) -c misc.c + $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c misc.c piggy.o: $(SYSTEM) tmppiggy=_tmp_$$$$piggy; \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/boot/setup.S linux-2.5/arch/i386/boot/setup.S --- linux-2.5.1/arch/i386/boot/setup.S Wed Nov 28 18:24:33 2001 +++ linux-2.5/arch/i386/boot/setup.S Wed Jan 2 03:06:15 2002 @@ -50,7 +50,8 @@ #include <linux/compile.h> #include <asm/boot.h> #include <asm/e820.h> - +#include <asm/page.h> + /* Signature words to ensure LILO loaded us right */ #define SIG1 0xAA55 #define SIG2 0x5A5A @@ -79,7 +80,7 @@ # This is the setup header, and it must start at %cs:2 (old 0x9020:2) .ascii "HdrS" # header signature - .word 0x0202 # header version number (>= 0x0105) + .word 0x0203 # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) realmode_swtch: .word 0, 0 # default_switch, SETUPSEG start_sys_seg: .word SYSSEG @@ -153,6 +154,10 @@ # can be located anywhere in # low memory 0x10000 or higher. +ramdisk_max: .long __MAXMEM-1 # (Header version 0x0203 or later) + # The highest safe address for + # the contents of an initrd + trampoline: call start_of_setup .space 1024 # End of setup header ##################################################### @@ -539,7 +544,7 @@ cmpw $0, %cs:realmode_swtch jz rmodeswtch_normal - lcall *%cs:realmode_swtch + lcall %cs:realmode_swtch jmp rmodeswtch_end diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/config.in linux-2.5/arch/i386/config.in --- linux-2.5.1/arch/i386/config.in Mon Nov 12 19:58:08 2001 +++ linux-2.5/arch/i386/config.in Mon Dec 31 00:19:52 2001 @@ -52,6 +52,7 @@ define_int CONFIG_X86_L1_CACHE_SHIFT 4 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n + define_bool CONFIG_X86_PPRO_FENCE y else define_bool CONFIG_X86_WP_WORKS_OK y define_bool CONFIG_X86_INVLPG y @@ -66,17 +67,20 @@ define_int CONFIG_X86_L1_CACHE_SHIFT 4 define_bool CONFIG_X86_USE_STRING_486 y define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_PPRO_FENCE y fi if [ "$CONFIG_M586" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_USE_STRING_486 y define_bool CONFIG_X86_ALIGNMENT_16 y + define_bool CONFIG_X86_PPRO_FENCE y fi if [ "$CONFIG_M586TSC" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_USE_STRING_486 y define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_TSC y + define_bool CONFIG_X86_PPRO_FENCE y fi if [ "$CONFIG_M586MMX" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 @@ -84,6 +88,7 @@ define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y + define_bool CONFIG_X86_PPRO_FENCE y fi if [ "$CONFIG_M686" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 @@ -91,6 +96,7 @@ define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_PGE y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_PPRO_FENCE y fi if [ "$CONFIG_MPENTIUMIII" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 @@ -135,21 +141,24 @@ 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 -tristate 'Dell Inspiron 8000 support' CONFIG_I8K +tristate 'Dell laptop support' CONFIG_I8K tristate '/dev/cpu/microcode - Intel IA32 CPU microcode support' CONFIG_MICROCODE tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR @@ -407,6 +416,7 @@ bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE + bool ' Debug 486 string copies' CONFIG_DEBUG_486_STRING fi endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/defconfig linux-2.5/arch/i386/defconfig --- linux-2.5.1/arch/i386/defconfig Sun Dec 9 04:30:25 2001 +++ linux-2.5/arch/i386/defconfig Thu Jan 10 22:41:07 2002 @@ -409,6 +409,7 @@ # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set +# CONFIG_DE2104X is not set # CONFIG_TULIP is not set # CONFIG_DE4X5 is not set # CONFIG_DGRS is not set @@ -496,6 +497,9 @@ # IrDA (infrared) support # # CONFIG_IRDA is not set +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y # # ISDN subsystem @@ -624,7 +628,7 @@ # CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set CONFIG_TMPFS=y -# CONFIG_RAMFS is not set +CONFIG_RAMFS=y CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set @@ -727,8 +731,9 @@ # CONFIG_USB_LONG_TIMEOUT is not set # -# USB Controllers +# USB Host Controller Drivers # +# CONFIG_USB_EHCI_HCD is not set CONFIG_USB_UHCI_ALT=y # CONFIG_USB_OHCI is not set @@ -799,6 +804,7 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set @@ -812,6 +818,7 @@ # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set @@ -821,6 +828,7 @@ # USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set # # Kernel hacking diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/Makefile linux-2.5/arch/i386/kernel/Makefile --- linux-2.5.1/arch/i386/kernel/Makefile Fri Nov 9 22:21:21 2001 +++ linux-2.5/arch/i386/kernel/Makefile Fri Dec 28 18:47:41 2001 @@ -18,7 +18,8 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ - pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o + pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \ + bootflag.o ifdef CONFIG_PCI @@ -39,6 +40,9 @@ 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 acpitable.o +ifdef CONFIG_VISWS +obj-y += setup-visws.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o +endif include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/apic.c linux-2.5/arch/i386/kernel/apic.c --- linux-2.5.1/arch/i386/kernel/apic.c Fri Nov 9 22:12:55 2001 +++ linux-2.5/arch/i386/kernel/apic.c Tue Jan 8 00:44:24 2002 @@ -56,6 +56,14 @@ maxlvt = get_maxlvt(); /* + * Masking an LVT entry on a P6 can trigger a local APIC error + * if the vector is zero. Mask LVTERR first to prevent this. + */ + if (maxlvt >= 3) { + v = ERROR_APIC_VECTOR; /* any non-zero vector will do */ + apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED); + } + /* * Careful: we have to set masks only first to deassert * any level-triggered sources. */ @@ -65,10 +73,6 @@ apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); v = apic_read(APIC_LVT1); apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED); - if (maxlvt >= 3) { - v = apic_read(APIC_LVTERR); - apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED); - } if (maxlvt >= 4) { v = apic_read(APIC_LVTPC); apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED); @@ -84,6 +88,12 @@ apic_write_around(APIC_LVTERR, APIC_LVT_MASKED); if (maxlvt >= 4) apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); + v = GET_APIC_VERSION(apic_read(APIC_LVR)); + if (APIC_INTEGRATED(v)) { /* !82489DX */ + if (maxlvt > 3) /* Due to Pentium errata 3AP and 11AP. */ + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + } } void __init connect_bsp_APIC(void) @@ -480,6 +490,7 @@ l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; wrmsr(MSR_IA32_APICBASE, l, h); + apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); 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); @@ -487,15 +498,15 @@ 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_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); 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); @@ -571,12 +582,17 @@ * Detect and enable local APICs on non-SMP boards. * Original code written by Keir Fraser. */ +int dont_enable_local_apic __initdata = 0; static int __init detect_init_APIC (void) { u32 h, l, features; extern void get_cpu_vendor(struct cpuinfo_x86*); + /* Disabled by DMI scan or kernel option? */ + if (dont_enable_local_apic) + return -1; + /* Workaround for us being called before identify_cpu(). */ get_cpu_vendor(&boot_cpu_data); @@ -785,8 +801,7 @@ */ slice = clocks / (smp_num_cpus+1); - printk("cpu: %d, clocks: %d, slice: %d\n", - smp_processor_id(), clocks, slice); + printk("cpu: %d, clocks: %d, slice: %d\n", smp_processor_id(), clocks, slice); /* * Wait for IRQ0's slice: @@ -809,8 +824,7 @@ __setup_APIC_LVTT(clocks); - printk("CPU%d<T0:%d,T1:%d,D:%d,S:%d,C:%d>\n", - smp_processor_id(), t0, t1, delta, slice, clocks); + printk("CPU%d<T0:%d,T1:%d,D:%d,S:%d,C:%d>\n", smp_processor_id(), t0, t1, delta, slice, clocks); __restore_flags(flags); } @@ -894,8 +908,14 @@ static unsigned int calibration_result; +int dont_use_local_apic_timer __initdata = 0; + void __init setup_APIC_clocks (void) { + /* Disabled by DMI scan or kernel option? */ + if (dont_use_local_apic_timer) + return; + printk("Using local APIC timer interrupts.\n"); using_apic_timer = 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/apm.c linux-2.5/arch/i386/kernel/apm.c --- linux-2.5.1/arch/i386/kernel/apm.c Fri Nov 30 16:38:44 2001 +++ linux-2.5/arch/i386/kernel/apm.c Mon Jan 14 22:39:44 2002 @@ -736,63 +736,71 @@ } } -#if 0 -extern int hlt_counter; - /* - * If no process has been interested in this - * CPU for some time, we want to wake up the - * power management thread - we probably want + * If no process has really been interested in + * CPU for some time, we want to call BIOS + * power management - we probably want * to conserve power. */ #define HARD_IDLE_TIMEOUT (HZ/3) +#define IDLE_CALC_LIMIT (HZ*100) +#define BIOS_IDLE_TRIGGER 95 -/* This should wake up kapmd and ask it to slow the CPU */ -#define powermanagement_idle() do { } while (0) +static void (*sys_idle)(void); +static unsigned int last_jiffies = 0; +static unsigned int last_stime = 0; +static int use_apm_idle = 0; /** * apm_cpu_idle - cpu idling for APM capable Linux * * This is the idling function the kernel executes when APM is available. It - * tries to save processor time directly by using hlt instructions. A - * separate apm thread tries to do the BIOS power management. - * - * N.B. This is curently not used for kernels 2.4.x. + * tries to do BIOS powermanagement based on the average system idle time. + * Furthermore it calls the system default idle routine. */ static void apm_cpu_idle(void) { - unsigned int start_idle; - - start_idle = jiffies; - while (1) { - if (!current->need_resched) { - if (jiffies - start_idle < HARD_IDLE_TIMEOUT) { - if (!current_cpu_data.hlt_works_ok) - continue; - if (hlt_counter) - continue; - __cli(); - if (!current->need_resched) - safe_halt(); - else - __sti(); - continue; - } + int apm_is_idle = 0; + unsigned int t1 = jiffies - last_jiffies; + unsigned int t2; + +recalc: if(t1 > IDLE_CALC_LIMIT) + goto reset; + + if(t1 > HARD_IDLE_TIMEOUT) { + t2 = current->times.tms_stime - last_stime; + t2 *= 100; + t2 /= t1; + if (t2 > BIOS_IDLE_TRIGGER) + use_apm_idle = 1; + else +reset: use_apm_idle = 0; + last_jiffies = jiffies; + last_stime = current->times.tms_stime; + } - /* - * Ok, do some power management - we've been idle for too long - */ - powermanagement_idle(); + while (!current->need_resched) { + if(use_apm_idle) + switch (apm_do_idle()) { + case 0: apm_is_idle = 1; + continue; + case 1: apm_is_idle = 1; + break; } - schedule(); - check_pgt_cache(); - start_idle = jiffies; + if (sys_idle) + sys_idle(); + + t1 = jiffies - last_jiffies; + if (t1 > HARD_IDLE_TIMEOUT) + goto recalc; } + + if (apm_is_idle) + apm_do_busy(); } #endif -#endif #ifdef CONFIG_SMP static int apm_magic(void * unused) @@ -1172,7 +1180,7 @@ struct apm_user *as; get_time_diff(); - cli(); +// cli(); err = apm_set_power_state(APM_STATE_SUSPEND); reinit_timer(); set_time(); @@ -1181,7 +1189,7 @@ if (err != APM_SUCCESS) apm_error("suspend", err); send_event(APM_NORMAL_RESUME); - sti(); +// sti(); queue_event(APM_NORMAL_RESUME, NULL); spin_lock(&user_list_lock); for (as = user_list; as != NULL; as = as->next) { @@ -1352,17 +1360,12 @@ static void apm_mainloop(void) { - int timeout = HZ; DECLARE_WAITQUEUE(wait, current); add_wait_queue(&apm_waitqueue, &wait); set_current_state(TASK_INTERRUPTIBLE); for (;;) { - /* Nothing to do, just sleep for the timeout */ - timeout = 2 * timeout; - if (timeout > APM_CHECK_TIMEOUT) - timeout = APM_CHECK_TIMEOUT; - schedule_timeout(timeout); + schedule_timeout(APM_CHECK_TIMEOUT); if (exit_kapmd) break; @@ -1372,34 +1375,6 @@ */ set_current_state(TASK_INTERRUPTIBLE); apm_event_handler(); -#ifdef CONFIG_APM_CPU_IDLE - if (!system_idle()) - continue; - - /* - * If we can idle... - */ - if (apm_do_idle() != -1) { - unsigned long start = jiffies; - while ((!exit_kapmd) && system_idle()) { - if (apm_do_idle()) { - set_current_state(TASK_INTERRUPTIBLE); - /* APM needs us to snooze .. either - the BIOS call failed (-1) or it - slowed the clock (1). We sleep - until it talks to us again */ - schedule_timeout(1); - } - if ((jiffies - start) > APM_CHECK_TIMEOUT) { - apm_event_handler(); - start = jiffies; - } - } - apm_do_busy(); - apm_event_handler(); - timeout = 1; - } -#endif } remove_wait_queue(&apm_waitqueue, &wait); } @@ -1477,7 +1452,7 @@ as = filp->private_data; if (check_apm_user(as, "ioctl")) return -EIO; - if ((!as->suser) || (!as->writer)) + if (!as->suser) return -EPERM; switch (cmd) { case APM_IOC_STANDBY: @@ -1976,12 +1951,21 @@ misc_register(&apm_device); +#ifdef CONFIG_APM_CPU_IDLE + sys_idle=pm_idle; + pm_idle=apm_cpu_idle; +#endif + return 0; } static void __exit apm_exit(void) { int error; + +#ifdef CONFIG_APM_CPU_IDLE + pm_idle=sys_idle; +#endif if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0) && (apm_info.connection_version > 0x0100)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/bluesmoke.c linux-2.5/arch/i386/kernel/bluesmoke.c --- linux-2.5.1/arch/i386/kernel/bluesmoke.c Mon Nov 12 17:59:43 2001 +++ linux-2.5/arch/i386/kernel/bluesmoke.c Sat Jan 12 11:10:25 2002 @@ -46,8 +46,7 @@ if(high&(1<<26)) { rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh); - printk(" at %08x%08x", - high, low); + printk(" at %08x%08x", ahigh, alow); } printk("\n"); /* Clear it */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/bootflag.c linux-2.5/arch/i386/kernel/bootflag.c --- linux-2.5.1/arch/i386/kernel/bootflag.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/i386/kernel/bootflag.c Mon Dec 31 18:32:31 2001 @@ -0,0 +1,253 @@ +/* + * Implement 'Simple Boot Flag Specification 1.0' + * + */ + + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <asm/io.h> + +#include <linux/mc146818rtc.h> + + +#define SBF_RESERVED (0x78) +#define SBF_PNPOS (1<<0) +#define SBF_BOOTING (1<<1) +#define SBF_DIAG (1<<2) +#define SBF_PARITY (1<<7) + + +struct sbf_boot +{ + u8 sbf_signature[4]; + u32 sbf_len; + u8 sbf_revision __attribute((packed)); + u8 sbf_csum __attribute((packed)); + u8 sbf_oemid[6] __attribute((packed)); + u8 sbf_oemtable[8] __attribute((packed)); + u8 sbf_revdata[4] __attribute((packed)); + u8 sbf_creator[4] __attribute((packed)); + u8 sbf_crearev[4] __attribute((packed)); + u8 sbf_cmos __attribute((packed)); + u8 sbf_spare[3] __attribute((packed)); +}; + + +static int sbf_port __initdata = -1; + +static int __init sbf_struct_valid(unsigned long tptr) +{ + u8 *ap; + u8 v; + unsigned int i; + struct sbf_boot sb; + + memcpy_fromio(&sb, tptr, sizeof(sb)); + + if(sb.sbf_len != 40 && sb.sbf_len != 39) + // 39 on IBM ThinkPad A21m, BIOS version 1.02b (KXET24WW; 2000-12-19). + return 0; + + ap = (u8 *)&sb; + v= 0; + + for(i=0;i<sb.sbf_len;i++) + v+=*ap++; + + if(v) + return 0; + + if(memcmp(sb.sbf_signature, "BOOT", 4)) + return 0; + + if (sb.sbf_len == 39) + printk (KERN_WARNING "SBF: ACPI BOOT descriptor is wrong length (%d)\n", + sb.sbf_len); + + sbf_port = sb.sbf_cmos; /* Save CMOS port */ + return 1; +} + +static int __init parity(u8 v) +{ + int x = 0; + int i; + + for(i=0;i<8;i++) + { + x^=(v&1); + v>>=1; + } + return x; +} + +static void __init sbf_write(u8 v) +{ + unsigned long flags; + if(sbf_port != -1) + { + v &= ~SBF_PARITY; + if(!parity(v)) + v|=SBF_PARITY; + + printk(KERN_INFO "SBF: Setting boot flags 0x%x\n",v); + + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(v, sbf_port); + spin_unlock_irqrestore(&rtc_lock, flags); + } +} + +static u8 __init sbf_read(void) +{ + u8 v; + unsigned long flags; + if(sbf_port == -1) + return 0; + spin_lock_irqsave(&rtc_lock, flags); + v = CMOS_READ(sbf_port); + spin_unlock_irqrestore(&rtc_lock, flags); + return v; +} + +static int __init sbf_value_valid(u8 v) +{ + if(v&SBF_RESERVED) /* Reserved bits */ + return 0; + if(!parity(v)) + return 0; + return 1; +} + + +static void __init sbf_bootup(void) +{ + u8 v; + if(sbf_port == -1) + return; + v = sbf_read(); + if(!sbf_value_valid(v)) + printk(KERN_WARNING "SBF: Simple boot flag value 0x%x read from CMOS RAM was invalid\n",v); + v &= ~SBF_RESERVED; + v &= ~SBF_BOOTING; + v &= ~SBF_DIAG; +#if defined(CONFIG_ISAPNP) + v |= SBF_PNPOS; +#endif + sbf_write(v); +} + +static int __init sbf_init(void) +{ + unsigned int i; + void *rsdt; + u32 rsdtlen = 0; + u32 rsdtbase = 0; + u8 sum = 0; + int n; + + u8 *p; + + for(i=0xE0000; i <= 0xFFFE0; i+=16) + { + p = phys_to_virt(i); + + if(memcmp(p, "RSD PTR ", 8)) + continue; + + sum = 0; + for(n=0; n<20; n++) + sum+=p[n]; + + if(sum != 0) + continue; + + /* So it says RSD PTR and it checksums... */ + + /* + * Process the RDSP pointer + */ + + rsdtbase = *(u32 *)(p+16); + + /* + * RSDT length is ACPI 2 only, for ACPI 1 we must map + * and remap. + */ + + if(p[15]>1) + rsdtlen = *(u32 *)(p+20); + else + rsdtlen = 36; + + if(rsdtlen < 36 || rsdtlen > 1024) + continue; + break; + } + if(i>0xFFFE0) + return 0; + + + rsdt = ioremap(rsdtbase, rsdtlen); + if(rsdt == 0) + return 0; + + i = readl(rsdt + 4); + + /* + * Remap if needed + */ + + if(i > rsdtlen) + { + rsdtlen = i; + iounmap(rsdt); + rsdt = ioremap(rsdtbase, rsdtlen); + if(rsdt == 0) + return 0; + } + + for(n = 0; n < i; n++) + sum += readb(rsdt + n); + + if(sum) + { + iounmap(rsdt); + return 0; + } + + /* Ok the RSDT checksums too */ + + for(n = 36; n+3 < i; n += 4) + { + unsigned long rp = readl(rsdt+n); + int len = 4096; + + if(rp > 0xFFFFFFFFUL - len) + len = 0xFFFFFFFFUL - rp; + + /* Too close to the end!! */ + if(len < 20) + continue; + rp = (unsigned long)ioremap(rp, 4096); + if(rp == 0) + continue; + if(sbf_struct_valid(rp)) + { + /* Found the BOOT table and processed it */ + printk(KERN_INFO "SBF: Simple Boot Flag extension found and enabled.\n"); + } + iounmap((void *)rp); + } + iounmap(rsdt); + sbf_bootup(); + return 0; +} + +module_init(sbf_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/cpuid.c linux-2.5/arch/i386/kernel/cpuid.c --- linux-2.5.1/arch/i386/kernel/cpuid.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/i386/kernel/cpuid.c Thu Jan 3 22:35:39 2002 @@ -101,7 +101,7 @@ u32 data[4]; size_t rv; u32 reg = *ppos; - int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int cpu = minor(file->f_dentry->d_inode->i_rdev); if ( count % 16 ) return -EINVAL; /* Invalid chunk size */ @@ -119,7 +119,7 @@ static int cpuid_open(struct inode *inode, struct file *file) { - int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int cpu = minor(file->f_dentry->d_inode->i_rdev); struct cpuinfo_x86 *c = &(cpu_data)[cpu]; if ( !(cpu_online_map & (1UL << cpu)) ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/dmi_scan.c linux-2.5/arch/i386/kernel/dmi_scan.c --- linux-2.5.1/arch/i386/kernel/dmi_scan.c Thu Dec 6 22:01:17 2001 +++ linux-2.5/arch/i386/kernel/dmi_scan.c Mon Jan 14 22:39:44 2002 @@ -9,6 +9,7 @@ #include <linux/pm.h> #include <asm/keyboard.h> #include <asm/system.h> +#include <linux/bootmem.h> unsigned long dmi_broken; int is_sony_vaio_laptop; @@ -51,7 +52,7 @@ u8 *data; int i=1; - buf = ioremap(base, len); + buf = bt_ioremap(base, len); if(buf==NULL) return -1; @@ -83,7 +84,7 @@ data+=2; i++; } - iounmap(buf); + bt_iounmap(buf, len); return 0; } @@ -155,7 +156,7 @@ return; if (dmi_ident[slot]) return; - dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL); + dmi_ident[slot] = alloc_bootmem(strlen(p)+1); if(dmi_ident[slot]) strcpy(dmi_ident[slot], p); else @@ -294,6 +295,20 @@ return 0; } +/* + * Work around broken HP Pavilion Notebooks which assign USB to + * IRQ 9 even though it is actually wired to IRQ 11 + */ +static __init int fix_broken_hp_bios_irq9(struct dmi_blacklist *d) +{ + extern int broken_hp_bios_irq9; + if (broken_hp_bios_irq9 == 0) + { + broken_hp_bios_irq9 = 1; + printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); + } + return 0; +} /* * Check for clue free BIOS implementations who use @@ -416,6 +431,43 @@ return 0; } +/* + * Some machines, usually laptops, can't handle an enabled local APIC. + * The symptoms include hangs or reboots when suspending or resuming, + * attaching or detaching the power cord, or entering BIOS setup screens + * through magic key sequences. + */ +static int __init local_apic_kills_bios(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_enable_local_apic; + if (!dont_enable_local_apic) { + dont_enable_local_apic = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "Refusing to enable the local APIC.\n", + d->ident); + } +#endif + return 0; +} + +/* + * The Intel AL440LX mainboard will hang randomly if the local APIC + * timer is running and the APM BIOS hasn't been disabled. + */ +static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_use_local_apic_timer; + if (apm_info.bios.version && !dont_use_local_apic_timer) { + dont_use_local_apic_timer = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "The local APIC timer will not be used.\n", + d->ident); + } +#endif + return 0; +} /* * Simple "print if true" callback @@ -469,6 +521,11 @@ MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), NO_MATCH, NO_MATCH } }, + { set_bios_reboot, "Dell PowerEdge 2400", { /* Handle problems with rebooting on Dell 300/800's */ + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), + NO_MATCH, NO_MATCH + } }, { set_apm_ints, "Dell Inspiron", { /* Allow interrupts during suspend on Dell Inspiron laptops*/ MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"), @@ -560,6 +617,25 @@ MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH } }, + /* Machines which have problems handling enabled local APICs */ + + { local_apic_kills_bios, "Dell Inspiron", { + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "Inspiron"), + NO_MATCH, NO_MATCH + } }, + + { local_apic_kills_bios, "Dell Latitude", { + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "Latitude"), + NO_MATCH, NO_MATCH + } }, + + { apm_kills_local_apic_timer, "Intel AL440LX", { + MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + MATCH(DMI_BOARD_NAME, "AL440LX"), + NO_MATCH, NO_MATCH } }, + /* Problem Intel 440GX bioses */ { broken_pirq, "SABR1 Bios", { /* Bad $PIR */ @@ -572,6 +648,11 @@ MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0094.P10"), NO_MATCH, NO_MATCH } }, + { broken_pirq, "l44GX Bios", { /* Bad $PIR */ + MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), + MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0120.P12"), + NO_MATCH, NO_MATCH + } }, { broken_pirq, "l44GX Bios", { /* Bad $PIR */ MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0125.P13"), @@ -611,7 +692,14 @@ NO_MATCH, NO_MATCH } }, - + { fix_broken_hp_bios_irq9, "HP Pavilion N5400 Series Laptop", { + MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + MATCH(DMI_BIOS_VERSION, "GE.M1.03"), + MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"), + MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736") + } }, + + /* * Generic per vendor APM settings */ @@ -723,12 +811,9 @@ } } -static int __init dmi_scan_machine(void) +void __init dmi_scan_machine(void) { int err = dmi_iterate(dmi_decode); if(err == 0) dmi_check_blacklist(); - return err; } - -module_init(dmi_scan_machine); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/head.S linux-2.5/arch/i386/kernel/head.S --- linux-2.5.1/arch/i386/kernel/head.S Wed Jun 20 18:00:53 2001 +++ linux-2.5/arch/i386/kernel/head.S Sat Dec 29 12:07:12 2001 @@ -445,13 +445,14 @@ .quad 0x00409a0000000000 /* 0x48 APM CS code */ .quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */ .quad 0x0040920000000000 /* 0x58 APM DS data */ + /* Segments used for calling PnP BIOS */ + .quad 0x00c09a0000000000 /* 0x60 32-bit code */ + .quad 0x00809a0000000000 /* 0x68 16-bit code */ + .quad 0x0080920000000000 /* 0x70 16-bit data */ + .quad 0x0080920000000000 /* 0x78 16-bit data */ + .quad 0x0080920000000000 /* 0x80 16-bit data */ + .quad 0x0000000000000000 /* 0x88 not used */ + .quad 0x0000000000000000 /* 0x90 not used */ + .quad 0x0000000000000000 /* 0x98 not used */ + /* Per CPU segments */ .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */ - -/* - * This is to aid debugging, the various locking macros will be putting - * code fragments here. When an oops occurs we'd rather know that it's - * inside the .text.lock section rather than as some offset from whatever - * function happens to be last in the .text segment. - */ -.section .text.lock -ENTRY(stext_lock) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/i386_ksyms.c linux-2.5/arch/i386/kernel/i386_ksyms.c --- linux-2.5.1/arch/i386/kernel/i386_ksyms.c Tue Nov 13 17:13:20 2001 +++ linux-2.5/arch/i386/kernel/i386_ksyms.c Fri Dec 28 18:07:07 2001 @@ -51,9 +51,7 @@ /* platform dependent support */ EXPORT_SYMBOL(boot_cpu_data); -#ifdef CONFIG_EISA EXPORT_SYMBOL(EISA_bus); -#endif EXPORT_SYMBOL(MCA_bus); EXPORT_SYMBOL(__verify_write); EXPORT_SYMBOL(dump_thread); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/irq.c linux-2.5/arch/i386/kernel/irq.c --- linux-2.5.1/arch/i386/kernel/irq.c Wed Nov 28 21:22:25 2001 +++ linux-2.5/arch/i386/kernel/irq.c Sun Jan 13 18:08:45 2002 @@ -336,8 +336,6 @@ global_irq_holder = cpu; } -#define EFLAGS_IF_SHIFT 9 - /* * A global "cli()" while in an interrupt context * turns into just a local cli(). Interrupts @@ -352,10 +350,7 @@ */ void __global_cli(void) { - unsigned int flags; - - __save_flags(flags); - if (flags & (1 << EFLAGS_IF_SHIFT)) { + if (irqs_enabled()) { int cpu = smp_processor_id(); __cli(); if (!local_irq_count(cpu)) @@ -383,11 +378,9 @@ { int retval; int local_enabled; - unsigned long flags; int cpu = smp_processor_id(); - __save_flags(flags); - local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; + local_enabled = irqs_enabled(); /* default to local */ retval = 2 + local_enabled; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/mpparse.c linux-2.5/arch/i386/kernel/mpparse.c --- linux-2.5.1/arch/i386/kernel/mpparse.c Fri Nov 9 22:58:18 2001 +++ linux-2.5/arch/i386/kernel/mpparse.c Fri Dec 28 11:27:00 2001 @@ -799,11 +799,13 @@ * trustworthy, simply because the SMP table may have been * stomped on during early boot. These loaders are buggy and * should be fixed. + * + * MP1.4 SPEC states to only scan first 1K of 4K EBDA. */ address = *(unsigned short *)phys_to_virt(0x40E); address <<= 4; - smp_scan_config(address, 0x1000); + smp_scan_config(address, 0x400); if (smp_found_config) printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n"); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/msr.c linux-2.5/arch/i386/kernel/msr.c --- linux-2.5.1/arch/i386/kernel/msr.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/i386/kernel/msr.c Thu Jan 3 22:36:07 2002 @@ -181,7 +181,7 @@ u32 data[2]; size_t rv; u32 reg = *ppos; - int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int cpu = minor(file->f_dentry->d_inode->i_rdev); int err; if ( count % 8 ) @@ -206,7 +206,7 @@ u32 data[2]; size_t rv; u32 reg = *ppos; - int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int cpu = minor(file->f_dentry->d_inode->i_rdev); int err; if ( count % 8 ) @@ -226,7 +226,7 @@ static int msr_open(struct inode *inode, struct file *file) { - int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int cpu = minor(file->f_dentry->d_inode->i_rdev); struct cpuinfo_x86 *c = &(cpu_data)[cpu]; if ( !(cpu_online_map & (1UL << cpu)) ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/mtrr.c linux-2.5/arch/i386/kernel/mtrr.c --- linux-2.5.1/arch/i386/kernel/mtrr.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/arch/i386/kernel/mtrr.c Mon Jan 14 23:46:21 2002 @@ -489,7 +489,6 @@ case MTRR_IF_INTEL: rdmsr (MTRRcap_MSR, config, dummy); return (config & (1<<10)); - return 1; case MTRR_IF_AMD_K6: case MTRR_IF_CENTAUR_MCR: case MTRR_IF_CYRIX_ARR: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/nmi.c linux-2.5/arch/i386/kernel/nmi.c --- linux-2.5.1/arch/i386/kernel/nmi.c Fri Sep 21 03:55:24 2001 +++ linux-2.5/arch/i386/kernel/nmi.c Sun Jan 13 18:08:45 2002 @@ -276,14 +276,14 @@ * wait a few IRQs (5 seconds) before doing the oops ... */ alert_counter[cpu]++; - if (alert_counter[cpu] == 5*nmi_hz) { + if (alert_counter[cpu] == 10*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); + printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip); show_registers(regs); printk("console shuts up ...\n"); console_silent(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/pci-irq.c linux-2.5/arch/i386/kernel/pci-irq.c --- linux-2.5.1/arch/i386/kernel/pci-irq.c Sun Nov 4 17:31:58 2001 +++ linux-2.5/arch/i386/kernel/pci-irq.c Mon Jan 14 22:39:44 2002 @@ -22,6 +22,8 @@ #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) #define PIRQ_VERSION 0x0100 +int broken_hp_bios_irq9; + static struct irq_routing_table *pirq_table; /* @@ -564,6 +566,15 @@ } DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs); mask &= pcibios_irq_mask; + + /* Work around broken HP Pavilion Notebooks which assign USB to + IRQ 9 even though it is actually wired to IRQ 11 */ + + if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) { + dev->irq = 11; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); + r->set(pirq_router_dev, dev, pirq, 11); + } /* * Find the best IRQ to assign: use the one diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/pci-pc.c linux-2.5/arch/i386/kernel/pci-pc.c --- linux-2.5.1/arch/i386/kernel/pci-pc.c Sat Dec 8 00:26:13 2001 +++ linux-2.5/arch/i386/kernel/pci-pc.c Thu Dec 27 16:05:22 2001 @@ -30,7 +30,7 @@ * This interrupt-safe spinlock protects all accesses to PCI * configuration space. */ -spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED; /* @@ -1109,17 +1109,15 @@ } /* - * Nobody seems to know what this does. Damn. - * - * But it does seem to fix some unspecified problem - * with 'movntq' copies on Athlons. + * Addresses issues with problems in the memory write queue timer in + * certain VIA Northbridges. This bugfix is per VIA's specifications. * * VIA 8363,8622,8361 Northbridges: * - bits 5, 6, 7 at offset 0x55 need to be turned off * VIA 8367 (KT266x) Northbridges: * - bits 5, 6, 7 at offset 0x95 need to be turned off */ -static void __init pci_fixup_via_athlon_bug(struct pci_dev *d) +static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d) { u8 v; int where = 0x55; @@ -1131,7 +1129,7 @@ pci_read_config_byte(d, where, &v); if (v & 0xe0) { - printk("Trying to stomp on Athlon bug...\n"); + printk("Disabling broken memory write queue.\n"); v &= 0x1f; /* clear bits 5, 6, 7 */ pci_write_config_byte(d, where, v); } @@ -1146,10 +1144,10 @@ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_athlon_bug }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_athlon_bug }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_athlon_bug }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_athlon_bug }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug }, { 0 } }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/process.c linux-2.5/arch/i386/kernel/process.c --- linux-2.5.1/arch/i386/kernel/process.c Fri Oct 5 01:42:54 2001 +++ linux-2.5/arch/i386/kernel/process.c Mon Jan 14 13:53:23 2002 @@ -42,7 +42,6 @@ #include <asm/processor.h> #include <asm/i387.h> #include <asm/desc.h> -#include <asm/mmu_context.h> #ifdef CONFIG_MATH_EMULATION #include <asm/math_emu.h> #endif @@ -123,10 +122,6 @@ void cpu_idle (void) { /* endless idle loop with no priority at all */ - init_idle(); - current->nice = 20; - current->counter = -100; - while (1) { void (*idle)(void) = pm_idle; if (!idle) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/setup-visws.c linux-2.5/arch/i386/kernel/setup-visws.c --- linux-2.5.1/arch/i386/kernel/setup-visws.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/i386/kernel/setup-visws.c Fri Dec 28 18:52:20 2001 @@ -0,0 +1,126 @@ +/* + * Unmaintained SGI Visual Workstation support. + * Split out from setup.c by davej@suse.de + */ + +char visws_board_type = -1; +char visws_board_rev = -1; + +#define PIIX_PM_START 0x0F80 + +#define SIO_GPIO_START 0x0FC0 + +#define SIO_PM_START 0x0FC8 + +#define PMBASE PIIX_PM_START +#define GPIREG0 (PMBASE+0x30) +#define GPIREG(x) (GPIREG0+((x)/8)) +#define PIIX_GPI_BD_ID1 18 +#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1) + +#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8) + +#define SIO_INDEX 0x2e +#define SIO_DATA 0x2f + +#define SIO_DEV_SEL 0x7 +#define SIO_DEV_ENB 0x30 +#define SIO_DEV_MSB 0x60 +#define SIO_DEV_LSB 0x61 + +#define SIO_GP_DEV 0x7 + +#define SIO_GP_BASE SIO_GPIO_START +#define SIO_GP_MSB (SIO_GP_BASE>>8) +#define SIO_GP_LSB (SIO_GP_BASE&0xff) + +#define SIO_GP_DATA1 (SIO_GP_BASE+0) + +#define SIO_PM_DEV 0x8 + +#define SIO_PM_BASE SIO_PM_START +#define SIO_PM_MSB (SIO_PM_BASE>>8) +#define SIO_PM_LSB (SIO_PM_BASE&0xff) +#define SIO_PM_INDEX (SIO_PM_BASE+0) +#define SIO_PM_DATA (SIO_PM_BASE+1) + +#define SIO_PM_FER2 0x1 + +#define SIO_PM_GP_EN 0x80 + +void __init visws_get_board_type_and_rev(void) +{ + int raw; + + visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) + >> PIIX_GPI_BD_SHIFT; +/* + * Get Board rev. + * First, we have to initialize the 307 part to allow us access + * to the GPIO registers. Let's map them at 0x0fc0 which is right + * after the PIIX4 PM section. + */ + outb_p(SIO_DEV_SEL, SIO_INDEX); + outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */ + + outb_p(SIO_DEV_MSB, SIO_INDEX); + outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */ + + outb_p(SIO_DEV_LSB, SIO_INDEX); + outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */ + + outb_p(SIO_DEV_ENB, SIO_INDEX); + outb_p(1, SIO_DATA); /* Enable GPIO registers. */ + +/* + * Now, we have to map the power management section to write + * a bit which enables access to the GPIO registers. + * What lunatic came up with this shit? + */ + outb_p(SIO_DEV_SEL, SIO_INDEX); + outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */ + + outb_p(SIO_DEV_MSB, SIO_INDEX); + outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */ + + outb_p(SIO_DEV_LSB, SIO_INDEX); + outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */ + + outb_p(SIO_DEV_ENB, SIO_INDEX); + outb_p(1, SIO_DATA); /* Enable PM registers. */ + +/* + * Now, write the PM register which enables the GPIO registers. + */ + outb_p(SIO_PM_FER2, SIO_PM_INDEX); + outb_p(SIO_PM_GP_EN, SIO_PM_DATA); + +/* + * Now, initialize the GPIO registers. + * We want them all to be inputs which is the + * power on default, so let's leave them alone. + * So, let's just read the board rev! + */ + raw = inb_p(SIO_GP_DATA1); + raw &= 0x7f; /* 7 bits of valid board revision ID. */ + + if (visws_board_type == VISWS_320) { + if (raw < 0x6) { + visws_board_rev = 4; + } else if (raw < 0xc) { + visws_board_rev = 5; + } else { + visws_board_rev = 6; + } + } else if (visws_board_type == VISWS_540) { + visws_board_rev = 2; + } else { + visws_board_rev = raw; + } + + printk(KERN_INFO "Silicon Graphics %s (rev %d)\n", + visws_board_type == VISWS_320 ? "320" : + (visws_board_type == VISWS_540 ? "540" : + "unknown"), visws_board_rev); + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/setup.c linux-2.5/arch/i386/kernel/setup.c --- linux-2.5.1/arch/i386/kernel/setup.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/arch/i386/kernel/setup.c Sun Jan 13 19:02:53 2002 @@ -112,7 +112,7 @@ #include <asm/e820.h> #include <asm/dma.h> #include <asm/mpspec.h> -#include <asm/mmu_context.h> +#include <asm/sched.h> /* * Machine setup.. */ @@ -125,9 +125,8 @@ /* * Bus types .. */ -#ifdef CONFIG_EISA + int EISA_bus; -#endif int MCA_bus; /* for MCA, but anyone else can use it if they want */ @@ -155,9 +154,11 @@ unsigned char aux_device_present; extern void mcheck_init(struct cpuinfo_x86 *c); +extern void dmi_scan_machine(void); extern int root_mountflags; extern char _text, _etext, _edata, _end; extern int blk_nohighio; +void __init visws_get_board_type_and_rev(void); static int disable_x86_serial_nr __initdata = 1; static int disable_x86_fxsr __initdata = 0; @@ -191,131 +192,6 @@ #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 -#ifdef CONFIG_VISWS -char visws_board_type = -1; -char visws_board_rev = -1; - -#define PIIX_PM_START 0x0F80 - -#define SIO_GPIO_START 0x0FC0 - -#define SIO_PM_START 0x0FC8 - -#define PMBASE PIIX_PM_START -#define GPIREG0 (PMBASE+0x30) -#define GPIREG(x) (GPIREG0+((x)/8)) -#define PIIX_GPI_BD_ID1 18 -#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1) - -#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8) - -#define SIO_INDEX 0x2e -#define SIO_DATA 0x2f - -#define SIO_DEV_SEL 0x7 -#define SIO_DEV_ENB 0x30 -#define SIO_DEV_MSB 0x60 -#define SIO_DEV_LSB 0x61 - -#define SIO_GP_DEV 0x7 - -#define SIO_GP_BASE SIO_GPIO_START -#define SIO_GP_MSB (SIO_GP_BASE>>8) -#define SIO_GP_LSB (SIO_GP_BASE&0xff) - -#define SIO_GP_DATA1 (SIO_GP_BASE+0) - -#define SIO_PM_DEV 0x8 - -#define SIO_PM_BASE SIO_PM_START -#define SIO_PM_MSB (SIO_PM_BASE>>8) -#define SIO_PM_LSB (SIO_PM_BASE&0xff) -#define SIO_PM_INDEX (SIO_PM_BASE+0) -#define SIO_PM_DATA (SIO_PM_BASE+1) - -#define SIO_PM_FER2 0x1 - -#define SIO_PM_GP_EN 0x80 - -static void __init visws_get_board_type_and_rev(void) -{ - int raw; - - visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) - >> PIIX_GPI_BD_SHIFT; -/* - * Get Board rev. - * First, we have to initialize the 307 part to allow us access - * to the GPIO registers. Let's map them at 0x0fc0 which is right - * after the PIIX4 PM section. - */ - outb_p(SIO_DEV_SEL, SIO_INDEX); - outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */ - - outb_p(SIO_DEV_MSB, SIO_INDEX); - outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */ - - outb_p(SIO_DEV_LSB, SIO_INDEX); - outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */ - - outb_p(SIO_DEV_ENB, SIO_INDEX); - outb_p(1, SIO_DATA); /* Enable GPIO registers. */ - -/* - * Now, we have to map the power management section to write - * a bit which enables access to the GPIO registers. - * What lunatic came up with this shit? - */ - outb_p(SIO_DEV_SEL, SIO_INDEX); - outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */ - - outb_p(SIO_DEV_MSB, SIO_INDEX); - outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */ - - outb_p(SIO_DEV_LSB, SIO_INDEX); - outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */ - - outb_p(SIO_DEV_ENB, SIO_INDEX); - outb_p(1, SIO_DATA); /* Enable PM registers. */ - -/* - * Now, write the PM register which enables the GPIO registers. - */ - outb_p(SIO_PM_FER2, SIO_PM_INDEX); - outb_p(SIO_PM_GP_EN, SIO_PM_DATA); - -/* - * Now, initialize the GPIO registers. - * We want them all to be inputs which is the - * power on default, so let's leave them alone. - * So, let's just read the board rev! - */ - raw = inb_p(SIO_GP_DATA1); - raw &= 0x7f; /* 7 bits of valid board revision ID. */ - - if (visws_board_type == VISWS_320) { - if (raw < 0x6) { - visws_board_rev = 4; - } else if (raw < 0xc) { - visws_board_rev = 5; - } else { - visws_board_rev = 6; - - } - } else if (visws_board_type == VISWS_540) { - visws_board_rev = 2; - } else { - visws_board_rev = raw; - } - - printk(KERN_INFO "Silicon Graphics %s (rev %d)\n", - visws_board_type == VISWS_320 ? "320" : - (visws_board_type == VISWS_540 ? "540" : - "unknown"), - visws_board_rev); - } -#endif - static char command_line[COMMAND_LINE_SIZE]; char saved_command_line[COMMAND_LINE_SIZE]; @@ -828,10 +704,8 @@ #define PFN_PHYS(x) ((x) << PAGE_SHIFT) /* - * 128MB for vmalloc and initrd + * Reserved space for vmalloc and iomap - defined in asm/page.h */ -#define VMALLOC_RESERVE (unsigned long)(128 << 20) -#define MAXMEM (unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE) #define MAXMEM_PFN PFN_DOWN(MAXMEM) #define MAX_NONPAE_PFN (1 << 20) @@ -993,7 +867,6 @@ */ if (smp_found_config) get_smp_config(); - init_apic_mappings(); #endif @@ -1045,6 +918,7 @@ conswitchp = &dummy_con; #endif #endif + dmi_scan_machine(); } static int cachesize_override __initdata = -1; @@ -1289,9 +1163,24 @@ } break; - case 6: /* An Athlon/Duron. We can trust the BIOS probably */ - mcheck_init(c); - break; + case 6: /* An Athlon/Duron */ + + /* Bit 15 of Athlon specific MSR 15, needs to be 0 + * to enable SSE on Palomino/Morgan CPU's. + * If the BIOS didn't enable it already, enable it + * here. + */ + if (c->x86_model == 6 || c->x86_model == 7) { + if (!test_bit(X86_FEATURE_XMM, &c->x86_capability)) { + printk(KERN_INFO "Enabling disabled K7/SSE Support.\n"); + rdmsr(MSR_K7_HWCR, l, h); + l &= ~0x00008000; + wrmsr(MSR_K7_HWCR, l, h); + set_bit(X86_FEATURE_XMM, &c->x86_capability); + } + } + break; + } display_cacheinfo(c); @@ -1361,40 +1250,6 @@ static char cyrix_model_mult1[] __initdata = "12??43"; static char cyrix_model_mult2[] __initdata = "12233445"; -/* - * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old - * BIOSes for compatability with DOS games. This makes the udelay loop - * work correctly, and improves performance. - * - * FIXME: our newer udelay uses the tsc. We dont need to frob with SLOP - */ - -extern void calibrate_delay(void) __init; - -static void __init check_cx686_slop(struct cpuinfo_x86 *c) -{ - unsigned long flags; - - if (Cx86_dir0_msb == 3) { - unsigned char ccr3, ccr5; - - local_irq_save(flags); - ccr3 = getCx86(CX86_CCR3); - setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ - ccr5 = getCx86(CX86_CCR5); - if (ccr5 & 2) - setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */ - setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ - local_irq_restore(flags); - - if (ccr5 & 2) { /* possible wrong calibration done */ - printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n"); - calibrate_delay(); - c->loops_per_jiffy = loops_per_jiffy; - } - } -} - static void __init init_cyrix(struct cpuinfo_x86 *c) { unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; @@ -1413,8 +1268,6 @@ do_cyrix_devid(&dir0, &dir1); - check_cx686_slop(c); - Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family" */ dir0_lsn = dir0 & 0xf; /* model or clock multiplier */ @@ -1471,7 +1324,7 @@ same. The MediaGX has deep magic SMM stuff that handles the SB emulation. It thows away the fifo on disable_dma() which is wrong and ruins the audio. - + Bug2: VSA1 has a wrap bug so that using maximum sized DMA causes bad things. According to NatSemi VSA2 has another bug to do with 'hlt'. I've not seen any boards using VSA2 @@ -1512,7 +1365,7 @@ tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0; Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7]; p = Cx86_cb+tmp; - if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20)) + if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20)) (c->x86_model)++; /* Emulate MTRRs using Cyrix's ARRs. */ set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability); @@ -1918,7 +1771,6 @@ c->x86_cache_size = (cc>>24)+(dd>>24); } sprintf( c->x86_model_id, "WinChip %s", name ); - mcheck_init(c); break; case 6: @@ -2157,7 +2009,7 @@ } if ( l1i || l1d ) printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n", - l1i, l1d); + l1i, l1d); if ( l2 ) printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); if ( l3 ) @@ -2202,9 +2054,57 @@ if ( p ) strcpy(c->x86_model_id, p); + +#ifdef CONFIG_SMP + if (test_bit(X86_FEATURE_HT, &c->x86_capability)) { + extern int phys_proc_id[NR_CPUS]; + + u32 eax, ebx, ecx, edx; + int index_lsb, index_msb, tmp; + int initial_apic_id; + int cpu = smp_processor_id(); + + cpuid(1, &eax, &ebx, &ecx, &edx); + smp_num_siblings = (ebx & 0xff0000) >> 16; + + if (smp_num_siblings == 1) { + printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); + } else if (smp_num_siblings > 1 ) { + index_lsb = 0; + index_msb = 31; + /* + * At this point we only support two siblings per + * processor package. + */ +#define NR_SIBLINGS 2 + if (smp_num_siblings != NR_SIBLINGS) { + printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings); + smp_num_siblings = 1; + goto too_many_siblings; + } + tmp = smp_num_siblings; + while ((tmp & 1) == 0) { + tmp >>=1 ; + index_lsb++; + } + tmp = smp_num_siblings; + while ((tmp & 0x80000000 ) == 0) { + tmp <<=1 ; + index_msb--; + } + if (index_lsb != index_msb ) + index_msb++; + initial_apic_id = ebx >> 24 & 0xff; + phys_proc_id[cpu] = initial_apic_id >> index_msb; - /* Enable MCA if available */ - mcheck_init(c); + printk(KERN_INFO "CPU: Physical Processor ID: %d\n", + phys_proc_id[cpu]); + } + + } +too_many_siblings: +#endif + dmi_scan_machine(); } void __init get_cpu_vendor(struct cpuinfo_x86 *c) @@ -2584,7 +2484,7 @@ init_rise(c); break; } - + printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n", c->x86_capability[0], c->x86_capability[1], @@ -2611,6 +2511,9 @@ /* Disable the PN if appropriate */ squash_the_stupid_serial_number(c); + /* Init Machine Check Exception if available. */ + mcheck_init(c); + /* If the model name is still unset, do table lookup. */ if ( !c->x86_model_id[0] ) { char *p; @@ -2708,12 +2611,12 @@ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", - "fxsr", "sse", "sse2", "ss", NULL, "tm", "ia64", NULL, + "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL, /* AMD-defined */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, "mmxext", NULL, + NULL, NULL, NULL, "mp", NULL, NULL, "mmxext", NULL, NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow", /* Transmeta-defined */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/signal.c linux-2.5/arch/i386/kernel/signal.c --- linux-2.5.1/arch/i386/kernel/signal.c Fri Sep 14 21:15:40 2001 +++ linux-2.5/arch/i386/kernel/signal.c Thu Dec 20 19:14:29 2001 @@ -28,7 +28,7 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); +int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/smp.c linux-2.5/arch/i386/kernel/smp.c --- linux-2.5.1/arch/i386/kernel/smp.c Tue Oct 23 21:17:10 2001 +++ linux-2.5/arch/i386/kernel/smp.c Tue Jan 8 00:44:24 2002 @@ -17,6 +17,7 @@ #include <linux/smp_lock.h> #include <linux/kernel_stat.h> #include <linux/mc146818rtc.h> +#include <linux/cache.h> #include <asm/mtrr.h> #include <asm/pgalloc.h> @@ -102,9 +103,9 @@ */ /* The 'big kernel lock' */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; -struct tlb_state cpu_tlbstate[NR_CPUS] = {[0 ... NR_CPUS-1] = { &init_mm, 0 }}; +struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0, }}; /* * the following functions deal with sending IPIs between CPUs. @@ -489,10 +490,20 @@ * it goes straight through and wastes no time serializing * anything. Worst case is that we lose a reschedule ... */ - void smp_send_reschedule(int cpu) { send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR); +} + +/* + * this function sends a reschedule IPI to all (other) CPUs. + * This should only be used if some 'global' task became runnable, + * such as a RT task, that must be handled now. The first CPU + * that manages to grab the task will run it. + */ +void smp_send_reschedule_all(void) +{ + send_IPI_allbutself(RESCHEDULE_VECTOR); } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/smpboot.c linux-2.5/arch/i386/kernel/smpboot.c --- linux-2.5.1/arch/i386/kernel/smpboot.c Wed Nov 21 18:35:48 2001 +++ linux-2.5/arch/i386/kernel/smpboot.c Tue Jan 8 00:44:24 2002 @@ -30,10 +30,12 @@ * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. * Maciej W. Rozycki : Bits for genuine 82489DX APICs * Martin J. Bligh : Added support for multi-quad systems + * Dave Jones : Report invalid combinations of Athlon CPUs. */ #include <linux/config.h> #include <linux/init.h> +#include <linux/kernel.h> #include <linux/mm.h> #include <linux/kernel_stat.h> @@ -56,6 +58,10 @@ /* Total count of live CPUs */ int smp_num_cpus = 1; +/* Number of siblings per CPU package */ +int smp_num_siblings = 1; +int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ + /* Bitmask of currently online CPUs */ unsigned long cpu_online_map; @@ -156,6 +162,35 @@ * Remember we have B step Pentia with bugs */ smp_b_stepping = 1; + + /* + * Certain Athlons might work (for various values of 'work') in SMP + * but they are not certified as MP capable. + */ + if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) { + + /* Athlon 660/661 is valid. */ + if ((c->x86_model==6) && ((c->x86_mask==0) || (c->x86_mask==1))) + goto valid_athlon; + + /* Duron 670 is valid */ + if ((c->x86_model==7) && (c->x86_mask==0)) + goto valid_athlon; + + /* Athlon 662, Duron 671, and Athlon >model 7 have capability bit */ + if (((c->x86_model==6) && (c->x86_mask>=2)) || + ((c->x86_model==7) && (c->x86_mask>=1)) || + (c->x86_model> 7)) + if (cpu_has_mp) + goto valid_athlon; + + /* If we get here, it's not a certified SMP capable AMD system. */ + printk (KERN_INFO "WARNING: This combination of AMD processors is not suitable for SMP.\n"); + tainted |= TAINT_UNSAFE_SMP; + + } +valid_athlon: + } /* @@ -304,14 +339,14 @@ if (tsc_values[i] < avg) realdelta = -realdelta; - printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n", - i, realdelta); + printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n", i, realdelta); } sum += delta; } if (!buggy) printk("passed.\n"); + ; } static void __init synchronize_tsc_ap (void) @@ -361,7 +396,7 @@ * (This works even if the APIC is not enabled.) */ phys_id = GET_APIC_ID(apic_read(APIC_ID)); - cpuid = current->processor; + cpuid = smp_processor_id(); if (test_and_set_bit(cpuid, &cpu_online_map)) { printk("huh, phys CPU#%d, CPU#%d already present??\n", phys_id, cpuid); @@ -467,6 +502,7 @@ */ local_flush_tlb(); + init_idle(); return cpu_idle(); } @@ -799,16 +835,13 @@ if (!idle) panic("No idle process for CPU %d", cpu); - idle->processor = cpu; - idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ + idle->cpu = cpu; map_cpu_to_boot_apicid(cpu, apicid); idle->thread.eip = (unsigned long) start_secondary; - del_from_runqueue(idle); unhash_process(idle); - init_tasks[cpu] = idle; /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); @@ -971,6 +1004,8 @@ /* Where the IO area was mapped on multiquad, always 0 otherwise */ void *xquad_portio = NULL; +int cpu_sibling_map[NR_CPUS] __cacheline_aligned; + void __init smp_boot_cpus(void) { int apicid, cpu, bit; @@ -1014,8 +1049,7 @@ map_cpu_to_boot_apicid(0, boot_cpu_apicid); global_irq_holder = 0; - current->processor = 0; - init_idle(); + current->cpu = 0; smp_tune_scheduling(); /* @@ -1162,6 +1196,34 @@ printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n"); Dprintk("Boot done.\n"); + /* + * If Hyper-Threading is avaialble, construct cpu_sibling_map[], so + * that we can tell the sibling CPU efficiently. + */ + if (test_bit(X86_FEATURE_HT, boot_cpu_data.x86_capability) + && smp_num_siblings > 1) { + for (cpu = 0; cpu < NR_CPUS; cpu++) + cpu_sibling_map[cpu] = NO_PROC_ID; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + int i; + + for (i = 0; i < smp_num_cpus; i++) { + if (i == cpu) + continue; + if (phys_proc_id[cpu] == phys_proc_id[i]) { + cpu_sibling_map[cpu] = i; + printk("cpu_sibling_map[%d] = %d\n", cpu, cpu_sibling_map[cpu]); + break; + } + } + if (cpu_sibling_map[cpu] == NO_PROC_ID) { + smp_num_siblings = 1; + printk(KERN_WARNING "WARNING: No sibling found for CPU %d.\n", cpu); + } + } + } + #ifndef CONFIG_VISWS /* * Here we can be sure that there is an IO-APIC in the system. Let's diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/traps.c linux-2.5/arch/i386/kernel/traps.c --- linux-2.5.1/arch/i386/kernel/traps.c Sun Nov 25 17:48:47 2001 +++ linux-2.5/arch/i386/kernel/traps.c Wed Jan 2 23:42:54 2002 @@ -271,6 +271,22 @@ { if (vm86 && regs->eflags & VM_MASK) goto vm86_trap; + +#ifdef CONFIG_PNPBIOS + if (regs->xcs == 0x60 || regs->xcs == 0x68) + { + extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; + extern u32 pnp_bios_is_utter_crap; + pnp_bios_is_utter_crap = 1; + printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n"); + __asm__ volatile( + "movl %0, %%esp\n\t" + "jmp %1\n\t" + : "=a" (pnp_bios_fault_esp), "=b" (pnp_bios_fault_eip)); + panic("do_trap: can't hit this"); + } +#endif + if (!(regs->xcs & 3)) goto kernel_trap; @@ -918,6 +934,10 @@ #ifdef CONFIG_EISA if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) EISA_bus = 1; +#endif + +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); #endif set_trap_gate(0,÷_error); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/kernel/vm86.c linux-2.5/arch/i386/kernel/vm86.c --- linux-2.5.1/arch/i386/kernel/vm86.c Sat Jul 7 00:05:07 2001 +++ linux-2.5/arch/i386/kernel/vm86.c Thu Dec 20 19:14:29 2001 @@ -62,7 +62,7 @@ ( (unsigned)( & (((struct kernel_vm86_regs *)0)->VM86_REGS_PART2) ) ) #define VM86_REGS_SIZE2 (sizeof(struct kernel_vm86_regs) - VM86_REGS_SIZE1) -asmlinkage struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs)); +struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs)); struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs) { struct tss_struct *tss; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/math-emu/fpu_system.h linux-2.5/arch/i386/math-emu/fpu_system.h --- linux-2.5.1/arch/i386/math-emu/fpu_system.h Fri Dec 29 22:07:20 2000 +++ linux-2.5/arch/i386/math-emu/fpu_system.h Sat Dec 29 02:13:06 2001 @@ -20,7 +20,9 @@ of the stack frame of math_emulate() */ #define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg -#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.segments)[(s) >> 3]) +/* s is always from a cpu register, and the cpu does bounds checking + * during register load --> no further bounds checks needed */ +#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3]) #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) #define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/mm/fault.c linux-2.5/arch/i386/mm/fault.c --- linux-2.5.1/arch/i386/mm/fault.c Tue Oct 9 22:13:03 2001 +++ linux-2.5/arch/i386/mm/fault.c Tue Jan 8 00:44:24 2002 @@ -27,8 +27,6 @@ extern void die(const char *,struct pt_regs *,long); -extern int console_loglevel; - /* * Ugly, ugly, but the goto's result in better assembly.. */ @@ -88,8 +86,7 @@ out_of_memory: if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); goto survive; } goto bad_area; @@ -344,8 +341,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (tsk->pid == 1) { - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/mm/init.c linux-2.5/arch/i386/mm/init.c --- linux-2.5.1/arch/i386/mm/init.c Sun Nov 25 17:48:47 2001 +++ linux-2.5/arch/i386/mm/init.c Wed Jan 2 23:42:54 2002 @@ -128,7 +128,6 @@ static inline void set_pte_phys (unsigned long vaddr, unsigned long phys, pgprot_t flags) { - pgprot_t prot; pgd_t *pgd; pmd_t *pmd; pte_t *pte; @@ -144,10 +143,8 @@ return; } pte = pte_offset(pmd, vaddr); - if (pte_val(*pte)) - pte_ERROR(*pte); - pgprot_val(prot) = pgprot_val(PAGE_KERNEL) | pgprot_val(flags); - set_pte(pte, mk_pte_phys(phys, prot)); + /* <phys,flags> stored as-is, to permit clearing entries */ + set_pte(pte, mk_pte_phys(phys, flags)); /* * It's enough to flush this one mapping. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/mm/ioremap.c linux-2.5/arch/i386/mm/ioremap.c --- linux-2.5.1/arch/i386/mm/ioremap.c Tue Mar 20 16:13:33 2001 +++ linux-2.5/arch/i386/mm/ioremap.c Thu Jan 3 02:13:52 2002 @@ -161,3 +161,69 @@ if (addr > high_memory) return vfree((void *) (PAGE_MASK & (unsigned long) addr)); } + +#include <asm/fixmap.h> +void __init *bt_ioremap(unsigned long phys_addr, unsigned long size) +{ + unsigned long offset, last_addr; + unsigned int nrpages; + enum fixed_addresses idx; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * 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); + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr) - phys_addr; + + /* + * Mappings have to fit in the FIX_BTMAP area. + */ + nrpages = size >> PAGE_SHIFT; + if (nrpages > NR_FIX_BTMAPS) + return NULL; + + /* + * Ok, go for it.. + */ + idx = FIX_BTMAP_BEGIN; + while (nrpages > 0) { + set_fixmap(idx, phys_addr); + phys_addr += PAGE_SIZE; + --idx; + --nrpages; + } + return (void*) (offset + fix_to_virt(FIX_BTMAP_BEGIN)); +} + +void __init bt_iounmap(void *addr, unsigned long size) +{ + unsigned long virt_addr; + unsigned long offset; + unsigned int nrpages; + enum fixed_addresses idx; + + virt_addr = (unsigned long)addr; + if (virt_addr < fix_to_virt(FIX_BTMAP_BEGIN)) + return; + offset = virt_addr & ~PAGE_MASK; + nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT; + + idx = FIX_BTMAP_BEGIN; + while (nrpages > 0) { + __set_fixmap(idx, 0, __pgprot(0)); + --idx; + --nrpages; + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/i386/vmlinux.lds linux-2.5/arch/i386/vmlinux.lds --- linux-2.5.1/arch/i386/vmlinux.lds Mon Jul 2 21:40:14 2001 +++ linux-2.5/arch/i386/vmlinux.lds Sat Dec 29 11:10:40 2001 @@ -13,7 +13,6 @@ *(.fixup) *(.gnu.warning) } = 0x9090 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ _etext = .; /* End of text section */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ia64/hp/hpsim_console.c linux-2.5/arch/ia64/hp/hpsim_console.c --- linux-2.5.1/arch/ia64/hp/hpsim_console.c Thu Oct 12 21:20:48 2000 +++ linux-2.5/arch/ia64/hp/hpsim_console.c Thu Dec 27 15:56:12 2001 @@ -24,14 +24,12 @@ static int simcons_init (struct console *, char *); static void simcons_write (struct console *, const char *, unsigned); -static int simcons_wait_key (struct console *); static kdev_t simcons_console_device (struct console *); struct console hpsim_cons = { name: "simcons", write: simcons_write, device: simcons_console_device, - wait_key: simcons_wait_key, setup: simcons_init, flags: CON_PRINTBUFFER, index: -1, @@ -54,17 +52,6 @@ if (ch == '\n') ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR); } -} - -static int -simcons_wait_key (struct console *cons) -{ - char ch; - - do { - ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR); - } while (ch == '\0'); - return ch; } static kdev_t diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ia64/kernel/process.c linux-2.5/arch/ia64/kernel/process.c --- linux-2.5.1/arch/ia64/kernel/process.c Fri Nov 9 22:26:17 2001 +++ linux-2.5/arch/ia64/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -114,8 +114,6 @@ /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; - current->counter = -100; - while (1) { #ifdef CONFIG_SMP diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ia64/kernel/smp.c linux-2.5/arch/ia64/kernel/smp.c --- linux-2.5.1/arch/ia64/kernel/smp.c Fri Nov 9 22:26:17 2001 +++ linux-2.5/arch/ia64/kernel/smp.c Thu Dec 13 16:32:35 2001 @@ -30,6 +30,7 @@ #include <linux/kernel_stat.h> #include <linux/mm.h> #include <linux/delay.h> +#include <linux/cache.h> #include <asm/atomic.h> #include <asm/bitops.h> @@ -51,7 +52,7 @@ #include <asm/mca.h> /* The 'big kernel lock' */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; /* * Structure and data for smp_call_function(). This is designed to minimise static memory diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ia64/sn/fprom/Makefile linux-2.5/arch/ia64/sn/fprom/Makefile --- linux-2.5.1/arch/ia64/sn/fprom/Makefile Thu Apr 5 19:51:47 2001 +++ linux-2.5/arch/ia64/sn/fprom/Makefile Sat Dec 29 11:10:40 2001 @@ -18,10 +18,12 @@ fprom: $(OBJ) $(LD) -static -Tfprom.lds -o fprom $(OBJ) $(LIB) +comma := , + .S.o: $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< .c.o: - $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -c -o $*.o $< + $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_KERNEL) -c -o $*.o $< clean: rm -f *.o fprom diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ia64/sn/io/hcl.c linux-2.5/arch/ia64/sn/io/hcl.c --- linux-2.5.1/arch/ia64/sn/io/hcl.c Thu Apr 5 19:51:47 2001 +++ linux-2.5/arch/ia64/sn/io/hcl.c Mon Dec 17 17:16:14 2001 @@ -1049,16 +1049,22 @@ struct file_operations * hwgraph_cdevsw_get(devfs_handle_t de) { - return(devfs_get_ops(de)); + struct file_operations *fops = devfs_get_ops(de); + + devfs_put_ops(de); /* FIXME: this may need to be moved to callers */ + return(fops); } /* * hwgraph_bdevsw_get - returns the fops of the given devfs entry. */ -struct file_operations * +struct file_operations * /* FIXME: shouldn't this be a blkdev? */ hwgraph_bdevsw_get(devfs_handle_t de) { - return(devfs_get_ops(de)); + struct file_operations *fops = devfs_get_ops(de); + + devfs_put_ops(de); /* FIXME: this may need to be moved to callers */ + return(fops); } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ia64/tools/Makefile linux-2.5/arch/ia64/tools/Makefile --- linux-2.5.1/arch/ia64/tools/Makefile Tue Oct 10 00:54:57 2000 +++ linux-2.5/arch/ia64/tools/Makefile Sat Dec 29 11:10:40 2001 @@ -31,8 +31,10 @@ offsets.h: print_offsets ./print_offsets > offsets.h +comma := , + print_offsets: print_offsets.c FORCE_RECOMPILE - $(CC) $(CFLAGS) print_offsets.c -o $@ + $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) print_offsets.c -o $@ FORCE_RECOMPILE: @@ -42,7 +44,7 @@ $(AWK) -f print_offsets.awk $^ > $@ print_offsets.s: print_offsets.c - $(CC) $(CFLAGS) -S print_offsets.c -o $@ + $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -S print_offsets.c -o $@ endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/m68k/amiga/config.c linux-2.5/arch/m68k/amiga/config.c --- linux-2.5.1/arch/m68k/amiga/config.c Wed Nov 28 21:22:25 2001 +++ linux-2.5/arch/m68k/amiga/config.c Thu Dec 27 15:56:12 2001 @@ -98,7 +98,6 @@ extern void amiga_floppy_setup(char *, int *); #endif static void amiga_reset (void); -static int amiga_wait_key (struct console *co); extern void amiga_init_sound(void); static void amiga_savekmsg_init(void); static void amiga_mem_console_write(struct console *co, const char *b, @@ -112,7 +111,6 @@ static struct console amiga_console_driver = { name: "debug", - wait_key: amiga_wait_key, flags: CON_PRINTBUFFER, index: -1, }; @@ -740,33 +738,6 @@ } return 0; -} - -static int amiga_wait_key (struct console *co) -{ - int i; - - while (1) { - while (ciaa.pra & 0x40); - - /* debounce */ - for (i = 0; i < 1000; i++); - - if (!(ciaa.pra & 0x40)) - break; - } - - /* wait for button up */ - while (1) { - while (!(ciaa.pra & 0x40)); - - /* debounce */ - for (i = 0; i < 1000; i++); - - if (ciaa.pra & 0x40) - break; - } - return 0; } static NORET_TYPE void amiga_reset( void ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/m68k/kernel/process.c linux-2.5/arch/m68k/kernel/process.c --- linux-2.5.1/arch/m68k/kernel/process.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/arch/m68k/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -81,7 +81,6 @@ /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; - current->counter = -100; idle(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/m68k/mac/debug.c linux-2.5/arch/m68k/mac/debug.c --- linux-2.5.1/arch/m68k/mac/debug.c Tue Jun 12 02:15:27 2001 +++ linux-2.5/arch/m68k/mac/debug.c Thu Dec 27 15:56:12 2001 @@ -248,17 +248,6 @@ return( scc.cha_b_data ); } -int mac_scca_console_wait_key(struct console *co) -{ - int i; - do { - for( i = uSEC; i > 0; --i ) - barrier(); - } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */ - for( i = uSEC; i > 0; --i ) - barrier(); - return( scc.cha_a_data ); -} #endif /* The following two functions do a quick'n'dirty initialization of the MFP or @@ -395,9 +384,6 @@ /* Mac modem port */ mac_init_scc_port( B9600|CS8, 0 ); mac_console_driver.write = mac_scca_console_write; -#ifdef CONFIG_SERIAL_CONSOLE - mac_console_driver.wait_key = mac_scca_console_wait_key; -#endif scc_port = 0; } else if (!strcmp( m68k_debug_device, "ser2" )) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/m68k/mvme147/config.c linux-2.5/arch/m68k/mvme147/config.c --- linux-2.5.1/arch/m68k/mvme147/config.c Wed Nov 28 21:22:25 2001 +++ linux-2.5/arch/m68k/mvme147/config.c Thu Dec 27 15:56:12 2001 @@ -241,31 +241,7 @@ restore_flags(flags); } - -static int m147_scc_wait_key (struct console *co) -{ - volatile unsigned char *p = (volatile char *)M147_SCC_A_ADDR; - unsigned long flags; - int c; - - /* wait for rx buf filled */ - while ((*p & 0x01) == 0) - ; - - save_flags(flags); - cli(); - - *p = 8; - scc_delay(); - c = *p; - - restore_flags(flags); - return c; -} - - void mvme147_init_console_port (struct console *co, int cflag) { co->write = m147_scc_write; - co->wait_key = m147_scc_wait_key; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/m68k/q40/config.c linux-2.5/arch/m68k/q40/config.c --- linux-2.5.1/arch/m68k/q40/config.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/arch/m68k/q40/config.c Thu Dec 27 15:56:12 2001 @@ -72,10 +72,8 @@ extern int ql_ticks; -static int q40_wait_key(struct console *co){return 0;} static struct console q40_console_driver = { name: "debug", - wait_key: q40_wait_key, flags: CON_PRINTBUFFER, index: -1, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/m68k/sun3x/prom.c linux-2.5/arch/m68k/sun3x/prom.c --- linux-2.5.1/arch/m68k/sun3x/prom.c Tue Jun 12 02:15:27 2001 +++ linux-2.5/arch/m68k/sun3x/prom.c Thu Dec 27 15:56:12 2001 @@ -96,7 +96,6 @@ sun3x_prom_write, /* write */ NULL, /* read */ NULL, /* device */ - NULL, /* wait_key */ NULL, /* unblank */ NULL, /* setup */ CON_PRINTBUFFER, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/m68k/vmlinux-sun3.lds linux-2.5/arch/m68k/vmlinux-sun3.lds --- linux-2.5.1/arch/m68k/vmlinux-sun3.lds Mon Jul 2 21:40:14 2001 +++ linux-2.5/arch/m68k/vmlinux-sun3.lds Sat Dec 29 11:10:40 2001 @@ -10,7 +10,6 @@ *(.head) *(.text) *(.fixup) - *(.text.lock) /* out-of-line lock text */ *(.gnu.warning) } = 0x4e75 .kstrtab : { *(.kstrtab) } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/m68k/vmlinux.lds linux-2.5/arch/m68k/vmlinux.lds --- linux-2.5.1/arch/m68k/vmlinux.lds Mon Jul 2 21:40:14 2001 +++ linux-2.5/arch/m68k/vmlinux.lds Sat Dec 29 11:10:40 2001 @@ -9,7 +9,6 @@ .text : { *(.text) *(.fixup) - *(.text.lock) /* out-of-line lock text */ *(.gnu.warning) } = 0x4e75 .rodata : { *(.rodata) *(.rodata.*) } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/mips/au1000/common/serial.c linux-2.5/arch/mips/au1000/common/serial.c --- linux-2.5.1/arch/mips/au1000/common/serial.c Fri Oct 5 19:06:51 2001 +++ linux-2.5/arch/mips/au1000/common/serial.c Sun Dec 30 13:55:22 2001 @@ -2606,7 +2606,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_AU1000_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -2922,35 +2924,6 @@ serial_out(info, UART_IER, ier); } -/* - * Receive character from the serial port - */ -static int serial_console_wait_key(struct console *co) -{ - static struct async_struct *info; - int ier, c; - - info = &async_sercons; - - /* - * First save the IER then disable the interrupts so - * that the real driver for the port does not get the - * character. - */ - ier = serial_in(info, UART_IER); - serial_out(info, UART_IER, 0x00); - - while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0); - c = serial_in(info, UART_RX); - - /* - * Restore the interrupts - */ - serial_out(info, UART_IER, ier); - - return c; -} - static kdev_t serial_console_device(struct console *c) { return MKDEV(TTY_MAJOR, 64 + c->index); @@ -3075,7 +3048,6 @@ name: "ttyS", write: serial_console_write, device: serial_console_device, - wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/mips/baget/vacserial.c linux-2.5/arch/mips/baget/vacserial.c --- linux-2.5.1/arch/mips/baget/vacserial.c Sun Sep 9 17:43:01 2001 +++ linux-2.5/arch/mips/baget/vacserial.c Sun Dec 30 13:55:22 2001 @@ -2373,7 +2373,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -2622,43 +2624,6 @@ serial_outp(&scr_info, VAC_UART_INT_MASK, ier); } -/* - * Receive character from the serial port - */ -static int serial_console_wait_key(struct console *co) -{ - struct serial_state *ser; - int ier; - int lsr; - int c; - struct async_struct scr_info; /* serial_{in,out} because HUB6 */ - - ser = rs_table + co->index; - scr_info.magic = SERIAL_MAGIC; - scr_info.port = ser->port; - scr_info.flags = ser->flags; - - /* - * First save the IER then disable the interrupts so - * that the real driver for the port does not get the - * character. - */ - ier = serial_inp(&scr_info, VAC_UART_INT_MASK); - serial_outp(&scr_info, VAC_UART_INT_MASK, 0x00); - - do { - lsr = serial_inp(&scr_info, VAC_UART_INT_STATUS); - } while (!(lsr & VAC_UART_STATUS_RX_READY)); - c = serial_inp(&scr_info, VAC_UART_RX); - - /* - * Restore the interrupts - */ - serial_outp(&scr_info, VAC_UART_INT_MASK, ier); - - return c; -} - static kdev_t serial_console_device(struct console *c) { return MKDEV(TTY_MAJOR, 64 + c->index); @@ -2812,7 +2777,6 @@ name: "ttyS", write: serial_console_write, device: serial_console_device, - wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/mips/dec/promcon.c linux-2.5/arch/mips/dec/promcon.c --- linux-2.5.1/arch/mips/dec/promcon.c Thu Oct 12 21:20:48 2000 +++ linux-2.5/arch/mips/dec/promcon.c Thu Dec 27 15:56:12 2001 @@ -30,11 +30,6 @@ } } -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; @@ -50,7 +45,6 @@ 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, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/mips/kernel/process.c linux-2.5/arch/mips/kernel/process.c --- linux-2.5.1/arch/mips/kernel/process.c Sun Sep 9 17:43:01 2001 +++ linux-2.5/arch/mips/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -36,7 +36,6 @@ { /* endless idle loop with no priority at all */ current->nice = 20; - current->counter = -100; init_idle(); while (1) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/mips/kernel/smp.c linux-2.5/arch/mips/kernel/smp.c --- linux-2.5.1/arch/mips/kernel/smp.c Wed Nov 21 18:31:09 2001 +++ linux-2.5/arch/mips/kernel/smp.c Thu Dec 13 16:32:35 2001 @@ -31,6 +31,7 @@ #include <linux/timex.h> #include <linux/sched.h> #include <linux/interrupt.h> +#include <linux/cache.h> #include <asm/atomic.h> #include <asm/processor.h> @@ -52,7 +53,7 @@ /* Ze Big Kernel Lock! */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; int smp_threads_ready; /* Not used */ int smp_num_cpus; int global_irq_holder = NO_PROC_ID; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/mips64/kernel/process.c linux-2.5/arch/mips64/kernel/process.c --- linux-2.5.1/arch/mips64/kernel/process.c Fri Feb 9 19:29:44 2001 +++ linux-2.5/arch/mips64/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -34,7 +34,6 @@ /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; - current->counter = -100; while (1) { while (!current->need_resched) if (wait_available) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/mips64/kernel/smp.c linux-2.5/arch/mips64/kernel/smp.c --- linux-2.5.1/arch/mips64/kernel/smp.c Wed Jul 4 18:50:39 2001 +++ linux-2.5/arch/mips64/kernel/smp.c Thu Dec 13 16:32:35 2001 @@ -5,6 +5,7 @@ #include <linux/time.h> #include <linux/timex.h> #include <linux/sched.h> +#include <linux/cache.h> #include <asm/atomic.h> #include <asm/processor.h> @@ -52,7 +53,7 @@ #endif /* CONFIG_SGI_IP27 */ /* The 'big kernel lock' */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; int smp_threads_ready; /* Not used */ atomic_t smp_commenced = ATOMIC_INIT(0); struct cpuinfo_mips cpu_data[NR_CPUS]; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/parisc/kernel/pdc_cons.c linux-2.5/arch/parisc/kernel/pdc_cons.c --- linux-2.5.1/arch/parisc/kernel/pdc_cons.c Mon Sep 17 04:23:15 2001 +++ linux-2.5/arch/parisc/kernel/pdc_cons.c Thu Dec 27 15:56:12 2001 @@ -105,10 +105,6 @@ static struct console pdc_cons = { name: "ttyB", write: pdc_console_write, - read: NULL, - device: NULL, - wait_key: pdc_console_wait_key, - unblank: NULL, setup: pdc_console_setup, flags: CON_PRINTBUFFER|CON_ENABLED, // |CON_CONSDEV, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/parisc/kernel/process.c linux-2.5/arch/parisc/kernel/process.c --- linux-2.5.1/arch/parisc/kernel/process.c Fri Feb 9 19:29:44 2001 +++ linux-2.5/arch/parisc/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -71,7 +71,6 @@ /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; - current->counter = -100; while (1) { while (!current->need_resched) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/parisc/kernel/traps.c linux-2.5/arch/parisc/kernel/traps.c --- linux-2.5.1/arch/parisc/kernel/traps.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/arch/parisc/kernel/traps.c Thu Dec 27 16:32:30 2001 @@ -43,7 +43,6 @@ static inline void console_verbose(void) { - extern int console_loglevel; console_loglevel = 15; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/8260_io/uart.c linux-2.5/arch/ppc/8260_io/uart.c --- linux-2.5.1/arch/ppc/8260_io/uart.c Tue May 22 00:04:46 2001 +++ linux-2.5/arch/ppc/8260_io/uart.c Thu Jan 10 22:41:07 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.uart.c 1.6 05/17/01 18:14:20 cort + * BK Id: SCCS/s.uart.c 1.13 12/29/01 14:50:03 trini */ /* * UART driver for MPC8260 CPM SCC or SMC @@ -1732,11 +1732,11 @@ printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif current->state = TASK_INTERRUPTIBLE; -/* current->counter = 0; make us low-priority */ +/* current->dyn_prio = 0; make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; bdp = info->tx_cur; } while (bdp->cbd_sc & BD_SC_READY); @@ -2216,54 +2216,6 @@ info->tx_cur = (cbd_t *)bdp; } -/* - * Receive character from the serial port. This only works well - * before the port is initialize for real use. - */ -static int serial_console_wait_key(struct console *co) -{ - struct serial_state *ser; - u_char c, *cp; - ser_info_t *info; - volatile cbd_t *bdp; - volatile smc_uart_t *up; - - ser = rs_table + co->index; - - /* Pointer to UART in parameter ram. - */ - up = (smc_uart_t *)&immr->im_dprambase[ser->port]; - - /* Get the address of the host memory buffer. - * If the port has been initialized for general use, we must - * use information from the port structure. - */ - if ((info = (ser_info_t *)ser->info)) - bdp = info->rx_cur; - else - bdp = (cbd_t *)&immr->im_dprambase[up->smc_rbase]; - - /* - * We need to gracefully shut down the receiver, disable - * interrupts, then read the input. - */ - while (bdp->cbd_sc & BD_SC_EMPTY); /* Wait for a character */ - cp = __va(bdp->cbd_bufaddr); - - if (info) { - if (bdp->cbd_sc & BD_SC_WRAP) { - bdp = info->rx_bd_base; - } - else { - bdp++; - } - info->rx_cur = (cbd_t *)bdp; - } - - c = *cp; - return((int)c); -} - static kdev_t serial_console_device(struct console *c) { return MKDEV(TTYAUX_MAJOR, 64 + c->index); @@ -2274,7 +2226,6 @@ name: "ttyS", write: serial_console_write, device: serial_console_device, - wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: CONFIG_SERIAL_CONSOLE_PORT, @@ -2325,7 +2276,11 @@ __clear_user(&serial_driver,sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "serial"; +#ifdef CONFIG_DEVFS_FS + serial_driver.name = "tts/%d"; +#else serial_driver.name = "ttyS"; +#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = NR_PORTS; @@ -2339,7 +2294,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_8xx_open; serial_driver.close = rs_8xx_close; serial_driver.write = rs_8xx_write; @@ -2363,7 +2320,11 @@ * major number and the subtype code. */ callout_driver = serial_driver; +#ifdef CONFIG_DEVFS_FS + callout_driver.name = "cua/%d"; +#else callout_driver.name = "cua"; +#endif callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; callout_driver.read_proc = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/8xx_io/uart.c linux-2.5/arch/ppc/8xx_io/uart.c --- linux-2.5.1/arch/ppc/8xx_io/uart.c Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/8xx_io/uart.c Thu Jan 10 22:41:07 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.uart.c 1.19 10/26/01 09:59:32 trini + * BK Id: SCCS/s.uart.c 1.23 12/29/01 14:50:03 trini */ /* * UART driver for MPC860 CPM SCC or SMC @@ -97,7 +97,6 @@ static void serial_console_write(struct console *c, const char *s, unsigned count); static kdev_t serial_console_device(struct console *c); -static int serial_console_wait_key(struct console *co); #if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) static unsigned long break_pressed; /* break, really ... */ @@ -218,7 +217,6 @@ name: "ttyS", write: serial_console_write, device: serial_console_device, - wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: CONFIG_SERIAL_CONSOLE_PORT, @@ -1798,11 +1796,11 @@ printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif current->state = TASK_INTERRUPTIBLE; -/* current->counter = 0; make us low-priority */ +/* current->dyn_prio = 0; make us low-priority */ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; /* The 'tx_cur' is really the next buffer to send. We @@ -2402,11 +2400,6 @@ return((int)c); } -static int serial_console_wait_key(struct console *co) -{ - return(my_console_wait_key(co->index, 0, NULL)); -} - #ifdef CONFIG_XMON int xmon_8xx_read_poll(void) @@ -2529,7 +2522,11 @@ __clear_user(&serial_driver,sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "serial"; +#ifdef CONFIG_DEVFS_FS + serial_driver.name = "tts/%d"; +#else serial_driver.name = "ttyS"; +#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = NR_PORTS; @@ -2543,7 +2540,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_8xx_open; serial_driver.close = rs_8xx_close; serial_driver.write = rs_8xx_write; @@ -2567,7 +2566,11 @@ * major number and the subtype code. */ callout_driver = serial_driver; +#ifdef CONFIG_DEVFS_FS + callout_driver.name = "cua/%d"; +#else callout_driver.name = "cua"; +#endif callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; callout_driver.read_proc = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/amiga/config.c linux-2.5/arch/ppc/amiga/config.c --- linux-2.5.1/arch/ppc/amiga/config.c Wed Nov 28 21:22:26 2001 +++ linux-2.5/arch/ppc/amiga/config.c Thu Dec 27 15:56:12 2001 @@ -104,7 +104,6 @@ extern void amiga_floppy_setup(char *, int *); #endif static void amiga_reset (void); -static int amiga_wait_key (struct console *co); extern void amiga_init_sound(void); static void amiga_savekmsg_init(void); static void amiga_mem_console_write(struct console *co, const char *b, @@ -118,7 +117,6 @@ static struct console amiga_console_driver = { name: "debug", - wait_key: amiga_wait_key, flags: CON_PRINTBUFFER, index: -1, }; @@ -734,33 +732,6 @@ } return 0; -} - -static int amiga_wait_key (struct console *co) -{ - int i; - - while (1) { - while (ciaa.pra & 0x40); - - /* debounce */ - for (i = 0; i < 1000; i++); - - if (!(ciaa.pra & 0x40)) - break; - } - - /* wait for button up */ - while (1) { - while (!(ciaa.pra & 0x40)); - - /* debounce */ - for (i = 0; i < 1000; i++); - - if (ciaa.pra & 0x40) - break; - } - return 0; } static NORET_TYPE void amiga_reset( void ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/common/misc-simple.c linux-2.5/arch/ppc/boot/common/misc-simple.c --- linux-2.5.1/arch/ppc/boot/common/misc-simple.c Tue Aug 28 13:58:33 2001 +++ linux-2.5/arch/ppc/boot/common/misc-simple.c Thu Dec 27 16:32:30 2001 @@ -45,6 +45,15 @@ char *cmd_line = cmd_buf; unsigned long initrd_start = 0, initrd_end = 0; + +/* These values must be variables. If not, the compiler optimizer + * will remove some code, causing the size of the code to vary + * when these values are zero. This is bad because we first + * compile with these zero to determine the size and offsets + * in an image, than compile again with these set to the proper + * discovered value. + */ +unsigned int initrd_offset, initrd_size; char *zimage_start; int zimage_size; @@ -69,7 +78,8 @@ * were relocated to. */ puts("loaded at: "); puthex(load_addr); - puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); + puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); + puts("\n"); if ( (unsigned long)load_addr != (unsigned long)&start ) { puts("relocated to: "); puthex((unsigned long)&start); @@ -82,45 +92,38 @@ the size of the elf header which we strip -- Cort */ zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); zimage_size = ZIMAGE_SIZE; + initrd_offset = INITRD_OFFSET; + initrd_size = INITRD_SIZE; - if ( INITRD_OFFSET ) - initrd_start = load_addr - 0x10000 + INITRD_OFFSET; + if ( initrd_offset ) + initrd_start = load_addr - 0x10000 + initrd_offset; else initrd_start = 0; - initrd_end = INITRD_SIZE + initrd_start; + initrd_end = initrd_size + initrd_start; - /* - * Find a place to stick the zimage and initrd and - * relocate them if we have to. -- Cort - */ + /* Relocate the zImage */ avail_ram = (char *)PAGE_ALIGN((unsigned long)_end); puts("zimage at: "); puthex((unsigned long)zimage_start); - puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); - if ( (unsigned long)zimage_start <= 0x00800000 ) - { - memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); - zimage_start = (char *)avail_ram; - puts("relocated to: "); puthex((unsigned long)zimage_start); - puts(" "); - puthex((unsigned long)zimage_size+(unsigned long)zimage_start); - puts("\n"); + puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); + puts("\n"); + memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size ); + zimage_start = (char *)avail_ram; + puts("relocated to: "); puthex((unsigned long)zimage_start); + puts(" "); + puthex((unsigned long)zimage_size+(unsigned long)zimage_start); + puts("\n"); - /* relocate initrd */ - if ( initrd_start ) - { - puts("initrd at: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - avail_ram = (char *)PAGE_ALIGN( - (unsigned long)zimage_size+(unsigned long)zimage_start); - memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE ); - initrd_start = (unsigned long)avail_ram; - initrd_end = initrd_start + INITRD_SIZE; - puts("relocated to: "); puthex(initrd_start); - puts(" "); puthex(initrd_end); puts("\n"); - } - } else if ( initrd_start ) { + if ( initrd_start ) { puts("initrd at: "); puthex(initrd_start); puts(" "); puthex(initrd_end); puts("\n"); + /* relocate initrd */ + avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_size + + (unsigned long)zimage_start); + memcpy( (void *)avail_ram, (void *)initrd_start, initrd_size ); + initrd_start = (unsigned long)avail_ram; + initrd_end = initrd_start + initrd_size; + puts("relocated to: "); puthex(initrd_start); + puts(" "); puthex(initrd_end); puts("\n"); } avail_ram = (char *)0x00400000; @@ -161,11 +164,9 @@ puts("\n"); /* mappings on early boot can only handle 16M */ - if ( (int)(cmd_line[0]) > (16<<20)) + if ( (u32)(cmd_line) > (16<<20)) puts("cmd_line located > 16M\n"); - if ( initrd_start > (16<<20)) - puts("initrd_start located > 16M\n"); - + puts("Uncompressing Linux..."); gunzip(0, 0x400000, zimage_start, &zimage_size); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/common/ns16550.c linux-2.5/arch/ppc/boot/common/ns16550.c --- linux-2.5.1/arch/ppc/boot/common/ns16550.c Tue Aug 28 13:58:33 2001 +++ linux-2.5/arch/ppc/boot/common/ns16550.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ns16550.c 1.9 07/30/01 17:19:40 trini + * BK Id: SCCS/s.ns16550.c 1.12 10/08/01 17:16:50 paulus */ /* * COM1 NS16550 support @@ -10,6 +10,9 @@ #include <linux/serial_reg.h> #include <asm/serial.h> +/* Default serial baud rate */ +#define SERIAL_BAUD 9600 + extern void outb(int port, unsigned char val); extern unsigned char inb(int port); extern unsigned long ISA_io; @@ -46,13 +49,20 @@ outb(com_port + (UART_IER << shift), 0x00); /* Access baud rate */ outb(com_port + (UART_LCR << shift), 0x80); -#ifdef CONFIG_SERIAL_CONSOLE_NONSTD - /* Input clock. */ - outb(com_port + (UART_DLL << shift), - (BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD)); - outb(com_port + (UART_DLM << shift), - (BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD) >> 8); -#endif + /* + * Test if serial port is unconfigured. + * We assume that no-one uses less than 110 baud or + * less than 7 bits per character these days. + * -- paulus. + */ + if (inb(com_port + (UART_DLM << shift)) > 4 + || (inb(com_port + (UART_LCR << shift)) & 2) == 0) { + /* Input clock. */ + outb(com_port + (UART_DLL << shift), + (BASE_BAUD / SERIAL_BAUD)); + outb(com_port + (UART_DLM << shift), + (BASE_BAUD / SERIAL_BAUD) >> 8); + } /* 8 data, 1 stop, no parity */ outb(com_port + (UART_LCR << shift), 0x03); /* RTS/DTR */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/images/Makefile linux-2.5/arch/ppc/boot/images/Makefile --- linux-2.5.1/arch/ppc/boot/images/Makefile Thu May 24 22:02:06 2001 +++ linux-2.5/arch/ppc/boot/images/Makefile Thu Dec 27 16:32:30 2001 @@ -9,4 +9,4 @@ gzip -vf9 vmlinux clean: - rm -f sImage vmapus vmlinux.* miboot.image* zImage* zvmlinux.* + rm -f sImage vmapus vmlinux* miboot* zImage* zvmlinux* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/mbx/Makefile linux-2.5/arch/ppc/boot/mbx/Makefile --- linux-2.5.1/arch/ppc/boot/mbx/Makefile Tue Jun 12 02:15:27 2001 +++ linux-2.5/arch/ppc/boot/mbx/Makefile Thu Dec 27 16:32:30 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.7 06/05/01 20:20:05 paulus +# BK Id: SCCS/s.Makefile 1.9 10/15/01 10:53:29 trini # # # arch/ppc/mbxboot/Makefile @@ -73,6 +73,12 @@ -DZIMAGE_SIZE=0 -c -o $@ $*.c zvmlinux.initrd: $(OBJECTS) $(LIBS) ../images/vmlinux.gz +# +# Recompile misc.o again with more 'correct' bogus offsets +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0x0008c8e3 -DINITRD_SIZE=0x0000111a \ + -DZIMAGE_OFFSET=0x00018000 -DZIMAGE_SIZE=0x000748e2 \ + -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ --add-section=initrd=../images/ramdisk.image.gz \ @@ -88,6 +94,8 @@ --add-section=initrd=../images/ramdisk.image.gz \ --add-section=image=../images/vmlinux.gz \ $@.tmp ../images/$@.embedded +# Remove zvmlinux and zvmlinux.temp, we have ../images/zvmlinux.embedded + rm -f $@.tmp $@ zImage: zvmlinux ifeq ($(CONFIG_RPXCLASSIC),y) @@ -104,6 +112,12 @@ endif zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz +# +# Recompile misc.o again with more 'correct' bogus offsets +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=0x00018000 -DZIMAGE_SIZE=0x000748e2 \ + -c -o misc.o misc.c # # build the boot loader image and then compute the offset into it # for the kernel image diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/mbx/misc.c linux-2.5/arch/ppc/boot/mbx/misc.c --- linux-2.5.1/arch/ppc/boot/mbx/misc.c Tue Aug 28 13:58:33 2001 +++ linux-2.5/arch/ppc/boot/mbx/misc.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.c 1.13 07/27/01 11:44:37 trini + * BK Id: SCCS/s.misc.c 1.15 10/15/01 10:53:29 trini */ /* * Adapted for PowerPC by Gary Thomas @@ -44,10 +44,6 @@ char *avail_ram; char *end_avail; -/* See comment below..... -*/ -unsigned int initrd_offset, initrd_size; - /* Because of the limited amount of memory on embedded, it presents * loading problems. The biggest is that we load this boot program * into a relatively low memory address, and the Linux kernel Bss often @@ -75,14 +71,13 @@ bd_t *hold_residual = &hold_resid_buf; unsigned long initrd_start = 0, initrd_end = 0; char *zimage_start; -int zimage_size; extern void gunzip(void *, int, unsigned char *, int *); unsigned long decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp) { - int timer; + int timer, zimage_size = ZIMAGE_SIZE; extern unsigned long start; char *cp, ch; @@ -93,17 +88,6 @@ serial_init(bp); #endif - /* These values must be variables. If not, the compiler optimizer - * will remove some code, causing the size of the code to vary - * when these values are zero. This is bad because we first - * compile with these zero to determine the size and offsets - * in an image, than compile again with these set to the proper - * discovered value.....Ya know, we used to read these from the - * header a long time ago..... - */ - initrd_offset = INITRD_OFFSET; - initrd_size = INITRD_SIZE; - /* Grab some space for the command line and board info. Since * we no longer use the ELF header, but it was loaded, grab * that space. @@ -154,13 +138,12 @@ /* we have to subtract 0x10000 here to correct for objdump including the size of the elf header which we strip -- Cort */ zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); - zimage_size = ZIMAGE_SIZE; - if ( initrd_offset ) - initrd_start = load_addr - 0x10000 + initrd_offset; + if ( INITRD_OFFSET ) + initrd_start = load_addr - 0x10000 + INITRD_OFFSET; else initrd_start = 0; - initrd_end = initrd_size + initrd_start; + initrd_end = INITRD_SIZE + initrd_start; /* * setup avail_ram - this is the first part of ram usable @@ -201,9 +184,9 @@ if ((unsigned long)initrd_start > 0x01000000) { memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE), (void *)initrd_start, - initrd_size ); + INITRD_SIZE ); initrd_start = PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE); - initrd_end = initrd_start + initrd_size; + initrd_end = initrd_start + INITRD_SIZE; end_avail = (char *)initrd_start; puts("relocated to: "); puthex(initrd_start); puts(" "); puthex(initrd_end); puts("\n"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/pmac/Makefile linux-2.5/arch/ppc/boot/pmac/Makefile --- linux-2.5.1/arch/ppc/boot/pmac/Makefile Tue Aug 28 13:58:33 2001 +++ linux-2.5/arch/ppc/boot/pmac/Makefile Thu Dec 27 16:32:30 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.14 07/27/01 20:24:17 trini +# BK Id: SCCS/s.Makefile 1.16 09/28/01 07:39:37 trini # # Makefile for making XCOFF bootable images for booting on PowerMacs # using Open Firmware. @@ -48,9 +48,9 @@ cp ../images/vmlinux.coff $(TFTPIMAGE) cp ../images/vmlinux.elf-pmac $(TFTPIMAGE).elf -znetboot.initrd: vmlinux.coff.initrd vmlinux.initrd.elf-pmac - cp ../images/vmlinux.coff.initrd $(TFTPIMAGE) - cp ../images/vmlinux.elf-pmac.initrd $(TFTPIMAGE).elf +znetboot.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac + cp ../images/vmlinux.initrd.coff $(TFTPIMAGE) + cp ../images/vmlinux.initrd.elf-pmac $(TFTPIMAGE).elf #floppy: zImage # mount -t hfs /dev/fd0 /mnt @@ -61,7 +61,7 @@ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=../images/vmlinux.gz \ dummy.o ../images/$@ -miboot.image.initrd: miboot.image ../images/ramdisk.image.gz +miboot.initrd.image: miboot.image ../images/ramdisk.image.gz $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=../images/ramdisk.image.gz \ ../images/miboot.image ../images/$@ @@ -83,11 +83,11 @@ rm -f coffboot ln -sf vmlinux.coff ../images/zImage.pmac -vmlinux.coff.initrd: coffboot.initrd $(HACKCOFF) +vmlinux.initrd.coff: coffboot.initrd $(HACKCOFF) $(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd ../images/$@ $(HACKCOFF) ../images/$@ rm -f coffboot.initrd - ln -sf vmlinux.coff.initrd ../images/zImage.initrd.pmac + ln -sf vmlinux.initrd.coff ../images/zImage.initrd.pmac vmlinux.elf-pmac: $(CHRPOBJS) $(LIBS) ../common/no_initrd.o $(MKNOTE) ../images/vmlinux.gz $(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) ../common/no_initrd.o $(LIBS) @@ -110,6 +110,6 @@ zImage: vmlinux.coff vmlinux.elf-pmac miboot.image -zImage.initrd: vmlinux.coff.initrd vmlinux.initrd.elf-pmac miboot.image.initrd +zImage.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac miboot.initrd.image include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/prep/Makefile linux-2.5/arch/ppc/boot/prep/Makefile --- linux-2.5.1/arch/ppc/boot/prep/Makefile Mon Oct 8 18:43:01 2001 +++ linux-2.5/arch/ppc/boot/prep/Makefile Thu Dec 27 16:32:30 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.26 09/25/01 07:54:40 trini +# BK Id: SCCS/s.Makefile 1.28 10/21/01 20:47:58 trini # # arch/ppc/boot/Makefile # @@ -45,6 +45,12 @@ -DZIMAGE_SIZE=0 -c -o $@ $*.c zvmlinux.initrd: $(obj-y) $(LIBS) ../images/vmlinux.gz +# +# Recompile misc.oagain with more 'correct' bogus offsets +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0x00138466 -DINITRD_SIZE=0x0000111a \ + -DZIMAGE_OFFSET=0x0001b000 -DZIMAGE_SIZE=0x0011d460 \ + -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o $@.tmp $(obj-y) $(LIBS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ --add-section=initrd=../images/ramdisk.image.gz \ @@ -60,7 +66,7 @@ --add-section=initrd=../images/ramdisk.image.gz \ --add-section=image=../images/vmlinux.gz \ $@.tmp $@ - rm -f $@.tmp zvmlinux + rm -f $@.tmp zImage: zvmlinux $(MKPREP) $(MKPREP) -pbp zvmlinux ../images/$@.prep @@ -72,6 +78,12 @@ zvmlinux: $(obj-y) $(LIBS) ../images/vmlinux.gz # +# Recompile misc.oagain with more 'correct' bogus offsets +# + $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=0x0001b000 -DZIMAGE_SIZE=0x0011d460 \ + -c -o misc.o misc.c +# # build the boot loader image and then compute the offset into it # for the kernel image # @@ -88,7 +100,7 @@ $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(obj-y) $(LIBS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ --add-section=image=../images/vmlinux.gz $@.tmp $@ - rm $@.tmp + rm -f $@.tmp floppy: zImage dd if=../images/zImage.prep of=/dev/fd0H1440 bs=64b diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/prep/misc.c linux-2.5/arch/ppc/boot/prep/misc.c --- linux-2.5.1/arch/ppc/boot/prep/misc.c Mon Oct 15 20:35:26 2001 +++ linux-2.5/arch/ppc/boot/prep/misc.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.c 1.20 09/24/01 18:42:54 trini + * BK Id: SCCS/s.misc.c 1.22 10/15/01 17:46:21 trini * * arch/ppc/boot/prep/misc.c * @@ -48,14 +48,6 @@ RESIDUAL *hold_residual = &hold_resid_buf; unsigned long initrd_start = 0, initrd_end = 0; -/* These values must be variables. If not, the compiler optimizer - * will remove some code, causing the size of the code to vary - * when these values are zero. This is bad because we first - * compile with these zero to determine the size and offsets - * in an image, than compile again with these set to the proper - * discovered value. - */ -unsigned int initrd_offset, initrd_size; char *zimage_start; int zimage_size; @@ -311,14 +303,12 @@ size of the elf header which we strip -- Cort */ zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); zimage_size = ZIMAGE_SIZE; - initrd_offset = INITRD_OFFSET; - initrd_size = INITRD_SIZE; - if ( initrd_offset ) - initrd_start = load_addr - 0x10000 + initrd_offset; + if ( INITRD_OFFSET ) + initrd_start = load_addr - 0x10000 + INITRD_OFFSET; else initrd_start = 0; - initrd_end = initrd_size + initrd_start; + initrd_end = INITRD_SIZE + initrd_start; /* * Find a place to stick the zimage and initrd and @@ -343,9 +333,9 @@ puts(" "); puthex(initrd_end); puts("\n"); avail_ram = (char *)PAGE_ALIGN( (unsigned long)zimage_size+(unsigned long)zimage_start); - memcpy ((void *)avail_ram, (void *)initrd_start, initrd_size ); + memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE ); initrd_start = (unsigned long)avail_ram; - initrd_end = initrd_start + initrd_size; + initrd_end = initrd_start + INITRD_SIZE; puts("relocated to: "); puthex(initrd_start); puts(" "); puthex(initrd_end); puts("\n"); } @@ -395,7 +385,7 @@ puts("\n"); /* mappings on early boot can only handle 16M */ - if ( (int)(cmd_line[0]) > (16<<20)) + if ( (int)(cmd_line) > (16<<20)) puts("cmd_line located > 16M\n"); if ( (int)hold_residual > (16<<20)) puts("hold_residual located > 16M\n"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/utils/mksimage.c linux-2.5/arch/ppc/boot/utils/mksimage.c --- linux-2.5.1/arch/ppc/boot/utils/mksimage.c Thu May 24 22:02:07 2001 +++ linux-2.5/arch/ppc/boot/utils/mksimage.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mksimage.c 1.6 05/18/01 15:16:42 cort + * BK Id: SCCS/s.mksimage.c 1.7 10/11/01 11:59:05 trini */ /* * @@ -96,7 +96,7 @@ 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); + len = sprintf(buffer, "bootloader: %lx %lx\n", ld_off, ld_size); close(fd); fd = open(kernel, O_RDONLY); @@ -104,7 +104,7 @@ 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); + len += sprintf(buffer+len, "zimage: %lx %lx\n", kern_off, kern_size); close(fd); if (rdimage) { @@ -116,7 +116,7 @@ close(fd); } - len += sprintf(buffer+len, "initrd: %x %x", rd_off, rd_size); + len += sprintf(buffer+len, "initrd: %lx %lx", rd_off, rd_size); close(ofd); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/utils/offset linux-2.5/arch/ppc/boot/utils/offset --- linux-2.5.1/arch/ppc/boot/utils/offset Thu May 24 22:02:07 2001 +++ linux-2.5/arch/ppc/boot/utils/offset Thu Dec 27 16:32:30 2001 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'` +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $6}'` echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/utils/sioffset linux-2.5/arch/ppc/boot/utils/sioffset --- linux-2.5.1/arch/ppc/boot/utils/sioffset Thu May 24 22:02:07 2001 +++ linux-2.5/arch/ppc/boot/utils/sioffset Thu Dec 27 16:32:30 2001 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh OFFSET=`grep $1 sImage.map | awk '{print $2}'` echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/utils/sisize linux-2.5/arch/ppc/boot/utils/sisize --- linux-2.5.1/arch/ppc/boot/utils/sisize Thu May 24 22:02:07 2001 +++ linux-2.5/arch/ppc/boot/utils/sisize Thu Dec 27 16:32:30 2001 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh OFFSET=`grep $1 sImage.map | awk '{print $3}'` echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/boot/utils/size linux-2.5/arch/ppc/boot/utils/size --- linux-2.5.1/arch/ppc/boot/utils/size Thu May 24 22:02:07 2001 +++ linux-2.5/arch/ppc/boot/utils/size Thu Dec 27 16:32:30 2001 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh -OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/config.in linux-2.5/arch/ppc/config.in --- linux-2.5.1/arch/ppc/config.in Fri Nov 16 18:10:08 2001 +++ linux-2.5/arch/ppc/config.in Thu Dec 27 16:32:30 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.config.in 1.45 11/08/01 07:57:40 paulus +# BK Id: SCCS/s.config.in 1.47 12/01/01 20:09:06 benh # # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. @@ -328,6 +328,10 @@ bool 'Support for PMU based PowerMacs' CONFIG_ADB_PMU if [ "$CONFIG_ADB_PMU" = "y" ]; then bool ' Power management support for PowerBooks' CONFIG_PMAC_PBOOK + if [ "$CONFIG_PMAC_PBOOK" = "y" ]; then + define_bool CONFIG_PM y + tristate ' APM emulation' CONFIG_PMAC_APM_EMU + fi # made a separate option since backlight may end up beeing used # on non-powerbook machines (but only on PMU based ones AFAIK) bool ' Backlight control for LCD screens' CONFIG_PMAC_BACKLIGHT @@ -352,6 +356,9 @@ # layer is used. if [ "$CONFIG_INPUT" != "n" ]; then define_bool CONFIG_MAC_HID y + fi + if [ "$CONFIG_ADB_CUDA" != "n" ]; then + bool 'Support for ANS LCD display' CONFIG_ANSLCD fi fi endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/configs/common_defconfig linux-2.5/arch/ppc/configs/common_defconfig --- linux-2.5.1/arch/ppc/configs/common_defconfig Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/configs/common_defconfig Thu Dec 27 16:32:30 2001 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -119,8 +120,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -133,6 +132,7 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y @@ -343,15 +343,11 @@ # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set -CONFIG_SCSI_NCR53C8XX=y -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_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set @@ -388,7 +384,9 @@ # # Appletalk devices # -# CONFIG_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_IPDDP is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set @@ -443,6 +441,7 @@ # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_NET_POCKET is not set @@ -544,6 +543,7 @@ CONFIG_FB_MATROX_MILLENIUM=y CONFIG_FB_MATROX_MYSTIQUE=y # CONFIG_FB_MATROX_G100 is not set +# CONFIG_FB_MATROX_I2C is not set # CONFIG_FB_MATROX_G450 is not set # CONFIG_FB_MATROX_MULTIHEAD is not set CONFIG_FB_ATY=y @@ -597,6 +597,7 @@ CONFIG_MAC_ADBKEYCODES=y CONFIG_MAC_EMUMOUSEBTN=y CONFIG_MAC_HID=y +# CONFIG_ANSLCD is not set # # Character devices @@ -612,7 +613,12 @@ # # I2C support # -# CONFIG_I2C is not set +CONFIG_I2C=m +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_KEYWEST=m +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_PROC=m # # Mice @@ -693,11 +699,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO 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=m # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set @@ -710,6 +720,7 @@ # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -734,6 +745,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set @@ -751,6 +763,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -818,8 +832,10 @@ # Sound # CONFIG_SOUND=m -CONFIG_DMASOUND_AWACS=m +CONFIG_DMASOUND_PMAC=m CONFIG_DMASOUND=m +CONFIG_I2C=m +CONFIG_I2C_KEYWEST=m # CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set @@ -854,7 +870,6 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_LONG_TIMEOUT is not set -# CONFIG_USB_LARGE_CONFIG is not set # # USB Controllers diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/configs/gemini_defconfig linux-2.5/arch/ppc/configs/gemini_defconfig --- linux-2.5.1/arch/ppc/configs/gemini_defconfig Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/configs/gemini_defconfig Thu Dec 27 16:32:30 2001 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -109,8 +110,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -122,6 +121,7 @@ # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set @@ -221,15 +221,11 @@ # CONFIG_SCSI_INIA100 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_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set @@ -432,11 +428,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO 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_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set @@ -449,6 +449,7 @@ # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -473,6 +474,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set @@ -490,6 +492,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/configs/ibmchrp_defconfig linux-2.5/arch/ppc/configs/ibmchrp_defconfig --- linux-2.5.1/arch/ppc/configs/ibmchrp_defconfig Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/configs/ibmchrp_defconfig Thu Dec 27 16:32:30 2001 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -112,8 +113,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -126,6 +125,7 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y @@ -252,15 +252,11 @@ # CONFIG_SCSI_INIA100 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_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set @@ -343,6 +339,7 @@ # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_NET_POCKET is not set @@ -546,7 +543,7 @@ # CONFIG_WATCHDOG is not set # CONFIG_INTEL_RNG is not set CONFIG_NVRAM=y -CONFIG_RTC=y +# CONFIG_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -571,11 +568,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO 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_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set @@ -588,6 +589,7 @@ # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -612,6 +614,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set # CONFIG_NFS_FS is not set # CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set @@ -629,6 +632,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -677,7 +682,7 @@ # 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_1=m # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/configs/pmac_defconfig linux-2.5/arch/ppc/configs/pmac_defconfig --- linux-2.5.1/arch/ppc/configs/pmac_defconfig Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/ppc/configs/pmac_defconfig Thu Dec 27 16:32:30 2001 @@ -0,0 +1,1076 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_6xx=y +# CONFIG_4xx is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +# CONFIG_8260 is not set +CONFIG_PPC_STD_MMU=y +CONFIG_ALL_PPC=y +# CONFIG_APUS is not set +# CONFIG_GEMINI is not set +# CONFIG_SMP is not set +CONFIG_ALTIVEC=y +CONFIG_TAU=y +# CONFIG_TAU_INT is not set +# CONFIG_TAU_AVERAGE is not set + +# +# General setup +# +# CONFIG_HIGHMEM is not set +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_PCI=y +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_PCI_NAMES=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +CONFIG_CARDBUS=y +CONFIG_I82092=y +CONFIG_I82365=y +CONFIG_TCIC=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +CONFIG_PPC_RTC=y +CONFIG_PPC601_SYNC_FIX=y +CONFIG_PROC_DEVICETREE=y +CONFIG_PPC_RTAS=y +CONFIG_BOOTX_TEXT=y +# CONFIG_PREP_RESIDUAL is not set +# CONFIG_CMDLINE_BOOL is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +CONFIG_BLK_DEV_FD=m +# 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=y +# CONFIG_BLK_DEV_NBD 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_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_TARGET_LOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX 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 +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED 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=m +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +CONFIG_BLK_DEV_IDESCSI=y + +# +# 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_ADMA=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_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +CONFIG_BLK_DEV_CMD64X=y +# 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_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS 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_BLK_DEV_SL82C105=y +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDE_CHIPSETS 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 +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# 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=y +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=y +# 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=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +CONFIG_SCSI_AIC7XXX_OLD=m +# CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set +CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_OLD_PROC_STATS=y +# CONFIG_SCSI_DPT_I2O is not set +CONFIG_SCSI_ADVANSYS=m +# 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_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED 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 +CONFIG_SCSI_MESH=y +CONFIG_SCSI_MESH_SYNC_RATE=5 +CONFIG_SCSI_MAC53C94=y + +# +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +CONFIG_IEEE1394=m + +# +# Device Drivers +# +CONFIG_IEEE1394_PCILYNX=m +# CONFIG_IEEE1394_PCILYNX_LOCALRAM is not set +# CONFIG_IEEE1394_PCILYNX_PORTS is not set +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +CONFIG_IEEE1394_RAWIO=m +# CONFIG_IEEE1394_VERBOSEDEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Appletalk devices +# +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_IPDDP is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MACE=y +# CONFIG_MACE_AAUI_PORT is not set +CONFIG_BMAC=y +# CONFIG_GMAC is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +CONFIG_SUNGEM=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_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=y +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y +CONFIG_DE4X5=m +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX 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_8139CP 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 +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 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_PLIP is not set +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=m +CONFIG_APPLE_AIRPORT=m +# CONFIG_PLX_HERMES is not set + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=m +# CONFIG_AIRO_CS is not set +CONFIG_NET_WIRELESS=y + +# +# 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 + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCMCIA_XIRTULIP is not set +CONFIG_NET_PCMCIA_RADIO=y +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_NETWAVE is not set +# CONFIG_PCMCIA_WAVELAN is not set +# CONFIG_AIRONET4500_CS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set +# CONFIG_IRDA_OPTIONS is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m +# CONFIG_IRPORT_SIR is not set + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set + +# +# 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_OF=y +CONFIG_FB_CONTROL=y +CONFIG_FB_PLATINUM=y +CONFIG_FB_VALKYRIE=y +CONFIG_FB_CT65550=y +CONFIG_FB_IMSTT=y +# CONFIG_FB_S3TRIO is not set +# CONFIG_FB_VGA16 is not set +CONFIG_FB_MATROX=y +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +# CONFIG_FB_MATROX_G100 is not set +# CONFIG_FB_MATROX_I2C is not set +# CONFIG_FB_MATROX_G450 is not set +# CONFIG_FB_MATROX_MULTIHEAD is not set +CONFIG_FB_ATY=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_ATY_CT=y +CONFIG_FB_RADEON=y +CONFIG_FB_ATY128=y +# CONFIG_FB_SIS is not set +CONFIG_FB_3DFX=y +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_SUN8x16=y +CONFIG_FONT_SUN12x22=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +CONFIG_FB_COMPAT_XPMAC=y + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# +# Macintosh device drivers +# +CONFIG_ADB_CUDA=y +CONFIG_ADB_PMU=y +CONFIG_PMAC_PBOOK=y +CONFIG_PM=y +CONFIG_PMAC_APM_EMU=y +CONFIG_PMAC_BACKLIGHT=y +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +CONFIG_ADB=y +CONFIG_ADB_MACIO=y +CONFIG_INPUT_ADBHID=y +CONFIG_MAC_ADBKEYCODES=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_MAC_HID=y +# CONFIG_ANSLCD is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=m +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +CONFIG_I2C=m +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_KEYWEST=m +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_PROC=m + +# +# Mice +# +CONFIG_BUSMOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +CONFIG_NVRAM=y +# 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 + +# +# PCMCIA character devices +# +# CONFIG_PCMCIA_SERIAL_CS 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_REISERFS_PROC_INFO 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=m +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_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 +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_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=y +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# 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_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_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +# CONFIG_NFSD_V3 is not set +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 +# 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 +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +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_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_SMB_NLS=y +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_936 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=m +# 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_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 + +# +# Sound +# +CONFIG_SOUND=m +CONFIG_DMASOUND_PMAC=m +CONFIG_DMASOUND=m +CONFIG_I2C=m +CONFIG_I2C_KEYWEST=m +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_OHCI=y + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +CONFIG_USB_SCANNER=m +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +CONFIG_USB_SERIAL_VISOR=m +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_MAGIC_SYSRQ=y +# CONFIG_KGDB is not set +CONFIG_XMON=y diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/configs/power3_defconfig linux-2.5/arch/ppc/configs/power3_defconfig --- linux-2.5.1/arch/ppc/configs/power3_defconfig Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/configs/power3_defconfig Thu Dec 27 16:32:30 2001 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -66,6 +67,7 @@ # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set # CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set # CONFIG_PARPORT_SUNBPP is not set # CONFIG_PARPORT_OTHER is not set # CONFIG_PARPORT_1284 is not set @@ -119,8 +121,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -132,6 +132,7 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set @@ -224,15 +225,11 @@ # 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_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set @@ -315,6 +312,7 @@ # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_NET_POCKET is not set @@ -474,6 +472,7 @@ # CONFIG_I2C_VELLEMAN is not set CONFIG_I2C_ALGOPCF=y # CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_KEYWEST is not set CONFIG_I2C_CHARDEV=y # CONFIG_I2C_PROC is not set @@ -553,11 +552,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO 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_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set @@ -570,6 +573,7 @@ # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -594,6 +598,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set @@ -611,6 +616,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -665,7 +672,7 @@ # Sound # CONFIG_SOUND=y -# CONFIG_DMASOUND_AWACS is not set +# CONFIG_DMASOUND_PMAC is not set # CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/defconfig linux-2.5/arch/ppc/defconfig --- linux-2.5.1/arch/ppc/defconfig Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/defconfig Thu Dec 27 16:32:30 2001 @@ -4,6 +4,7 @@ # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y # # Code maturity level options @@ -119,8 +120,6 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -CONFIG_NETLINK=y -# CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set @@ -133,6 +132,7 @@ # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y @@ -343,15 +343,11 @@ # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set -CONFIG_SCSI_NCR53C8XX=y -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_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set @@ -388,7 +384,9 @@ # # Appletalk devices # -# CONFIG_APPLETALK is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_IPDDP is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set @@ -443,6 +441,7 @@ # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_NET_POCKET is not set @@ -544,6 +543,7 @@ CONFIG_FB_MATROX_MILLENIUM=y CONFIG_FB_MATROX_MYSTIQUE=y # CONFIG_FB_MATROX_G100 is not set +# CONFIG_FB_MATROX_I2C is not set # CONFIG_FB_MATROX_G450 is not set # CONFIG_FB_MATROX_MULTIHEAD is not set CONFIG_FB_ATY=y @@ -597,6 +597,7 @@ CONFIG_MAC_ADBKEYCODES=y CONFIG_MAC_EMUMOUSEBTN=y CONFIG_MAC_HID=y +# CONFIG_ANSLCD is not set # # Character devices @@ -612,7 +613,12 @@ # # I2C support # -# CONFIG_I2C is not set +CONFIG_I2C=m +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_KEYWEST=m +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_PROC=m # # Mice @@ -693,11 +699,15 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO 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=m # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set @@ -710,6 +720,7 @@ # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -734,6 +745,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set @@ -751,6 +763,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -818,8 +832,10 @@ # Sound # CONFIG_SOUND=m -CONFIG_DMASOUND_AWACS=m +CONFIG_DMASOUND_PMAC=m CONFIG_DMASOUND=m +CONFIG_I2C=m +CONFIG_I2C_KEYWEST=m # CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set @@ -854,7 +870,6 @@ CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_LONG_TIMEOUT is not set -# CONFIG_USB_LARGE_CONFIG is not set # # USB Controllers diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/Makefile linux-2.5/arch/ppc/kernel/Makefile --- linux-2.5.1/arch/ppc/kernel/Makefile Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/kernel/Makefile Thu Dec 27 16:32:30 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.34 10/16/01 15:58:42 trini +# BK Id: SCCS/s.Makefile 1.36 12/01/01 20:09:06 benh # # # Makefile for the linux kernel. @@ -56,7 +56,7 @@ obj-$(CONFIG_PCI) += apus_pci.o endif obj-$(CONFIG_ALL_PPC) += pmac_pic.o pmac_setup.o pmac_time.o prom.o \ - feature.o pmac_pci.o chrp_setup.o \ + pmac_feature.o pmac_pci.o chrp_setup.o \ chrp_time.o chrp_pci.o open_pic.o \ indirect_pci.o i8259.o prep_pci.o \ prep_time.o prep_nvram.o prep_setup.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/btext.c linux-2.5/arch/ppc/kernel/btext.c --- linux-2.5.1/arch/ppc/kernel/btext.c Sat Sep 8 19:38:41 2001 +++ linux-2.5/arch/ppc/kernel/btext.c Thu Dec 27 16:32:30 2001 @@ -133,14 +133,19 @@ { unsigned long offset = reloc_offset(); boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); - unsigned long addr = (unsigned long)bi->dispDeviceBase; unsigned long vaddr = KERNELBASE + 0x10000000; + unsigned long addr; unsigned long lowbits; if (!RELOC(disp_bi)) { RELOC(boot_text_mapped) = 0; return; } + addr = (unsigned long)bi->dispDeviceBase; + if (!addr) { + RELOC(boot_text_mapped) = 0; + return; + } if (PVR_VER(mfspr(PVR)) != 1) { /* 603, 604, G3, G4, ... */ lowbits = addr & ~0xFF000000UL; @@ -231,10 +236,10 @@ { if (disp_bi == 0) return; - /* check it's the same frame buffer (within 64MB) */ - if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xfc000000) { + + /* check it's the same frame buffer (within 256MB) */ + if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xf0000000) return; - } disp_bi->dispDeviceBase = (__u8 *) phys; disp_bi->dispDeviceRect[0] = 0; @@ -423,9 +428,11 @@ int rb = bi->dispDeviceRowBytes; switch(bi->dispDeviceDepth) { + case 24: case 32: draw_byte_32(font, (unsigned long *)base, rb); break; + case 15: case 16: draw_byte_16(font, (unsigned long *)base, rb); break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/chrp_setup.c linux-2.5/arch/ppc/kernel/chrp_setup.c --- linux-2.5.1/arch/ppc/kernel/chrp_setup.c Fri Nov 16 18:10:08 2001 +++ linux-2.5/arch/ppc/kernel/chrp_setup.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.chrp_setup.c 1.38 11/13/01 21:26:07 paulus + * BK Id: SCCS/s.chrp_setup.c 1.40 12/19/01 09:45:54 trini */ /* * linux/arch/ppc/kernel/setup.c @@ -374,7 +374,7 @@ openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq); for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) irq_desc[i].handler = &i8259_pic; - i8259_init(); + i8259_init(NULL); #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON) /* see if there is a keyboard in the device tree with a parent of type "adb" */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/chrp_smp.c linux-2.5/arch/ppc/kernel/chrp_smp.c --- linux-2.5.1/arch/ppc/kernel/chrp_smp.c Sat Sep 8 19:38:41 2001 +++ linux-2.5/arch/ppc/kernel/chrp_smp.c Thu Dec 27 16:32:30 2001 @@ -36,7 +36,6 @@ #include <asm/prom.h> #include <asm/smp.h> #include <asm/residual.h> -#include <asm/feature.h> #include <asm/time.h> #include "open_pic.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/cputable.c linux-2.5/arch/ppc/kernel/cputable.c --- linux-2.5.1/arch/ppc/kernel/cputable.c Mon Oct 8 18:40:13 2001 +++ linux-2.5/arch/ppc/kernel/cputable.c Thu Dec 27 16:32:30 2001 @@ -26,6 +26,7 @@ extern void __setup_cpu_604(int cpu_nr); extern void __setup_cpu_750(int cpu_nr); extern void __setup_cpu_7400(int cpu_nr); +extern void __setup_cpu_7410(int cpu_nr); extern void __setup_cpu_7450(int cpu_nr); extern void __setup_cpu_power3(int cpu_nr); extern void __setup_cpu_power4(int cpu_nr); @@ -113,14 +114,22 @@ 32, 32, __setup_cpu_604 }, - { /* 750 (0x4202, don't support TAU ?) */ - 0xffffffff, 0x00084202, "750", + { /* 740/750 (0x4202, don't support TAU ?) */ + 0xffffffff, 0x00084202, "740/750", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE, COMMON_PPC, 32, 32, __setup_cpu_750 }, + { /* 745/755 */ + 0xfffff000, 0x00083000, "745/755", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE, + COMMON_PPC, + 32, 32, + __setup_cpu_750 + }, { /* 750CX */ 0xffffff00, 0x00082200, "750CX", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | @@ -159,9 +168,18 @@ CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE, COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, 32, 32, - __setup_cpu_7400 + __setup_cpu_7410 + }, + { /* 7450 2.0 - no doze/nap */ + 0xffffffff, 0x80000200, "7450", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | + CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | + CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450, + COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC, + 32, 32, + __setup_cpu_7450 }, - { /* 7450 */ + { /* 7450 others */ 0xffff0000, 0x80000000, "7450", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/head.S linux-2.5/arch/ppc/kernel/head.S --- linux-2.5.1/arch/ppc/kernel/head.S Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/kernel/head.S Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head.S 1.31 10/18/01 15:02:09 trini + * BK Id: SCCS/s.head.S 1.34 12/02/01 11:35:27 benh */ /* * PowerPC version @@ -1347,7 +1347,19 @@ bl setup_750_7400_hid0 mtlr r4 blr +_GLOBAL(__setup_cpu_7410) + mflr r4 + bl setup_common_caches + bl setup_750_7400_hid0 + li r3,0 + mtspr SPRN_L2CR2,r3 + mtlr r4 + blr _GLOBAL(__setup_cpu_7450) + mflr r4 + bl setup_common_caches + bl setup_7450_hid0 + mtlr r4 blr _GLOBAL(__setup_cpu_power3) blr @@ -1400,6 +1412,47 @@ li r3,HID0_SPD andc r11,r11,r3 /* clear SPD: enable speculative */ li r3,0 + mtspr ICTC,r3 /* Instruction Cache Throttling off */ + isync + mtspr HID0,r11 + sync + isync + blr + +/* 7450 + * Enable Store Gathering (SGE), Branch Folding (FOLD) + * Branch History Table (BHTE), Branch Target ICache (BTIC) + * Dynamic Power Management (DPM), Speculative (SPD) + * Ensure our data cache instructions really operate. + * Timebase has to be running or we wouldn't have made it here, + * just ensure we don't disable it. + * Clear Instruction cache throttling (ICTC) + */ +setup_7450_hid0: + /* We check for the presence of an L3 cache setup by + * the firmware. If any, we disable DOZE capability + */ + mfspr r11,SPRN_L3CR + andis. r11,r11,L3CR_L3E@h + beq 1f + li r7,CPU_FTR_CAN_DOZE + lwz r6,CPU_SPEC_FEATURES(r5) + andc r6,r6,r7 + stw r6,CPU_SPEC_FEATURES(r5) +1: + mfspr r11,HID0 + + /* All of the bits we have to set..... + */ + ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC + oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ + + /* All of the bits we have to clear.... + */ + li r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI + andc r11,r11,r3 /* clear SPD: enable speculative */ + li r3,0 + mtspr ICTC,r3 /* Instruction Cache Throttling off */ isync mtspr HID0,r11 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/i8259.c linux-2.5/arch/ppc/kernel/i8259.c --- linux-2.5.1/arch/ppc/kernel/i8259.c Mon Dec 10 21:52:53 2001 +++ linux-2.5/arch/ppc/kernel/i8259.c Thu Dec 27 16:32:30 2001 @@ -1,14 +1,18 @@ /* - * BK Id: SCCS/s.i8259.c 1.7 05/17/01 18:14:21 cort + * BK Id: SCCS/s.i8259.c 1.11 12/19/01 09:45:54 trini */ #include <linux/stddef.h> #include <linux/init.h> +#include <linux/irq.h> +#include <linux/ioport.h> #include <linux/sched.h> #include <linux/signal.h> #include <asm/io.h> #include "i8259.h" +static volatile char *pci_intack; /* RO, gives us the irq vector */ + unsigned char cached_8259[2] = { 0xff, 0xff }; #define cached_A1 (cached_8259[0]) #define cached_21 (cached_8259[1]) @@ -17,32 +21,56 @@ int i8259_pic_irq_offset; -int i8259_irq(int cpu) +/* Acknowledge the irq using the PCI host bridge's interrupt acknowledge + * feature. (Polling is somehow broken on some IBM and Motorola PReP boxes.) + */ +int i8259_irq(void) +{ + int irq; + + spin_lock/*_irqsave*/(&i8259_lock/*, flags*/); + + irq = *pci_intack & 0xff; + if (irq==7) { + /* + * This may be a spurious interrupt. + * + * Read the interrupt status register (ISR). If the most + * significant bit is not set then there is no valid + * interrupt. + */ + if(~inb(0x20)&0x80) { + irq = -1; + } + } + spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); + return irq; +} + +/* Poke the 8259's directly using poll commands. */ +int i8259_poll(void) { int irq; - + spin_lock/*_irqsave*/(&i8259_lock/*, flags*/); - /* - * Perform an interrupt acknowledge cycle on controller 1 - */ - outb(0x0C, 0x20); - irq = inb(0x20) & 7; - if (irq == 2) - { - /* - * Interrupt is cascaded so perform interrupt - * acknowledge on controller 2 - */ - outb(0x0C, 0xA0); - irq = (inb(0xA0) & 7) + 8; - } - else if (irq==7) - { - /* - * This may be a spurious interrupt - * - * Read the interrupt status register. If the most - * significant bit is not set then there is no valid + /* + * Perform an interrupt acknowledge cycle on controller 1 + */ + outb(0x0C, 0x20); /* prepare for poll */ + irq = inb(0x20) & 7; + if (irq == 2) { + /* + * Interrupt is cascaded so perform interrupt + * acknowledge on controller 2 + */ + outb(0x0C, 0xA0); /* prepare for poll */ + irq = (inb(0xA0) & 7) + 8; + } else if (irq==7) { + /* + * This may be a spurious interrupt + * + * Read the interrupt status register. If the most + * significant bit is not set then there is no valid * interrupt */ outb(0x0b, 0x20); @@ -58,44 +86,44 @@ static void i8259_mask_and_ack_irq(unsigned int irq_nr) { unsigned long flags; - + spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; + if ( irq_nr >= i8259_pic_irq_offset ) + irq_nr -= i8259_pic_irq_offset; - if (irq_nr > 7) { - cached_A1 |= 1 << (irq_nr-8); - inb(0xA1); /* DUMMY */ - outb(cached_A1,0xA1); - outb(0x20,0xA0); /* Non-specific EOI */ - outb(0x20,0x20); /* Non-specific EOI to cascade */ - } else { - cached_21 |= 1 << irq_nr; - inb(0x21); /* DUMMY */ - outb(cached_21,0x21); - outb(0x20,0x20); /* Non-specific EOI */ - } + if (irq_nr > 7) { + cached_A1 |= 1 << (irq_nr-8); + inb(0xA1); /* DUMMY */ + outb(cached_A1,0xA1); + outb(0x20,0xA0); /* Non-specific EOI */ + outb(0x20,0x20); /* Non-specific EOI to cascade */ + } else { + cached_21 |= 1 << irq_nr; + inb(0x21); /* DUMMY */ + outb(cached_21,0x21); + outb(0x20,0x20); /* Non-specific EOI */ + } spin_unlock_irqrestore(&i8259_lock, flags); } static void i8259_set_irq_mask(int irq_nr) { - outb(cached_A1,0xA1); - outb(cached_21,0x21); + outb(cached_A1,0xA1); + outb(cached_21,0x21); } - + static void i8259_mask_irq(unsigned int irq_nr) { unsigned long flags; spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - if ( irq_nr < 8 ) - cached_21 |= 1 << irq_nr; - else - cached_A1 |= 1 << (irq_nr-8); - i8259_set_irq_mask(irq_nr); + if ( irq_nr >= i8259_pic_irq_offset ) + irq_nr -= i8259_pic_irq_offset; + if ( irq_nr < 8 ) + cached_21 |= 1 << irq_nr; + else + cached_A1 |= 1 << (irq_nr-8); + i8259_set_irq_mask(irq_nr); spin_unlock_irqrestore(&i8259_lock, flags); } @@ -104,13 +132,13 @@ unsigned long flags; spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - if ( irq_nr < 8 ) - cached_21 &= ~(1 << irq_nr); - else - cached_A1 &= ~(1 << (irq_nr-8)); - i8259_set_irq_mask(irq_nr); + if ( irq_nr >= i8259_pic_irq_offset ) + irq_nr -= i8259_pic_irq_offset; + if ( irq_nr < 8 ) + cached_21 &= ~(1 << irq_nr); + else + cached_A1 &= ~(1 << (irq_nr-8)); + i8259_set_irq_mask(irq_nr); spin_unlock_irqrestore(&i8259_lock, flags); } @@ -121,36 +149,62 @@ } struct hw_interrupt_type i8259_pic = { - " i8259 ", - NULL, - NULL, - i8259_unmask_irq, - i8259_mask_irq, - i8259_mask_and_ack_irq, - i8259_end_irq, - NULL + " i8259 ", + NULL, + NULL, + i8259_unmask_irq, + i8259_mask_irq, + i8259_mask_and_ack_irq, + i8259_end_irq, + NULL +}; + +static struct resource pic1_iores = { + "8259 (master)", 0x20, 0x21, IORESOURCE_BUSY }; -void __init i8259_init(void) +static struct resource pic2_iores = { + "8259 (slave)", 0xa0, 0xa1, IORESOURCE_BUSY +}; + +static struct resource pic_edgectrl_iores = { + "8259 edge control", 0x4d0, 0x4d1, IORESOURCE_BUSY +}; + +void __init i8259_init(long intack_addr) { unsigned long flags; - + spin_lock_irqsave(&i8259_lock, flags); - /* init master interrupt controller */ - outb(0x11, 0x20); /* Start init sequence */ - outb(0x00, 0x21); /* Vector base */ - outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ - outb(0x01, 0x21); /* Select 8086 mode */ - outb(0xFF, 0x21); /* Mask all */ - /* init slave interrupt controller */ - outb(0x11, 0xA0); /* Start init sequence */ - outb(0x08, 0xA1); /* Vector base */ - outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ - outb(0x01, 0xA1); /* Select 8086 mode */ - outb(0xFF, 0xA1); /* Mask all */ - outb(cached_A1, 0xA1); - outb(cached_21, 0x21); + /* init master interrupt controller */ + outb(0x11, 0x20); /* Start init sequence */ + outb(0x00, 0x21); /* Vector base */ + outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ + outb(0x01, 0x21); /* Select 8086 mode */ + + /* init slave interrupt controller */ + outb(0x11, 0xA0); /* Start init sequence */ + outb(0x08, 0xA1); /* Vector base */ + outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ + outb(0x01, 0xA1); /* Select 8086 mode */ + + /* always read ISR */ + outb(0x0B, 0x20); + outb(0x0B, 0xA0); + + /* Mask all interrupts */ + outb(cached_A1, 0xA1); + outb(cached_21, 0x21); + spin_unlock_irqrestore(&i8259_lock, flags); - request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT, - "82c59 secondary cascade", NULL ); + + /* reserve our resources */ + request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT, + "82c59 secondary cascade", NULL ); + request_resource(&ioport_resource, &pic1_iores); + request_resource(&ioport_resource, &pic2_iores); + request_resource(&ioport_resource, &pic_edgectrl_iores); + + if (intack_addr) + pci_intack = ioremap(intack_addr, 1); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/i8259.h linux-2.5/arch/ppc/kernel/i8259.h --- linux-2.5.1/arch/ppc/kernel/i8259.h Tue May 22 00:04:47 2001 +++ linux-2.5/arch/ppc/kernel/i8259.h Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.i8259.h 1.5 05/17/01 18:14:21 cort + * BK Id: SCCS/s.i8259.h 1.8 12/19/01 09:45:54 trini */ #ifndef _PPC_KERNEL_i8259_H @@ -9,7 +9,8 @@ extern struct hw_interrupt_type i8259_pic; -void i8259_init(void); -int i8259_irq(int); +void i8259_init(long); +int i8259_irq(void); +int i8259_poll(void); #endif /* _PPC_KERNEL_i8259_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/idle.c linux-2.5/arch/ppc/kernel/idle.c --- linux-2.5.1/arch/ppc/kernel/idle.c Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/kernel/idle.c Thu Dec 27 22:10:28 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.idle.c 1.16 10/16/01 15:58:42 trini + * BK Id: SCCS/s.idle.c 1.18 12/01/01 20:09:06 benh */ /* * Idle daemon for PowerPC. Idle daemon will handle any action @@ -54,11 +54,9 @@ /* endless loop with no priority at all */ current->nice = 20; - current->counter = -100; init_idle(); for (;;) { #ifdef CONFIG_SMP - if (!do_power_save) { /* * Deal with another CPU just having chosen a thread to @@ -231,6 +229,13 @@ void power_save(void) { unsigned long hid0; + int nap = powersave_nap; + + /* 7450 has no DOZE mode mode, we return if powersave_nap + * isn't enabled + */ + if (!nap && cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_SPEC7450) + return; /* * Disable interrupts to prevent a lost wakeup * when going to sleep. This is necessary even with diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/irq.c linux-2.5/arch/ppc/kernel/irq.c --- linux-2.5.1/arch/ppc/kernel/irq.c Wed Nov 28 21:22:26 2001 +++ linux-2.5/arch/ppc/kernel/irq.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.irq.c 1.32 08/24/01 20:07:37 paulus + * BK Id: SCCS/s.irq.c 1.34 12/01/01 20:09:06 benh */ /* * arch/ppc/kernel/irq.c @@ -538,21 +538,29 @@ int do_IRQ(struct pt_regs *regs) { int cpu = smp_processor_id(); - int irq; - hardirq_enter(cpu); + int irq, first = 1; + hardirq_enter( cpu ); - /* every arch is required to have a get_irq -- Cort */ - irq = ppc_md.get_irq(regs); + for (;;) { + /* + * Every arch is required to implement ppc_md.get_irq. + * This function will either return an irq number or -1 to + * indicate there are no more pending. But the first time + * through the loop this means there wasn't and IRQ pending. + * The value -2 is for buggy hardware and means that this IRQ + * has already been handled. -- Tom + */ + irq = ppc_md.get_irq( regs ); - if (irq >= 0) { - ppc_irq_dispatch_handler( regs, irq ); - } else if (irq != -2) { - /* -2 means ignore, already handled */ - if (ppc_spurious_interrupts < 10) - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - /* That's not SMP safe ... but who cares ? */ - ppc_spurious_interrupts++; + if (irq >= 0) + ppc_irq_dispatch_handler( regs, irq ); + else { + if (irq != -2 && first) + /* That's not SMP safe ... but who cares ? */ + ppc_spurious_interrupts++; + break; + } + first = 0; } hardirq_exit( cpu ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/l2cr.S linux-2.5/arch/ppc/kernel/l2cr.S --- linux-2.5.1/arch/ppc/kernel/l2cr.S Tue Aug 28 13:58:33 2001 +++ linux-2.5/arch/ppc/kernel/l2cr.S Thu Dec 27 16:32:30 2001 @@ -30,6 +30,12 @@ *********** Thu, July 13, 2000. - Terry: Added isync to correct for an errata. + + 22 August 2001. + - DanM: Finally added the 7450 patch I've had for the past + several months. The L2CR is similar, but I'm going + to assume the user of this functions knows what they + are doing. Author: Terry Greeniaus (tgree@phys.ualberta.ca) Please e-mail updates to this file to me, thanks! @@ -71,6 +77,15 @@ features, such as L2DO which caches only data, or L2TS which causes cache pushes from the L1 cache to go to the L2 cache instead of to main memory. + +IMPORTANT: + Starting with the 7450, the bits in this register have moved + or behave differently. The Enable, Parity Enable, Size, + and L2 Invalidate are the only bits that have not moved. + The size is read-only for these processors with internal L2 + cache, and the invalidate is a control as well as status. + -- Dan + */ /* * Summary: this procedure ignores the L2I bit in the value passed in, @@ -115,6 +130,8 @@ /**** Might be a good idea to set L2DO here - to prevent instructions from getting into the cache. But since we invalidate the next time we enable the cache it doesn't really matter. + Don't do this unless you accomodate all processor variations. + The bit moved on the 7450..... ****/ lis r4,0x0002 @@ -159,12 +176,21 @@ sync isync /* For errata */ +BEGIN_FTR_SECTION + /* On the 7450, we wait for the L2I bit to clear...... + */ +10: mfspr r3,L2CR + andis. r4,r3,0x0020 + bne 10b + b 11f +END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450) + /* Wait for the invalidation to complete */ 3: mfspr r3,L2CR rlwinm. r4,r3,0,31,31 bne 3b - rlwinm r3,r3,0,11,9 /* Turn off the L2I bit */ +11: rlwinm r3,r3,0,11,9 /* Turn off the L2I bit */ sync mtspr L2CR,r3 sync diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/m8xx_setup.c linux-2.5/arch/ppc/kernel/m8xx_setup.c --- linux-2.5.1/arch/ppc/kernel/m8xx_setup.c Fri Nov 16 18:10:08 2001 +++ linux-2.5/arch/ppc/kernel/m8xx_setup.c Thu Dec 20 19:14:29 2001 @@ -55,12 +55,6 @@ extern void m8xx_ide_init(void); -#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 unsigned long find_available_memory(void); extern void m8xx_cpm_reset(uint); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/misc.S linux-2.5/arch/ppc/kernel/misc.S --- linux-2.5.1/arch/ppc/kernel/misc.S Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/kernel/misc.S Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.S 1.32 10/18/01 17:29:53 trini + * BK Id: SCCS/s.misc.S 1.36 12/01/01 20:09:06 benh */ /* * This file contains miscellaneous low-level functions. @@ -128,6 +128,9 @@ /* * call_setup_cpu - call the setup_cpu function for this cpu * r3 = data offset, r24 = cpu number + * + * Don't change register layout, the setup function may rely + * on r5 containing a relocated pointer to the current cpu spec. */ _GLOBAL(call_setup_cpu) addis r5,r3,cur_cpu_spec@ha @@ -866,10 +869,8 @@ sc cmpi 0,r3,0 /* parent or child? */ bnelr /* return if parent */ - li r0,0 /* clear out p->thread.regs */ - stw r0,THREAD+PT_REGS(r2) /* since we don't have user ctx */ - addi r1,r2,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD - stw r0,0(r1) + li r0,0 /* make top-level stack frame */ + stwu r0,-16(r1) mtlr r6 /* fn addr in lr */ mr r3,r4 /* load arg and call fn */ blrl diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/open_pic.c linux-2.5/arch/ppc/kernel/open_pic.c --- linux-2.5.1/arch/ppc/kernel/open_pic.c Sat Nov 3 01:43:54 2001 +++ linux-2.5/arch/ppc/kernel/open_pic.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.open_pic.c 1.31 10/11/01 12:09:11 trini + * BK Id: SCCS/s.open_pic.c 1.33 12/19/01 09:45:54 trini */ /* * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling @@ -28,6 +28,7 @@ #include "local_irq.h" #include "open_pic.h" #include "open_pic_defs.h" +#include "i8259.h" void* OpenPIC_Addr; static volatile struct OpenPIC *OpenPIC = NULL; @@ -784,9 +785,6 @@ /* * 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 */ @@ -801,7 +799,7 @@ irq = *chrp_int_ack_special; #ifndef CONFIG_GEMINI else - irq = i8259_irq( smp_processor_id() ); + irq = i8259_poll(); #endif openpic_eoi(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/pci.c linux-2.5/arch/ppc/kernel/pci.c --- linux-2.5.1/arch/ppc/kernel/pci.c Fri Nov 16 18:10:08 2001 +++ linux-2.5/arch/ppc/kernel/pci.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pci.c 1.35 11/13/01 08:19:57 trini + * BK Id: SCCS/s.pci.c 1.38 12/11/01 14:57:05 benh */ /* * Common pmac/prep/chrp pci routines. -- Cort @@ -19,6 +19,7 @@ #include <asm/processor.h> #include <asm/io.h> #include <asm/prom.h> +#include <asm/sections.h> #include <asm/pci-bridge.h> #include <asm/residual.h> #include <asm/byteorder.h> @@ -66,7 +67,7 @@ { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources }, #ifdef CONFIG_ALL_PPC /* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */ - { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211, pcibios_fixup_cardbus }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pcibios_fixup_cardbus }, #endif /* CONFIG_ALL_PPC */ { 0 } }; @@ -175,18 +176,25 @@ static void pcibios_fixup_cardbus(struct pci_dev* dev) { + if (_machine != _MACH_Pmac) + return; /* * Fix the interrupt routing on the TI1211 chip on the 1999 * G3 powerbook, which doesn't get initialized properly by OF. + * Same problem with the 1410 of the new titanium pbook which + * has the same register. */ if (dev->vendor == PCI_VENDOR_ID_TI - && dev->device == PCI_DEVICE_ID_TI_1211) { - u32 val; + && (dev->device == PCI_DEVICE_ID_TI_1211 || + dev->device == PCI_DEVICE_ID_TI_1410)) { + u8 val; /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA signal out the MFUNC0 pin */ - if (pci_read_config_dword(dev, 0x8c, &val) == 0 - && val == 0) - pci_write_config_dword(dev, 0x8c, 2); + if (pci_read_config_byte(dev, 0x8c, &val) == 0) + pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2); + /* Disable ISA interrupt mode */ + if (pci_read_config_byte(dev, 0x92, &val) == 0) + pci_write_config_byte(dev, 0x92, val & ~0x06); } } #endif /* CONFIG_ALL_PPC */ @@ -438,7 +446,7 @@ /* * Functions below are used on OpenFirmware machines. */ -static void +static void __openfirmware make_one_node_map(struct device_node* node, u8 pci_bus) { int *bus_range; @@ -472,7 +480,7 @@ } } -void +void __openfirmware pcibios_make_OF_bus_map(void) { int i; @@ -512,17 +520,17 @@ #endif } -static struct device_node* -scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) +typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data); + +static struct device_node* __openfirmware +scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data) { struct device_node* sub_node; for (; node != 0;node = node->sibling) { - unsigned int *class_code, *reg; + unsigned int *class_code; - reg = (unsigned int *) get_property(node, "reg", 0); - if (reg && ((reg[0] >> 8) & 0xff) == dev_fn - && ((reg[0] >> 16) & 0xff) == bus) + if (filter(node, data)) return node; /* For PCI<->PCI bridges or CardBus bridges, we go down @@ -535,13 +543,34 @@ (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) && strcmp(node->name, "multifunc-device")) continue; - sub_node = scan_OF_childs_for_device(node->child, bus, dev_fn); + sub_node = scan_OF_pci_childs(node->child, filter, data); if (sub_node) return sub_node; } return NULL; } +static int +scan_OF_pci_childs_iterator(struct device_node* node, void* data) +{ + unsigned int *reg; + u8* fdata = (u8*)data; + + reg = (unsigned int *) get_property(node, "reg", 0); + if (reg && ((reg[0] >> 8) & 0xff) == fdata[1] + && ((reg[0] >> 16) & 0xff) == fdata[0]) + return 1; + return 0; +} + +static struct device_node* __openfirmware +scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) +{ + u8 filter_data[2] = {bus, dev_fn}; + + return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data); +} + /* * Scans the OF tree for a device node matching a PCI device */ @@ -598,6 +627,12 @@ return NULL; } +static int __openfirmware +find_OF_pci_device_filter(struct device_node* node, void* data) +{ + return ((void *)node == data); +} + /* * Returns the PCI device matching a given OF node */ @@ -605,21 +640,40 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn) { unsigned int *reg; - int i; + struct pci_controller* hose; + struct pci_dev* dev; if (!have_of) return -ENODEV; + /* Make sure it's really a PCI device */ + hose = pci_find_hose_for_OF_device(node); + if (!hose || !hose->arch_data) + return -ENODEV; + if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child, + find_OF_pci_device_filter, (void *)node)) + return -ENODEV; reg = (unsigned int *) get_property(node, "reg", 0); if (!reg) return -ENODEV; *bus = (reg[0] >> 16) & 0xff; - for (i=0; pci_to_OF_bus_map && i<pci_bus_count; i++) - if (pci_to_OF_bus_map[i] == *bus) { - *bus = i; - break; - } *devfn = ((reg[0] >> 8) & 0xff); - return 0; + + /* Ok, here we need some tweak. If we have already renumbered + * all busses, we can't rely on the OF bus number any more. + * the pci_to_OF_bus_map is not enough as several PCI busses + * may match the same OF bus number. + */ + if (!pci_to_OF_bus_map) + return 0; + pci_for_each_dev(dev) { + if (pci_to_OF_bus_map[dev->bus->number] != *bus) + continue; + if (dev->devfn != *devfn) + continue; + *bus = dev->bus->number; + return 0; + } + return -ENODEV; } void __init diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/pmac_backlight.c linux-2.5/arch/ppc/kernel/pmac_backlight.c --- linux-2.5.1/arch/ppc/kernel/pmac_backlight.c Sat Sep 8 19:38:41 2001 +++ linux-2.5/arch/ppc/kernel/pmac_backlight.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_backlight.c 1.8 09/08/01 15:47:42 paulus + * BK Id: SCCS/s.pmac_backlight.c 1.10 12/01/01 20:09:06 benh */ /* * Miscellaneous procedures for dealing with the PowerMac hardware. @@ -78,7 +78,7 @@ pmu_request(&req, NULL, 2, 0xd9, 0); while (!req.complete) pmu_poll(); - backlight_level = req.reply[1] >> 4; + backlight_level = req.reply[0] >> 4; } #endif if (!backlighter->set_enable(1, backlight_level, data)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/pmac_feature.c linux-2.5/arch/ppc/kernel/pmac_feature.c --- linux-2.5.1/arch/ppc/kernel/pmac_feature.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/ppc/kernel/pmac_feature.c Thu Dec 27 16:32:30 2001 @@ -0,0 +1,2075 @@ +/* + * BK Id: %F% %I% %G% %U% %#% + */ +/* + * arch/ppc/kernel/pmac_feature.c + * + * Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au) + * Ben. Herrenschmidt (benh@kernel.crashing.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. + * + * TODO: + * + * - Replace mdelay with some schedule loop if possible + * - Shorten some obfuscated delays on some routines (like modem + * power) + * + */ +#include <linux/config.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/adb.h> +#include <linux/pmu.h> +#include <asm/sections.h> +#include <asm/errno.h> +#include <asm/ohare.h> +#include <asm/heathrow.h> +#include <asm/keylargo.h> +#include <asm/uninorth.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> +#include <asm/dbdma.h> + +#undef DEBUG_FEATURE + +#ifdef DEBUG_FEATURE +#define DBG(fmt,...) printk(KERN_DEBUG fmt) +#else +#define DBG(fmt,...) +#endif + +/* Exported from arch/ppc/kernel/idle.c */ +extern unsigned long powersave_nap; + +/* + * We use a single global lock to protect accesses. Each driver has + * to take care of it's own locking + */ +static spinlock_t feature_lock __pmacdata = SPIN_LOCK_UNLOCKED; + +#define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); +#define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); + +/* + * Helper functions regarding the various flavors of mac-io + */ + +#define MAX_MACIO_CHIPS 2 + +enum { + macio_unknown = 0, + macio_grand_central, + macio_ohare, + macio_ohareII, + macio_heathrow, + macio_gatwick, + macio_paddington, + macio_keylargo, + macio_pangea +}; + +static const char* macio_names[] __pmacdata = +{ + "Unknown", + "Grand Central", + "OHare", + "OHareII", + "Heathrow", + "Gatwick", + "Paddington", + "Keylargo", + "Pangea" +}; + +static struct macio_chip +{ + struct device_node* of_node; + int type; + int rev; + volatile u32* base; + unsigned long flags; +} macio_chips[MAX_MACIO_CHIPS] __pmacdata; + +#define MACIO_FLAG_SCCA_ON 0x00000001 +#define MACIO_FLAG_SCCB_ON 0x00000002 +#define MACIO_FLAG_SCC_LOCKED 0x00000004 +#define MACIO_FLAG_AIRPORT_ON 0x00000010 +#define MACIO_FLAG_FW_SUPPORTED 0x00000020 + +static struct macio_chip* __pmac +macio_find(struct device_node* child, int type) +{ + while(child) { + int i; + + for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++) + if (child == macio_chips[i].of_node && + (!type || macio_chips[i].type == type)) + return &macio_chips[i]; + child = child->parent; + } + return NULL; +} + +#define MACIO_FCR32(macio, r) ((macio)->base + ((r) >> 2)) +#define MACIO_FCR8(macio, r) (((volatile u8*)((macio)->base)) + (r)) + +#define MACIO_IN32(r) (in_le32(MACIO_FCR32(macio,r))) +#define MACIO_OUT32(r,v) (out_le32(MACIO_FCR32(macio,r), (v))) +#define MACIO_BIS(r,v) (MACIO_OUT32((r), MACIO_IN32(r) | (v))) +#define MACIO_BIC(r,v) (MACIO_OUT32((r), MACIO_IN32(r) & ~(v))) +#define MACIO_IN8(r) (in_8(MACIO_FCR8(macio,r))) +#define MACIO_OUT8(r,v) (out_8(MACIO_FCR8(macio,r), (v))) + +/* + * Uninorth reg. access. Note that Uni-N regs are big endian + */ + +#define UN_REG(r) (uninorth_base + ((r) >> 2)) +#define UN_IN(r) (in_be32(UN_REG(r))) +#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) +#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) +#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) + +static struct device_node* uninorth_node __pmacdata; +static u32* uninorth_base __pmacdata; +static u32 uninorth_rev __pmacdata; + + +/* + * For each motherboard family, we have a table of functions pointers + * that handle the various features. + */ + +typedef int (*feature_call)(struct device_node* node, int param, int value); + +struct feature_table_entry { + unsigned int selector; + feature_call function; +}; + +struct pmac_mb_def +{ + const char* model_string; + const char* model_name; + int model_id; + struct feature_table_entry* features; + unsigned long board_flags; +}; +static struct pmac_mb_def pmac_mb __pmacdata; + +/* + * Here are the chip specific feature functions + */ + +static inline int __pmac +simple_feature_tweak(struct device_node* node, int type, int reg, u32 mask, int value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, type); + if (!macio) + return -ENODEV; + LOCK(flags); + if (value) + MACIO_BIS(reg, mask); + else + MACIO_BIC(reg, mask); + (void)MACIO_IN32(reg); + UNLOCK(flags); + + return 0; +} + +static int __pmac +generic_scc_enable(struct device_node* node, u32 enable_mask, u32 reset_mask, + int param, int value) +{ + struct macio_chip* macio; + unsigned long chan_mask; + unsigned long fcr; + unsigned long flags; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (!strcmp(node->name, "ch-a")) + chan_mask = MACIO_FLAG_SCCA_ON; + else if (!strcmp(node->name, "ch-b")) + chan_mask = MACIO_FLAG_SCCB_ON; + else + return -ENODEV; + + if (value) { + LOCK(flags); + fcr = MACIO_IN32(OHARE_FCR); + /* Check if scc cell need enabling */ + if (!(fcr & OH_SCC_ENABLE)) { + fcr |= enable_mask; + MACIO_OUT32(OHARE_FCR, fcr); + fcr |= reset_mask; + MACIO_OUT32(OHARE_FCR, fcr); + UNLOCK(flags); + (void)MACIO_IN32(OHARE_FCR); + mdelay(15); + LOCK(flags); + fcr &= ~reset_mask; + MACIO_OUT32(OHARE_FCR, fcr); + } + if (chan_mask & MACIO_FLAG_SCCA_ON) + fcr |= OH_SCCA_IO; + if (chan_mask & MACIO_FLAG_SCCB_ON) + fcr |= OH_SCCB_IO; + MACIO_OUT32(OHARE_FCR, fcr); + macio->flags |= chan_mask; + UNLOCK(flags); + if (param & PMAC_SCC_FLAG_XMON) + macio->flags |= MACIO_FLAG_SCC_LOCKED; + } else { + if (macio->flags & MACIO_FLAG_SCC_LOCKED) + return -EPERM; + LOCK(flags); + fcr = MACIO_IN32(OHARE_FCR); + if (chan_mask & MACIO_FLAG_SCCA_ON) + fcr &= ~OH_SCCA_IO; + if (chan_mask & MACIO_FLAG_SCCB_ON) + fcr &= ~OH_SCCB_IO; + MACIO_OUT32(OHARE_FCR, fcr); + if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) { + fcr &= ~enable_mask; + MACIO_OUT32(OHARE_FCR, fcr); + } + macio->flags &= ~(chan_mask); + UNLOCK(flags); + mdelay(10); + } + return 0; +} + +static int __pmac +ohare_scc_enable(struct device_node* node, int param, int value) +{ + int rc; + +#ifdef CONFIG_ADB_PMU + if (value && (param & 0xfff) == PMAC_SCC_IRDA) + pmu_enable_irled(1); +#endif /* CONFIG_ADB_PMU */ + rc = generic_scc_enable(node, OH_SCC_ENABLE, OH_SCC_RESET, param, value); +#ifdef CONFIG_ADB_PMU + if ((param & 0xfff) == PMAC_SCC_IRDA && (rc || !value)) + pmu_enable_irled(0); +#endif /* CONFIG_ADB_PMU */ + return rc; +} + +static int __pmac +ohare_floppy_enable(struct device_node* node, int param, int value) +{ + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_FLOPPY_ENABLE, value); +} + +static int __pmac +ohare_mesh_enable(struct device_node* node, int param, int value) +{ + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_MESH_ENABLE, value); +} + +static int __pmac +ohare_ide_enable(struct device_node* node, int param, int value) +{ + switch(param) { + case 0: + /* For some reason, setting the bit in set_initial_features() + * doesn't stick. I'm still investigating... --BenH. + */ + if (value) + simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IOBUS_ENABLE, 1); + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IDE0_ENABLE, value); + case 1: + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_BAY_IDE_ENABLE, value); + default: + return -ENODEV; + } +} + +static int __pmac +ohare_ide_reset(struct device_node* node, int param, int value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IDE0_RESET_N, !value); + case 1: + return simple_feature_tweak(node, macio_ohare, + OHARE_FCR, OH_IDE1_RESET_N, !value); + default: + return -ENODEV; + } +} + +static int __pmac +ohare_sleep_state(struct device_node* node, int param, int value) +{ + struct macio_chip* macio = &macio_chips[0]; + + if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) + return -EPERM; + if (value) { + MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE); + } else { + MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); + } + + return 0; +} + +static int __pmac +heathrow_scc_enable(struct device_node* node, int param, int value) +{ + int rc; + +#ifdef CONFIG_ADB_PMU + if (value && param == PMAC_SCC_IRDA) + pmu_enable_irled(1); +#endif /* CONFIG_ADB_PMU */ + /* Fixme: It's possible that wallstreet (heathrow) is different + * than other paddington machines. I still have to figure that + * out exactly, for now, the paddington values are used + */ + rc = generic_scc_enable(node, HRW_SCC_ENABLE, PADD_RESET_SCC, param, value); +#ifdef CONFIG_ADB_PMU + if (param == PMAC_SCC_IRDA && (rc || !value)) + pmu_enable_irled(0); +#endif /* CONFIG_ADB_PMU */ + return rc; +} + +static int __pmac +heathrow_modem_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + macio = macio_find(node, macio_unknown); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1; + if (!value) { + LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + mdelay(250); + } + if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE && + pmac_mb.model_id != PMAC_TYPE_YIKES) { + LOCK(flags); + /* We use the paddington values as they seem to work properly + * on the wallstreet (heathrow) as well. I can't tell why we + * had to flip them on older feature.c, the fact is that new + * code uses the paddington values which are also the ones used + * in Darwin, and that works on wallstreet ! + */ + if (value) + MACIO_BIC(HEATHROW_FCR, PADD_MODEM_POWER_N); + else + MACIO_BIS(HEATHROW_FCR, PADD_MODEM_POWER_N); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + mdelay(250); + } + if (value) { + LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1); + (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + } + return 0; +} + +static int __pmac +heathrow_floppy_enable(struct device_node* node, int param, int value) +{ + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, + HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE, + value); +} + +static int __pmac +heathrow_mesh_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, macio_unknown); + if (!macio) + return -ENODEV; + LOCK(flags); + /* Set clear mesh cell enable */ + if (value) + MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE); + else + MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE); + (void)MACIO_IN32(HEATHROW_FCR); + udelay(10); + /* Set/Clear termination power (todo: test ! the bit value + * used by Darwin doesn't seem to match what we used so + * far. If you experience problems, turn #if 1 into #if 0 + * and tell me about it --BenH. + */ +#if 1 + if (value) + MACIO_BIC(HEATHROW_MBCR, 0x00000004); + else + MACIO_BIS(HEATHROW_MBCR, 0x00000004); +#else + if (value) + MACIO_BIC(HEATHROW_MBCR, 0x00040000); + else + MACIO_BIS(HEATHROW_MBCR, 0x00040000); +#endif + (void)MACIO_IN32(HEATHROW_MBCR); + udelay(10); + UNLOCK(flags); + + return 0; +} + +static int __pmac +heathrow_ide_enable(struct device_node* node, int param, int value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_IDE0_ENABLE, value); + case 1: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value); + default: + return -ENODEV; + } +} + +static int __pmac +heathrow_ide_reset(struct device_node* node, int param, int value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_IDE0_RESET_N, !value); + case 1: + return simple_feature_tweak(node, macio_unknown, + HEATHROW_FCR, HRW_IDE1_RESET_N, !value); + default: + return -ENODEV; + } +} + +static int __pmac +heathrow_bmac_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (value) { + LOCK(flags); + MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE); + MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + mdelay(10); + LOCK(flags); + MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + mdelay(10); + } else { + LOCK(flags); + MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE); + UNLOCK(flags); + } + return 0; +} + +static int __pmac +heathrow_sound_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + unsigned long flags; + + /* B&W G3 and Yikes don't support that properly (the + * sound appear to never come back after beeing shut down). + */ + if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE || + pmac_mb.model_id == PMAC_TYPE_YIKES) + return 0; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (value) { + LOCK(flags); + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); + UNLOCK(flags); + (void)MACIO_IN32(HEATHROW_FCR); + } else { + LOCK(flags); + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + UNLOCK(flags); + } + return 0; +} + +static u32 save_fcr[5] __pmacdata; +static u32 save_mbcr __pmacdata; +static u32 save_gpio_levels[2] __pmacdata; +static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata; +static u8 save_gpio_normal[KEYLARGO_GPIO_CNT] __pmacdata; +static u32 save_unin_clock_ctl __pmacdata; +static struct dbdma_regs save_dbdma[13] __pmacdata; +static struct dbdma_regs save_alt_dbdma[13] __pmacdata; + +static void __pmac +dbdma_save(struct macio_chip* macio, struct dbdma_regs* save) +{ + int i; + + /* Save state & config of DBDMA channels */ + for (i=0; i<13; i++) { + volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*) + (macio->base + ((0x8000+i*0x100)>>2)); + save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi); + save[i].cmdptr = in_le32(&chan->cmdptr); + save[i].intr_sel = in_le32(&chan->intr_sel); + save[i].br_sel = in_le32(&chan->br_sel); + save[i].wait_sel = in_le32(&chan->wait_sel); + } +} + +static void __pmac +dbdma_restore(struct macio_chip* macio, struct dbdma_regs* save) +{ + int i; + + /* Save state & config of DBDMA channels */ + for (i=0; i<13; i++) { + volatile struct dbdma_regs* chan = (volatile struct dbdma_regs*) + (macio->base + ((0x8000+i*0x100)>>2)); + out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16); + while (in_le32(&chan->status) & ACTIVE) + mb(); + out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi); + out_le32(&chan->cmdptr, save[i].cmdptr); + out_le32(&chan->intr_sel, save[i].intr_sel); + out_le32(&chan->br_sel, save[i].br_sel); + out_le32(&chan->wait_sel, save[i].wait_sel); + } +} + +static void __pmac +heathrow_sleep(struct macio_chip* macio, int secondary) +{ + if (secondary) { + dbdma_save(macio, save_alt_dbdma); + save_fcr[2] = MACIO_IN32(0x38); + save_fcr[3] = MACIO_IN32(0x3c); + } else { + dbdma_save(macio, save_dbdma); + save_fcr[0] = MACIO_IN32(0x38); + save_fcr[1] = MACIO_IN32(0x3c); + save_mbcr = MACIO_IN32(0x34); + /* Make sure sound is shut down */ + MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N); + MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE); + /* This seems to be necessary as well or the fan + * keeps coming up and battery drains fast */ + MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE); + } + /* Make sure modem is shut down */ + MACIO_OUT8(HRW_GPIO_MODEM_RESET, + MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1); + MACIO_BIS(HEATHROW_FCR, PADD_MODEM_POWER_N); + MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE); + + /* Let things settle */ + (void)MACIO_IN32(HEATHROW_FCR); + mdelay(1); +} + +static void __pmac +heathrow_wakeup(struct macio_chip* macio, int secondary) +{ + if (secondary) { + MACIO_OUT32(0x38, save_fcr[2]); + (void)MACIO_IN32(0x38); + mdelay(1); + MACIO_OUT32(0x3c, save_fcr[3]); + (void)MACIO_IN32(0x38); + mdelay(10); + dbdma_restore(macio, save_alt_dbdma); + } else { + MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE); + (void)MACIO_IN32(0x38); + mdelay(1); + MACIO_OUT32(0x3c, save_fcr[1]); + (void)MACIO_IN32(0x38); + mdelay(1); + MACIO_OUT32(0x34, save_mbcr); + (void)MACIO_IN32(0x38); + mdelay(10); + dbdma_restore(macio, save_dbdma); + } +} + +static int __pmac +heathrow_sleep_state(struct device_node* node, int param, int value) +{ + if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) + return -EPERM; + if (value == 1) { + if (macio_chips[1].type == macio_gatwick) + heathrow_sleep(&macio_chips[0], 1); + heathrow_sleep(&macio_chips[0], 0); + } else if (value == 0) { + heathrow_wakeup(&macio_chips[0], 0); + if (macio_chips[1].type == macio_gatwick) + heathrow_wakeup(&macio_chips[0], 1); + } + return 0; +} + +static int __pmac +core99_scc_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + unsigned long flags; + unsigned long chan_mask; + u32 fcr; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + if (!strcmp(node->name, "ch-a")) + chan_mask = MACIO_FLAG_SCCA_ON; + else if (!strcmp(node->name, "ch-b")) + chan_mask = MACIO_FLAG_SCCB_ON; + else + return -ENODEV; + + if (value) { + int need_reset_scc = 0; + int need_reset_irda = 0; + + LOCK(flags); + fcr = MACIO_IN32(KEYLARGO_FCR0); + /* Check if scc cell need enabling */ + if (!(fcr & KL0_SCC_CELL_ENABLE)) { + fcr |= KL0_SCC_CELL_ENABLE; + need_reset_scc = 1; + } + if (chan_mask & MACIO_FLAG_SCCA_ON) { + fcr |= KL0_SCCA_ENABLE; + /* Don't enable line drivers for I2S modem */ + if ((param & 0xfff) == PMAC_SCC_I2S1) + fcr &= ~KL0_SCC_A_INTF_ENABLE; + else + fcr |= KL0_SCC_A_INTF_ENABLE; + } + if (chan_mask & MACIO_FLAG_SCCB_ON) { + fcr |= KL0_SCCB_ENABLE; + /* Perform irda specific inits */ + if ((param & 0xfff) == PMAC_SCC_IRDA) { + fcr &= ~KL0_SCC_B_INTF_ENABLE; + fcr |= KL0_IRDA_ENABLE; + fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE; + fcr |= KL0_IRDA_SOURCE1_SEL; + fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0); + fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND); + need_reset_irda = 1; + } else + fcr |= KL0_SCC_B_INTF_ENABLE; + } + MACIO_OUT32(KEYLARGO_FCR0, fcr); + macio->flags |= chan_mask; + if (need_reset_scc) { + MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET); + (void)MACIO_IN32(KEYLARGO_FCR0); + UNLOCK(flags); + mdelay(15); + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET); + } + if (need_reset_irda) { + MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET); + (void)MACIO_IN32(KEYLARGO_FCR0); + UNLOCK(flags); + mdelay(15); + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET); + } + UNLOCK(flags); + if (param & PMAC_SCC_FLAG_XMON) + macio->flags |= MACIO_FLAG_SCC_LOCKED; + } else { + if (macio->flags & MACIO_FLAG_SCC_LOCKED) + return -EPERM; + LOCK(flags); + fcr = MACIO_IN32(KEYLARGO_FCR0); + if (chan_mask & MACIO_FLAG_SCCA_ON) + fcr &= ~KL0_SCCA_ENABLE; + if (chan_mask & MACIO_FLAG_SCCB_ON) { + fcr &= ~KL0_SCCB_ENABLE; + /* Perform irda specific clears */ + if ((param & 0xfff) == PMAC_SCC_IRDA) { + fcr &= ~KL0_IRDA_ENABLE; + fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE); + fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0); + fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND); + } + } + MACIO_OUT32(KEYLARGO_FCR0, fcr); + if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) { + fcr &= ~KL0_SCC_CELL_ENABLE; + MACIO_OUT32(KEYLARGO_FCR0, fcr); + } + macio->flags &= ~(chan_mask); + UNLOCK(flags); + mdelay(10); + } + return 0; +} + +static int __pmac +core99_modem_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(KL_GPIO_MODEM_RESET); + gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE; + gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA; + + if (!value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + mdelay(250); + } + LOCK(flags); + if (value) { + MACIO_BIC(KEYLARGO_FCR2, KL2_MODEM_POWER_N); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR2); + mdelay(250); + } else { + MACIO_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N); + UNLOCK(flags); + } + if (value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + } + return 0; +} + +static int __pmac +core99_ide_enable(struct device_node* node, int param, int value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value); + case 1: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value); + case 2: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_UIDE_ENABLE, value); + default: + return -ENODEV; + } +} + +static int __pmac +core99_ide_reset(struct device_node* node, int param, int value) +{ + switch(param) { + case 0: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value); + case 1: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value); + case 2: + return simple_feature_tweak(node, macio_unknown, + KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value); + default: + return -ENODEV; + } +} + +static int __pmac +core99_gmac_enable(struct device_node* node, int param, int value) +{ + unsigned long flags; + + LOCK(flags); + if (value) + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + else + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + (void)UN_IN(UNI_N_CLOCK_CNTL); + UNLOCK(flags); + udelay(20); + + return 0; +} + +static int __pmac +core99_gmac_phy_reset(struct device_node* node, int param, int value) +{ + unsigned long flags; + struct macio_chip* macio; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea) + return -ENODEV; + + LOCK(flags); + MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET); + UNLOCK(flags); + mdelay(10); + LOCK(flags); + MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE + | KEYLARGO_GPIO_OUTOUT_DATA); + UNLOCK(flags); + mdelay(10); + + return 0; +} + +static int __pmac +core99_sound_chip_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + unsigned long flags; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + + /* Do a better probe code, screamer G4 desktops & + * iMacs can do that too, add a recalibrate in + * the driver as well + */ + if (pmac_mb.model_id == PMAC_TYPE_PISMO || + pmac_mb.model_id == PMAC_TYPE_TITANIUM) { + LOCK(flags); + if (value) + MACIO_OUT8(KL_GPIO_SOUND_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE | + KEYLARGO_GPIO_OUTOUT_DATA); + else + MACIO_OUT8(KL_GPIO_SOUND_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(KL_GPIO_SOUND_POWER); + UNLOCK(flags); + } + return 0; +} + +static int __pmac +core99_airport_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + unsigned long flags; + int state; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + + /* Hint: we allow passing of macio itself for the sake of the + * sleep code + */ + if (node != macio->of_node && + (!node->parent || node->parent != macio->of_node)) + return -ENODEV; + state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0; + if (value == state) + return 0; + if (value) { + /* This code is a reproduction of OF enable-cardslot + * and init-wireless methods, slightly hacked until + * I got it working. + */ + LOCK(flags); + MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf); + UNLOCK(flags); + mdelay(10); + LOCK(flags); + MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf); + UNLOCK(flags); + + mdelay(10); + + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N); + (void)MACIO_IN32(KEYLARGO_FCR2); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0); + (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xd); + udelay(10); + MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28); + (void)MACIO_IN8(KEYLARGO_GPIO_0+0xe); + UNLOCK(flags); + udelay(10); + MACIO_OUT32(0x1c000, 0); + mdelay(1); + MACIO_OUT8(0x1a3e0, 0x41); + (void)MACIO_IN8(0x1a3e0); + udelay(10); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N); + (void)MACIO_IN32(KEYLARGO_FCR2); + UNLOCK(flags); + mdelay(100); + + macio->flags |= MACIO_FLAG_AIRPORT_ON; + } else { + LOCK(flags); + MACIO_BIC(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N); + (void)MACIO_IN32(KEYLARGO_FCR2); + MACIO_OUT8(KL_GPIO_AIRPORT_0, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_1, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_2, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_3, 0); + MACIO_OUT8(KL_GPIO_AIRPORT_4, 0); + (void)MACIO_IN8(KL_GPIO_AIRPORT_4); + UNLOCK(flags); + + macio->flags &= ~MACIO_FLAG_AIRPORT_ON; + } + return 0; +} + +#ifdef CONFIG_SMP +static int __pmac +core99_reset_cpu(struct device_node* node, int param, int value) +{ + const int reset_lines[] = { KL_GPIO_RESET_CPU0, + KL_GPIO_RESET_CPU1, + KL_GPIO_RESET_CPU2, + KL_GPIO_RESET_CPU3 }; + int reset_io; + unsigned long flags; + struct macio_chip* macio; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea) + return -ENODEV; + if (param > 3 || param < 0) + return -ENODEV; + + reset_io = reset_lines[param]; + + LOCK(flags); + MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); + (void)MACIO_IN8(reset_io); + udelay(1); + MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(reset_io); + UNLOCK(flags); + + return 0; +} +#endif /* CONFIG_SMP */ + +static int __pmac +core99_usb_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + unsigned long flags; + char* prop; + int number; + u32 reg; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea) + return -ENODEV; + + prop = (char *)get_property(node, "AAPL,clock-id", NULL); + if (!prop) + return -ENODEV; + if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0) + number = 0; + else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0) + number = 2; + else + return -ENODEV; + + /* Sorry for the brute-force locking, but this is only used during + * sleep and the timing seem to be critical + */ + LOCK(flags); + if (value) { + /* Turn ON */ + if (number == 0) { + MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR0); + UNLOCK(flags); + mdelay(1); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + } else { + MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR0); + mdelay(1); + LOCK(flags); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + } + reg = MACIO_IN32(KEYLARGO_FCR4); + reg &= ~(KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | + KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number)); + reg &= ~(KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | + KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1)); + MACIO_OUT32(KEYLARGO_FCR4, reg); + (void)MACIO_IN32(KEYLARGO_FCR4); + udelay(10); + } else { + /* Turn OFF */ + reg = MACIO_IN32(KEYLARGO_FCR4); + reg |= KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | + KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number); + reg |= KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | + KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1); + MACIO_OUT32(KEYLARGO_FCR4, reg); + (void)MACIO_IN32(KEYLARGO_FCR4); + udelay(1); + if (number == 0) { + MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + (void)MACIO_IN32(KEYLARGO_FCR0); + udelay(1); + MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR0); + } else { + MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + (void)MACIO_IN32(KEYLARGO_FCR0); + udelay(1); + MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + (void)MACIO_IN32(KEYLARGO_FCR0); + } + udelay(1); + } + UNLOCK(flags); + + return 0; +} + +static int __pmac +core99_firewire_enable(struct device_node* node, int param, int value) +{ + unsigned long flags; + struct macio_chip* macio; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea) + return -ENODEV; + if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED)) + return -ENODEV; + + LOCK(flags); + if (value) { + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); + (void)UN_IN(UNI_N_CLOCK_CNTL); + } else { + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW); + (void)UN_IN(UNI_N_CLOCK_CNTL); + } + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static int __pmac +core99_firewire_cable_power(struct device_node* node, int param, int value) +{ + unsigned long flags; + struct macio_chip* macio; + + /* Trick: we allow NULL node */ + if (pmac_mb.model_id != PMAC_TYPE_FW_IBOOK && + pmac_mb.model_id != PMAC_TYPE_PISMO && + pmac_mb.model_id != PMAC_TYPE_IBOOK2) + return -ENODEV; + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea) + return -ENODEV; + if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED)) + return -ENODEV; + + LOCK(flags); + if (value) { + MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0); + MACIO_IN8(KL_GPIO_FW_CABLE_POWER); + udelay(10); + } else { + MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4); + MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10); + } + UNLOCK(flags); + mdelay(1); + + return 0; +} + +static int __pmac +core99_read_gpio(struct device_node* node, int param, int value) +{ + struct macio_chip* macio = &macio_chips[0]; + + return MACIO_IN8(param); +} + + +static int __pmac +core99_write_gpio(struct device_node* node, int param, int value) +{ + struct macio_chip* macio = &macio_chips[0]; + + MACIO_OUT8(param, (u8)(value & 0xff)); + return 0; +} + +static void __pmac +keylargo_shutdown(struct macio_chip* macio, int restart) +{ + u32 temp; + + mdelay(1); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND); + (void)MACIO_IN32(KEYLARGO_FCR0); + mdelay(100); + + MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | + KL0_IRDA_CLK19_ENABLE); + + (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); + MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); + (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + + MACIO_BIC(KEYLARGO_FCR1, + KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | + KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | + KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N | + KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N | + KL1_UIDE_ENABLE); + (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10); + + MACIO_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N); + udelay(10); + MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE); + udelay(10); + temp = MACIO_IN32(KEYLARGO_FCR3); + if (macio->rev >= 2) + temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL); + + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12; + temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE + | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + MACIO_OUT32(KEYLARGO_FCR3, temp); + (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); +} + +static void __pmac +pangea_shutdown(struct macio_chip* macio, int restart) +{ + u32 temp; + + MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE); + + (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); + MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); + (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + + MACIO_BIC(KEYLARGO_FCR1, + KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | + KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | + KL1_UIDE_ENABLE); + (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10); + + MACIO_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N); + udelay(10); + temp = MACIO_IN32(KEYLARGO_FCR3); + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35; + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE + | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + MACIO_OUT32(KEYLARGO_FCR3, temp); + (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); +} + +static int __pmac +core99_sleep(void) +{ + struct macio_chip* macio; + int i; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea) + return -ENODEV; + + /* We power off the wireless slot in case it was not done + * by the driver. We don't power it on automatically however + */ + if (macio->flags & MACIO_FLAG_AIRPORT_ON) + core99_airport_enable(macio->of_node, 0, 0); + + /* We power off the FW cable. Should be done by the driver... */ + if (macio->flags & MACIO_FLAG_FW_SUPPORTED) { + core99_firewire_enable(NULL, 0, 0); + core99_firewire_cable_power(NULL, 0, 0); + } + + /* We make sure int. modem is off (in case driver lost it) */ + core99_modem_enable(macio->of_node, 0, 0); + /* We make sure the sound is off as well */ + core99_sound_chip_enable(macio->of_node, 0, 0); + + /* + * Save various bits of KeyLargo + */ + + /* Save the state of the various GPIOs */ + save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0); + save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1); + for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++) + save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i); + for (i=0; i<KEYLARGO_GPIO_CNT; i++) + save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i); + + /* Save the FCRs */ + save_mbcr = MACIO_IN32(KEYLARGO_MBCR); + save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0); + save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1); + save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2); + save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3); + save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4); + + /* Save state & config of DBDMA channels */ + dbdma_save(macio, save_dbdma); + + /* + * Turn off as much as we can + */ + if (macio->type == macio_pangea) + pangea_shutdown(macio, 0); + else if (macio->type == macio_keylargo) + keylargo_shutdown(macio, 0); + + /* + * Put the host bridge to sleep + */ + + save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL); + UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl & + ~(UNI_N_CLOCK_CNTL_GMAC|UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/)); + udelay(100); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING); + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP); + + /* + * FIXME: A bit of black magic with OpenPIC (don't ask me why) + */ + if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) { + MACIO_BIS(0x506e0, 0x00400000); + MACIO_BIS(0x506e0, 0x80000000); + } + return 0; +} + +static int __pmac +core99_wake_up(void) +{ + struct macio_chip* macio; + int i; + + macio = &macio_chips[0]; + if (macio->type != macio_keylargo && macio->type != macio_pangea) + return -ENODEV; + + /* + * Wakeup the host bridge + */ + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL); + udelay(10); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING); + udelay(10); + + /* + * Restore KeyLargo + */ + + MACIO_OUT32(KEYLARGO_MBCR, save_mbcr); + (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]); + (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); + MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]); + (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10); + MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]); + (void)MACIO_IN32(KEYLARGO_FCR2); udelay(10); + MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]); + (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); + MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]); + (void)MACIO_IN32(KEYLARGO_FCR4); udelay(10); + + dbdma_restore(macio, save_dbdma); + + MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]); + MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]); + for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++) + MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]); + for (i=0; i<KEYLARGO_GPIO_CNT; i++) + MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]); + + /* FIXME more black magic with OpenPIC ... */ + if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) { + MACIO_BIC(0x506e0, 0x00400000); + MACIO_BIC(0x506e0, 0x80000000); + } + + UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl); + udelay(100); + + return 0; +} + +static int __pmac +core99_sleep_state(struct device_node* node, int param, int value) +{ + if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) + return -EPERM; + if (value == 1) + return core99_sleep(); + else if (value == 0) + return core99_wake_up(); + return 0; +} + +static int __pmac +pangea_modem_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(KL_GPIO_MODEM_RESET); + gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE; + gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA; + + if (!value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + mdelay(250); + } + LOCK(flags); + if (value) { + MACIO_OUT8(KL_GPIO_MODEM_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR2); + mdelay(250); + } else { + MACIO_OUT8(KL_GPIO_MODEM_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); + UNLOCK(flags); + } + if (value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + } + return 0; +} + + +static int __pmac +generic_get_mb_info(struct device_node* node, int param, int value) +{ + switch(param) { + case PMAC_MB_INFO_MODEL: + return pmac_mb.model_id; + case PMAC_MB_INFO_FLAGS: + return pmac_mb.board_flags; + case PMAC_MB_INFO_NAME: + /* hack hack hack... but should work */ + return (int)pmac_mb.model_name; + } + return 0; +} + + +/* + * Table definitions + */ + +/* Used on any machine + */ +static struct feature_table_entry any_features[] __pmacdata = { + { PMAC_FTR_GET_MB_INFO, generic_get_mb_info }, + { 0, NULL } +}; + +/* OHare based motherboards. Currently, we only use these on the + * 2400,3400 and 3500 series powerbooks. Some older desktops seem + * to have issues with turning on/off those asic cells + */ +static struct feature_table_entry ohare_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, ohare_scc_enable }, + { PMAC_FTR_SWIM3_ENABLE, ohare_floppy_enable }, + { PMAC_FTR_MESH_ENABLE, ohare_mesh_enable }, + { PMAC_FTR_IDE_ENABLE, ohare_ide_enable}, + { PMAC_FTR_IDE_RESET, ohare_ide_reset}, + { PMAC_FTR_SLEEP_STATE, ohare_sleep_state }, + { 0, NULL } +}; + +/* Heathrow desktop machines (Beige G3). + * Separated as some features couldn't be properly tested + * and the serial port control bits appear to confuse it. + */ +static struct feature_table_entry heathrow_desktop_features[] __pmacdata = { + { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, + { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable }, + { PMAC_FTR_IDE_ENABLE, heathrow_ide_enable }, + { PMAC_FTR_IDE_RESET, heathrow_ide_reset }, + { PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable }, + { 0, NULL } +}; + +/* Heathrow based laptop, that is the Wallstreet and mainstreet + * powerbooks. + */ +static struct feature_table_entry heathrow_laptop_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, heathrow_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable }, + { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, + { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable }, + { PMAC_FTR_IDE_ENABLE, heathrow_ide_enable }, + { PMAC_FTR_IDE_RESET, heathrow_ide_reset }, + { PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable }, + { PMAC_FTR_SOUND_CHIP_ENABLE, heathrow_sound_enable }, + { PMAC_FTR_SLEEP_STATE, heathrow_sleep_state }, + { 0, NULL } +}; + +/* Paddington based machines + * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4. + */ +static struct feature_table_entry paddington_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, heathrow_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable }, + { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable }, + { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable }, + { PMAC_FTR_IDE_ENABLE, heathrow_ide_enable }, + { PMAC_FTR_IDE_RESET, heathrow_ide_reset }, + { PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable }, + { PMAC_FTR_SOUND_CHIP_ENABLE, heathrow_sound_enable }, + { PMAC_FTR_SLEEP_STATE, heathrow_sleep_state }, + { 0, NULL } +}; + +/* Core99 & MacRISC 2 machines (all machines released since the + * iBook (included), that is all AGP machines, except pangea + * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo + * used on iBook2 & iMac "flow power". + */ +static struct feature_table_entry core99_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, core99_modem_enable }, + { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, + { PMAC_FTR_IDE_RESET, core99_ide_reset }, + { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable }, + { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset }, + { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable }, + { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable }, + { PMAC_FTR_USB_ENABLE, core99_usb_enable }, + { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, + { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, + { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, +#ifdef CONFIG_SMP + { PMAC_FTR_RESET_CPU, core99_reset_cpu }, +#endif /* CONFIG_SMP */ + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { 0, NULL } +}; + +/* Pangea features + */ +static struct feature_table_entry pangea_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, pangea_modem_enable }, + { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, + { PMAC_FTR_IDE_RESET, core99_ide_reset }, + { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable }, + { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset }, + { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable }, + { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable }, + { PMAC_FTR_USB_ENABLE, core99_usb_enable }, + { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, + { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, + { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { 0, NULL } +}; + +static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { + /* Warning: ordering is important as some models may claim + * beeing compatible with several types + */ + { "AAPL,8500", "PowerMac 8500/8600", + PMAC_TYPE_PSURGE, NULL, + 0 + }, + { "AAPL,9500", "PowerMac 9500/9600", + PMAC_TYPE_PSURGE, NULL, + 0 + }, + { "AAPL,7500", "PowerMac 7500", + PMAC_TYPE_PSURGE, NULL, + 0 + }, + { "AAPL,e407", "Alchemy", + PMAC_TYPE_ALCHEMY, NULL, + 0 + }, + { "AAPL,e411", "Gazelle", + PMAC_TYPE_GAZELLE, NULL, + 0 + }, + { "AAPL,3400/2400", "PowerBook 3400", + PMAC_TYPE_HOOPER, ohare_features, + PMAC_MB_CAN_SLEEP + }, + { "AAPL,3500", "PowerBook 3500", + PMAC_TYPE_KANGA, ohare_features, + PMAC_MB_CAN_SLEEP + }, + { "AAPL,Gossamer", "PowerMac G3 (Gossamer)", + PMAC_TYPE_GOSSAMER, heathrow_desktop_features, + 0 + }, + { "AAPL,PowerMac G3", "PowerMac G3 (Silk)", + PMAC_TYPE_SILK, heathrow_desktop_features, + 0 + }, + { "AAPL,PowerBook1998", "PowerBook Wallstreet", + PMAC_TYPE_WALLSTREET, heathrow_laptop_features, + PMAC_MB_CAN_SLEEP + }, + { "AAPL,PowerBook1,1", "PowerBook 101 (Lombard)", + PMAC_TYPE_101_PBOOK, paddington_features, + PMAC_MB_CAN_SLEEP + }, + { "iMac,1", "iMac (first generation)", + PMAC_TYPE_ORIG_IMAC, paddington_features, + 0 + }, + { "PowerMac4,1", "iMac \"Flower Power\"", + PMAC_TYPE_PANGEA_IMAC, pangea_features, + PMAC_MB_CAN_SLEEP + }, + { "PowerBook4,1", "iBook 2", + PMAC_TYPE_IBOOK2, pangea_features, + PMAC_MB_CAN_SLEEP + }, + { "PowerMac1,1", "Blue&White G3", + PMAC_TYPE_YOSEMITE, paddington_features, + 0 + }, + { "PowerMac1,2", "PowerMac G4 PCI Graphics", + PMAC_TYPE_YIKES, paddington_features, + 0 + }, + { "PowerBook2,1", "iBook (first generation)", + PMAC_TYPE_ORIG_IBOOK, core99_features, + PMAC_MB_CAN_SLEEP + }, + { "PowerMac3,1", "PowerMac G4 AGP Graphics", + PMAC_TYPE_SAWTOOTH, core99_features, + 0 + }, + { "PowerMac3,2", "PowerMac G4 AGP Graphics", + PMAC_TYPE_SAWTOOTH, core99_features, + 0 + }, + { "PowerMac3,3", "PowerMac G4 AGP Graphics", + PMAC_TYPE_SAWTOOTH, core99_features, + 0 + }, + { "PowerMac2,1", "iMac FireWire", + PMAC_TYPE_FW_IMAC, core99_features, + PMAC_MB_CAN_SLEEP + }, + { "PowerMac2,2", "iMac FireWire", + PMAC_TYPE_FW_IMAC, core99_features, + PMAC_MB_CAN_SLEEP + }, + { "PowerBook2,2", "iBook FireWire", + PMAC_TYPE_FW_IBOOK, core99_features, + PMAC_MB_CAN_SLEEP + }, + { "PowerMac5,1", "PowerMac G4 Cube", + PMAC_TYPE_CUBE, core99_features, + }, + { "PowerMac3,4", "PowerMac G4 Silver", + PMAC_TYPE_QUICKSILVER, core99_features, + 0 + }, + { "PowerMac3,5", "PowerMac G4 Silver", + PMAC_TYPE_QUICKSILVER, core99_features, + 0 + }, + { "PowerBook3,1", "PowerBook Pismo", + PMAC_TYPE_PISMO, core99_features, + PMAC_MB_CAN_SLEEP + }, + { "PowerBook3,2", "PowerBook Titanium", + PMAC_TYPE_TITANIUM, core99_features, + PMAC_MB_CAN_SLEEP + }, + { "PowerBook3,3", "PowerBook Titanium II", + PMAC_TYPE_TITANIUM2, core99_features, + PMAC_MB_CAN_SLEEP + }, +}; + +/* + * The toplevel feature_call callback + */ +int __pmac +pmac_do_feature_call(unsigned int selector, ...) +{ + struct device_node* node; + int param, value, i; + feature_call func = NULL; + va_list args; + + if (!pmac_mb.features) + return -ENODEV; + for (i=0; pmac_mb.features[i].function; i++) + if (pmac_mb.features[i].selector == selector) { + func = pmac_mb.features[i].function; + break; + } + if (!func) + for (i=0; any_features[i].function; i++) + if (any_features[i].selector == selector) { + func = any_features[i].function; + break; + } + if (!func) + return -ENODEV; + + va_start(args, selector); + node = (struct device_node*)va_arg(args, void*); + param = va_arg(args, int); + value = va_arg(args, int); + va_end(args); + + return func(node, param, value); +} + +static int __init +probe_motherboard(void) +{ + int i; + struct macio_chip* macio = &macio_chips[0]; + + /* Lookup known motherboard type in device-tree */ + for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { + if (machine_is_compatible(pmac_mb_defs[i].model_string)) { + pmac_mb = pmac_mb_defs[i]; + goto found; + } + } + + /* Fallback to selection depending on mac-io chip type */ + switch(macio->type) { + case macio_grand_central: + pmac_mb.model_id = PMAC_TYPE_PSURGE; + pmac_mb.model_name = "Unknown PowerSurge"; + break; + case macio_ohare: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE; + pmac_mb.model_name = "Unknown OHare-based"; + break; + case macio_heathrow: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW; + pmac_mb.model_name = "Unknown Heathrow-based"; + pmac_mb.features = heathrow_desktop_features; + break; + case macio_paddington: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON; + pmac_mb.model_name = "Unknown Paddington-based"; + pmac_mb.features = paddington_features; + break; + case macio_keylargo: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99; + pmac_mb.model_name = "Unknown Keylargo-based"; + pmac_mb.features = core99_features; + break; + case macio_pangea: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA; + pmac_mb.model_name = "Unknown Pangea-based"; + pmac_mb.features = pangea_features; + break; + default: + return -ENODEV; + } +found: + /* Fixup Hooper vs. Comet */ + if (pmac_mb.model_id == PMAC_TYPE_HOOPER) { + u32* mach_id_ptr = (u32*)ioremap(0xf3000034, 4); + if (!mach_id_ptr) + return -ENODEV; + /* Here, I used to disable the media-bay on comet. It + * appears this is wrong, the floppy connector is actually + * a kind of media-bay and works with the current driver. + */ + if ((*mach_id_ptr) & 0x20000000UL) + pmac_mb.model_id = PMAC_TYPE_COMET; + iounmap(mach_id_ptr); + } + + /* Set default value of powersave_nap on machines that support it. + * It appears that uninorth rev 3 has a problem with it, we don't + * enable it on those. In theory, the flush-on-lock property is + * supposed to be set when not supported, but I'm not very confident + * that all Apple OF revs did it properly, I do it the paranoid way. + */ + while (uninorth_base && uninorth_rev > 3) { + struct device_node* np = find_path_device("/cpus"); + u32 pvr = mfspr(PVR); + if (!np || !np->child) { + printk(KERN_WARNING "Can't find CPU(s) in device tree !\n"); + break; + } + np = np->child; + /* Nap mode not supported on SMP */ + if (np->sibling) + break; + /* Nap mode not supported if flush-on-lock property is present */ + if (get_property(np, "flush-on-lock", NULL)) + break; + /* Some 7450 may have problem with NAP mode too ... */ + if (((pvr >> 16) == 0x8000) && ((pvr & 0xffff) < 0x0201)) + break; + powersave_nap = 1; + printk(KERN_INFO "Processor NAP mode on idle enabled.\n"); + break; + } + + printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); + return 0; +} + +/* Initialize the Core99 UniNorth host bridge and memory controller + */ +static void __init +probe_uninorth(void) +{ + unsigned long actrl; + + /* Locate core99 Uni-N */ + uninorth_node = find_devices("uni-n"); + if (uninorth_node && uninorth_node->n_addrs > 0) { + uninorth_base = ioremap(uninorth_node->addrs[0].address, 0x1000); + uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); + } else + uninorth_node = NULL; + + if (!uninorth_node) + return; + + printk(KERN_INFO "Found Uninorth memory controller & host bridge, revision: %d\n", + uninorth_rev); + + /* Set the arbitrer QAck delay according to what Apple does + */ + if (uninorth_rev < 0x10) { + actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; + actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : + UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; + UN_OUT(UNI_N_ARB_CTRL, actrl); + } +} + +static void __init +probe_one_macio(const char* name, const char* compat, int type) +{ + struct device_node* node; + int i; + volatile u32* base; + u32* revp; + + node = find_devices(name); + if (!node || !node->n_addrs) + return; + if (compat) + do { + if (device_is_compatible(node, compat)) + break; + node = node->next; + } while (node); + if (!node) + return; + for(i=0; i<MAX_MACIO_CHIPS; i++) { + if (!macio_chips[i].of_node) + break; + if (macio_chips[i].of_node == node) + return; + } + if (i >= MAX_MACIO_CHIPS) { + printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); + printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); + return; + } + base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size); + if (!base) { + printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); + return; + } + if (type == macio_keylargo) { + u32* did = (u32 *)get_property(node, "device-id", NULL); + if (*did == 0x00000025) + type = macio_pangea; + } + macio_chips[i].of_node = node; + macio_chips[i].type = type; + macio_chips[i].base = base; + macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; + revp = (u32 *)get_property(node, "revision-id", NULL); + if (revp) + macio_chips[i].rev = *revp; + printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n", + macio_names[type], macio_chips[i].rev, macio_chips[i].base); +} + +static int __init +probe_macios(void) +{ + /* Warning, ordering is important */ + probe_one_macio("gc", NULL, macio_grand_central); + probe_one_macio("ohare", NULL, macio_ohare); + probe_one_macio("pci106b,7", NULL, macio_ohareII); + probe_one_macio("mac-io", "keylargo", macio_keylargo); + probe_one_macio("mac-io", "paddington", macio_paddington); + probe_one_macio("mac-io", "gatwick", macio_gatwick); + probe_one_macio("mac-io", "heathrow", macio_heathrow); + + /* Make sure the "main" macio chip appear first */ + if (macio_chips[0].type == macio_gatwick + && macio_chips[1].type == macio_heathrow) { + struct macio_chip temp = macio_chips[0]; + macio_chips[0] = macio_chips[1]; + macio_chips[1] = temp; + } + if (macio_chips[0].type == macio_ohareII + && macio_chips[1].type == macio_ohare) { + struct macio_chip temp = macio_chips[0]; + macio_chips[0] = macio_chips[1]; + macio_chips[1] = temp; + } + + return (macio_chips[0].of_node == NULL) ? -ENODEV : 0; +} + +static void __init +set_initial_features(void) +{ + struct device_node* np; + + /* That hack appears to be necessary for some StarMax motherboards + * but I'm not too sure it was audited for side-effects on other + * ohare based machines... + * Since I still have difficulties figuring the right way to + * differenciate them all and since that hack was there for a long + * time, I'll keep it around + */ + if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) { + struct macio_chip* macio = &macio_chips[0]; + MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES); + } else if (macio_chips[0].type == macio_ohare) { + struct macio_chip* macio = &macio_chips[0]; + MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); + } else if (macio_chips[1].type == macio_ohare) { + struct macio_chip* macio = &macio_chips[1]; + MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); + } + + if (macio_chips[0].type == macio_keylargo || + macio_chips[0].type == macio_pangea) { + /* Enable GMAC for now for PCI probing. It will be disabled + * later on after PCI probe + */ + np = find_devices("ethernet"); + while(np) { + if (np && device_is_compatible(np, "gmac")) + core99_gmac_enable(np, 0, 1); + np = np->next; + } + + /* Enable FW before PCI probe. Will be disabled later on + */ + np = find_devices("firewire"); + while(np) { + if (device_is_compatible(np, "pci106b,18") || + device_is_compatible(np, "pci106b,30")) { + macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; + core99_firewire_enable(np, 0, 1); + } + np = np->next; + } + + /* Switch airport off */ + np = find_devices("radio"); + while(np) { + if (np && np->parent == macio_chips[0].of_node) { + macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON; + core99_airport_enable(np, 0, 0); + } + np = np->next; + } + } + + /* On all machines, switch sound off */ + if (macio_chips[0].of_node) + pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, + macio_chips[0].of_node, 0, 0); + + /* Let hardware settle down */ + mdelay(1); +} + +void __init +pmac_feature_init(void) +{ + /* Detect the UniNorth memory controller */ + probe_uninorth(); + + /* Probe mac-io controllers */ + if (probe_macios()) { + printk(KERN_WARNING "No mac-io chip found\n"); + return; + } + + /* Probe machine type */ + if (probe_motherboard()) + printk(KERN_WARNING "Unknown PowerMac !\n"); + + /* Set some initial features (turn off some chips that will + * be later turned on) + */ + set_initial_features(); +} + +void __init +pmac_feature_late_init(void) +{ + struct device_node* np; + + /* Request some resources late */ + if (uninorth_node) + request_OF_resource(uninorth_node, 0, NULL); + np = find_devices("hammerhead"); + if (np) + request_OF_resource(np, 0, NULL); + np = find_devices("interrupt-controller"); + if (np) + request_OF_resource(np, 0, NULL); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/pmac_nvram.c linux-2.5/arch/ppc/kernel/pmac_nvram.c --- linux-2.5.1/arch/ppc/kernel/pmac_nvram.c Sat Sep 8 19:38:41 2001 +++ linux-2.5/arch/ppc/kernel/pmac_nvram.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_nvram.c 1.15 09/08/01 15:47:42 paulus + * BK Id: SCCS/s.pmac_nvram.c 1.17 12/01/01 20:09:06 benh */ /* * Miscellaneous procedures for dealing with the PowerMac hardware. @@ -326,7 +326,7 @@ break; while (!req.complete) pmu_poll(); - return req.reply[1]; + return req.reply[0]; } #endif case 1: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/pmac_pci.c linux-2.5/arch/ppc/kernel/pmac_pci.c --- linux-2.5.1/arch/ppc/kernel/pmac_pci.c Sat Sep 8 19:38:41 2001 +++ linux-2.5/arch/ppc/kernel/pmac_pci.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_pci.c 1.27 09/08/01 15:47:42 paulus + * BK Id: SCCS/s.pmac_pci.c 1.29 12/01/01 20:09:06 benh */ /* * Support for PCI bridges found on Power Macintoshes. @@ -27,7 +27,7 @@ #include <asm/prom.h> #include <asm/pci-bridge.h> #include <asm/machdep.h> -#include <asm/feature.h> +#include <asm/pmac_feature.h> #include "pci.h" @@ -545,13 +545,13 @@ if (node && !strcmp(node->name, "firewire") && (device_is_compatible(node, "pci106b,18") || device_is_compatible(node, "pci106b,30"))) { - feature_set_firewire_cable_power(node, 1); - feature_set_firewire_power(node, 1); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1); + pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1); updatecfg = 1; } if (node && !strcmp(node->name, "ethernet") && device_is_compatible(node, "gmac")) { - feature_set_gmac_power(node, 1); + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1); updatecfg = 1; } @@ -610,8 +610,8 @@ if (nd->parent && (device_is_compatible(nd, "pci106b,18") || device_is_compatible(nd, "pci106b,30")) && device_is_compatible(nd->parent, "uni-north")) { - feature_set_firewire_power(nd, 0); - feature_set_firewire_cable_power(nd, 0); + pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0); } nd = nd->next; } @@ -619,7 +619,7 @@ while (nd) { if (nd->parent && device_is_compatible(nd, "gmac") && device_is_compatible(nd->parent, "uni-north")) - feature_set_gmac_power(nd, 0); + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0); nd = nd->next; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/pmac_pic.c linux-2.5/arch/ppc/kernel/pmac_pic.c --- linux-2.5.1/arch/ppc/kernel/pmac_pic.c Mon Dec 10 21:52:53 2001 +++ linux-2.5/arch/ppc/kernel/pmac_pic.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_pic.c 1.20 09/08/01 15:47:42 paulus + * BK Id: SCCS/s.pmac_pic.c 1.24 12/19/01 10:53:01 paulus */ #include <linux/config.h> #include <linux/stddef.h> @@ -18,44 +18,52 @@ #include "pmac_pic.h" #include "open_pic.h" -/* pmac */struct pmac_irq_hw { - unsigned int flag; +struct pmac_irq_hw { + unsigned int event; unsigned int enable; unsigned int ack; unsigned int level; }; -/* XXX these addresses should be obtained from the device tree */ -static volatile struct pmac_irq_hw *pmac_irq_hw[4] = { +/* Default addresses */ +static volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmacdata = { (struct pmac_irq_hw *) 0xf3000020, (struct pmac_irq_hw *) 0xf3000010, (struct pmac_irq_hw *) 0xf4000020, (struct pmac_irq_hw *) 0xf4000010, }; -static int max_irqs; -static int max_real_irqs; +#define GC_LEVEL_MASK 0x3ff00000 +#define OHARE_LEVEL_MASK 0x1ff00000 +#define HEATHROW_LEVEL_MASK 0x1ff00000 + +static int max_irqs __pmacdata; +static int max_real_irqs __pmacdata; +static u32 level_mask[4] __pmacdata; -static spinlock_t pmac_pic_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t pmac_pic_lock __pmacdata = SPIN_LOCK_UNLOCKED; #define GATWICK_IRQ_POOL_SIZE 10 -static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; +static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE] __pmacdata; /* * Mark an irq as "lost". This is only used on the pmac * since it can lose interrupts (see pmac_set_irq_mask). * -- Cort */ -void __pmac __set_lost(unsigned long irq_nr) +void __pmac +__set_lost(unsigned long irq_nr, int nokick) { if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { atomic_inc(&ppc_n_lost_interrupts); - set_dec(1); + if (!nokick) + set_dec(1); } } -static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr) +static void __pmac +pmac_mask_and_ack_irq(unsigned int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; @@ -68,18 +76,18 @@ if (test_and_clear_bit(irq_nr, ppc_lost_interrupts)) atomic_dec(&ppc_n_lost_interrupts); spin_lock_irqsave(&pmac_pic_lock, flags); - out_le32(&pmac_irq_hw[i]->ack, bit); out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); out_le32(&pmac_irq_hw[i]->ack, bit); do { /* make sure ack gets to controller before we enable interrupts */ mb(); - } while(in_le32(&pmac_irq_hw[i]->flag) & bit); + } while((in_le32(&pmac_irq_hw[i]->enable) & bit) + != (ppc_cached_irq_mask[i] & bit)); spin_unlock_irqrestore(&pmac_pic_lock, flags); } -static void __pmac pmac_set_irq_mask(unsigned int irq_nr) +static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; @@ -104,31 +112,29 @@ * when the device interrupt is already on *doesn't* set * the bit in the flag register or request another interrupt. */ - if ((bit & ppc_cached_irq_mask[i]) - && (ld_le32(&pmac_irq_hw[i]->level) & bit) - && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) - __set_lost((ulong)irq_nr); + if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level)) + __set_lost((ulong)irq_nr, nokicklost); spin_unlock_irqrestore(&pmac_pic_lock, flags); } static void __pmac pmac_mask_irq(unsigned int irq_nr) { clear_bit(irq_nr, ppc_cached_irq_mask); - pmac_set_irq_mask(irq_nr); + pmac_set_irq_mask(irq_nr, 0); mb(); } static void __pmac pmac_unmask_irq(unsigned int irq_nr) { set_bit(irq_nr, ppc_cached_irq_mask); - pmac_set_irq_mask(irq_nr); + pmac_set_irq_mask(irq_nr, 0); } static void __pmac pmac_end_irq(unsigned int irq_nr) { if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { set_bit(irq_nr, ppc_cached_irq_mask); - pmac_set_irq_mask(irq_nr); + pmac_set_irq_mask(irq_nr, 1); } } @@ -161,8 +167,10 @@ for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { int i = irq >> 5; - bits = ld_le32(&pmac_irq_hw[i]->flag) - | ppc_lost_interrupts[i]; + bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; + /* We must read level interrupts from the level register */ + bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); + bits &= ppc_cached_irq_mask[i]; if (bits == 0) continue; irq += __ilog2(bits); @@ -195,8 +203,10 @@ #endif /* CONFIG_SMP */ for (irq = max_real_irqs; (irq -= 32) >= 0; ) { int i = irq >> 5; - bits = ld_le32(&pmac_irq_hw[i]->flag) - | ppc_lost_interrupts[i]; + bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; + /* We must read level interrupts from the level register */ + bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); + bits &= ppc_cached_irq_mask[i]; if (bits == 0) continue; irq += __ilog2(bits); @@ -374,6 +384,24 @@ irqctrler = NULL; } + /* Get the level/edge settings, assume if it's not + * a Grand Central nor an OHare, then it's an Heathrow + * (or Paddington). + */ + if (find_devices("gc")) + level_mask[0] = GC_LEVEL_MASK; + else if (find_devices("ohare")) { + level_mask[0] = OHARE_LEVEL_MASK; + /* We might have a second cascaded ohare */ + level_mask[1] = OHARE_LEVEL_MASK; + } else { + level_mask[0] = HEATHROW_LEVEL_MASK; + level_mask[1] = 0; + /* We might have a second cascaded heathrow */ + level_mask[2] = HEATHROW_LEVEL_MASK; + level_mask[3] = 0; + } + /* * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, * 1998 G3 Series PowerBooks have 128, @@ -433,6 +461,10 @@ /* disable all interrupts in all controllers */ for (i = 0; i * 32 < max_irqs; ++i) out_le32(&pmac_irq_hw[i]->enable, 0); + /* mark level interrupts */ + for (i = 0; i < max_irqs; i++) + if (level_mask[i >> 5] & (1UL << (i & 0x1f))) + irq_desc[i].status = IRQ_LEVEL; /* get interrupt line of secondary interrupt controller */ if (irq_cascade >= 0) { @@ -474,7 +506,7 @@ out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]); if (max_real_irqs > 32) out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]); - (void)in_le32(&pmac_irq_hw[0]->flag); + (void)in_le32(&pmac_irq_hw[0]->event); /* make sure mask gets to controller before we return to caller */ mb(); (void)in_le32(&pmac_irq_hw[0]->enable); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/pmac_setup.c linux-2.5/arch/ppc/kernel/pmac_setup.c --- linux-2.5.1/arch/ppc/kernel/pmac_setup.c Fri Nov 16 18:10:08 2001 +++ linux-2.5/arch/ppc/kernel/pmac_setup.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_setup.c 1.43 11/13/01 21:26:07 paulus + * BK Id: SCCS/s.pmac_setup.c 1.45 12/01/01 20:09:06 benh */ /* * linux/arch/ppc/kernel/setup.c @@ -61,7 +61,6 @@ #include <asm/pci-bridge.h> #include <asm/ohare.h> #include <asm/mediabay.h> -#include <asm/feature.h> #include <asm/machdep.h> #include <asm/keyboard.h> #include <asm/dma.h> @@ -69,6 +68,7 @@ #include <asm/cputable.h> #include <asm/btext.h> +#include <asm/pmac_feature.h> #include <asm/time.h> #include "local_irq.h" #include "pmac_pic.h" @@ -83,6 +83,10 @@ extern void pmac_calibrate_decr(void); extern void pmac_pcibios_fixup(void); extern void pmac_find_bridges(void); +extern int pmac_ide_check_base(ide_ioreg_t base); +extern ide_ioreg_t pmac_ide_get_base(int index); +extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, + ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq); extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int mackbd_getkeycode(unsigned int scancode); @@ -436,7 +440,8 @@ #endif #ifdef CONFIG_PMAC_PBOOK media_bay_init(); -#endif +#endif + pmac_feature_late_init(); } #ifdef CONFIG_SCSI @@ -604,14 +609,11 @@ static int __pmac pmac_ide_check_region(ide_ioreg_t from, unsigned int extent) { - /* - * We only do the check_region if `from' looks like a genuine - * I/O port number. If it actually refers to a memory-mapped - * register, it should be OK. - */ - if (from < ~_IO_BASE) - return check_region(from, extent); - return 0; +#ifdef CONFIG_BLK_DEV_IDE_PMAC + if (pmac_ide_check_base(from) >= 0) + return 0; +#endif + return check_region(from, extent); } static void __pmac @@ -619,24 +621,31 @@ unsigned int extent, const char *name) { - if (from < ~_IO_BASE) - request_region(from, extent, name); +#ifdef CONFIG_BLK_DEV_IDE_PMAC + if (pmac_ide_check_base(from) >= 0) + return; +#endif + request_region(from, extent, name); } static void __pmac pmac_ide_release_region(ide_ioreg_t from, unsigned int extent) { - if (from < ~_IO_BASE) - release_region(from, extent); +#ifdef CONFIG_BLK_DEV_IDE_PMAC + if (pmac_ide_check_base(from) >= 0) + return; +#endif + release_region(from, extent); } +#ifndef CONFIG_BLK_DEV_IDE_PMAC /* * This is only used if we have a PCI IDE controller, not * for the IDE controller in the ohare/paddington/heathrow/keylargo. */ static void __pmac -pmac_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, +pmac_ide_pci_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { ide_ioreg_t reg = data_port; @@ -648,7 +657,8 @@ } hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; } -#endif +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ +#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ /* * Read in a property describing some pieces of memory. @@ -806,14 +816,21 @@ ppc_md.find_end_of_memory = pmac_find_end_of_memory; + ppc_md.feature_call = pmac_do_feature_call; + select_adb_keyboard(); -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ppc_ide_md.ide_check_region = pmac_ide_check_region; ppc_ide_md.ide_request_region = pmac_ide_request_region; ppc_ide_md.ide_release_region = pmac_ide_release_region; +#ifdef CONFIG_BLK_DEV_IDE_PMAC ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; -#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ + ppc_ide_md.default_io_base = pmac_ide_get_base; +#else /* CONFIG_BLK_DEV_IDE_PMAC */ + ppc_ide_md.ide_init_hwif = pmac_ide_pci_init_hwif_ports; +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ +#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ #ifdef CONFIG_BOOTX_TEXT ppc_md.progress = pmac_progress; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/pmac_smp.c linux-2.5/arch/ppc/kernel/pmac_smp.c --- linux-2.5.1/arch/ppc/kernel/pmac_smp.c Sat Sep 8 19:38:42 2001 +++ linux-2.5/arch/ppc/kernel/pmac_smp.c Thu Dec 27 16:32:30 2001 @@ -43,7 +43,8 @@ #include <asm/prom.h> #include <asm/smp.h> #include <asm/residual.h> -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #include <asm/time.h> #include <asm/gemini.h> @@ -442,7 +443,7 @@ flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); /* Put some life in our friend */ - feature_core99_kick_cpu(nr); + pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); /* FIXME: We wait a bit for the CPU to take the exception, I should * instead wait for the entry code to set something for me. Well, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/pmac_time.c linux-2.5/arch/ppc/kernel/pmac_time.c --- linux-2.5.1/arch/ppc/kernel/pmac_time.c Sat Sep 8 19:38:42 2001 +++ linux-2.5/arch/ppc/kernel/pmac_time.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.pmac_time.c 1.16 09/08/01 15:47:42 paulus + * BK Id: SCCS/s.pmac_time.c 1.19 12/04/01 01:24:51 benh */ /* * Support for periodic interrupts (100 per second) and for getting @@ -110,11 +110,11 @@ return 0; while (!req.complete) pmu_poll(); - if (req.reply_len != 5) + if (req.reply_len != 4) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); - now = (req.reply[1] << 24) + (req.reply[2] << 16) - + (req.reply[3] << 8) + req.reply[4]; + now = (req.reply[0] << 24) + (req.reply[1] << 16) + + (req.reply[2] << 8) + req.reply[3]; return now - RTC_OFFSET; #endif /* CONFIG_ADB_PMU */ default: ; @@ -228,10 +228,6 @@ case PBOOK_WAKE: write_lock_irqsave(&xtime_lock, flags); xtime.tv_sec = pmac_get_rtc_time() + time_diff; - set_dec(tb_ticks_per_jiffy); - /* No currently-supported powerbook has a 601, - so use get_tbl, not native */ - last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); xtime.tv_usec = 0; last_rtc_update = xtime.tv_sec; write_unlock_irqrestore(&xtime_lock, flags); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/ppc8xx_pic.c linux-2.5/arch/ppc/kernel/ppc8xx_pic.c --- linux-2.5.1/arch/ppc/kernel/ppc8xx_pic.c Tue May 22 00:04:47 2001 +++ linux-2.5/arch/ppc/kernel/ppc8xx_pic.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc8xx_pic.c 1.10 05/17/01 18:14:21 cort + * BK Id: SCCS/s.ppc8xx_pic.c 1.13 12/01/01 17:19:48 trini */ #include <linux/config.h> #include <linux/stddef.h> @@ -44,6 +44,21 @@ ppc_cached_irq_mask[word]; } +static void m8xx_end_irq(unsigned int irq_nr) +{ + if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { + int bit, word; + + bit = irq_nr & 0x1f; + word = irq_nr >> 5; + + ppc_cached_irq_mask[word] |= (1 << (31-bit)); + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = + ppc_cached_irq_mask[word]; + } +} + + static void m8xx_mask_and_ack(unsigned int irq_nr) { int bit, word; @@ -64,6 +79,7 @@ m8xx_unmask_irq, m8xx_mask_irq, m8xx_mask_and_ack, + m8xx_end_irq, 0 }; @@ -97,19 +113,26 @@ #endif +/* + * We either return a valid interrupt or -1 if there is nothing pending + */ int m8xx_get_irq(struct pt_regs *regs) { int irq; - unsigned long bits = 0; - /* For MPC8xx, read the SIVEC register and shift the bits down - * to get the irq number. */ - bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec; - irq = bits >> 26; -#if 0 - irq += ppc8xx_pic.irq_offset; -#endif + /* For MPC8xx, read the SIVEC register and shift the bits down + * to get the irq number. + */ + irq = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26; + + /* + * When we read the sivec without an interrupt to process, we will + * get back SIU_LEVEL7. In this case, return -1 + */ + if (irq == SIU_LEVEL7) + return -1; + return irq; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/ppc_ksyms.c linux-2.5/arch/ppc/kernel/ppc_ksyms.c --- linux-2.5.1/arch/ppc/kernel/ppc_ksyms.c Fri Nov 16 18:10:08 2001 +++ linux-2.5/arch/ppc/kernel/ppc_ksyms.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc_ksyms.c 1.59 11/04/01 22:58:20 paulus + * BK Id: SCCS/s.ppc_ksyms.c 1.61 12/01/01 20:09:06 benh */ #include <linux/config.h> #include <linux/module.h> @@ -36,7 +36,7 @@ #include <asm/system.h> #include <asm/pci-bridge.h> #include <asm/irq.h> -#include <asm/feature.h> +#include <asm/pmac_feature.h> #include <asm/dma.h> #include <asm/machdep.h> #include <asm/hw_irq.h> @@ -247,6 +247,8 @@ EXPORT_SYMBOL(machine_is_compatible); EXPORT_SYMBOL(find_all_nodes); EXPORT_SYMBOL(get_property); +EXPORT_SYMBOL(request_OF_resource); +EXPORT_SYMBOL(release_OF_resource); EXPORT_SYMBOL(pci_bus_io_base); EXPORT_SYMBOL(pci_bus_io_base_phys); EXPORT_SYMBOL(pci_bus_mem_base_phys); @@ -257,16 +259,6 @@ EXPORT_SYMBOL(pci_phys_to_bus); EXPORT_SYMBOL(pci_bus_to_phys); EXPORT_SYMBOL(pmac_newworld); -EXPORT_SYMBOL(feature_set); -EXPORT_SYMBOL(feature_clear); -EXPORT_SYMBOL(feature_test); -EXPORT_SYMBOL(feature_set_gmac_power); -EXPORT_SYMBOL(feature_gmac_phy_reset); -EXPORT_SYMBOL(feature_set_usb_power); -EXPORT_SYMBOL(feature_set_firewire_power); -EXPORT_SYMBOL(feature_set_firewire_cable_power); -EXPORT_SYMBOL(feature_set_modem_power); -EXPORT_SYMBOL(feature_set_airport_power); #endif /* defined(CONFIG_ALL_PPC) */ #if defined(CONFIG_BOOTX_TEXT) EXPORT_SYMBOL(btext_update_display); @@ -319,7 +311,9 @@ EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); #ifdef CONFIG_XMON +extern void xmon_printf(char *fmt, ...); EXPORT_SYMBOL(xmon); +EXPORT_SYMBOL(xmon_printf); #endif EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down); @@ -361,3 +355,8 @@ extern long *ret_from_intercept; EXPORT_SYMBOL(ret_from_intercept); EXPORT_SYMBOL(cur_cpu_spec); +#if defined(CONFIG_ALL_PPC) +extern unsigned long agp_special_page; +EXPORT_SYMBOL_NOVERS(agp_special_page); +#endif /* defined(CONFIG_ALL_PPC) */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/prep_pci.c linux-2.5/arch/ppc/kernel/prep_pci.c --- linux-2.5.1/arch/ppc/kernel/prep_pci.c Mon Oct 15 20:35:26 2001 +++ linux-2.5/arch/ppc/kernel/prep_pci.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prep_pci.c 1.31 10/05/01 17:48:18 trini + * BK Id: SCCS/s.prep_pci.c 1.33 12/20/01 15:36:12 trini */ /* * PReP pci functions. @@ -1190,6 +1190,27 @@ } static void __init +prep_pcibios_after_init(void) +{ + struct pci_dev *dev; + + /* If there is a WD 90C, reset the IO BAR to 0x0 (it started that + * way, but the PCI layer relocated it because it thought 0x0 was + * invalid for a BAR). + * If you don't do this, the card's VGA base will be <IO BAR>+0xc0000 + * instead of 0xc0000. vgacon.c (for example) is completely unaware of + * this little quirk. + */ + dev = pci_find_device(PCI_VENDOR_ID_WD, PCI_DEVICE_ID_WD_90C, NULL); + if (dev) { + dev->resource[1].end -= dev->resource[1].start; + dev->resource[1].start = 0; + /* tell the hardware */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0x0); + } +} + +static void __init prep_init_resource(struct resource *res, unsigned long start, unsigned long end, int flags) { @@ -1246,4 +1267,5 @@ } ppc_md.pcibios_fixup = prep_pcibios_fixup; + ppc_md.pcibios_after_init = prep_pcibios_after_init; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/prep_setup.c linux-2.5/arch/ppc/kernel/prep_setup.c --- linux-2.5.1/arch/ppc/kernel/prep_setup.c Fri Nov 16 18:10:08 2001 +++ linux-2.5/arch/ppc/kernel/prep_setup.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prep_setup.c 1.44 11/13/01 21:26:07 paulus + * BK Id: SCCS/s.prep_setup.c 1.47 12/19/01 09:45:54 trini */ /* * linux/arch/ppc/kernel/setup.c @@ -111,12 +111,6 @@ extern int probingmem; extern unsigned long loops_per_jiffy; -#ifdef CONFIG_BLK_DEV_RAM -extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ -extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ -extern int rd_image_start; /* starting block # of image */ -#endif - #ifdef CONFIG_SOUND_MODULE EXPORT_SYMBOL(ppc_cs4232_dma); EXPORT_SYMBOL(ppc_cs4232_dma2); @@ -189,7 +183,7 @@ no_l2: #ifdef CONFIG_PREP_RESIDUAL - if (res->ResidualLength == 0) { + if (res->ResidualLength != 0) { /* print info about SIMMs */ seq_printf(m, "simms\t\t: "); for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) { @@ -645,7 +639,7 @@ static int __prep prep_get_irq(struct pt_regs *regs) { - return i8259_irq(smp_processor_id()); + return i8259_irq(); } static void __init @@ -657,7 +651,7 @@ openpic_init(1, NUM_8259_INTERRUPTS, 0, -1); for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) irq_desc[i].handler = &i8259_pic; - i8259_init(); + i8259_init(0xbffffff0); /* PCI interrupt ack address for MPC105 and 106 */ } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/prom.c linux-2.5/arch/ppc/kernel/prom.c --- linux-2.5.1/arch/ppc/kernel/prom.c Mon Dec 10 21:52:53 2001 +++ linux-2.5/arch/ppc/kernel/prom.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prom.c 1.42 09/08/01 15:47:42 paulus + * BK Id: SCCS/s.prom.c 1.48 12/19/01 10:50:58 paulus */ /* * Procedures for interfacing to the Open Firmware PROM on @@ -19,6 +19,9 @@ #include <linux/version.h> #include <linux/threads.h> #include <linux/spinlock.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/slab.h> #include <asm/sections.h> #include <asm/prom.h> @@ -34,6 +37,7 @@ #include <asm/bitops.h> #include <asm/bootinfo.h> #include <asm/btext.h> +#include <asm/pci-bridge.h> #include "open_pic.h" #ifdef CONFIG_FB @@ -371,8 +375,8 @@ btext_drawstring(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n")); btext_flushscreen(); } -#endif /* CONFIG_BOOTX_TEXT */ - +#endif /* CONFIG_BOOTX_TEXT */ + /* New BootX enters kernel with MMU off, i/os are not allowed here. This hack will have been done by the boostrap anyway. */ @@ -388,7 +392,7 @@ out_le32((unsigned *)0x80880008, 1); /* XXX */ } } - + /* Move klimit to enclose device tree, args, ramdisk, etc... */ if (bi->version < 5) { space = bi->deviceTreeOffset + bi->deviceTreeSize; @@ -411,7 +415,7 @@ ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) x = *(volatile unsigned long *)ptr; } - + #ifdef CONFIG_BOOTX_TEXT /* * Note that after we call prepare_disp_BAT, we can't do @@ -620,7 +624,7 @@ phys = 0; else { if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), - RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) { + RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) { prom_print(RELOC(" no MMU found\n")); } else { int nargs; @@ -653,7 +657,8 @@ call_prom(RELOC("quiesce"), 0, 0); #ifdef CONFIG_BOOTX_TEXT - btext_prepare_BAT(); + if (RELOC(prom_disp_node) != 0) + btext_prepare_BAT(); #endif prom_print(RELOC("returning ")); @@ -793,7 +798,7 @@ for (i=1; i<RELOC(prom_num_displays); i++) { RELOC(prom_display_paths[i-1]) = RELOC(prom_display_paths[i]); RELOC(prom_display_nodes[i-1]) = RELOC(prom_display_nodes[i]); - } + } if (--RELOC(prom_num_displays) > 0) RELOC(prom_disp_node) = RELOC(prom_display_nodes[0]); else @@ -880,7 +885,7 @@ } } /* kludge for valkyrie */ - if (strcmp(name, RELOC("valkyrie")) == 0) + if (strcmp(name, RELOC("valkyrie")) == 0) address += 0x1000; btext_setup_display(width, height, depth, pitch, address); @@ -1111,10 +1116,15 @@ np->name = get_property(np, "name", 0); np->type = get_property(np, "device_type", 0); + if (!np->name) + np->name = "<NULL>"; + if (!np->type) + np->type = "<NULL>"; + /* get the device addresses and interrupts */ - if (ifunc != NULL) { + if (ifunc != NULL) mem_start = ifunc(np, mem_start, naddrc, nsizec); - } + if (use_of_interrupt_tree) mem_start = finish_node_interrupts(np, mem_start); @@ -1126,11 +1136,18 @@ if (ip != NULL) nsizec = *ip; - /* the f50 sets the name to 'display' and 'compatible' to what we - * expect for the name -- Cort + /* + * The F50 sets the name to 'display' and 'compatible' to what we + * expect for the name. -- Cort + * + * But sometimes you get a 'display' name for non-OF cards, and thus + * no compatible property. And very rarely we won't have a name + * property either. -- Tom */ if (!strcmp(np->name, "display")) np->name = get_property(np, "compatible", 0); + if (!np->name) + np->name = get_property(np, "name", 0); if (np->parent == NULL) ifunc = interpret_root_props; @@ -1145,6 +1162,8 @@ ifunc = interpret_macio_props; else if (!strcmp(np->type, "isa")) ifunc = interpret_isa_props; + else if (!strcmp(np->name, "uni-n")) + ifunc = interpret_root_props; else if (!((ifunc == interpret_dbdma_props || ifunc == interpret_macio_props) && (!strcmp(np->type, "escc") @@ -1508,7 +1527,7 @@ i = 0; adr = (struct address_range *) mem_start; while ((l -= sizeof(struct reg_property)) >= 0) { - adr[i].space = 0; + adr[i].space = 2; adr[i].address = rp[i].address + base_address; adr[i].size = rp[i].size; ++i; @@ -1544,14 +1563,13 @@ struct reg_property *rp; struct address_range *adr; unsigned long base_address; - int i, l, keylargo, *ip; + int i, l, *ip; struct device_node *db; base_address = 0; for (db = np->parent; db != NULL; db = db->parent) { if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) { base_address = db->addrs[0].address; - keylargo = device_is_compatible(db, "Keylargo"); break; } } @@ -1561,7 +1579,7 @@ i = 0; adr = (struct address_range *) mem_start; while ((l -= sizeof(struct reg_property)) >= 0) { - adr[i].space = 0; + adr[i].space = 2; adr[i].address = rp[i].address + base_address; adr[i].size = rp[i].size; ++i; @@ -1616,7 +1634,7 @@ if (use_of_interrupt_tree) return mem_start; - + ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; @@ -1645,7 +1663,7 @@ i = 0; adr = (struct address_range *) mem_start; while ((l -= rpsize) >= 0) { - adr[i].space = (naddrc >= 2? rp[naddrc-2]: 0); + adr[i].space = (naddrc >= 2? rp[naddrc-2]: 2); adr[i].address = rp[naddrc - 1]; adr[i].size = rp[naddrc + nsizec - 1]; ++i; @@ -1786,7 +1804,7 @@ machine_is_compatible(const char *compat) { struct device_node *root; - + root = find_path_device("/"); if (root == 0) return 0; @@ -1870,10 +1888,176 @@ { struct property **next = &np->properties; - prop->next = NULL; + prop->next = NULL; while (*next) next = &(*next)->next; *next = prop; +} + +/* I quickly hacked that one, check against spec ! */ +static inline unsigned long __openfirmware +bus_space_to_resource_flags(unsigned int bus_space) +{ + u8 space = (bus_space >> 24) & 0xf; + if (space == 0) + space = 0x02; + if (space == 0x02) + return IORESOURCE_MEM; + else if (space == 0x01) + return IORESOURCE_IO; + else { + printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n", + bus_space); + return 0; + } +} + +static struct resource* __openfirmware +find_parent_pci_resource(struct pci_dev* pdev, struct address_range *range) +{ + unsigned long mask; + int i; + + /* Check this one */ + mask = bus_space_to_resource_flags(range->space); + for (i=0; i<DEVICE_COUNT_RESOURCE; i++) { + if ((pdev->resource[i].flags & mask) == mask && + pdev->resource[i].start <= range->address && + pdev->resource[i].end > range->address) { + if ((range->address + range->size - 1) > pdev->resource[i].end) { + /* Add better message */ + printk(KERN_WARNING "PCI/OF resource overlap !\n"); + return NULL; + } + break; + } + } + if (i == DEVICE_COUNT_RESOURCE) + return NULL; + return &pdev->resource[i]; +} + +/* + * Request an OF device resource. Currently handles child of PCI devices, + * or other nodes attached to the root node. Ultimately, put some + * link to resources in the OF node. + * WARNING: out_resource->name should be initialized before calling this + * function. + */ +struct resource* __openfirmware +request_OF_resource(struct device_node* node, int index, const char* name_postfix) +{ + struct pci_dev* pcidev; + u8 pci_bus, pci_devfn; + unsigned long iomask; + struct device_node* nd; + struct resource* parent; + struct resource *res = NULL; + int nlen, plen; + + if (index >= node->n_addrs) + goto fail; + + /* Sanity check on bus space */ + iomask = bus_space_to_resource_flags(node->addrs[index].space); + if (iomask & IORESOURCE_MEM) + parent = &iomem_resource; + else if (iomask & IORESOURCE_IO) + parent = &ioport_resource; + else + goto fail; + + /* Find a PCI parent if any */ + nd = node; + pcidev = NULL; + while(nd) { + if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) + pcidev = pci_find_slot(pci_bus, pci_devfn); + if (pcidev) break; + nd = nd->parent; + } + if (pcidev) + parent = find_parent_pci_resource(pcidev, &node->addrs[index]); + if (!parent) { + printk(KERN_WARNING "request_OF_resource(%s), parent not found\n", + node->name); + goto fail; + } + + res = __request_region(parent, node->addrs[index].address, node->addrs[index].size, NULL); + if (!res) + goto fail; + nlen = strlen(node->name); + plen = name_postfix ? strlen(name_postfix) : 0; + res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL); + if (res->name) { + strcpy((char *)res->name, node->name); + if (plen) + strcpy((char *)res->name+nlen, name_postfix); + } + return res; +fail: + return NULL; +} + +int __openfirmware +release_OF_resource(struct device_node* node, int index) +{ + struct pci_dev* pcidev; + u8 pci_bus, pci_devfn; + unsigned long iomask; + struct device_node* nd; + struct resource* parent; + struct resource *res = NULL; + + if (index >= node->n_addrs) + return -EINVAL; + + /* Sanity check on bus space */ + iomask = bus_space_to_resource_flags(node->addrs[index].space); + if (iomask & IORESOURCE_MEM) + parent = &iomem_resource; + else if (iomask & IORESOURCE_IO) + parent = &ioport_resource; + else + return -EINVAL; + + /* Find a PCI parent if any */ + nd = node; + pcidev = NULL; + while(nd) { + if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) + pcidev = pci_find_slot(pci_bus, pci_devfn); + if (pcidev) break; + nd = nd->parent; + } + if (pcidev) + parent = find_parent_pci_resource(pcidev, &node->addrs[index]); + if (!parent) { + printk(KERN_WARNING "request_OF_resource(%s), parent not found\n", + node->name); + return -ENODEV; + } + + /* Find us in the parent */ + res = parent->child; + while (res) { + if (res->start == node->addrs[index].address && + res->end == (res->start + node->addrs[index].size - 1)) + break; + res = res->sibling; + } + if (!res) + return -ENODEV; + + if (res->name) { + kfree(res->name); + res->name = NULL; + } + release_resource(res); + kfree(res); + + return 0; } #if 0 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/setup.c linux-2.5/arch/ppc/kernel/setup.c --- linux-2.5.1/arch/ppc/kernel/setup.c Wed Nov 21 17:59:11 2001 +++ linux-2.5/arch/ppc/kernel/setup.c Mon Jan 14 22:39:44 2002 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.setup.c 1.65 11/18/01 20:57:25 trini + * BK Id: SCCS/s.setup.c 1.67 12/01/01 20:09:07 benh */ /* * Common prep/pmac/chrp boot and setup code. @@ -43,9 +43,9 @@ #include <asm/bootx.h> #include <asm/btext.h> #include <asm/machdep.h> -#include <asm/feature.h> #include <asm/uaccess.h> #include <asm/system.h> +#include <asm/pmac_feature.h> extern void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); @@ -547,8 +547,13 @@ loops_per_jiffy = 500000000 / HZ; #ifdef CONFIG_ALL_PPC - feature_init(); -#endif + /* This could be called "early setup arch", it must be done + * now because xmon need it + */ + if (_machine == _MACH_Pmac) + pmac_feature_init(); /* New cool way */ +#endif /* CONFIG_ALL_PPC */ + #ifdef CONFIG_XMON xmon_map_scc(); if (strstr(cmd_line, "xmon")) @@ -689,8 +694,12 @@ id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); id->word92 = __le16_to_cpu(id->word92); id->hw_config = __le16_to_cpu(id->hw_config); - for (i = 0; i < 32; i++) - id->words94_125[i] = __le16_to_cpu(id->words94_125[i]); + id->acoustic = __le16_to_cpu(id->acoustic); + for (i = 0; i < 5; i++) + id->words95_99[i] = __le16_to_cpu(id->words95_99[i]); + id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2); + for (i = 0; i < 22; i++) + id->words104_125[i] = __le16_to_cpu(id->words104_125[i]); id->last_lun = __le16_to_cpu(id->last_lun); id->word127 = __le16_to_cpu(id->word127); id->dlf = __le16_to_cpu(id->dlf); @@ -700,6 +709,12 @@ id->word156 = __le16_to_cpu(id->word156); for (i = 0; i < 3; i++) id->words157_159[i] = __le16_to_cpu(id->words157_159[i]); - for (i = 0; i < 96; i++) - id->words160_255[i] = __le16_to_cpu(id->words160_255[i]); + id->cfa_power = __le16_to_cpu(id->cfa_power); + for (i = 0; i < 14; i++) + id->words161_175[i] = __le16_to_cpu(id->words161_175[i]); + for (i = 0; i < 31; i++) + id->words176_205[i] = __le16_to_cpu(id->words176_205[i]); + for (i = 0; i < 48; i++) + id->words206_254[i] = __le16_to_cpu(id->words206_254[i]); + id->integrity_word = __le16_to_cpu(id->integrity_word); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/sleep.S linux-2.5/arch/ppc/kernel/sleep.S --- linux-2.5.1/arch/ppc/kernel/sleep.S Tue Aug 28 13:58:33 2001 +++ linux-2.5/arch/ppc/kernel/sleep.S Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.sleep.S 1.13 08/19/01 22:23:04 paulus + * BK Id: SCCS/s.sleep.S 1.18 12/02/01 12:38:54 benh */ /* * This file contains sleep low-level functions for PowerBook G3. @@ -16,6 +16,7 @@ #include "ppc_asm.tmpl" #include <asm/processor.h> #include <asm/page.h> +#include <asm/cputable.h> #define MAGIC 0x4c617273 /* 'Lars' */ @@ -37,8 +38,15 @@ #define SL_IBAT3 0x58 #define SL_TB 0x60 #define SL_HID0 0x68 -#define SL_R2 0x6c -#define SL_R12 0x70 /* r12 to r31 */ +#define SL_HID1 0x6c +#define SL_MSSCR0 0x70 +#define SL_MSSSR0 0x74 +#define SL_ICTRL 0x78 +#define SL_LDSTCR 0x7c +#define SL_LDSTDB 0x80 +#define SL_R2 0x84 +#define SL_CR 0x88 +#define SL_R12 0x8c /* r12 to r31 */ #define SL_SIZE (SL_R12 + 80) #define tophys(rd,rs) addis rd,rs,-KERNELBASE@h @@ -56,6 +64,8 @@ mflr r0 stw r0,4(r1) stwu r1,-SL_SIZE(r1) + mfcr r0 + stw r0,SL_CR(r1) stw r2,SL_R2(r1) stmw r12,SL_R12(r1) @@ -121,7 +131,31 @@ /* Save HID0 */ mfspr r4,HID0 stw r4,SL_HID0(r1) - + + /* Save 7400/7410/7450 specific registers */ + mfspr r3,PVR + srwi r3,r3,16 + cmpli cr0,r3,0x8000 + cmpli cr1,r3,0x000c + cmpli cr2,r3,0x800c + cror 4*cr1+eq,4*cr1+eq,4*cr2+eq + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq + bne 1f + mfspr r4,SPRN_MSSCR0 + stw r4,SL_MSSCR0(r1) + mfspr r4,SPRN_MSSSR0 + stw r4,SL_MSSSR0(r1) + /* Save 7450 specific registers */ + beq cr1,1f + mfspr r4,HID1 + stw r4,SL_HID1(r1) + mfspr r4,SPRN_ICTRL + stw r4,SL_ICTRL(r1) + mfspr r4,SPRN_LDSTCR + stw r4,SL_LDSTCR(r1) + mfspr r4,SPRN_LDSTDB + stw r4,SL_LDSTDB(r1) +1: /* The ROM can wake us up via 2 different vectors: * - On wallstreet & lombard, we must write a magic * value 'Lars' at address 4 and a pointer to a @@ -257,6 +291,19 @@ mtspr HID0,r3 sync + /* Restore the kernel's segment registers before + * we do any r1 memory access as we are not sure they + * are in a sane state above the first 256Mb region + */ + li r0,16 /* load up segment register values */ + mtctr r0 /* for context 0 */ + lis r3,0x2000 /* Ku = 1, VSID = 0 */ + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,0x111 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b + /* Restore the remaining bits of the HID0 register. */ subi r1,r1,SL_PC lwz r3,SL_HID0(r1) @@ -266,17 +313,52 @@ sync isync - /* Restore the kernel's segment registers, the - BATs, and SDR1. Then we can turn on the MMU. */ - li r0,16 /* load up segment register values */ - mtctr r0 /* for context 0 */ - lis r3,0x2000 /* Ku = 1, VSID = 0 */ + /* Restore 7400/7410/7450 specific registers */ + mfspr r3,PVR + srwi r3,r3,16 + cmpli cr0,r3,0x8000 + cmpli cr1,r3,0x000c + cmpli cr2,r3,0x800c + cror 4*cr1+eq,4*cr1+eq,4*cr2+eq + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq + bne 1f + lwz r4,SL_MSSCR0(r1) + sync + mtspr SPRN_MSSCR0,r4 + sync + isync + lwz r4,SL_MSSSR0(r1) + sync + mtspr SPRN_MSSSR0,r4 + sync + isync + bne cr2,1f li r4,0 -3: mtsrin r3,r4 - addi r3,r3,0x111 /* increment VSID */ - addis r4,r4,0x1000 /* address of next segment */ - bdnz 3b - + mtspr SPRN_L2CR2,r4 + /* Restore 7450 specific registers */ + beq cr1,1f + lwz r4,SL_HID1(r1) + sync + mtspr HID1,r4 + isync + sync + lwz r4,SPRN_ICTRL(r1) + sync + mtspr SPRN_ICTRL,r4 + isync + sync + lwz r4,SPRN_LDSTCR(r1) + sync + mtspr SPRN_LDSTCR,r4 + isync + sync + lwz r4,SL_LDSTDB(r1) + sync + mtspr SPRN_LDSTDB,r4 + isync + sync +1: + /* Restore the BATs, and SDR1. Then we can turn on the MMU. */ lwz r4,SL_SDR1(r1) mtsdr1 r4 lwz r4,SL_SPRG0(r1) @@ -344,6 +426,8 @@ mttbl r4 /* Restore the callee-saved registers and return */ + lwz r0,SL_CR(r1) + mtcr r0 lwz r2,SL_R2(r1) lmw r12,SL_R12(r1) addi r1,r1,SL_SIZE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/smp.c linux-2.5/arch/ppc/kernel/smp.c --- linux-2.5.1/arch/ppc/kernel/smp.c Wed Nov 21 18:31:09 2001 +++ linux-2.5/arch/ppc/kernel/smp.c Thu Dec 13 16:32:35 2001 @@ -23,6 +23,7 @@ #include <linux/unistd.h> #include <linux/init.h> #include <linux/spinlock.h> +#include <linux/cache.h> #include <asm/ptrace.h> #include <asm/atomic.h> @@ -47,7 +48,7 @@ struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 }; atomic_t ipi_recv; atomic_t ipi_sent; -spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; cycles_t cacheflush_time; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/time.c linux-2.5/arch/ppc/kernel/time.c --- linux-2.5.1/arch/ppc/kernel/time.c Mon Oct 8 18:43:01 2001 +++ linux-2.5/arch/ppc/kernel/time.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.time.c 1.26 10/05/01 08:29:42 trini + * BK Id: SCCS/s.time.c 1.29 12/11/01 11:40:45 trini */ /* * Common time routines among all ppc machines. @@ -356,11 +356,10 @@ do_get_fast_time = do_gettimeofday; } -#define TICK_SIZE tick -#define FEBRUARY 2 -#define STARTOFTIME 1970 -#define SECDAY 86400L -#define SECYR (SECDAY * 365) +#define FEBRUARY 2 +#define STARTOFTIME 1970 +#define SECDAY 86400L +#define SECYR (SECDAY * 365) #define leapyear(year) ((year) % 4 == 0) #define days_in_year(a) (leapyear(a) ? 366 : 365) #define days_in_month(a) (month_days[(a) - 1]) @@ -369,55 +368,12 @@ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -/* - * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) - */ -void GregorianDay(struct rtc_time * tm) -{ - int leapsToDate; - int lastYear; - int day; - int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - - lastYear=tm->tm_year-1; - - /* - * Number of leap corrections to apply up to end of last year - */ - leapsToDate = lastYear/4 - lastYear/100 + lastYear/400; - - /* - * This year is a leap year if it is divisible by 4 except when it is - * divisible by 100 unless it is divisible by 400 - * - * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be - */ - if((tm->tm_year%4==0) && - ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && - (tm->tm_mon>2)) - { - /* - * We are past Feb. 29 in a leap year - */ - day=1; - } - else - { - day=0; - } - - day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + - tm->tm_mday; - - tm->tm_wday=day%7; -} - void to_tm(int tim, struct rtc_time * tm) { - register int i; - register long hms, day; + register int i; + register long hms, day, gday; - day = tim / SECDAY; + gday = day = tim / SECDAY; hms = tim % SECDAY; /* Hours, minutes, seconds are easy */ @@ -442,9 +398,9 @@ tm->tm_mday = day + 1; /* - * Determine the day of week + * Determine the day of week. Jan. 1, 1970 was a Thursday. */ - GregorianDay(tm); + tm->tm_wday = (gday + 4) % 7; } /* Auxiliary function to compute scaling factors */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/kernel/xics.c linux-2.5/arch/ppc/kernel/xics.c --- linux-2.5.1/arch/ppc/kernel/xics.c Tue May 22 00:04:47 2001 +++ linux-2.5/arch/ppc/kernel/xics.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.xics.c 1.5 05/17/01 18:14:22 cort + * BK Id: SCCS/s.xics.c 1.8 12/19/01 09:48:40 trini */ /* * arch/ppc/kernel/xics.c @@ -157,7 +157,7 @@ vec &= 0x00ffffff; /* for sanity, this had better be < NR_IRQS - 16 */ if( vec == XICS_IRQ_8259_CASCADE ) - irq = i8259_irq(cpu); + irq = i8259_poll(); else if( vec == XICS_IRQ_SPURIOUS ) irq = -1; else diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/mm/init.c linux-2.5/arch/ppc/mm/init.c --- linux-2.5.1/arch/ppc/mm/init.c Tue Oct 2 16:12:44 2001 +++ linux-2.5/arch/ppc/mm/init.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.init.c 1.36 09/22/01 14:03:09 paulus + * BK Id: SCCS/s.init.c 1.38 12/01/01 20:09:07 benh */ /* * PowerPC version @@ -62,6 +62,9 @@ int boot_mapsize; unsigned long totalram_pages; unsigned long totalhigh_pages; +#ifdef CONFIG_ALL_PPC +unsigned long agp_special_page; +#endif extern char _end[]; extern char etext[], _stext[]; @@ -85,7 +88,7 @@ char *klimit = _end; struct mem_pieces phys_avail; -extern char *sysmap; +extern char *sysmap; extern unsigned long sysmap_size; /* @@ -352,9 +355,10 @@ ppc_md.progress("MMU:exit", 0x211); #ifdef CONFIG_BOOTX_TEXT - /* Must be done last, or ppc_md.progress will die */ - if (have_of) - map_boot_text(); + /* By default, we are no longer mapped */ + boot_text_mapped = 0; + /* Must be done last, or ppc_md.progress will die. */ + map_boot_text(); #endif } @@ -474,20 +478,22 @@ } #endif /* CONFIG_BLK_DEV_INITRD */ -#if defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* mark the RTAS pages as reserved */ if ( rtas_data ) for (addr = (ulong)__va(rtas_data); addr < PAGE_ALIGN((ulong)__va(rtas_data)+rtas_size) ; addr += PAGE_SIZE) SetPageReserved(virt_to_page(addr)); + if (agp_special_page) + SetPageReserved(virt_to_page(agp_special_page)); #endif /* defined(CONFIG_ALL_PPC) */ if ( sysmap ) for (addr = (unsigned long)sysmap; addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ; addr += PAGE_SIZE) SetPageReserved(virt_to_page(addr)); - + for (addr = PAGE_OFFSET; addr < (unsigned long)end_of_DRAM; addr += PAGE_SIZE) { if (!PageReserved(virt_to_page(addr))) @@ -526,6 +532,10 @@ if (sysmap) printk("System.map loaded at 0x%08x for debugger, size: %ld bytes\n", (unsigned int)sysmap, sysmap_size); +#if defined(CONFIG_ALL_PPC) + if (agp_special_page) + printk(KERN_INFO "AGP special page: 0x%08lx\n", agp_special_page); +#endif /* defined(CONFIG_ALL_PPC) */ mem_init_done = 1; } @@ -572,6 +582,20 @@ /* remove the sysmap pages from the available memory */ if (sysmap) mem_pieces_remove(&phys_avail, __pa(sysmap), sysmap_size, 1); + /* Because of some uninorth weirdness, we need a page of + * memory as high as possible (it must be outside of the + * bus address seen as the AGP aperture). It will be used + * by the r128 DRM driver + * + * FIXME: We need to make sure that page doesn't overlap any of the\ + * above. This could be done by improving mem_pieces_find to be able + * to do a backward search from the end of the list. + */ + if (_machine == _MACH_Pmac && find_devices("uni-north-agp")) { + agp_special_page = (total_memory - PAGE_SIZE); + mem_pieces_remove(&phys_avail, agp_special_page, PAGE_SIZE, 0); + agp_special_page = (unsigned long)__va(agp_special_page); + } #endif /* CONFIG_ALL_PPC */ } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/xmon/nonstdio.h linux-2.5/arch/ppc/xmon/nonstdio.h --- linux-2.5.1/arch/ppc/xmon/nonstdio.h Tue May 22 00:04:47 2001 +++ linux-2.5/arch/ppc/xmon/nonstdio.h Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.nonstdio.h 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.nonstdio.h 1.8 12/01/01 20:09:07 benh */ typedef int FILE; extern FILE *xmon_stdin, *xmon_stdout; @@ -21,5 +21,6 @@ extern void xmon_printf(const char *, ...); extern void xmon_fprintf(void *, const char *, ...); extern void xmon_sprintf(char *, const char *, ...); +extern void xmon_puts(char*); #define perror(s) printf("%s: no files!\n", (s)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/xmon/start.c linux-2.5/arch/ppc/xmon/start.c --- linux-2.5.1/arch/ppc/xmon/start.c Tue Aug 28 13:58:33 2001 +++ linux-2.5/arch/ppc/xmon/start.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.start.c 1.16 08/20/01 22:17:58 paulus + * BK Id: SCCS/s.start.c 1.18 12/01/01 20:09:07 benh */ /* * Copyright (C) 1996 Paul Mackerras. @@ -13,9 +13,11 @@ #include <linux/pmu.h> #include <linux/cuda.h> #include <linux/kernel.h> +#include <linux/errno.h> #include <asm/prom.h> #include <asm/bootx.h> -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #include <asm/processor.h> #include <asm/delay.h> #include <asm/btext.h> @@ -32,7 +34,7 @@ static int use_screen; static int via_modem; static int xmon_use_sccb; -static struct device_node *macio_node; +static struct device_node *channel_node; #define TB_SPEED 25000000 @@ -99,6 +101,7 @@ np = np->sibling; if (np != NULL) { /* XXX should parse this properly */ + channel_node = np; slots = get_property(np, "slot-names", &l); if (slots != NULL && l >= 10 && strcmp(slots+4, "Modem") == 0) @@ -126,10 +129,8 @@ RXRDY = 1; np = find_devices("mac-io"); - if (np && np->n_addrs) { - macio_node = np; + if (np && np->n_addrs) addr = np->addrs[0].address + 0x13020; - } base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE); sccc = base + (addr & ~PAGE_MASK); sccd = sccc + 0x10; @@ -349,12 +350,19 @@ { int i, x; - if (macio_node != 0) - feature_set(macio_node, FEATURE_Serial_enable); - if (via_modem && macio_node != 0) { + if (channel_node != 0) + pmac_call_feature( + PMAC_FTR_SCC_ENABLE, + channel_node, + PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); + printk(KERN_INFO "Serial port locked ON by debugger !\n"); + if (via_modem && channel_node != 0) { unsigned int t0; - feature_set(macio_node, FEATURE_Modem_power); + pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, + channel_node, 0, 1); + printk(KERN_INFO "Modem powered up by debugger !\n"); t0 = readtb(); while (readtb() - t0 < 3*TB_SPEED) eieio(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/xmon/subr_prf.c linux-2.5/arch/ppc/xmon/subr_prf.c --- linux-2.5.1/arch/ppc/xmon/subr_prf.c Tue May 22 00:04:47 2001 +++ linux-2.5/arch/ppc/xmon/subr_prf.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.subr_prf.c 1.5 05/17/01 18:14:23 cort + * BK Id: SCCS/s.subr_prf.c 1.8 12/01/01 20:09:07 benh */ /* * Written by Cort Dougan to replace the version originally used @@ -51,3 +51,8 @@ va_end(ap); } +void +xmon_puts(char *s) +{ + xmon_write(stdout, s, strlen(s)); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/ppc/xmon/xmon.c linux-2.5/arch/ppc/xmon/xmon.c --- linux-2.5.1/arch/ppc/xmon/xmon.c Mon Oct 8 18:40:13 2001 +++ linux-2.5/arch/ppc/xmon/xmon.c Thu Dec 27 16:32:30 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.xmon.c 1.16 09/22/01 15:25:10 trini + * BK Id: SCCS/s.xmon.c 1.18 12/01/01 20:09:07 benh */ /* * Routines providing a simple monitor for use on the PowerMac. @@ -90,6 +90,7 @@ static void write_spr(int, unsigned); static void super_regs(void); static void print_sysmap(void); +static void sysmap_lookup(void); static void remove_bpts(void); static void insert_bpts(void); static struct bpt *at_breakpoint(unsigned pc); @@ -98,10 +99,7 @@ #ifdef CONFIG_SMP static void cpu_cmd(void); #endif /* CONFIG_SMP */ -#if 0 /* Makes compile with -Wall */ -static char *pretty_print_addr(unsigned long addr); -static char *lookup_name(unsigned long addr); -#endif +static int pretty_print_addr(unsigned long addr); static void csum(void); extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned); @@ -112,6 +110,8 @@ extern void xmon_enter(void); extern void xmon_leave(void); +extern char* xmon_find_symbol(unsigned long addr, unsigned long* saddr); +extern unsigned long xmon_symbol_to_addr(char* symbol); #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) @@ -121,6 +121,7 @@ #define isalnum(c) (('0' <= (c) && (c) <= '9') \ || ('a' <= (c) && (c) <= 'z') \ || ('A' <= (c) && (c) <= 'Z')) +#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0) static char *help_string = "\ Commands:\n\ @@ -138,6 +139,8 @@ r print registers\n\ S print special registers\n\ t print backtrace\n\ + la lookup address in system.map\n\ + ls lookup symbol in system.map\n\ x exit monitor\n\ "; @@ -147,6 +150,19 @@ static struct pt_regs *xmon_regs[NR_CPUS]; +extern inline void sync(void) +{ + asm volatile("sync; isync"); +} + +extern inline void __delay(unsigned int loops) +{ + if (loops != 0) + __asm__ __volatile__("mtctr %0; 1: bdnz 1b" : : + "r" (loops) : "ctr"); +} + + void xmon(struct pt_regs *excp) { @@ -398,6 +414,9 @@ case 'd': dump(); break; + case 'l': + sysmap_lookup(); + break; case 'r': if (excp != NULL) prregs(excp); /* print regs */ @@ -464,8 +483,8 @@ if (cmd == 'i') { /* interrupt other cpu(s) */ cpu = MSG_ALL_BUT_SELF; - scanhex(&cpu); - smp_send_xmon_break(cpu); + if (scanhex(&cpu)) + smp_send_xmon_break(cpu); return; } termch = cmd; @@ -547,8 +566,10 @@ unsigned short fcs; unsigned char v; - scanhex(&adrs); - scanhex(&ncsum); + if (!scanhex(&adrs)) + return; + if (!scanhex(&ncsum)) + return; fcs = 0xffff; for (i = 0; i < ncsum; ++i) { if (mread(adrs+i, &v, 1) == 0) { @@ -580,6 +601,11 @@ mode = 6; else termch = cmd; + cmd = inchar(); + if (cmd == 'p') + mode &= ~4; + else + termch = cmd; dabr.address = 0; dabr.count = 0; dabr.enabled = scanhex(&dabr.address); @@ -588,11 +614,16 @@ dabr.address = (dabr.address & ~7) | mode; break; case 'i': + cmd = inchar(); + if (cmd == 'p') + mode = 2; + else + mode = 3; iabr.address = 0; iabr.count = 0; iabr.enabled = scanhex(&iabr.address); if (iabr.enabled) - iabr.address |= 3; + iabr.address |= mode; scanhex(&iabr.count); break; #endif @@ -625,6 +656,8 @@ printf("r"); if (dabr.address & 2) printf("w"); + if (dabr.address & 4) + printf("p"); printf("]\n"); } if (iabr.enabled) @@ -674,7 +707,8 @@ for (; sp != 0; sp = stack[0]) { if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) break; - printf("%x ", stack[1]); + pretty_print_addr(stack[1]); + printf(" "); if (stack[1] == (unsigned) &ret_from_intercept || stack[1] == (unsigned) &ret_from_except || stack[1] == (unsigned) &ret_from_syscall_1 @@ -688,8 +722,8 @@ if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) break; } + printf("\n"); } - printf("\n"); } int @@ -707,10 +741,11 @@ #ifdef CONFIG_SMP printf("cpu %d: ", smp_processor_id()); #endif /* CONFIG_SMP */ - printf("vector: %x at pc = %x", - fp->trap, fp->nip); - printf(", lr = %x, msr = %x, sp = %x [%x]\n", - fp->link, fp->msr, fp->gpr[1], fp); + printf("vector: %x at pc = ", fp->trap); + pretty_print_addr(fp->nip); + printf(", lr = "); + pretty_print_addr(fp->link); + printf("\nmsr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp); if (fp->trap == 0x300 || fp->trap == 0x600) printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr); if (current) @@ -795,8 +830,16 @@ print_sysmap(void) { extern char *sysmap; - if ( sysmap ) - printf("System.map: \n%s", sysmap); + if ( sysmap ) { + printf("System.map: \n"); + if( setjmp(bus_error_jmp) == 0 ) { + debugger_fault_handler = handle_fault; + sync(); + xmon_puts(sysmap); + sync(); + } + debugger_fault_handler = 0; + } else printf("No System.map\n"); } @@ -1028,17 +1071,6 @@ /* * Stuff for reading and writing memory safely */ -extern inline void sync(void) -{ - asm volatile("sync; isync"); -} - -extern inline void __delay(unsigned int loops) -{ - if (loops != 0) - __asm__ __volatile__("mtctr %0; 1: bdnz 1b" : : - "r" (loops) : "ctr"); -} int mread(unsigned adrs, void *buf, int size) @@ -1565,6 +1597,24 @@ } printf("invalid register name '%%%s'\n", regname); return 0; + } else if (c == '$') { + static char symname[64]; + int i; + for (i=0; i<63; i++) { + c = inchar(); + if (isspace(c)) { + termch = c; + break; + } + symname[i] = c; + } + symname[i++] = 0; + *vp = xmon_symbol_to_addr(symname); + if (!(*vp)) { + printf("unknown symbol\n"); + return 0; + } + return 1; } d = hexdigit(c); @@ -1652,38 +1702,169 @@ lineptr = str; } -#if 0 /* Makes compile with -Wall */ -static char *pretty_print_addr(unsigned long addr) +void +sysmap_lookup(void) { - printf("%08x", addr); - if ( lookup_name(addr) ) - printf(" %s", lookup_name(addr) ); - return NULL; + int type = inchar(); + unsigned addr; + static char tmp[64]; + char* cur; + + extern char *sysmap; + extern unsigned long sysmap_size; + if ( !sysmap || !sysmap_size ) + return; + + switch(type) { + case 'a': + if (scanhex(&addr)) { + pretty_print_addr(addr); + printf("\n"); + } + termch = 0; + break; + case 's': + getstring(tmp, 64); + if( setjmp(bus_error_jmp) == 0 ) { + debugger_fault_handler = handle_fault; + sync(); + cur = sysmap; + do { + cur = strstr(cur, tmp); + if (cur) { + static char res[64]; + char *p, *d; + p = cur; + while(p > sysmap && *p != 10) + p--; + if (*p == 10) p++; + d = res; + while(*p && p < (sysmap + sysmap_size) && *p != 10) + *(d++) = *(p++); + *(d++) = 0; + printf("%s\n", res); + cur++; + } + } while (cur); + sync(); + } + debugger_fault_handler = 0; + termch = 0; + break; + } } -#endif -#if 0 /* Makes compile with -Wall */ -static char *lookup_name(unsigned long addr) +static int +pretty_print_addr(unsigned long addr) { + char *sym; + unsigned long saddr; + + printf("%08x", addr); + sym = xmon_find_symbol(addr, &saddr); + if (sym) + printf(" (%s+0x%x)", sym, addr-saddr); + return (sym != 0); +} + +char* +xmon_find_symbol(unsigned long addr, unsigned long* saddr) +{ + static char rbuffer[64]; + char *p, *ep, *limit; + unsigned long prev, next; + char* psym; + extern char *sysmap; extern unsigned long sysmap_size; - char *c = sysmap; - unsigned long cmp; if ( !sysmap || !sysmap_size ) return NULL; -return NULL; -#if 0 - cmp = simple_strtoul(c, &c, 8); - /* XXX crap, we don't want the whole of the rest of the map - paulus */ - strcpy( last, strsep( &c, "\n")); - while ( c < (sysmap+sysmap_size) ) - { - cmp = simple_strtoul(c, &c, 8); - if ( cmp < addr ) - break; - strcpy( last, strsep( &c, "\n")); + + prev = 0; + psym = NULL; + p = sysmap; + limit = p + sysmap_size; + if( setjmp(bus_error_jmp) == 0 ) { + debugger_fault_handler = handle_fault; + sync(); + do { + next = simple_strtoul(p, &p, 16); + if (next > addr && prev <= addr) { + if (!psym) + goto bail; + ep = rbuffer; + p = psym; + while(*p && p < limit && *p == 32) + p++; + while(*p && p < limit && *p != 10 && (ep - rbuffer) < 63) + *(ep++) = *(p++); + *(ep++) = 0; + if (saddr) + *saddr = prev; + debugger_fault_handler = 0; + return rbuffer; + } + prev = next; + psym = p; + while(*p && p < limit && *p != 10) + p++; + if (*p) p++; + } while(*p && p < limit && next); +bail: + sync(); } - return last; -#endif + debugger_fault_handler = 0; + return NULL; } -#endif + +unsigned long +xmon_symbol_to_addr(char* symbol) +{ + char *p, *cur; + char *match; + int goodness = 0; + int result = 0; + + extern char *sysmap; + extern unsigned long sysmap_size; + if ( !sysmap || !sysmap_size ) + return 0; + + if( setjmp(bus_error_jmp) == 0 ) { + debugger_fault_handler = handle_fault; + sync(); + cur = sysmap; + while(cur) { + cur = strstr(cur, symbol); + if (cur) { + int gd = 1; + + /* best match if equal, better match if + * begins with + */ + if (cur == sysmap || *(cur-1) == ' ') { + gd++; + if (cur[strlen(symbol)] == 10) + gd++; + } + if (gd > goodness) { + match = cur; + goodness = gd; + if (gd == 3) + break; + } + cur++; + } + } + if (goodness) { + p = match; + while(p > sysmap && *p != 10) + p--; + if (*p == 10) p++; + result = simple_strtoul(p, &p, 16); + } + sync(); + } + debugger_fault_handler = 0; + return result; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/Makefile linux-2.5/arch/s390/Makefile --- linux-2.5.1/arch/s390/Makefile Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390/Makefile Thu Dec 27 16:32:30 2001 @@ -65,3 +65,6 @@ archdep: @$(MAKEBOOT) dep + +install: vmlinux + @$(MAKEBOOT) BOOTIMAGE=image install diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/boot/Makefile linux-2.5/arch/s390/boot/Makefile --- linux-2.5.1/arch/s390/boot/Makefile Wed Jul 25 21:12:01 2001 +++ linux-2.5/arch/s390/boot/Makefile Thu Dec 27 16:32:30 2001 @@ -35,3 +35,6 @@ clean: rm -f image listing iplfba.boot ipleckd.boot ipldump.boot +install: $(CONFIGURE) $(BOOTIMAGE) + sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map $(TOPDIR)/Kerntypes "$(INSTALL_PATH)" + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/config.in linux-2.5/arch/s390/config.in --- linux-2.5.1/arch/s390/config.in Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390/config.in Thu Dec 27 16:32:30 2001 @@ -67,9 +67,9 @@ comment 'Kernel hacking' #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -if [ "$CONFIG_CTC" = "y" ]; then - bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG -fi +#if [ "$CONFIG_CTC" = "y" ]; then +# bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG +#fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/defconfig linux-2.5/arch/s390/defconfig --- linux-2.5.1/arch/s390/defconfig Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390/defconfig Thu Dec 27 16:32:30 2001 @@ -7,7 +7,7 @@ CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_GENERIC_BUST_SPINLOCK=n +# CONFIG_GENERIC_BUST_SPINLOCK is not set CONFIG_ARCH_S390=y # @@ -103,8 +103,8 @@ # # S/390 tape hardware support # -CONFIG_S390_TAPE_3490=y -CONFIG_S390_TAPE_3480=y +CONFIG_S390_TAPE_3490=m +CONFIG_S390_TAPE_3480=m # # Network device drivers @@ -150,6 +150,7 @@ # CONFIG_IPV6_NETLINK is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -180,12 +181,12 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO 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_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -203,7 +204,7 @@ # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/kernel/debug.c linux-2.5/arch/s390/kernel/debug.c --- linux-2.5.1/arch/s390/kernel/debug.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390/kernel/debug.c Thu Dec 27 16:32:30 2001 @@ -228,8 +228,10 @@ 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 *)); +#ifdef CONFIG_PROC_FS memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * sizeof(struct proc_dir_entry*)); +#endif /* CONFIG_PROC_FS */ atomic_set(&(rc->ref_count), 0); return rc; @@ -346,8 +348,10 @@ if (!db_info) return; if (atomic_dec_and_test(&db_info->ref_count)) { +#ifdef DEBUG printk(KERN_INFO "debug: freeing debug area %p (%s)\n", db_info, db_info->name); +#endif for (i = 0; i < DEBUG_MAX_VIEWS; i++) { if (db_info->views[i] != NULL) debug_delete_proc_dir_entry @@ -541,14 +545,18 @@ debug_info_snapshot = debug_info_copy(debug_info); if(!debug_info_snapshot){ +#ifdef DEBUG printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n"); +#endif rc = -ENOMEM; goto out; } if ((file->private_data = kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { +#ifdef DEBUG printk(KERN_ERR "debug_open: kmalloc failed\n"); +#endif debug_info_free(debug_info_snapshot); rc = -ENOMEM; goto out; @@ -602,6 +610,7 @@ { struct proc_dir_entry *rc = NULL; +#ifdef CONFIG_PROC_FS #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) const char *fn = name; int len; @@ -634,6 +643,7 @@ #endif out: +#endif /* CONFIG_PROC_FS */ return rc; } @@ -646,12 +656,14 @@ (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry) { +#ifdef CONFIG_PROC_FS #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) proc_unregister(root, proc_entry->low_ino); kfree(proc_entry); #else remove_proc_entry(proc_entry->name, root); #endif +#endif /* CONFIG_PROC_FS */ } /* @@ -677,9 +689,11 @@ goto out; debug_register_view(rc, &debug_level_view); debug_register_view(rc, &debug_flush_view); +#ifdef DEBUG printk(KERN_INFO "debug: reserved %d areas of %d pages for debugging %s\n", nr_areas, 1 << page_order, rc->name); +#endif out: if (rc == NULL){ printk(KERN_ERR "debug: debug_register failed for %s\n",name); @@ -699,7 +713,9 @@ if (!id) goto out; down(&debug_lock); +#ifdef DEBUG printk(KERN_INFO "debug: unregistering %s\n", id->name); +#endif debug_info_put(id); up(&debug_lock); @@ -906,11 +922,13 @@ down(&debug_lock); if (!initialized) { +#ifdef CONFIG_PROC_FS debug_proc_root_entry = debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT, S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP, NULL, NULL); +#endif /* CONFIG_PROC_FS */ printk(KERN_INFO "debug: Initialization complete\n"); initialized = 1; } @@ -1271,7 +1289,9 @@ #ifdef DEBUG printk("debug_cleanup_module: \n"); #endif +#ifdef CONFIG_PROC_FS debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry); +#endif /* CONFIG_PROC_FS */ return; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/kernel/entry.S linux-2.5/arch/s390/kernel/entry.S --- linux-2.5.1/arch/s390/kernel/entry.S Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390/kernel/entry.S Thu Dec 27 16:32:30 2001 @@ -79,7 +79,7 @@ sigpending = 8 need_resched = 24 tsk_ptrace = 28 -processor = 56 +processor = 52 /* * Base Address of this Module --- saved in __LC_ENTRY_BASE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/kernel/init_task.c linux-2.5/arch/s390/kernel/init_task.c --- linux-2.5.1/arch/s390/kernel/init_task.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390/kernel/init_task.c Thu Dec 27 16:32:30 2001 @@ -12,7 +12,6 @@ #include <asm/uaccess.h> #include <asm/pgtable.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; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/kernel/process.c linux-2.5/arch/s390/kernel/process.c --- linux-2.5.1/arch/s390/kernel/process.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -57,7 +57,6 @@ /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; - current->counter = -100; wait_psw.mask = _WAIT_PSW_MASK; wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L; while(1) { @@ -75,173 +74,24 @@ } } -/* - As all the register will only be made displayable to the root - user ( via printk ) or checking if the uid of the user is 0 from - the /proc filesystem please god this will be secure enough DJB. - The lines are given one at a time so as not to chew stack space in - printk on a crash & also for the proc filesystem when you get - 0 returned you know you've got all the lines - */ - -static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs) -{ - int linelen=0; - int regno,chaincnt; - u32 backchain,prev_backchain,endchain; - u32 ksp = 0; - char *mode = "???"; - - enum - { - sp_linefeed, - sp_psw, - sp_ksp, - sp_gprs, - sp_gprs1, - sp_gprs2, - sp_gprs3, - sp_gprs4, - sp_acrs, - sp_acrs1, - sp_acrs2, - sp_acrs3, - sp_acrs4, - sp_kern_backchain, - sp_kern_backchain1 - }; - - if (task) - ksp = task->thread.ksp; - if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE)) - ksp = regs->gprs[15]; - - if (regs) - mode = (regs->psw.mask & PSW_PROBLEM_STATE)? - "User" : "Kernel"; - - switch(line) - { - case sp_linefeed: - linelen=sprintf(buff,"\n"); - break; - case sp_psw: - if(regs) - linelen=sprintf(buff, "%s PSW: %08lx %08lx %s\n", mode, - (unsigned long) regs->psw.mask, - (unsigned long) regs->psw.addr, - print_tainted()); - else - linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n"); - break; - case sp_ksp: - linelen=sprintf(&buff[linelen], - "task: %08x ksp: %08x pt_regs: %08x\n", - (addr_t)task, (addr_t)ksp, (addr_t)regs); - break; - case sp_gprs: - if(regs) - linelen=sprintf(buff, "%s GPRS:\n", mode); - break; - case sp_gprs1 ... sp_gprs4: - if(regs) - { - regno=(line-sp_gprs1)*4; - linelen=sprintf(buff,"%08x %08x %08x %08x\n", - regs->gprs[regno], - regs->gprs[regno+1], - regs->gprs[regno+2], - regs->gprs[regno+3]); - } - break; - case sp_acrs: - if(regs) - linelen=sprintf(buff, "%s ACRS:\n", mode); - break; - case sp_acrs1 ... sp_acrs4: - if(regs) - { - regno=(line-sp_acrs1)*4; - linelen=sprintf(buff,"%08x %08x %08x %08x\n", - regs->acrs[regno], - regs->acrs[regno+1], - regs->acrs[regno+2], - regs->acrs[regno+3]); - } - break; - case sp_kern_backchain: - if (regs && (regs->psw.mask & PSW_PROBLEM_STATE)) - break; - if (ksp) - linelen=sprintf(buff, "Kernel BackChain CallChain\n"); - break; - default: - if (ksp) - { - - backchain=ksp&PSW_ADDR_MASK; - endchain=((backchain&(-8192))+8192); - prev_backchain=backchain-1; - line-=sp_kern_backchain1; - for(chaincnt=0;;chaincnt++) - { - if((backchain==0)||(backchain>=endchain) - ||(chaincnt>=8)||(prev_backchain>=backchain)) - break; - if(chaincnt==line) - { - linelen+=sprintf(&buff[linelen]," %08x [<%08lx>]\n", - backchain, - *(u32 *)(backchain+56)&PSW_ADDR_MASK); - break; - } - prev_backchain=backchain; - backchain=(*((u32 *)backchain))&PSW_ADDR_MASK; - } - } - } - return(linelen); -} - +extern void show_registers(struct pt_regs *regs); +extern void show_trace(unsigned long *sp); void show_regs(struct pt_regs *regs) { - char buff[80]; - int i, line; + struct task_struct *tsk = current; - printk("CPU: %d\n",smp_processor_id()); - printk("Process %s (pid: %d, stackpage=%08X)\n", - current->comm, current->pid, 4096+(addr_t)current); - - for (line = 0; sprintf_regs(line, buff, current, regs); line++) - printk(buff); - - if (regs->psw.mask & PSW_PROBLEM_STATE) - { - printk("User Code:\n"); - memset(buff, 0, 20); - copy_from_user(buff, - (char *) (regs->psw.addr & PSW_ADDR_MASK), 20); - for (i = 0; i < 20; i++) - printk("%02x ", buff[i]); - printk("\n"); - } + printk("CPU: %d %s\n", tsk->processor, print_tainted()); + printk("Process %s (pid: %d, task: %08lx, ksp: %08x)\n", + current->comm, current->pid, (unsigned long) tsk, + tsk->thread.ksp); + + show_registers(regs); + /* Show stack backtrace if pt_regs is from kernel mode */ + if (!(regs->psw.mask & PSW_PROBLEM_STATE)) + show_trace((unsigned long *) regs->gprs[15]); } -char *task_show_regs(struct task_struct *task, char *buffer) -{ - int line, len; - - for (line = 0; ; line++) - { - len = sprintf_regs(line, buffer, task, task->thread.regs); - if (!len) break; - buffer += len; - } - return buffer; -} - - int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { int clone_arg = flags | CLONE_VM; @@ -301,16 +151,10 @@ unsigned long gprs[10]; /* gprs 6 -15 */ unsigned long fprs[4]; /* fpr 4 and 6 */ unsigned long empty[4]; -#if CONFIG_REMOTE_DEBUG - struct gdb_pt_regs childregs; -#else struct pt_regs childregs; -#endif } *frame; frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1; - frame = (struct stack_frame *) (((unsigned long) frame)&-8L); - p->thread.regs = (struct pt_regs *)&frame->childregs; p->thread.ksp = (unsigned long) frame; memcpy(&frame->childregs,regs,sizeof(struct pt_regs)); frame->childregs.gprs[15] = new_stackp; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/kernel/ptrace.c linux-2.5/arch/s390/kernel/ptrace.c --- linux-2.5.1/arch/s390/kernel/ptrace.c Tue Sep 18 23:58:03 2001 +++ linux-2.5/arch/s390/kernel/ptrace.c Thu Dec 27 16:32:31 2001 @@ -41,7 +41,7 @@ void FixPerRegisters(struct task_struct *task) { - struct pt_regs *regs = task->thread.regs; + struct pt_regs *regs = __KSTK_PTREGS(task); per_struct *per_info= (per_struct *)&task->thread.per_info; @@ -155,7 +155,7 @@ mask=0xffffffff; if(useraddr<PT_FPC) { - realuseraddr=(addr_t)&(((u8 *)task->thread.regs)[useraddr]); + realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr; if(useraddr<PT_PSWMASK) { copymax=PT_PSWMASK; @@ -217,7 +217,6 @@ { struct task_struct *child; int ret = -EPERM; - unsigned long flags; unsigned long tmp; int copied; ptrace_area parea; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/kernel/s390_ksyms.c linux-2.5/arch/s390/kernel/s390_ksyms.c --- linux-2.5.1/arch/s390/kernel/s390_ksyms.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390/kernel/s390_ksyms.c Thu Dec 27 16:32:31 2001 @@ -18,8 +18,9 @@ EXPORT_SYMBOL_NOVERS(_oi_bitmap); EXPORT_SYMBOL_NOVERS(_ni_bitmap); EXPORT_SYMBOL_NOVERS(_zb_findmap); -EXPORT_SYMBOL_NOVERS(__copy_from_user_fixup); -EXPORT_SYMBOL_NOVERS(__copy_to_user_fixup); +EXPORT_SYMBOL_NOVERS(__copy_from_user_asm); +EXPORT_SYMBOL_NOVERS(__copy_to_user_asm); +EXPORT_SYMBOL_NOVERS(__clear_user_asm); /* * semaphore ops @@ -35,6 +36,7 @@ EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(memscan); EXPORT_SYMBOL_NOVERS(strlen); EXPORT_SYMBOL_NOVERS(strchr); EXPORT_SYMBOL_NOVERS(strcmp); @@ -57,5 +59,3 @@ EXPORT_SYMBOL(console_mode); EXPORT_SYMBOL(console_device); EXPORT_SYMBOL_NOVERS(do_call_softirq); - - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/kernel/setup.c linux-2.5/arch/s390/kernel/setup.c --- linux-2.5.1/arch/s390/kernel/setup.c Sat Nov 17 02:38:39 2001 +++ linux-2.5/arch/s390/kernel/setup.c Thu Dec 27 16:32:31 2001 @@ -439,6 +439,7 @@ lowcore->kernel_stack = ((__u32) &init_task_union) + 8192; lowcore->async_stack = (__u32) __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0) + 8192; + lowcore->jiffy_timer = -1LL; set_prefix((__u32) lowcore); cpu_init(); boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr; @@ -485,15 +486,16 @@ static int show_cpuinfo(struct seq_file *m, void *v) { struct cpuinfo_S390 *cpuinfo; - unsigned n = v; + unsigned long n = (unsigned long) v - 1; - if (!n--) { + if (!n) { seq_printf(m, "vendor_id : IBM/S390\n" "# processors : %i\n" "bogomips per cpu: %lu.%02lu\n", smp_num_cpus, loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ))%100); - } else if (cpu_online_map & (1 << n)) { + } + if (cpu_online_map & (1 << n)) { cpuinfo = &safe_get_cpu_lowcore(n).cpu_data; seq_printf(m, "processor %i: " "version = %02X, " @@ -508,7 +510,7 @@ static void *c_start(struct seq_file *m, loff_t *pos) { - return *pos <= NR_CPUS ? (void)(*pos+1) : NULL; + return *pos <= NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL; } static void *c_next(struct seq_file *m, void *v, loff_t *pos) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/kernel/smp.c linux-2.5/arch/s390/kernel/smp.c --- linux-2.5.1/arch/s390/kernel/smp.c Wed Nov 21 18:31:09 2001 +++ linux-2.5/arch/s390/kernel/smp.c Thu Dec 27 16:32:31 2001 @@ -29,6 +29,7 @@ #include <linux/smp_lock.h> #include <linux/delay.h> +#include <linux/cache.h> #include <asm/sigp.h> #include <asm/pgalloc.h> @@ -48,14 +49,11 @@ static int max_cpus = NR_CPUS; /* Setup configured maximum number of CPUs to activate */ int smp_num_cpus; struct _lowcore *lowcore_ptr[NR_CPUS]; -unsigned int prof_multiplier[NR_CPUS]; -unsigned int prof_old_multiplier[NR_CPUS]; -unsigned int prof_counter[NR_CPUS]; cycles_t cacheflush_time=0; int smp_threads_ready=0; /* Set when the idlers are all forked. */ static atomic_t smp_commenced = ATOMIC_INIT(0); -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; unsigned long cpu_online_map; @@ -472,7 +470,7 @@ /* * Activate a secondary processor. */ -extern void init_100hz_timer(void); +extern void init_cpu_timer(void); extern int pfault_init(void); extern int pfault_token(void); @@ -485,8 +483,8 @@ /* Wait for completion of smp startup */ while (!atomic_read(&smp_commenced)) /* nothing */ ; - /* init per CPU 100 hz timer */ - init_100hz_timer(); + /* init per CPU timer */ + init_cpu_timer(); #ifdef CONFIG_PFAULT /* Enable pfault pseudo page faults on this cpu. */ pfault_init(); @@ -539,7 +537,7 @@ cpu_lowcore=&get_cpu_lowcore(cpu); cpu_lowcore->save_area[15] = idle->thread.ksp; - cpu_lowcore->kernel_stack = (idle->thread.ksp | 8191) + 1; + cpu_lowcore->kernel_stack = (__u32) idle + 8192; __asm__ __volatile__("la 1,%0\n\t" "stctl 0,15,0(1)\n\t" "la 1,%1\n\t" @@ -590,15 +588,7 @@ /* * Initialize the logical to physical CPU number mapping - * and the per-CPU profiling counter/multiplier */ - - for (i = 0; i < NR_CPUS; i++) { - prof_counter[i] = 1; - prof_old_multiplier[i] = 1; - prof_multiplier[i] = 1; - } - print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data); for(i = 0; i < smp_num_cpus; i++) @@ -645,58 +635,6 @@ int setup_profiling_timer(unsigned int multiplier) { return 0; -} - -/* - * Local timer interrupt handler. It does both profiling and - * process statistics/rescheduling. - * - * We do profiling in every local tick, statistics/rescheduling - * happen only every 'profiling multiplier' ticks. The default - * multiplier is 1 and it can be changed by writing the new multiplier - * value into /proc/profile. - */ - -void smp_local_timer_interrupt(struct pt_regs * regs) -{ - int user = (user_mode(regs) != 0); - int cpu = smp_processor_id(); - - /* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ - if (!user_mode(regs)) - s390_do_profile(regs->psw.addr); - - if (!--prof_counter[cpu]) { - - /* - * The multiplier may have changed since the last time we got - * to this point as a result of the user writing to - * /proc/profile. In this case we need to adjust the APIC - * timer accordingly. - * - * Interrupts are already masked off at this point. - */ - prof_counter[cpu] = prof_multiplier[cpu]; - if (prof_counter[cpu] != prof_old_multiplier[cpu]) { - /* FIXME setup_APIC_timer(calibration_result/prof_counter[cpu] - ); */ - prof_old_multiplier[cpu] = prof_counter[cpu]; - } - - /* - * After doing the above, we need to make like - * a normal interrupt - otherwise timer interrupts - * ignore the global interrupt lock, which is the - * WrongThing (tm) to do. - */ - - update_process_times(user); - } } EXPORT_SYMBOL(lowcore_ptr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/kernel/time.c linux-2.5/arch/s390/kernel/time.c --- linux-2.5.1/arch/s390/kernel/time.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390/kernel/time.c Thu Dec 27 16:32:31 2001 @@ -33,19 +33,18 @@ #include <asm/irq.h> - /* change this if you have some constant time drift */ -#define USECS_PER_JIFFY ((signed long)1000000/HZ) -#define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12) +#define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) +#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) #define TICK_SIZE tick -static uint64_t init_timer_cc, last_timer_cc; +static uint64_t init_timer_cc; extern rwlock_t xtime_lock; extern unsigned long wall_jiffies; -void tod_to_timeval(uint64_t todval, struct timeval *xtime) +void tod_to_timeval(__u64 todval, struct timeval *xtime) { const int high_bit = 0x80000000L; const int c_f4240 = 0xf4240L; @@ -79,13 +78,15 @@ : "cc", "memory", "2", "3", "4" ); } -unsigned long do_gettimeoffset(void) +static inline unsigned long do_gettimeoffset(void) { - __u64 timer_cc; + __u64 now; - asm volatile ("STCK %0" : "=m" (timer_cc)); - /* We require the offset from the previous interrupt */ - return ((unsigned long)((timer_cc - last_timer_cc)>>12)); + asm ("STCK %0" : "=m" (now)); + now = (now - init_timer_cc) >> 12; + /* We require the offset from the latest update of xtime */ + now -= (__u64) wall_jiffies*USECS_PER_JIFFY; + return (unsigned long) now; } /* @@ -95,15 +96,10 @@ { unsigned long flags; unsigned long usec, sec; - unsigned long lost_ticks; read_lock_irqsave(&xtime_lock, flags); - lost_ticks = jiffies - wall_jiffies; - usec = do_gettimeoffset(); - if (lost_ticks) - usec +=(USECS_PER_JIFFY*lost_ticks); sec = xtime.tv_sec; - usec += xtime.tv_usec; + usec = xtime.tv_usec + do_gettimeoffset(); read_unlock_irqrestore(&xtime_lock, flags); while (usec >= 1000000) { @@ -149,51 +145,31 @@ extern __u16 boot_cpu_addr; #endif -void do_timer_interrupt(struct pt_regs *regs, __u16 error_code) +static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code) { int cpu = smp_processor_id(); irq_enter(cpu, 0); - /* - * reset timer to 10ms minus time already elapsed - * since timer-interrupt pending - */ + /* + * set clock comparator for next tick + */ + S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; + asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer)); + #ifdef CONFIG_SMP - if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) { + if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) write_lock(&xtime_lock); - last_timer_cc = S390_lowcore.jiffy_timer_cc; - } -#else - last_timer_cc = S390_lowcore.jiffy_timer_cc; -#endif - /* set clock comparator */ - S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY; - asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc)); -/* - * In the SMP case we use the local timer interrupt to do the - * profiling, except when we simulate SMP mode on a uniprocessor - * system, in that case we have to call the local interrupt handler. - */ -#ifdef CONFIG_SMP - /* when SMP, do smp_local_timer_interrupt for *all* CPUs, - but only do the rest for the boot CPU */ - smp_local_timer_interrupt(regs); -#else - if (!user_mode(regs)) - s390_do_profile(regs->psw.addr); -#endif + update_process_times(user_mode(regs)); -#ifdef CONFIG_SMP - if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) -#endif - { + if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) { do_timer(regs); -#ifdef CONFIG_SMP write_unlock(&xtime_lock); -#endif } +#else + do_timer(regs); +#endif irq_exit(cpu, 0); } @@ -201,19 +177,17 @@ /* * Start the clock comparator on the current CPU */ -static long cr0 __attribute__ ((aligned (8))); - -void init_100hz_timer(void) +void init_cpu_timer(void) { + unsigned long cr0; + /* allow clock comparator timer interrupt */ asm volatile ("STCTL 0,0,%0" : "=m" (cr0) : : "memory"); cr0 |= 0x800; asm volatile ("LCTL 0,0,%0" : : "m" (cr0) : "memory"); - /* set clock comparator */ - /* read the TOD clock */ - asm volatile ("STCK %0" : "=m" (S390_lowcore.jiffy_timer_cc)); - S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY; - asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc)); + S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY; + S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY; + asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer)); } /* @@ -222,6 +196,7 @@ */ void __init time_init(void) { + __u64 set_time_cc; int cc; /* kick the TOD clock */ @@ -241,14 +216,18 @@ printk("time_init: TOD clock stopped/non-operational\n"); break; } + + /* set xtime */ + set_time_cc = init_timer_cc - 0x8126d60e46000000LL + + (0x3c26700LL*1000000*4096); + tod_to_timeval(set_time_cc, &xtime); + /* request the 0x1004 external interrupt */ - if (register_external_interrupt(0x1004, do_timer_interrupt) != 0) - panic("Couldn't request external interrupts 0x1004"); - init_100hz_timer(); - init_timer_cc = S390_lowcore.jiffy_timer_cc; - init_timer_cc -= 0x8126d60e46000000LL - - (0x3c26700LL*1000000*4096); - tod_to_timeval(init_timer_cc, &xtime); + if (register_external_interrupt(0x1004, do_comparator_interrupt) != 0) + panic("Couldn't request external interrupt 0x1004"); + + /* init CPU timer */ + init_cpu_timer(); /* Set do_get_fast_time function pointer. */ do_get_fast_time = do_gettimeofday; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/kernel/traps.c linux-2.5/arch/s390/kernel/traps.c --- linux-2.5.1/arch/s390/kernel/traps.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390/kernel/traps.c Thu Dec 27 16:32:31 2001 @@ -26,15 +26,13 @@ #include <linux/smp_lock.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/module.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/atomic.h> #include <asm/mathemu.h> -#if CONFIG_REMOTE_DEBUG -#include <asm/gdb-stub.h> -#endif #include <asm/cpcmd.h> #include <asm/s390_ext.h> @@ -60,6 +58,203 @@ extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code); #endif +int kstack_depth_to_print = 12; + +/* + * If the address is either in the .text section of the + * kernel, or in the vmalloc'ed module regions, it *may* + * be the address of a calling routine + */ +extern char _stext, _etext; + +#ifdef CONFIG_MODULES + +extern struct module *module_list; +extern struct module kernel_module; + +static inline int kernel_text_address(unsigned long addr) +{ + int retval = 0; + struct module *mod; + + if (addr >= (unsigned long) &_stext && + addr <= (unsigned long) &_etext) + return 1; + + for (mod = module_list; mod != &kernel_module; mod = mod->next) { + /* mod_bound tests for addr being inside the vmalloc'ed + * module area. Of course it'd be better to test only + * for the .text subset... */ + if (mod_bound(addr, 0, mod)) { + retval = 1; + break; + } + } + + return retval; +} + +#else + +static inline int kernel_text_address(unsigned long addr) +{ + return (addr >= (unsigned long) &_stext && + addr <= (unsigned long) &_etext); +} + +#endif + +void show_trace(unsigned long * stack) +{ + unsigned long backchain, low_addr, high_addr, ret_addr; + int i; + + if (!stack) + stack = (unsigned long*)&stack; + + printk("Call Trace: "); + low_addr = ((unsigned long) stack) & PSW_ADDR_MASK; + high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE; + /* Skip the first frame (biased stack) */ + backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK; + /* Print up to 8 lines */ + for (i = 0; i < 8; i++) { + if (backchain < low_addr || backchain >= high_addr) + break; + ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_MASK; + if (!kernel_text_address(ret_addr)) + break; + if (i && ((i % 6) == 0)) + printk("\n "); + printk("[<%08lx>] ", ret_addr); + low_addr = backchain; + backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK; + } + printk("\n"); +} + +void show_trace_task(struct task_struct *tsk) +{ + /* + * We can't print the backtrace of a running process. It is + * unreliable at best and can cause kernel oopses. + */ + if (task_has_cpu(tsk)) + return; + show_trace((unsigned long *) tsk->thread.ksp); +} + +void show_stack(unsigned long *sp) +{ + unsigned long *stack; + int i; + + // debugging aid: "show_stack(NULL);" prints the + // back trace for this cpu. + + if(sp == NULL) + sp = (unsigned long*) &sp; + + stack = sp; + for (i = 0; i < kstack_depth_to_print; i++) { + if (((addr_t) stack & (THREAD_SIZE-1)) == 0) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + printk("%08lx ", *stack++); + } + printk("\n"); + show_trace(sp); +} + +void show_registers(struct pt_regs *regs) +{ + mm_segment_t old_fs; + char *mode; + int i; + + mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl"; + printk("%s PSW : %08lx %08lx\n", + mode, (unsigned long) regs->psw.mask, + (unsigned long) regs->psw.addr); + printk("%s GPRS: %08x %08x %08x %08x\n", mode, + regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); + printk(" %08x %08x %08x %08x\n", + regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); + printk(" %08x %08x %08x %08x\n", + regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]); + printk(" %08x %08x %08x %08x\n", + regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); + printk("%s ACRS: %08x %08x %08x %08x\n", mode, + regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]); + printk(" %08x %08x %08x %08x\n", + regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]); + printk(" %08x %08x %08x %08x\n", + regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]); + printk(" %08x %08x %08x %08x\n", + regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]); + + /* + * Print the first 20 byte of the instruction stream at the + * time of the fault. + */ + old_fs = get_fs(); + if (regs->psw.mask & PSW_PROBLEM_STATE) + set_fs(USER_DS); + else + set_fs(KERNEL_DS); + printk("%s Code: ", mode); + for (i = 0; i < 20; i++) { + unsigned char c; + if (__get_user(c, (char *)(regs->psw.addr + i))) { + printk(" Bad PSW."); + break; + } + printk("%02x ", c); + } + set_fs(old_fs); + + printk("\n"); +} + +/* This is called from fs/proc/array.c */ +char *task_show_regs(struct task_struct *task, char *buffer) +{ + struct pt_regs *regs; + + regs = __KSTK_PTREGS(task); + buffer += sprintf(buffer, "task: %08lx, ksp: %08x\n", + (unsigned long) task, task->thread.ksp); + buffer += sprintf(buffer, "User PSW : %08lx %08lx\n", + (unsigned long) regs->psw.mask, + (unsigned long) regs->psw.addr); + buffer += sprintf(buffer, "User GPRS: %08x %08x %08x %08x\n", + regs->gprs[0], regs->gprs[1], + regs->gprs[2], regs->gprs[3]); + buffer += sprintf(buffer, " %08x %08x %08x %08x\n", + regs->gprs[4], regs->gprs[5], + regs->gprs[6], regs->gprs[7]); + buffer += sprintf(buffer, " %08x %08x %08x %08x\n", + regs->gprs[8], regs->gprs[9], + regs->gprs[10], regs->gprs[11]); + buffer += sprintf(buffer, " %08x %08x %08x %08x\n", + regs->gprs[12], regs->gprs[13], + regs->gprs[14], regs->gprs[15]); + buffer += sprintf(buffer, "User ACRS: %08x %08x %08x %08x\n", + regs->acrs[0], regs->acrs[1], + regs->acrs[2], regs->acrs[3]); + buffer += sprintf(buffer, " %08x %08x %08x %08x\n", + regs->acrs[4], regs->acrs[5], + regs->acrs[6], regs->acrs[7]); + buffer += sprintf(buffer, " %08x %08x %08x %08x\n", + regs->acrs[8], regs->acrs[9], + regs->acrs[10], regs->acrs[11]); + buffer += sprintf(buffer, " %08x %08x %08x %08x\n", + regs->acrs[12], regs->acrs[13], + regs->acrs[14], regs->acrs[15]); + return buffer; +} + spinlock_t die_lock = SPIN_LOCK_UNLOCKED; void die(const char * str, struct pt_regs * regs, long err) @@ -145,7 +340,7 @@ #if CONFIG_REMOTE_DEBUG if(gdb_stub_initialised) { - gdb_stub_handle_exception((struct gdb_pt_regs *)regs,signal); + gdb_stub_handle_exception(regs, signal); return 0; } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/lib/uaccess.S linux-2.5/arch/s390/lib/uaccess.S --- linux-2.5.1/arch/s390/lib/uaccess.S Tue Feb 13 22:13:44 2001 +++ linux-2.5/arch/s390/lib/uaccess.S Thu Dec 27 16:32:31 2001 @@ -6,46 +6,92 @@ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) * - * These functions have a non-standard call interface + * These functions have standard call interface */ #include <asm/lowcore.h> .text .align 4 - .globl __copy_from_user_fixup -__copy_from_user_fixup: - l 1,__LC_PGM_OLD_PSW+4 - sll 4,1 - srl 4,1 -0: lhi 3,-4096 - sll 3,1 - srl 3,1 - n 3,__LC_TRANS_EXC_ADDR - sr 3,4 - bm 4(1) -1: mvcle 2,4,0 - b 4(1) + .globl __copy_from_user_asm +__copy_from_user_asm: + lr %r5,%r3 + sacf 512 +0: mvcle %r2,%r4,0 + jo 0b + sacf 0 + lr %r2,%r5 + br %r14 +1: l %r1,__LC_PGM_OLD_PSW+4 + sll %r4,1 + srl %r4,1 +2: lhi %r3,-4096 + sll %r3,1 + srl %r3,1 + n %r3,__LC_TRANS_EXC_ADDR + sr %r3,%r4 + bm 4(%r1) +3: mvcle %r2,%r4,0 + b 4(%r1) .section __ex_table,"a" - .long 1b,0b + .long 0b,1b + .long 3b,2b .previous .align 4 .text - .globl __copy_to_user_fixup -__copy_to_user_fixup: - l 1,__LC_PGM_OLD_PSW+4 - sll 4,1 - srl 4,1 -0: lhi 5,-4096 - sll 5,1 - srl 5,1 - n 5,__LC_TRANS_EXC_ADDR - sr 5,4 - bm 4(1) -1: mvcle 4,2,0 - b 4(1) + .globl __copy_to_user_asm +__copy_to_user_asm: + lr %r5,%r3 + sacf 512 +0: mvcle %r4,%r2,0 + jo 0b + sacf 0 + lr %r2,%r3 + br %r14 +1: l %r1,__LC_PGM_OLD_PSW+4 + sll %r4,1 + srl %r4,1 +2: lhi %r5,-4096 + sll %r5,1 + srl %r5,1 + n %r5,__LC_TRANS_EXC_ADDR + sr %r5,%r4 + bm 4(%r1) +3: mvcle %r4,%r2,0 + b 4(%r1) .section __ex_table,"a" - .long 1b,0b + .long 0b,1b + .long 3b,2b + .previous + + .align 4 + .text + .globl __clear_user_asm +__clear_user_asm: + lr %r4,%r2 + lr %r5,%r3 + sr %r2,%r2 + sr %r3,%r3 + sacf 512 +0: mvcle %r4,%r2,0 + jo 0b + sacf 0 + lr %r2,%r3 + br %r14 +1: l %r1,__LC_PGM_OLD_PSW+4 + sll %r4,1 + srl %r4,1 +2: lhi %r5,-4096 + sll %r5,1 + srl %r5,1 + n %r5,__LC_TRANS_EXC_ADDR + sr %r5,%r4 + bm 4(%r1) +3: mvcle %r4,%r2,0 + b 4(%r1) + .section __ex_table,"a" + .long 0b,1b + .long 3b,2b .previous diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/math-emu/math.c linux-2.5/arch/s390/math-emu/math.c --- linux-2.5.1/arch/s390/math-emu/math.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390/math-emu/math.c Thu Dec 27 16:32:31 2001 @@ -96,7 +96,7 @@ return SIGSEGV; \ } while (0) -static void display_emulation_not_implemented(char *instr) +static void display_emulation_not_implemented(struct pt_regs *regs, char *instr) { struct pt_regs *regs; __u16 *location; @@ -105,7 +105,6 @@ 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", @@ -116,10 +115,9 @@ } } -static inline void emu_set_CC (int cc) +static inline void emu_set_CC (struct pt_regs *regs, int cc) { - current->thread.regs->psw.mask = - (current->thread.regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12); + regs->psw.mask = (regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12); } /* @@ -129,24 +127,24 @@ * 2 : Result is greater than zero * 3 : Result is NaN or INF */ -static inline void emu_set_CC_cs(int class, int sign) +static inline void emu_set_CC_cs(struct pt_regs *regs, int class, int sign) { switch (class) { case FP_CLS_NORMAL: case FP_CLS_INF: - emu_set_CC(sign ? 1 : 2); + emu_set_CC(regs, sign ? 1 : 2); break; case FP_CLS_ZERO: - emu_set_CC(0); + emu_set_CC(regs, 0); break; case FP_CLS_NAN: - emu_set_CC(3); + emu_set_CC(regs, 3); break; } } /* Add long double */ -static int emu_axbr (int rx, int ry) { +static int emu_axbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -163,12 +161,12 @@ 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); + emu_set_CC_cs(regs, QR_c, QR_s); return _fex; } /* Add double */ -static int emu_adbr (int rx, int ry) { +static int emu_adbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -178,12 +176,12 @@ 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); + emu_set_CC_cs(regs, DR_c, DR_s); return _fex; } /* Add double */ -static int emu_adb (int rx, double *val) { +static int emu_adb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -193,12 +191,12 @@ 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); + emu_set_CC_cs(regs, DR_c, DR_s); return _fex; } /* Add float */ -static int emu_aebr (int rx, int ry) { +static int emu_aebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -208,12 +206,12 @@ 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); + emu_set_CC_cs(regs, SR_c, SR_s); return _fex; } /* Add float */ -static int emu_aeb (int rx, float *val) { +static int emu_aeb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -223,12 +221,12 @@ 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); + emu_set_CC_cs(regs, SR_c, SR_s); return _fex; } /* Compare long double */ -static int emu_cxbr (int rx, int ry) { +static int emu_cxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QB); mathemu_ldcv cvt; int IR; @@ -244,12 +242,12 @@ * 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); + emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); return 0; } /* Compare double */ -static int emu_cdbr (int rx, int ry) { +static int emu_cdbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DB); int IR; @@ -260,12 +258,12 @@ * 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); + emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); return 0; } /* Compare double */ -static int emu_cdb (int rx, double *val) { +static int emu_cdb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_D(DB); int IR; @@ -276,12 +274,12 @@ * 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); + emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); return 0; } /* Compare float */ -static int emu_cebr (int rx, int ry) { +static int emu_cebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SB); int IR; @@ -292,12 +290,12 @@ * 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); + emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); return 0; } /* Compare float */ -static int emu_ceb (int rx, float *val) { +static int emu_ceb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_S(SB); int IR; @@ -308,12 +306,12 @@ * 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); + emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); return 0; } /* Compare and signal long double */ -static int emu_kxbr (int rx, int ry) { +static int emu_kxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_EX; mathemu_ldcv cvt; @@ -330,14 +328,14 @@ * 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); + emu_set_CC(regs, (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) { +static int emu_kdbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_EX; int IR; @@ -349,14 +347,14 @@ * 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); + emu_set_CC(regs, (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) { +static int emu_kdb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_EX; int IR; @@ -368,14 +366,14 @@ * 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); + emu_set_CC(regs, (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) { +static int emu_kebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_EX; int IR; @@ -387,14 +385,14 @@ * 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); + emu_set_CC(regs, (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) { +static int emu_keb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_EX; int IR; @@ -406,14 +404,14 @@ * 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); + emu_set_CC(regs, (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) { +static int emu_cxfbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -421,7 +419,7 @@ int mode; mode = current->thread.fp_regs.fpc & 3; - si = current->thread.regs->gprs[ry]; + si = 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; @@ -430,35 +428,35 @@ } /* Convert from fixed double */ -static int emu_cdfbr (int rx, int ry) { +static int emu_cdfbr (struct pt_regs *regs, 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]; + si = 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) { +static int emu_cefbr (struct pt_regs *regs, 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]; + si = 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) { +static int emu_cfxbr (struct pt_regs *regs, int rx, int ry, int mask) { FP_DECL_Q(QA); FP_DECL_EX; mathemu_ldcv cvt; @@ -475,13 +473,13 @@ 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); + regs->gprs[rx] = si; + emu_set_CC_cs(regs, QA_c, QA_s); return _fex; } /* Convert to fixed double */ -static int emu_cfdbr (int rx, int ry, int mask) { +static int emu_cfdbr (struct pt_regs *regs, int rx, int ry, int mask) { FP_DECL_D(DA); FP_DECL_EX; __s32 si; @@ -495,13 +493,13 @@ 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); + regs->gprs[rx] = si; + emu_set_CC_cs(regs, DA_c, DA_s); return _fex; } /* Convert to fixed float */ -static int emu_cfebr (int rx, int ry, int mask) { +static int emu_cfebr (struct pt_regs *regs, int rx, int ry, int mask) { FP_DECL_S(SA); FP_DECL_EX; __s32 si; @@ -515,13 +513,13 @@ 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); + regs->gprs[rx] = si; + emu_set_CC_cs(regs, SA_c, SA_s); return _fex; } /* Divide long double */ -static int emu_dxbr (int rx, int ry) { +static int emu_dxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -542,7 +540,7 @@ } /* Divide double */ -static int emu_ddbr (int rx, int ry) { +static int emu_ddbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -556,7 +554,7 @@ } /* Divide double */ -static int emu_ddb (int rx, double *val) { +static int emu_ddb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -570,7 +568,7 @@ } /* Divide float */ -static int emu_debr (int rx, int ry) { +static int emu_debr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -584,7 +582,7 @@ } /* Divide float */ -static int emu_deb (int rx, float *val) { +static int emu_deb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -598,25 +596,25 @@ } /* Divide to integer double */ -static int emu_didbr (int rx, int ry, int mask) { - display_emulation_not_implemented("didbr"); +static int emu_didbr (struct pt_regs *regs, int rx, int ry, int mask) { + display_emulation_not_implemented(regs, "didbr"); return 0; } /* Divide to integer float */ -static int emu_diebr (int rx, int ry, int mask) { - display_emulation_not_implemented("diebr"); +static int emu_diebr (struct pt_regs *regs, int rx, int ry, int mask) { + display_emulation_not_implemented(regs, "diebr"); return 0; } /* Extract fpc */ -static int emu_efpc (int rx, int ry) { - current->thread.regs->gprs[rx] = current->thread.fp_regs.fpc; +static int emu_efpc (struct pt_regs *regs, int rx, int ry) { + regs->gprs[rx] = current->thread.fp_regs.fpc; return 0; } /* Load and test long double */ -static int emu_ltxbr (int rx, int ry) { +static int emu_ltxbr (struct pt_regs *regs, int rx, int ry) { s390_fp_regs *fp_regs = ¤t->thread.fp_regs; mathemu_ldcv cvt; FP_DECL_Q(QA); @@ -627,36 +625,36 @@ 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); + emu_set_CC_cs(regs, QA_c, QA_s); return _fex; } /* Load and test double */ -static int emu_ltdbr (int rx, int ry) { +static int emu_ltdbr (struct pt_regs *regs, 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); + emu_set_CC_cs(regs, DA_c, DA_s); return _fex; } /* Load and test double */ -static int emu_ltebr (int rx, int ry) { +static int emu_ltebr (struct pt_regs *regs, 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); + emu_set_CC_cs(regs, SA_c, SA_s); return _fex; } /* Load complement long double */ -static int emu_lcxbr (int rx, int ry) { +static int emu_lcxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -670,12 +668,12 @@ 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); + emu_set_CC_cs(regs, QR_c, QR_s); return _fex; } /* Load complement double */ -static int emu_lcdbr (int rx, int ry) { +static int emu_lcdbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -684,12 +682,12 @@ 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); + emu_set_CC_cs(regs, DR_c, DR_s); return _fex; } /* Load complement float */ -static int emu_lcebr (int rx, int ry) { +static int emu_lcebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -698,12 +696,12 @@ 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); + emu_set_CC_cs(regs, SR_c, SR_s); return _fex; } /* Load floating point integer long double */ -static int emu_fixbr (int rx, int ry, int mask) { +static int emu_fixbr (struct pt_regs *regs, int rx, int ry, int mask) { s390_fp_regs *fp_regs = ¤t->thread.fp_regs; FP_DECL_Q(QA); FP_DECL_EX; @@ -728,7 +726,7 @@ } /* Load floating point integer double */ -static int emu_fidbr (int rx, int ry, int mask) { +static int emu_fidbr (struct pt_regs *regs, int rx, int ry, int mask) { /* FIXME: rounding mode !! */ s390_fp_regs *fp_regs = ¤t->thread.fp_regs; FP_DECL_D(DA); @@ -749,7 +747,7 @@ } /* Load floating point integer float */ -static int emu_fiebr (int rx, int ry, int mask) { +static int emu_fiebr (struct pt_regs *regs, int rx, int ry, int mask) { s390_fp_regs *fp_regs = ¤t->thread.fp_regs; FP_DECL_S(SA); FP_DECL_EX; @@ -769,7 +767,7 @@ } /* Load lengthened double to long double */ -static int emu_lxdbr (int rx, int ry) { +static int emu_lxdbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -785,7 +783,7 @@ } /* Load lengthened double to long double */ -static int emu_lxdb (int rx, double *val) { +static int emu_lxdb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -801,7 +799,7 @@ } /* Load lengthened float to long double */ -static int emu_lxebr (int rx, int ry) { +static int emu_lxebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -817,7 +815,7 @@ } /* Load lengthened float to long double */ -static int emu_lxeb (int rx, float *val) { +static int emu_lxeb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -833,7 +831,7 @@ } /* Load lengthened float to double */ -static int emu_ldebr (int rx, int ry) { +static int emu_ldebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -846,7 +844,7 @@ } /* Load lengthened float to double */ -static int emu_ldeb (int rx, float *val) { +static int emu_ldeb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -859,7 +857,7 @@ } /* Load negative long double */ -static int emu_lnxbr (int rx, int ry) { +static int emu_lnxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -880,12 +878,12 @@ current->thread.fp_regs.fprs[rx+2].ui = current->thread.fp_regs.fprs[ry+2].ui; } - emu_set_CC_cs(QR_c, QR_s); + emu_set_CC_cs(regs, QR_c, QR_s); return _fex; } /* Load negative double */ -static int emu_lndbr (int rx, int ry) { +static int emu_lndbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -898,12 +896,12 @@ } else current->thread.fp_regs.fprs[rx].ui = current->thread.fp_regs.fprs[ry].ui; - emu_set_CC_cs(DR_c, DR_s); + emu_set_CC_cs(regs, DR_c, DR_s); return _fex; } /* Load negative float */ -static int emu_lnebr (int rx, int ry) { +static int emu_lnebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -916,12 +914,12 @@ } else current->thread.fp_regs.fprs[rx].ui = current->thread.fp_regs.fprs[ry].ui; - emu_set_CC_cs(SR_c, SR_s); + emu_set_CC_cs(regs, SR_c, SR_s); return _fex; } /* Load positive long double */ -static int emu_lpxbr (int rx, int ry) { +static int emu_lpxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -942,12 +940,12 @@ current->thread.fp_regs.fprs[rx+2].ui = current->thread.fp_regs.fprs[ry+2].ui; } - emu_set_CC_cs(QR_c, QR_s); + emu_set_CC_cs(regs, QR_c, QR_s); return _fex; } /* Load positive double */ -static int emu_lpdbr (int rx, int ry) { +static int emu_lpdbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -960,12 +958,12 @@ } else current->thread.fp_regs.fprs[rx].ui = current->thread.fp_regs.fprs[ry].ui; - emu_set_CC_cs(DR_c, DR_s); + emu_set_CC_cs(regs, DR_c, DR_s); return _fex; } /* Load positive float */ -static int emu_lpebr (int rx, int ry) { +static int emu_lpebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -978,12 +976,12 @@ } else current->thread.fp_regs.fprs[rx].ui = current->thread.fp_regs.fprs[ry].ui; - emu_set_CC_cs(SR_c, SR_s); + emu_set_CC_cs(regs, SR_c, SR_s); return _fex; } /* Load rounded long double to double */ -static int emu_ldxbr (int rx, int ry) { +static int emu_ldxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_D(DR); FP_DECL_EX; mathemu_ldcv cvt; @@ -999,7 +997,7 @@ } /* Load rounded long double to float */ -static int emu_lexbr (int rx, int ry) { +static int emu_lexbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_S(SR); FP_DECL_EX; mathemu_ldcv cvt; @@ -1015,7 +1013,7 @@ } /* Load rounded double to float */ -static int emu_ledbr (int rx, int ry) { +static int emu_ledbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -1028,7 +1026,7 @@ } /* Multiply long double */ -static int emu_mxbr (int rx, int ry) { +static int emu_mxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -1049,7 +1047,7 @@ } /* Multiply double */ -static int emu_mdbr (int rx, int ry) { +static int emu_mdbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -1063,7 +1061,7 @@ } /* Multiply double */ -static int emu_mdb (int rx, double *val) { +static int emu_mdb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -1077,7 +1075,7 @@ } /* Multiply double to long double */ -static int emu_mxdbr (int rx, int ry) { +static int emu_mxdbr (struct pt_regs *regs, 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; @@ -1096,7 +1094,7 @@ } /* Multiply double to long double */ -static int emu_mxdb (int rx, long double *val) { +static int emu_mxdb (struct pt_regs *regs, int rx, long double *val) { FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -1115,7 +1113,7 @@ } /* Multiply float */ -static int emu_meebr (int rx, int ry) { +static int emu_meebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -1129,7 +1127,7 @@ } /* Multiply float */ -static int emu_meeb (int rx, float *val) { +static int emu_meeb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -1143,7 +1141,7 @@ } /* Multiply float to double */ -static int emu_mdebr (int rx, int ry) { +static int emu_mdebr (struct pt_regs *regs, 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; @@ -1159,7 +1157,7 @@ } /* Multiply float to double */ -static int emu_mdeb (int rx, float *val) { +static int emu_mdeb (struct pt_regs *regs, 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; @@ -1175,7 +1173,7 @@ } /* Multiply and add double */ -static int emu_madbr (int rx, int ry, int rz) { +static int emu_madbr (struct pt_regs *regs, 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; @@ -1191,7 +1189,7 @@ } /* Multiply and add double */ -static int emu_madb (int rx, double *val, int rz) { +static int emu_madb (struct pt_regs *regs, 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; @@ -1207,7 +1205,7 @@ } /* Multiply and add float */ -static int emu_maebr (int rx, int ry, int rz) { +static int emu_maebr (struct pt_regs *regs, 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; @@ -1223,7 +1221,7 @@ } /* Multiply and add float */ -static int emu_maeb (int rx, float *val, int rz) { +static int emu_maeb (struct pt_regs *regs, 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; @@ -1239,7 +1237,7 @@ } /* Multiply and subtract double */ -static int emu_msdbr (int rx, int ry, int rz) { +static int emu_msdbr (struct pt_regs *regs, 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; @@ -1255,7 +1253,7 @@ } /* Multiply and subtract double */ -static int emu_msdb (int rx, double *val, int rz) { +static int emu_msdb (struct pt_regs *regs, 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; @@ -1271,7 +1269,7 @@ } /* Multiply and subtract float */ -static int emu_msebr (int rx, int ry, int rz) { +static int emu_msebr (struct pt_regs *regs, 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; @@ -1287,7 +1285,7 @@ } /* Multiply and subtract float */ -static int emu_mseb (int rx, float *val, int rz) { +static int emu_mseb (struct pt_regs *regs, 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; @@ -1303,10 +1301,10 @@ } /* Set floating point control word */ -static int emu_sfpc (int rx, int ry) { +static int emu_sfpc (struct pt_regs *regs, int rx, int ry) { __u32 temp; - temp = current->thread.regs->gprs[rx]; + temp = regs->gprs[rx]; if ((temp & ~FPC_VALID_MASK) != 0) return SIGILL; current->thread.fp_regs.fpc = temp; @@ -1314,7 +1312,7 @@ } /* Square root long double */ -static int emu_sqxbr (int rx, int ry) { +static int emu_sqxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -1328,12 +1326,12 @@ 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); + emu_set_CC_cs(regs, QR_c, QR_s); return _fex; } /* Square root double */ -static int emu_sqdbr (int rx, int ry) { +static int emu_sqdbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -1342,12 +1340,12 @@ 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); + emu_set_CC_cs(regs, DR_c, DR_s); return _fex; } /* Square root double */ -static int emu_sqdb (int rx, double *val) { +static int emu_sqdb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -1356,12 +1354,12 @@ 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); + emu_set_CC_cs(regs, DR_c, DR_s); return _fex; } /* Square root float */ -static int emu_sqebr (int rx, int ry) { +static int emu_sqebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -1370,12 +1368,12 @@ 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); + emu_set_CC_cs(regs, SR_c, SR_s); return _fex; } /* Square root float */ -static int emu_sqeb (int rx, float *val) { +static int emu_sqeb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -1384,12 +1382,12 @@ 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); + emu_set_CC_cs(regs, SR_c, SR_s); return _fex; } /* Subtract long double */ -static int emu_sxbr (int rx, int ry) { +static int emu_sxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; @@ -1406,12 +1404,12 @@ 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); + emu_set_CC_cs(regs, QR_c, QR_s); return _fex; } /* Subtract double */ -static int emu_sdbr (int rx, int ry) { +static int emu_sdbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -1421,12 +1419,12 @@ 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); + emu_set_CC_cs(regs, DR_c, DR_s); return _fex; } /* Subtract double */ -static int emu_sdb (int rx, double *val) { +static int emu_sdb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); FP_DECL_EX; int mode; @@ -1436,12 +1434,12 @@ 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); + emu_set_CC_cs(regs, DR_c, DR_s); return _fex; } /* Subtract float */ -static int emu_sebr (int rx, int ry) { +static int emu_sebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -1451,12 +1449,12 @@ 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); + emu_set_CC_cs(regs, SR_c, SR_s); return _fex; } /* Subtract float */ -static int emu_seb (int rx, float *val) { +static int emu_seb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); FP_DECL_EX; int mode; @@ -1466,12 +1464,12 @@ 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); + emu_set_CC_cs(regs, SR_c, SR_s); return _fex; } /* Test data class long double */ -static int emu_tcxb (int rx, long val) { +static int emu_tcxb (struct pt_regs *regs, int rx, long val) { FP_DECL_Q(QA); mathemu_ldcv cvt; int bit; @@ -1500,12 +1498,12 @@ } if (!QA_s) bit++; - emu_set_CC(((__u32) val >> bit) & 1); + emu_set_CC(regs, ((__u32) val >> bit) & 1); return 0; } /* Test data class double */ -static int emu_tcdb (int rx, long val) { +static int emu_tcdb (struct pt_regs *regs, int rx, long val) { FP_DECL_D(DA); int bit; @@ -1531,12 +1529,12 @@ } if (!DA_s) bit++; - emu_set_CC(((__u32) val >> bit) & 1); + emu_set_CC(regs, ((__u32) val >> bit) & 1); return 0; } /* Test data class float */ -static int emu_tceb (int rx, long val) { +static int emu_tceb (struct pt_regs *regs, int rx, long val) { FP_DECL_S(SA); int bit; @@ -1562,7 +1560,7 @@ } if (!SA_s) bit++; - emu_set_CC(((__u32) val >> bit) & 1); + emu_set_CC(regs, ((__u32) val >> bit) & 1); return 0; } @@ -1666,8 +1664,9 @@ 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); + _fex = ((int (*)(struct pt_regs *,int, int)) + jump_table[opcode[1]]) + (regs, 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); @@ -1677,8 +1676,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, opcode[3] >> 4, opcode[3] & 15); emu_load_regd((opcode[3] >> 4) & 15); emu_load_regd(opcode[3] & 15); break; @@ -1686,8 +1686,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, opcode[3] >> 4, opcode[3] & 15); emu_load_rege((opcode[3] >> 4) & 15); emu_load_rege(opcode[3] & 15); break; @@ -1699,8 +1700,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int, int)) + jump_table[opcode[1]]) + (regs, 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); @@ -1711,8 +1713,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int, int)) + jump_table[opcode[1]]) + (regs, 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); @@ -1722,8 +1725,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int, int)) + jump_table[opcode[1]]) + (regs, 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); @@ -1732,21 +1736,24 @@ /* call the emulation function */ if (opcode[3] & 0x20) return SIGILL; - _fex = ((int (*)(int, int)) jump_table[opcode[1]]) - (opcode[3] >> 4, opcode[3] & 15); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, opcode[3] >> 4, opcode[3] & 15); emu_load_rege((opcode[3] >> 4) & 15); break; case 10: /* RRF format, cfxbr instruction */ @@ -1758,8 +1765,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int, int)) + jump_table[opcode[1]]) + (regs, 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) @@ -1767,8 +1775,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int, int)) + jump_table[opcode[1]]) + (regs, 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) @@ -1776,8 +1785,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int, int)) + jump_table[opcode[1]]) + (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4); break; case 13: /* RRE format, ldxbr & mdxbr instruction */ /* double store but long double load */ @@ -1786,8 +1796,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, opcode[3] >> 4, opcode[3] & 15); emu_load_regd((opcode[3] >> 4) & 15); emu_load_regd(((opcode[3] >> 4) & 15) + 2); break; @@ -1798,8 +1809,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, opcode[3] >> 4, opcode[3] & 15); emu_load_regd((opcode[3] >> 4) & 15); emu_load_regd(((opcode[3] >> 4) & 15) + 2); break; @@ -1808,8 +1820,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, opcode[3] >> 4, opcode[3] & 15); emu_load_regd((opcode[3] >> 4) & 15); break; case 16: /* RRE format, ldxbr instruction */ @@ -1819,8 +1832,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, opcode[3] >> 4, opcode[3] & 15); emu_load_regd((opcode[3] >> 4) & 15); break; case 17: /* RRE format, ldxbr instruction */ @@ -1830,22 +1844,25 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, 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); + _fex = ((int (*)(struct pt_regs *, int, int)) + jump_table[opcode[1]]) + (regs, opcode[3] >> 4, opcode[3] & 15); break; default: /* invalid operation */ return SIGILL; @@ -1904,8 +1921,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, double *)) + jump_table[opcode[5]]) + (regs, opcode[1] >> 4, (double *) &temp); emu_load_regd((opcode[1] >> 4) & 15); break; } @@ -1918,8 +1936,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, float *)) + jump_table[opcode[5]]) + (regs, opcode[1] >> 4, (float *) &temp); emu_load_rege((opcode[1] >> 4) & 15); break; } @@ -1933,8 +1952,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, double *, int)) + jump_table[opcode[5]]) + (regs, opcode[1] >> 4, (double *) &temp, opcode[4] >> 4); emu_load_regd((opcode[1] >> 4) & 15); break; } @@ -1948,8 +1968,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, float *, int)) + jump_table[opcode[5]]) + (regs, opcode[1] >> 4, (float *) &temp, opcode[4] >> 4); emu_load_rege((opcode[4] >> 4) & 15); break; } @@ -1965,8 +1986,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, double *)) + jump_table[opcode[5]]) + (regs, opcode[1] >> 4, (double *) &temp); emu_load_regd((opcode[1] >> 4) & 15); emu_load_regd(((opcode[1] >> 4) & 15) + 2); break; @@ -1981,8 +2003,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, float *)) + jump_table[opcode[5]]) + (regs, opcode[1] >> 4, (float *) &temp); emu_load_regd((opcode[1] >> 4) & 15); break; } @@ -1998,8 +2021,9 @@ 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); + _fex = ((int (*)(struct pt_regs *, int, float *)) + jump_table[opcode[5]]) + (regs, opcode[1] >> 4, (float *) &temp); emu_load_regd((opcode[1] >> 4) & 15); emu_load_regd(((opcode[1] >> 4) & 15) + 2); break; @@ -2012,8 +2036,9 @@ opc = *((__u32 *) opcode); dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc); /* call the emulation function */ - _fex = ((int (*)(int, long)) jump_table[opcode[5]]) - (opcode[1] >> 4, dxb); + _fex = ((int (*)(struct pt_regs *, int, long)) + jump_table[opcode[5]]) + (regs, opcode[1] >> 4, dxb); break; } case 9: /* RXE format, RX address used as int value */ { @@ -2024,8 +2049,9 @@ opc = *((__u32 *) opcode); dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc); /* call the emulation function */ - _fex = ((int (*)(int, long)) jump_table[opcode[5]]) - (opcode[1] >> 4, dxb); + _fex = ((int (*)(struct pt_regs *, int, long)) + jump_table[opcode[5]]) + (regs, opcode[1] >> 4, dxb); break; } case 10: /* RXE format, RX address used as int value */ { @@ -2039,8 +2065,9 @@ opc = *((__u32 *) opcode); dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc); /* call the emulation function */ - _fex = ((int (*)(int, long)) jump_table[opcode[5]]) - (opcode[1] >> 4, dxb); + _fex = ((int (*)(struct pt_regs *, int, long)) + jump_table[opcode[5]]) + (regs, opcode[1] >> 4, dxb); break; } default: /* invalid operation */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/vmlinux-shared.lds linux-2.5/arch/s390/vmlinux-shared.lds --- linux-2.5.1/arch/s390/vmlinux-shared.lds Sun Aug 12 17:38:48 2001 +++ linux-2.5/arch/s390/vmlinux-shared.lds Sat Dec 29 11:10:40 2001 @@ -13,7 +13,6 @@ *(.fixup) *(.gnu.warning) } = 0x0700 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) } .kstrtab : { *(.kstrtab) } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390/vmlinux.lds linux-2.5/arch/s390/vmlinux.lds --- linux-2.5.1/arch/s390/vmlinux.lds Mon Jul 2 21:40:58 2001 +++ linux-2.5/arch/s390/vmlinux.lds Sat Dec 29 11:10:40 2001 @@ -13,7 +13,6 @@ *(.fixup) *(.gnu.warning) } = 0x0700 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/Makefile linux-2.5/arch/s390x/Makefile --- linux-2.5.1/arch/s390x/Makefile Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390x/Makefile Thu Dec 27 16:32:31 2001 @@ -55,6 +55,9 @@ image: vmlinux @$(MAKEBOOT) image +install: vmlinux + @$(MAKEBOOT) BOOTIMAGE=image install + archclean: @$(MAKEBOOT) clean diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/boot/Makefile linux-2.5/arch/s390x/boot/Makefile --- linux-2.5.1/arch/s390x/boot/Makefile Thu Apr 12 02:02:29 2001 +++ linux-2.5/arch/s390x/boot/Makefile Thu Dec 27 16:32:31 2001 @@ -35,3 +35,5 @@ clean: rm -f image listing iplfba.boot ipleckd.boot ipldump.boot +install: $(CONFIGURE) $(BOOTIMAGE) + sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map $(TOPDIR)/Kerntypes "$(INSTALL_PATH)" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/config.in linux-2.5/arch/s390x/config.in --- linux-2.5.1/arch/s390x/config.in Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390x/config.in Thu Dec 27 16:32:31 2001 @@ -71,9 +71,9 @@ comment 'Kernel hacking' #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -if [ "$CONFIG_CTC" = "y" ]; then - bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG -fi +#if [ "$CONFIG_CTC" = "y" ]; then +# bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG +#fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/defconfig linux-2.5/arch/s390x/defconfig --- linux-2.5.1/arch/s390x/defconfig Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390x/defconfig Thu Dec 27 16:32:31 2001 @@ -6,7 +6,7 @@ # CONFIG_MCA is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -CONFIG_GENERIC_BUST_SPINLOCK=n +# CONFIG_GENERIC_BUST_SPINLOCK is not set CONFIG_ARCH_S390=y CONFIG_ARCH_S390X=y @@ -103,8 +103,8 @@ # # S/390 tape hardware support # -CONFIG_S390_TAPE_3490=y -CONFIG_S390_TAPE_3480=y +CONFIG_S390_TAPE_3490=m +CONFIG_S390_TAPE_3480=m # # Network device drivers @@ -150,6 +150,7 @@ # CONFIG_IPV6_NETLINK is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -180,12 +181,12 @@ # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO 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_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -203,7 +204,7 @@ # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/debug.c linux-2.5/arch/s390x/kernel/debug.c --- linux-2.5.1/arch/s390x/kernel/debug.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390x/kernel/debug.c Thu Dec 27 16:32:31 2001 @@ -228,8 +228,10 @@ 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 *)); +#ifdef CONFIG_PROC_FS memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * sizeof(struct proc_dir_entry*)); +#endif /* CONFIG_PROC_FS */ atomic_set(&(rc->ref_count), 0); return rc; @@ -346,8 +348,10 @@ if (!db_info) return; if (atomic_dec_and_test(&db_info->ref_count)) { +#ifdef DEBUG printk(KERN_INFO "debug: freeing debug area %p (%s)\n", db_info, db_info->name); +#endif for (i = 0; i < DEBUG_MAX_VIEWS; i++) { if (db_info->views[i] != NULL) debug_delete_proc_dir_entry @@ -541,14 +545,18 @@ debug_info_snapshot = debug_info_copy(debug_info); if(!debug_info_snapshot){ +#ifdef DEBUG printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n"); +#endif rc = -ENOMEM; goto out; } if ((file->private_data = kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { +#ifdef DEBUG printk(KERN_ERR "debug_open: kmalloc failed\n"); +#endif debug_info_free(debug_info_snapshot); rc = -ENOMEM; goto out; @@ -602,6 +610,7 @@ { struct proc_dir_entry *rc = NULL; +#ifdef CONFIG_PROC_FS #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) const char *fn = name; int len; @@ -634,6 +643,7 @@ #endif out: +#endif /* CONFIG_PROC_FS */ return rc; } @@ -646,12 +656,14 @@ (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry) { +#ifdef CONFIG_PROC_FS #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) proc_unregister(root, proc_entry->low_ino); kfree(proc_entry); #else remove_proc_entry(proc_entry->name, root); #endif +#endif /* CONFIG_PROC_FS */ } /* @@ -677,9 +689,11 @@ goto out; debug_register_view(rc, &debug_level_view); debug_register_view(rc, &debug_flush_view); +#ifdef DEBUG printk(KERN_INFO "debug: reserved %d areas of %d pages for debugging %s\n", nr_areas, 1 << page_order, rc->name); +#endif out: if (rc == NULL){ printk(KERN_ERR "debug: debug_register failed for %s\n",name); @@ -699,7 +713,9 @@ if (!id) goto out; down(&debug_lock); +#ifdef DEBUG printk(KERN_INFO "debug: unregistering %s\n", id->name); +#endif debug_info_put(id); up(&debug_lock); @@ -906,11 +922,13 @@ down(&debug_lock); if (!initialized) { +#ifdef CONFIG_PROC_FS debug_proc_root_entry = debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT, S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP, NULL, NULL); +#endif /* CONFIG_PROC_FS */ printk(KERN_INFO "debug: Initialization complete\n"); initialized = 1; } @@ -1271,7 +1289,9 @@ #ifdef DEBUG printk("debug_cleanup_module: \n"); #endif +#ifdef CONFIG_PROC_FS debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry); +#endif /* CONFIG_PROC_FS */ return; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/entry.S linux-2.5/arch/s390x/kernel/entry.S --- linux-2.5.1/arch/s390x/kernel/entry.S Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390x/kernel/entry.S Thu Dec 27 16:32:31 2001 @@ -79,7 +79,7 @@ sigpending = 16 need_resched = 32 tsk_ptrace = 40 -processor = 92 +processor = 88 /* * Register usage in interrupt handlers: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/init_task.c linux-2.5/arch/s390x/kernel/init_task.c --- linux-2.5.1/arch/s390x/kernel/init_task.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390x/kernel/init_task.c Thu Dec 27 16:32:31 2001 @@ -12,7 +12,6 @@ #include <asm/uaccess.h> #include <asm/pgtable.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; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/ioctl32.c linux-2.5/arch/s390x/kernel/ioctl32.c --- linux-2.5.1/arch/s390x/kernel/ioctl32.c Wed Nov 7 22:39:36 2001 +++ linux-2.5/arch/s390x/kernel/ioctl32.c Thu Dec 27 16:32:31 2001 @@ -24,6 +24,7 @@ #include <linux/route.h> #include <linux/ext2_fs.h> #include <linux/hdreg.h> +#include <linux/if_bonding.h> #include <asm/types.h> #include <asm/uaccess.h> #include <asm/dasd.h> @@ -195,6 +196,58 @@ out: if(ifc.ifc_buf != NULL) kfree (ifc.ifc_buf); + return err; +} + +static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + mm_segment_t old_fs; + int err, len; + u32 data; + + 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; + + switch (cmd) { + case SIOCBONDENSLAVE: + case SIOCBONDRELEASE: + case SIOCBONDSETHWADDR: + case SIOCBONDCHANGEACTIVE: + len = IFNAMSIZ * sizeof(char); + break; + case SIOCBONDSLAVEINFOQUERY: + len = sizeof(struct ifslave); + break; + case SIOCBONDINFOQUERY: + len = sizeof(struct ifbond); + break; + default: + err = -EINVAL; + goto out; + }; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + 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) { + 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; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/linux32.c linux-2.5/arch/s390x/kernel/linux32.c --- linux-2.5.1/arch/s390x/kernel/linux32.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390x/kernel/linux32.c Thu Dec 27 16:32:31 2001 @@ -897,24 +897,24 @@ return sys32_fcntl(fd, cmd, arg); } -struct mem_dqblk32 { +struct dqblk32 { + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u32 dqb_curblocks; __u32 dqb_ihardlimit; __u32 dqb_isoftlimit; __u32 dqb_curinodes; - __u32 dqb_bhardlimit; - __u32 dqb_bsoftlimit; - __u64 dqb_curspace; __kernel_time_t32 dqb_btime; __kernel_time_t32 dqb_itime; }; -extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, __kernel_caddr_t addr); +extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) { int cmds = cmd >> SUBCMDSHIFT; int err; - struct mem_dqblk d; + struct dqblk d; mm_segment_t old_fs; char *spec; @@ -924,32 +924,32 @@ case Q_SETQUOTA: case Q_SETUSE: case Q_SETQLIM: - if (copy_from_user (&d, (struct mem_dqblk32 *)addr, - sizeof (struct mem_dqblk32))) + if (copy_from_user (&d, (struct dqblk32 *)addr, + sizeof (struct dqblk32))) return -EFAULT; - d.dqb_itime = ((struct mem_dqblk32 *)&d)->dqb_itime; - d.dqb_btime = ((struct mem_dqblk32 *)&d)->dqb_btime; + d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; + d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; break; default: return sys_quotactl(cmd, special, - id, (__kernel_caddr_t)addr); + id, (caddr_t)addr); } spec = getname (special); err = PTR_ERR(spec); if (IS_ERR(spec)) return err; old_fs = get_fs (); set_fs (KERNEL_DS); - err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d); + err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); set_fs (old_fs); putname (spec); if (err) return err; if (cmds == Q_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; - ((struct mem_dqblk32 *)&d)->dqb_itime = i; - ((struct mem_dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct mem_dqblk32 *)addr, &d, - sizeof (struct mem_dqblk32))) + ((struct dqblk32 *)&d)->dqb_itime = i; + ((struct dqblk32 *)&d)->dqb_btime = b; + if (copy_to_user ((struct dqblk32 *)addr, &d, + sizeof (struct dqblk32))) return -EFAULT; } return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/process.c linux-2.5/arch/s390x/kernel/process.c --- linux-2.5.1/arch/s390x/kernel/process.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390x/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -57,7 +57,6 @@ /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; - current->counter = -100; wait_psw.mask = _WAIT_PSW_MASK; wait_psw.addr = (unsigned long) &&idle_wakeup; while(1) { @@ -75,171 +74,22 @@ } } -/* - As all the register will only be made displayable to the root - user ( via printk ) or checking if the uid of the user is 0 from - the /proc filesystem please god this will be secure enough DJB. - The lines are given one at a time so as not to chew stack space in - printk on a crash & also for the proc filesystem when you get - 0 returned you know you've got all the lines - */ - -static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs) -{ - int linelen=0; - int regno,chaincnt; - u64 backchain,prev_backchain,endchain; - u64 ksp = 0; - char *mode = "???"; - - enum - { - sp_linefeed, - sp_psw, - sp_ksp, - sp_gprs, - sp_gprs1, - sp_gprs2, - sp_gprs3, - sp_gprs4, - sp_gprs5, - sp_gprs6, - sp_gprs7, - sp_gprs8, - sp_acrs, - sp_acrs1, - sp_acrs2, - sp_acrs3, - sp_acrs4, - sp_kern_backchain, - sp_kern_backchain1 - }; - - if (task) - ksp = task->thread.ksp; - if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE)) - ksp = regs->gprs[15]; - - if (regs) - mode = (regs->psw.mask & PSW_PROBLEM_STATE)? - "User" : "Kernel"; - - switch(line) - { - case sp_linefeed: - linelen=sprintf(buff,"\n"); - break; - case sp_psw: - if(regs) - linelen=sprintf(buff, "%s PSW: %016lx %016lx %s\n", mode, - (unsigned long) regs->psw.mask, - (unsigned long) regs->psw.addr, - print_tainted()); - else - linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n"); - break; - case sp_ksp: - linelen=sprintf(&buff[linelen], - "task: %016lx ksp: %016lx pt_regs: %016lx\n", - (addr_t)task, (addr_t)ksp, (addr_t)regs); - break; - case sp_gprs: - if(regs) - linelen=sprintf(buff, "%s GPRS:\n", mode); - break; - case sp_gprs1 ... sp_gprs8: - if(regs) - { - regno=(line-sp_gprs1)*2; - linelen = sprintf(buff,"%016lx %016lx\n", - regs->gprs[regno], - regs->gprs[regno+1]); - } - break; - case sp_acrs: - if(regs) - linelen=sprintf(buff, "%s ACRS:\n", mode); - break; - case sp_acrs1 ... sp_acrs4: - if(regs) - { - regno=(line-sp_acrs1)*4; - linelen=sprintf(buff,"%08x %08x %08x %08x\n", - regs->acrs[regno], - regs->acrs[regno+1], - regs->acrs[regno+2], - regs->acrs[regno+3]); - } - break; - case sp_kern_backchain: - if (regs && (regs->psw.mask & PSW_PROBLEM_STATE)) - break; - if (ksp) - linelen=sprintf(buff, "Kernel BackChain CallChain\n"); - break; - default: - if (ksp) - { - - backchain=ksp&PSW_ADDR_MASK; - endchain=((backchain&(-THREAD_SIZE))+THREAD_SIZE); - prev_backchain=backchain-1; - line-=sp_kern_backchain1; - for(chaincnt=0;;chaincnt++) - { - if((backchain==0)||(backchain>=endchain) - ||(chaincnt>=8)||(prev_backchain>=backchain)) - break; - if(chaincnt==line) - { - linelen+=sprintf(&buff[linelen]," %016lx [<%016lx>]\n", - backchain, - *(u64 *)(backchain+112)&PSW_ADDR_MASK); - break; - } - prev_backchain=backchain; - backchain=(*((u64 *)backchain))&PSW_ADDR_MASK; - } - } - } - return(linelen); -} +extern void show_registers(struct pt_regs *regs); +extern void show_trace(unsigned long *sp); void show_regs(struct pt_regs *regs) { - char buff[80]; - int i, line; + struct task_struct *tsk = current; - printk("CPU: %d\n",smp_processor_id()); - printk("Process %s (pid: %d, stackpage=%016lX)\n", - current->comm, current->pid, 4096+(addr_t)current); - - for (line = 0; sprintf_regs(line, buff, current, regs); line++) - printk(buff); - - if (regs->psw.mask & PSW_PROBLEM_STATE) - { - printk("User Code:\n"); - memset(buff, 0, 20); - copy_from_user(buff, - (char *) (regs->psw.addr & PSW_ADDR_MASK), 20); - for (i = 0; i < 20; i++) - printk("%02x ", buff[i]); - printk("\n"); - } -} - -char *task_show_regs(struct task_struct *task, char *buffer) -{ - int line, len; - - for (line = 0; ; line++) - { - len = sprintf_regs(line, buffer, task, NULL); - if (!len) break; - buffer += len; - } - return buffer; + printk("CPU: %d %s\n", tsk->processor, print_tainted()); + printk("Process %s (pid: %d, task: %016lx, ksp: %016lx)\n", + current->comm, current->pid, (unsigned long) tsk, + tsk->thread.ksp); + + show_registers(regs); + /* Show stack backtrace if pt_regs is from kernel mode */ + if (!(regs->psw.mask & PSW_PROBLEM_STATE)) + show_trace((unsigned long *) regs->gprs[15]); } int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) @@ -301,16 +151,10 @@ unsigned long gprs[10]; /* gprs 6 -15 */ unsigned long fprs[2]; /* fpr 4 and 6 */ unsigned long empty[2]; -#if CONFIG_REMOTE_DEBUG - struct gdb_pt_regs childregs; -#else struct pt_regs childregs; -#endif } *frame; frame = (struct stack_frame *) (4*PAGE_SIZE + (unsigned long) p) -1; - frame = (struct stack_frame *) (((unsigned long) frame)&-8L); - p->thread.regs = &frame->childregs; p->thread.ksp = (unsigned long) frame; frame->childregs = *regs; frame->childregs.gprs[15] = new_stackp; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/ptrace.c linux-2.5/arch/s390x/kernel/ptrace.c --- linux-2.5.1/arch/s390x/kernel/ptrace.c Tue Sep 18 23:56:19 2001 +++ linux-2.5/arch/s390x/kernel/ptrace.c Thu Dec 27 16:32:31 2001 @@ -41,7 +41,7 @@ void FixPerRegisters(struct task_struct *task) { - struct pt_regs *regs = task->thread.regs; + struct pt_regs *regs = __KSTK_PTREGS(task); per_struct *per_info= (per_struct *)&task->thread.per_info; @@ -169,7 +169,7 @@ mask=PSW_ADDR_MASK; if(useraddr<PT_FPC) { - realuseraddr=(addr_t)&(((u8 *)task->thread.regs)[useraddr]); + realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr; if(useraddr<PT_PSWMASK) { copymax=PT_PSWMASK; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/s390_ksyms.c linux-2.5/arch/s390x/kernel/s390_ksyms.c --- linux-2.5.1/arch/s390x/kernel/s390_ksyms.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390x/kernel/s390_ksyms.c Thu Dec 27 16:32:31 2001 @@ -21,8 +21,9 @@ EXPORT_SYMBOL_NOVERS(_oi_bitmap); EXPORT_SYMBOL_NOVERS(_ni_bitmap); EXPORT_SYMBOL_NOVERS(_zb_findmap); -EXPORT_SYMBOL_NOVERS(__copy_from_user_fixup); -EXPORT_SYMBOL_NOVERS(__copy_to_user_fixup); +EXPORT_SYMBOL_NOVERS(__copy_from_user_asm); +EXPORT_SYMBOL_NOVERS(__copy_to_user_asm); +EXPORT_SYMBOL_NOVERS(__clear_user_asm); /* * semaphore ops @@ -38,6 +39,7 @@ EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(memscan); EXPORT_SYMBOL_NOVERS(strlen); EXPORT_SYMBOL_NOVERS(strchr); EXPORT_SYMBOL_NOVERS(strcmp); @@ -67,4 +69,3 @@ EXPORT_SYMBOL(console_mode); EXPORT_SYMBOL(console_device); EXPORT_SYMBOL_NOVERS(do_call_softirq); - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/setup.c linux-2.5/arch/s390x/kernel/setup.c --- linux-2.5.1/arch/s390x/kernel/setup.c Sat Nov 17 02:38:39 2001 +++ linux-2.5/arch/s390x/kernel/setup.c Thu Dec 27 16:32:31 2001 @@ -425,9 +425,10 @@ lowcore->io_new_psw.mask = _IO_PSW_MASK; lowcore->io_new_psw.addr = (addr_t) &io_int_handler; lowcore->ipl_device = S390_lowcore.ipl_device; - lowcore->kernel_stack = ((__u32) &init_task_union) + 16384; + lowcore->kernel_stack = ((__u64) &init_task_union) + 16384; lowcore->async_stack = (__u64) __alloc_bootmem(4*PAGE_SIZE, 4*PAGE_SIZE, 0) + 16384; + lowcore->jiffy_timer = -1LL; set_prefix((__u32)(__u64) lowcore); cpu_init(); boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr; @@ -474,15 +475,16 @@ static int show_cpuinfo(struct seq_file *m, void *v) { struct cpuinfo_S390 *cpuinfo; - unsigned n = v; + unsigned long n = (unsigned long) v - 1; - if (!n--) { + if (!n) { seq_printf(m, "vendor_id : IBM/S390\n" "# processors : %i\n" "bogomips per cpu: %lu.%02lu\n", smp_num_cpus, loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ))%100); - } else if (cpu_online_map & (1 << n)) { + } + if (cpu_online_map & (1 << n)) { cpuinfo = &safe_get_cpu_lowcore(n).cpu_data; seq_printf(m, "processor %i: " "version = %02X, " @@ -497,7 +499,7 @@ static void *c_start(struct seq_file *m, loff_t *pos) { - return *pos <= NR_CPUS ? (void)(*pos+1) : NULL; + return *pos <= NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL; } static void *c_next(struct seq_file *m, void *v, loff_t *pos) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/smp.c linux-2.5/arch/s390x/kernel/smp.c --- linux-2.5.1/arch/s390x/kernel/smp.c Wed Nov 21 18:31:09 2001 +++ linux-2.5/arch/s390x/kernel/smp.c Thu Dec 27 16:32:31 2001 @@ -29,6 +29,7 @@ #include <linux/smp_lock.h> #include <linux/delay.h> +#include <linux/cache.h> #include <asm/sigp.h> #include <asm/pgalloc.h> @@ -48,14 +49,11 @@ static int max_cpus = NR_CPUS; /* Setup configured maximum number of CPUs to activate */ int smp_num_cpus; struct _lowcore *lowcore_ptr[NR_CPUS]; -unsigned int prof_multiplier[NR_CPUS]; -unsigned int prof_old_multiplier[NR_CPUS]; -unsigned int prof_counter[NR_CPUS]; cycles_t cacheflush_time=0; int smp_threads_ready=0; /* Set when the idlers are all forked. */ static atomic_t smp_commenced = ATOMIC_INIT(0); -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; unsigned long cpu_online_map; @@ -452,7 +450,7 @@ /* * Activate a secondary processor. */ -extern void init_100hz_timer(void); +extern void init_cpu_timer(void); extern int pfault_init(void); int __init start_secondary(void *cpuvoid) @@ -464,8 +462,8 @@ /* Wait for completion of smp startup */ while (!atomic_read(&smp_commenced)) /* nothing */ ; - /* init per CPU 100 hz timer */ - init_100hz_timer(); + /* init per CPU timer */ + init_cpu_timer(); #ifdef CONFIG_PFAULT /* Enable pfault pseudo page faults on this cpu. */ pfault_init(); @@ -518,7 +516,7 @@ cpu_lowcore=&get_cpu_lowcore(cpu); cpu_lowcore->save_area[15] = idle->thread.ksp; - cpu_lowcore->kernel_stack = (idle->thread.ksp | 16383) + 1; + cpu_lowcore->kernel_stack = (__u64) idle + 16384; __asm__ __volatile__("la 1,%0\n\t" "stctg 0,15,0(1)\n\t" "la 1,%1\n\t" @@ -570,15 +568,7 @@ /* * Initialize the logical to physical CPU number mapping - * and the per-CPU profiling counter/multiplier */ - - for (i = 0; i < NR_CPUS; i++) { - prof_counter[i] = 1; - prof_old_multiplier[i] = 1; - prof_multiplier[i] = 1; - } - print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data); for(i = 0; i < smp_num_cpus; i++) @@ -630,56 +620,6 @@ int setup_profiling_timer(unsigned int multiplier) { return 0; -} - -/* - * Local timer interrupt handler. It does both profiling and - * process statistics/rescheduling. - * - * We do profiling in every local tick, statistics/rescheduling - * happen only every 'profiling multiplier' ticks. The default - * multiplier is 1 and it can be changed by writing the new multiplier - * value into /proc/profile. - */ - -void smp_local_timer_interrupt(struct pt_regs * regs) -{ - int user = (user_mode(regs) != 0); - int cpu = smp_processor_id(); - - /* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ - if (!user_mode(regs)) - s390_do_profile(regs->psw.addr); - - if (!--prof_counter[cpu]) { - - /* - * The multiplier may have changed since the last time we got - * to this point as a result of the user writing to - * /proc/profile. In this case we need to adjust the APIC - * timer accordingly. - * - * Interrupts are already masked off at this point. - */ - prof_counter[cpu] = prof_multiplier[cpu]; - if (prof_counter[cpu] != prof_old_multiplier[cpu]) { - prof_old_multiplier[cpu] = prof_counter[cpu]; - } - - /* - * After doing the above, we need to make like - * a normal interrupt - otherwise timer interrupts - * ignore the global interrupt lock, which is the - * WrongThing (tm) to do. - */ - - update_process_times(user); - } } EXPORT_SYMBOL(lowcore_ptr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/time.c linux-2.5/arch/s390x/kernel/time.c --- linux-2.5.1/arch/s390x/kernel/time.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/arch/s390x/kernel/time.c Thu Dec 27 16:32:31 2001 @@ -33,65 +33,33 @@ #include <asm/irq.h> #include <asm/s390_ext.h> - /* change this if you have some constant time drift */ -#define USECS_PER_JIFFY ((signed long)1000000/HZ) -#define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12) +#define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) +#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) #define TICK_SIZE tick -static uint64_t init_timer_cc, last_timer_cc; +static uint64_t init_timer_cc; extern rwlock_t xtime_lock; extern unsigned long wall_jiffies; -void tod_to_timeval(uint64_t todval, struct timeval *xtime) +void tod_to_timeval(__u64 todval, struct timeval *xtime) { -#if 0 - const int high_bit = 0x80000000L; - const int c_f4240 = 0xf4240L; - const int c_7a120 = 0x7a120; - /* We have to divide the 64 bit value todval by 4096 - * (because the 2^12 bit is the one that changes every - * microsecond) and then split it into seconds and - * microseconds. A value of max (2^52-1) divided by - * the value 0xF4240 can yield a max result of approx - * (2^32.068). Thats to big to fit into a signed int - * ... hacking time! - */ - asm volatile ("L 2,%1\n\t" - "LR 3,2\n\t" - "SRL 2,12\n\t" - "SLL 3,20\n\t" - "L 4,%O1+4(%R1)\n\t" - "SRL 4,12\n\t" - "OR 3,4\n\t" /* now R2/R3 contain (todval >> 12) */ - "SR 4,4\n\t" - "CL 2,%2\n\t" - "JL .+12\n\t" - "S 2,%2\n\t" - "L 4,%3\n\t" - "D 2,%4\n\t" - "OR 3,4\n\t" - "ST 2,%O0+4(%R0)\n\t" - "ST 3,%0" - : "=m" (*xtime) : "m" (todval), - "m" (c_7a120), "m" (high_bit), "m" (c_f4240) - : "cc", "memory", "2", "3", "4" ); -#else - todval >>= 12; - xtime->tv_sec = todval / 1000000; - xtime->tv_usec = todval % 1000000; -#endif + todval >>= 12; + xtime->tv_sec = todval / 1000000; + xtime->tv_usec = todval % 1000000; } -unsigned long do_gettimeoffset(void) +static inline unsigned long do_gettimeoffset(void) { - __u64 timer_cc; + __u64 now; - asm volatile ("STCK %0" : "=m" (timer_cc)); - /* We require the offset from the previous interrupt */ - return ((unsigned long)((timer_cc - last_timer_cc)>>12)); + asm ("STCK %0" : "=m" (now)); + now = (now - init_timer_cc) >> 12; + /* We require the offset from the latest update of xtime */ + now -= (__u64) wall_jiffies*USECS_PER_JIFFY; + return (unsigned long) now; } /* @@ -101,15 +69,10 @@ { unsigned long flags; unsigned long usec, sec; - unsigned long lost_ticks; read_lock_irqsave(&xtime_lock, flags); - lost_ticks = jiffies - wall_jiffies; - usec = do_gettimeoffset(); - if (lost_ticks) - usec +=(USECS_PER_JIFFY*lost_ticks); sec = xtime.tv_sec; - usec += xtime.tv_usec; + usec = xtime.tv_usec + do_gettimeoffset(); read_unlock_irqrestore(&xtime_lock, flags); while (usec >= 1000000) { @@ -155,51 +118,31 @@ extern __u16 boot_cpu_addr; #endif -void do_timer_interrupt(struct pt_regs *regs, __u16 error_code) +static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code) { int cpu = smp_processor_id(); irq_enter(cpu, 0); - /* - * reset timer to 10ms minus time already elapsed - * since timer-interrupt pending - */ + /* + * set clock comparator for next tick + */ + S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; + asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer)); + #ifdef CONFIG_SMP - if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) { + if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) write_lock(&xtime_lock); - last_timer_cc = S390_lowcore.jiffy_timer_cc; - } -#else - last_timer_cc = S390_lowcore.jiffy_timer_cc; -#endif - /* set clock comparator */ - S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY; - asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc)); -/* - * In the SMP case we use the local timer interrupt to do the - * profiling, except when we simulate SMP mode on a uniprocessor - * system, in that case we have to call the local interrupt handler. - */ -#ifdef CONFIG_SMP - /* when SMP, do smp_local_timer_interrupt for *all* CPUs, - but only do the rest for the boot CPU */ - smp_local_timer_interrupt(regs); -#else - if (!user_mode(regs)) - s390_do_profile(regs->psw.addr); -#endif + update_process_times(user_mode(regs)); -#ifdef CONFIG_SMP - if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) -#endif - { + if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) { do_timer(regs); -#ifdef CONFIG_SMP write_unlock(&xtime_lock); -#endif } +#else + do_timer(regs); +#endif irq_exit(cpu, 0); } @@ -207,19 +150,17 @@ /* * Start the clock comparator on the current CPU */ -static unsigned long cr0 __attribute__ ((aligned (8))); - -void init_100hz_timer(void) +void init_cpu_timer(void) { + unsigned long cr0; + /* allow clock comparator timer interrupt */ asm volatile ("STCTG 0,0,%0" : "=m" (cr0) : : "memory"); cr0 |= 0x800; asm volatile ("LCTLG 0,0,%0" : : "m" (cr0) : "memory"); - /* set clock comparator */ - /* read the TOD clock */ - asm volatile ("STCK %0" : "=m" (S390_lowcore.jiffy_timer_cc)); - S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY; - asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc)); + S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY; + S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY; + asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer)); } /* @@ -228,6 +169,7 @@ */ void __init time_init(void) { + __u64 set_time_cc; int cc; /* kick the TOD clock */ @@ -247,14 +189,18 @@ printk("time_init: TOD clock stopped/non-operational\n"); break; } + + /* set xtime */ + set_time_cc = init_timer_cc - 0x8126d60e46000000LL + + (0x3c26700LL*1000000*4096); + tod_to_timeval(set_time_cc, &xtime); + /* request the 0x1004 external interrupt */ - if (register_external_interrupt(0x1004, do_timer_interrupt) != 0) - panic("Couldn't request external interrupts 0x1004"); - init_100hz_timer(); - init_timer_cc = S390_lowcore.jiffy_timer_cc; - init_timer_cc -= 0x8126d60e46000000LL - - (0x3c26700LL*1000000*4096); - tod_to_timeval(init_timer_cc, &xtime); + if (register_external_interrupt(0x1004, do_comparator_interrupt) != 0) + panic("Couldn't request external interrupt 0x1004"); + + /* init CPU timer */ + init_cpu_timer(); /* Set do_get_fast_time function pointer. */ do_get_fast_time = do_gettimeofday; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/traps.c linux-2.5/arch/s390x/kernel/traps.c --- linux-2.5.1/arch/s390x/kernel/traps.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390x/kernel/traps.c Thu Dec 27 16:32:31 2001 @@ -26,6 +26,7 @@ #include <linux/smp_lock.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/module.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -58,6 +59,203 @@ extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code); #endif +int kstack_depth_to_print = 20; + +/* + * If the address is either in the .text section of the + * kernel, or in the vmalloc'ed module regions, it *may* + * be the address of a calling routine + */ +extern char _stext, _etext; + +#ifdef CONFIG_MODULES + +extern struct module *module_list; +extern struct module kernel_module; + +static inline int kernel_text_address(unsigned long addr) +{ + int retval = 0; + struct module *mod; + + if (addr >= (unsigned long) &_stext && + addr <= (unsigned long) &_etext) + return 1; + + for (mod = module_list; mod != &kernel_module; mod = mod->next) { + /* mod_bound tests for addr being inside the vmalloc'ed + * module area. Of course it'd be better to test only + * for the .text subset... */ + if (mod_bound(addr, 0, mod)) { + retval = 1; + break; + } + } + + return retval; +} + +#else + +static inline int kernel_text_address(unsigned long addr) +{ + return (addr >= (unsigned long) &_stext && + addr <= (unsigned long) &_etext); +} + +#endif + +void show_trace(unsigned long * stack) +{ + unsigned long backchain, low_addr, high_addr, ret_addr; + int i; + + if (!stack) + stack = (unsigned long*)&stack; + + printk("Call Trace: "); + low_addr = ((unsigned long) stack) & PSW_ADDR_MASK; + high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE; + /* Skip the first frame (biased stack) */ + backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK; + /* Print up to 8 lines */ + for (i = 0; i < 8; i++) { + if (backchain < low_addr || backchain >= high_addr) + break; + ret_addr = *((unsigned long *) (backchain+112)) & PSW_ADDR_MASK; + if (!kernel_text_address(ret_addr)) + break; + if (i && ((i % 3) == 0)) + printk("\n "); + printk("[<%016lx>] ", ret_addr); + low_addr = backchain; + backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK; + } + printk("\n"); +} + +void show_trace_task(struct task_struct *tsk) +{ + /* + * We can't print the backtrace of a running process. It is + * unreliable at best and can cause kernel oopses. + */ + if (task_has_cpu(tsk)) + return; + show_trace((unsigned long *) tsk->thread.ksp); +} + +void show_stack(unsigned long *sp) +{ + unsigned long *stack; + int i; + + // debugging aid: "show_stack(NULL);" prints the + // back trace for this cpu. + + if (sp == NULL) + sp = (unsigned long*) &sp; + + stack = sp; + for (i = 0; i < kstack_depth_to_print; i++) { + if (((addr_t) stack & (THREAD_SIZE-1)) == 0) + break; + if (i && ((i % 4) == 0)) + printk("\n "); + printk("%016lx ", *stack++); + } + printk("\n"); + show_trace(sp); +} + +void show_registers(struct pt_regs *regs) +{ + mm_segment_t old_fs; + char *mode; + int i; + + mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl"; + printk("%s PSW : %016lx %016lx\n", + mode, (unsigned long) regs->psw.mask, + (unsigned long) regs->psw.addr); + printk("%s GPRS: %016lx %016lx %016lx %016lx\n", mode, + regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); + printk(" %016lx %016lx %016lx %016lx\n", + regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); + printk(" %016lx %016lx %016lx %016lx\n", + regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]); + printk(" %016lx %016lx %016lx %016lx\n", + regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); + printk("%s ACRS: %08x %08x %08x %08x\n", mode, + regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]); + printk(" %08x %08x %08x %08x\n", + regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]); + printk(" %08x %08x %08x %08x\n", + regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]); + printk(" %08x %08x %08x %08x\n", + regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]); + + /* + * Print the first 20 byte of the instruction stream at the + * time of the fault. + */ + old_fs = get_fs(); + if (regs->psw.mask & PSW_PROBLEM_STATE) + set_fs(USER_DS); + else + set_fs(KERNEL_DS); + printk("%s Code: ", mode); + for (i = 0; i < 20; i++) { + unsigned char c; + if (__get_user(c, (char *)(regs->psw.addr + i))) { + printk(" Bad PSW."); + break; + } + printk("%02x ", c); + } + set_fs(old_fs); + + printk("\n"); +} + +/* This is called from fs/proc/array.c */ +char *task_show_regs(struct task_struct *task, char *buf) +{ + struct pt_regs *regs; + + regs = __KSTK_PTREGS(task); + buf += sprintf(buf, "task: %016lx, ksp: %016lx\n", + (unsigned long) task, task->thread.ksp); + buf += sprintf(buf, "User PSW : %016lx %016lx\n", + (unsigned long) regs->psw.mask, + (unsigned long) regs->psw.addr); + buf += sprintf(buf, "User GPRS: %016lx %016lx %016lx %016lx\n", + regs->gprs[0], regs->gprs[1], + regs->gprs[2], regs->gprs[3]); + buf += sprintf(buf, " %016lx %016lx %016lx %016lx\n", + regs->gprs[4], regs->gprs[5], + regs->gprs[6], regs->gprs[7]); + buf += sprintf(buf, " %016lx %016lx %016lx %016lx\n", + regs->gprs[8], regs->gprs[9], + regs->gprs[10], regs->gprs[11]); + buf += sprintf(buf, " %016lx %016lx %016lx %016lx\n", + regs->gprs[12], regs->gprs[13], + regs->gprs[14], regs->gprs[15]); + buf += sprintf(buf, "User ACRS: %08x %08x %08x %08x\n", + regs->acrs[0], regs->acrs[1], + regs->acrs[2], regs->acrs[3]); + buf += sprintf(buf, " %08x %08x %08x %08x\n", + regs->acrs[4], regs->acrs[5], + regs->acrs[6], regs->acrs[7]); + buf += sprintf(buf, " %08x %08x %08x %08x\n", + regs->acrs[8], regs->acrs[9], + regs->acrs[10], regs->acrs[11]); + buf += sprintf(buf, " %08x %08x %08x %08x\n", + regs->acrs[12], regs->acrs[13], + regs->acrs[14], regs->acrs[15]); + return buf; +} + spinlock_t die_lock = SPIN_LOCK_UNLOCKED; void die(const char * str, struct pt_regs * regs, long err) @@ -142,7 +340,7 @@ #if CONFIG_REMOTE_DEBUG if(gdb_stub_initialised) { - gdb_stub_handle_exception((gdb_pt_regs *)regs,signal); + gdb_stub_handle_exception(regs, signal); return 0; } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/kernel/wrapper32.S linux-2.5/arch/s390x/kernel/wrapper32.S --- linux-2.5.1/arch/s390x/kernel/wrapper32.S Fri Nov 9 21:58:02 2001 +++ linux-2.5/arch/s390x/kernel/wrapper32.S Thu Dec 27 16:32:31 2001 @@ -120,8 +120,8 @@ lgfr %r2,%r2 # long lgfr %r3,%r3 # long llgtr %r4,%r4 # long - lgfr %r5,%r5 # long - jg sys32_ptrace # branch to system call + llgfr %r5,%r5 # long + jg sys_ptrace # branch to system call .globl sys32_alarm_wrapper sys32_alarm_wrapper: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/lib/uaccess.S linux-2.5/arch/s390x/lib/uaccess.S --- linux-2.5.1/arch/s390x/lib/uaccess.S Tue Feb 13 22:13:44 2001 +++ linux-2.5/arch/s390x/lib/uaccess.S Thu Dec 27 16:32:31 2001 @@ -6,40 +6,82 @@ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) * - * These functions have a non-standard call interface + * These functions have standard call interface */ #include <asm/lowcore.h> .text .align 4 - .globl __copy_from_user_fixup -__copy_from_user_fixup: - lg 1,__LC_PGM_OLD_PSW+8 -0: lghi 3,-4096 - ng 3,__LC_TRANS_EXC_ADDR - sgr 3,4 - bm 4(1) -1: mvcle 2,4,0 - b 4(1) + .globl __copy_from_user_asm +__copy_from_user_asm: + lgr %r5,%r3 + sacf 512 +0: mvcle %r2,%r4,0 + jo 0b + sacf 0 + lgr %r2,%r5 + br %r14 +1: lg %r1,__LC_PGM_OLD_PSW+8 +2: lghi %r3,-4096 + ng %r3,__LC_TRANS_EXC_ADDR + sgr %r3,%r4 + bm 4(%r1) +3: mvcle %r2,%r4,0 + b 4(%r1) .section __ex_table,"a" - .align 8 - .quad 1b,0b + .align 8 + .quad 0b,1b + .quad 3b,2b .previous .align 4 .text - .globl __copy_to_user_fixup -__copy_to_user_fixup: - lg 1,__LC_PGM_OLD_PSW+8 -0: lghi 5,-4096 - ng 5,__LC_TRANS_EXC_ADDR - sgr 5,4 - bm 4(1) -1: mvcle 4,2,0 - b 4(1) + .globl __copy_to_user_asm +__copy_to_user_asm: + lgr %r5,%r3 + sacf 512 +0: mvcle %r4,%r2,0 + jo 0b + sacf 0 + lgr %r2,%r3 + br %r14 +1: lg %r1,__LC_PGM_OLD_PSW+8 +2: lghi %r5,-4096 + ng %r5,__LC_TRANS_EXC_ADDR + sgr %r5,%r4 + bm 4(%r1) +3: mvcle %r4,%r2,0 + b 4(%r1) .section __ex_table,"a" - .align 8 - .quad 1b,0b + .align 8 + .quad 0b,1b + .quad 3b,2b .previous + .align 4 + .text + .globl __clear_user_asm +__clear_user_asm: + lgr %r4,%r2 + lgr %r5,%r3 + sgr %r2,%r2 + sgr %r3,%r3 + sacf 512 +0: mvcle %r4,%r2,0 + jo 0b + sacf 0 + lgr %r2,%r5 + br %r14 +1: lg %r1,__LC_PGM_OLD_PSW+8 +2: lghi %r5,-4096 + ng %r5,__LC_TRANS_EXC_ADDR + sgr %r5,%r4 + bm 4(%r1) +3: mvcle %r4,%r2,0 + b 4(%r1) + .section __ex_table,"a" + .align 8 + .quad 0b,1b + .quad 3b,2b + .previous diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/vmlinux-shared.lds linux-2.5/arch/s390x/vmlinux-shared.lds --- linux-2.5.1/arch/s390x/vmlinux-shared.lds Sun Aug 12 17:38:48 2001 +++ linux-2.5/arch/s390x/vmlinux-shared.lds Sat Dec 29 11:10:40 2001 @@ -13,7 +13,6 @@ *(.fixup) *(.gnu.warning) } = 0x0700 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) } .kstrtab : { *(.kstrtab) } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/s390x/vmlinux.lds linux-2.5/arch/s390x/vmlinux.lds --- linux-2.5.1/arch/s390x/vmlinux.lds Mon Jul 2 21:40:58 2001 +++ linux-2.5/arch/s390x/vmlinux.lds Sat Dec 29 11:10:40 2001 @@ -13,7 +13,6 @@ *(.fixup) *(.gnu.warning) } = 0x0700 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sh/kernel/process.c linux-2.5/arch/sh/kernel/process.c --- linux-2.5.1/arch/sh/kernel/process.c Mon Oct 15 20:36:48 2001 +++ linux-2.5/arch/sh/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -41,7 +41,6 @@ /* endless idle loop with no priority at all */ init_idle(); current->nice = 20; - current->counter = -100; while (1) { if (hlt_counter) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sh/kernel/rtc.c linux-2.5/arch/sh/kernel/rtc.c --- linux-2.5.1/arch/sh/kernel/rtc.c Wed Jun 27 20:55:29 2001 +++ linux-2.5/arch/sh/kernel/rtc.c Thu Dec 27 16:32:31 2001 @@ -46,7 +46,7 @@ } while ((ctrl_inb(RCR1) & RCR1_CF) != 0); #if RTC_BIT_INVERTED != 0 - /* Work around to avoid reading correct value. */ + /* Work around to avoid reading incorrect value. */ if (sec128 == RTC_BIT_INVERTED) { schedule_timeout(1); goto again; @@ -81,12 +81,18 @@ goto again; } +#if RTC_BIT_INVERTED != 0 + if ((sec128 & RTC_BIT_INVERTED)) + sec--; +#endif + tv->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec); - tv->tv_usec = ((sec128 ^ RTC_BIT_INVERTED) * 1000000) / 128; + tv->tv_usec = (sec128 * 1000000) / 128; } -static int set_rtc_time(unsigned long nowtime) +int sh_rtc_settimeofday(const struct timeval *tv) { + unsigned long nowtime = tv->tv_sec; int retval = 0; int real_seconds, real_minutes, cmos_minutes; @@ -122,13 +128,4 @@ ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */ return retval; -} - -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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sh/kernel/setup.c linux-2.5/arch/sh/kernel/setup.c --- linux-2.5.1/arch/sh/kernel/setup.c Sat Nov 17 02:38:39 2001 +++ linux-2.5/arch/sh/kernel/setup.c Thu Dec 27 15:56:12 2001 @@ -140,15 +140,6 @@ sh_bios_console_write(s, count); } -/* - * Receive character from the serial port - */ -static int sh_console_wait_key(struct console *co) -{ - /* Not implemented yet */ - return 0; -} - static kdev_t sh_console_device(struct console *c) { /* TODO: this is totally bogus */ @@ -183,7 +174,6 @@ name: "bios", write: sh_console_write, device: sh_console_device, - wait_key: sh_console_wait_key, setup: sh_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sh/vmlinux.lds.S linux-2.5/arch/sh/vmlinux.lds.S --- linux-2.5.1/arch/sh/vmlinux.lds.S Sat Sep 8 19:29:09 2001 +++ linux-2.5/arch/sh/vmlinux.lds.S Sat Dec 29 11:10:40 2001 @@ -23,7 +23,6 @@ *(.fixup) *(.gnu.warning) } = 0x0009 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) *(.rodata.*) } .kstrtab : { *(.kstrtab) } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc/defconfig linux-2.5/arch/sparc/defconfig --- linux-2.5.1/arch/sparc/defconfig Tue Nov 13 17:16:05 2001 +++ linux-2.5/arch/sparc/defconfig Thu Dec 13 16:32:35 2001 @@ -138,7 +138,7 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK is not set +CONFIG_NETLINK_DEV=y # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y @@ -148,6 +148,7 @@ # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set CONFIG_IPV6=m diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc/kernel/process.c linux-2.5/arch/sparc/kernel/process.c --- linux-2.5.1/arch/sparc/kernel/process.c Tue Nov 13 17:16:05 2001 +++ linux-2.5/arch/sparc/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.157 2001/11/13 00:57:05 davem Exp $ +/* $Id: process.c,v 1.158 2001/11/26 23:45:00 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -61,7 +61,6 @@ /* endless idle loop with no priority at all */ current->nice = 20; - current->counter = -100; init_idle(); for (;;) { @@ -110,7 +109,6 @@ { /* endless idle loop with no priority at all */ current->nice = 20; - current->counter = -100; init_idle(); while(1) { @@ -285,37 +283,29 @@ show_regwindow((struct reg_window *)regs->u_regs[14]); } -#if NOTUSED -void show_thread(struct thread_struct *thread) +void show_trace_task(struct task_struct *tsk) { - int i; - - printk("uwinmask: 0x%08lx kregs: 0x%08lx\n", thread->uwinmask, (unsigned long)thread->kregs); - show_regs(thread->kregs); - printk("ksp: 0x%08lx kpc: 0x%08lx\n", thread->ksp, thread->kpc); - printk("kpsr: 0x%08lx kwim: 0x%08lx\n", thread->kpsr, thread->kwim); - printk("fork_kpsr: 0x%08lx fork_kwim: 0x%08lx\n", thread->fork_kpsr, thread->fork_kwim); - - for (i = 0; i < NSWINS; i++) { - if (!thread->rwbuf_stkptrs[i]) - continue; - printk("reg_window[%d]:\n", i); - printk("stack ptr: 0x%08lx\n", thread->rwbuf_stkptrs[i]); - show_regwindow(&thread->reg_window[i]); - } - printk("w_saved: 0x%08lx\n", thread->w_saved); - - /* XXX missing: float_regs */ - printk("fsr: 0x%08lx fpqdepth: 0x%08lx\n", thread->fsr, thread->fpqdepth); - /* XXX missing: fpqueue */ + unsigned long pc, fp; + unsigned long task_base = (unsigned long) tsk; + struct reg_window *rw; + int count = 0; - printk("flags: 0x%08lx current_ds: 0x%08lx\n", thread->flags, thread->current_ds.seg); - - show_regwindow((struct reg_window *)thread->ksp); + if (!tsk) + return; - /* XXX missing: core_exec */ + fp = tsk->thread.ksp; + do { + /* Bogus frame pointer? */ + if (fp < (task_base + sizeof(struct task_struct)) || + fp >= (task_base + (PAGE_SIZE << 1))) + break; + rw = (struct reg_window *) fp; + pc = rw->ins[7]; + printk("[%08lx] ", pc); + fp = rw->ins[6]; + } while (++count < 16); + printk("\n"); } -#endif /* * Free current thread data structures etc.. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc/kernel/smp.c linux-2.5/arch/sparc/kernel/smp.c --- linux-2.5.1/arch/sparc/kernel/smp.c Tue Nov 13 17:16:05 2001 +++ linux-2.5/arch/sparc/kernel/smp.c Thu Dec 13 16:32:35 2001 @@ -18,6 +18,7 @@ #include <linux/mm.h> #include <linux/fs.h> #include <linux/seq_file.h> +#include <linux/cache.h> #include <asm/ptrace.h> #include <asm/atomic.h> @@ -66,7 +67,7 @@ */ /* Kernel spinlock */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; /* Used to make bitops atomic */ unsigned char bitops_spinlock = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc/kernel/sunos_ioctl.c linux-2.5/arch/sparc/kernel/sunos_ioctl.c --- linux-2.5.1/arch/sparc/kernel/sunos_ioctl.c Thu Sep 7 15:32:00 2000 +++ linux-2.5/arch/sparc/kernel/sunos_ioctl.c Mon Jan 14 22:39:45 2002 @@ -39,8 +39,12 @@ { int ret = -EBADF; - if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) + read_lock(¤t->files->file_lock); + if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) { + read_unlock(¤t->files->file_lock); goto out; + } + read_unlock(¤t->files->file_lock); /* First handle an easy compat. case for tty ldisc. */ if(cmd == TIOCSETD) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc/mm/extable.c linux-2.5/arch/sparc/mm/extable.c --- linux-2.5.1/arch/sparc/mm/extable.c Sun Aug 12 18:23:32 2001 +++ linux-2.5/arch/sparc/mm/extable.c Thu Dec 13 16:32:35 2001 @@ -11,35 +11,49 @@ static unsigned long search_one_table(const struct exception_table_entry *start, - const struct exception_table_entry *last, + const struct exception_table_entry *end, unsigned long value, unsigned long *g2) { - const struct exception_table_entry *first = start; - const struct exception_table_entry *mid; - long diff = 0; - while (first <= last) { - mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) { - if (!mid->fixup) { - *g2 = 0; - return (mid + 1)->fixup; - } else - return mid->fixup; - } else if (diff < 0) - first = mid+1; - else - last = mid-1; - } - if (last->insn < value && !last->fixup && last[1].insn > value) { - *g2 = (value - last->insn)/4; - return last[1].fixup; - } - if (first > start && first[-1].insn < value - && !first[-1].fixup && first->insn < value) { - *g2 = (value - first[-1].insn)/4; - return first->fixup; - } + const struct exception_table_entry *walk; + + /* Single insn entries are encoded as: + * word 1: insn address + * word 2: fixup code address + * + * Range entries are encoded as: + * word 1: first insn address + * word 2: 0 + * word 3: last insn address + 4 bytes + * word 4: fixup code address + * + * See asm/uaccess.h for more details. + */ + + /* 1. Try to find an exact match. */ + for (walk = start; walk <= end; walk++) { + if (walk->fixup == 0) { + /* A range entry, skip both parts. */ + walk++; + continue; + } + + if (walk->insn == value) + return walk->fixup; + } + + /* 2. Try to find a range match. */ + for (walk = start; walk <= (end - 1); walk++) { + if (walk->fixup) + continue; + + if (walk[0].insn <= value && + walk[1].insn > value) { + *g2 = (value - walk[0].insn) / 4; + return walk[1].fixup; + } + walk++; + } + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc/mm/fault.c linux-2.5/arch/sparc/mm/fault.c --- linux-2.5.1/arch/sparc/mm/fault.c Tue Oct 30 23:08:11 2001 +++ linux-2.5/arch/sparc/mm/fault.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.121 2001/10/30 04:54:22 davem Exp $ +/* $Id: fault.c,v 1.122 2001/11/17 07:19:26 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -155,34 +155,47 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, unsigned long address) { + struct pt_regs regs; unsigned long g2; + unsigned int insn; int i; - unsigned insn; - struct pt_regs regs; - i = search_exception_table (ret_pc, &g2); + i = search_exception_table(ret_pc, &g2); switch (i) { - /* load & store will be handled by fixup */ - case 3: return 3; - /* store will be handled by fixup, load will bump out */ - /* for _to_ macros */ - case 1: insn = (unsigned)pc; if ((insn >> 21) & 1) return 1; break; - /* load will be handled by fixup, store will bump out */ - /* for _from_ macros */ - case 2: insn = (unsigned)pc; - if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2; + case 3: + /* load & store will be handled by fixup */ + return 3; + + case 1: + /* store will be handled by fixup, load will bump out */ + /* for _to_ macros */ + insn = *((unsigned int *) pc); + if ((insn >> 21) & 1) + return 1; + break; + + case 2: + /* load will be handled by fixup, store will bump out */ + /* for _from_ macros */ + insn = *((unsigned int *) pc); + if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) + return 2; break; - default: break; - } - memset (®s, 0, sizeof (regs)); + + default: + break; + }; + + memset(®s, 0, sizeof (regs)); regs.pc = pc; regs.npc = pc + 4; - __asm__ __volatile__ ( + __asm__ __volatile__( "rd %%psr, %0\n\t" "nop\n\t" "nop\n\t" "nop\n" : "=r" (regs.psr)); - unhandled_fault (address, current, ®s); + unhandled_fault(address, current, ®s); + /* Not reached */ return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc/mm/init.c linux-2.5/arch/sparc/mm/init.c --- linux-2.5.1/arch/sparc/mm/init.c Mon Oct 1 16:19:56 2001 +++ linux-2.5/arch/sparc/mm/init.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.100 2001/09/21 22:51:47 davem Exp $ +/* $Id: init.c,v 1.103 2001/11/19 19:03:08 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -410,9 +410,6 @@ int datapages = 0; int initpages = 0; int i; -#ifdef CONFIG_BLK_DEV_INITRD - unsigned long addr, last; -#endif highmem_start_page = mem_map + highstart_pfn; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/Makefile linux-2.5/arch/sparc64/Makefile --- linux-2.5.1/arch/sparc64/Makefile Sun Oct 21 17:36:54 2001 +++ linux-2.5/arch/sparc64/Makefile Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.49 2001/10/17 18:26:58 davem Exp $ +# $Id: Makefile,v 1.51 2001/11/17 00:15:27 davem Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -38,11 +38,6 @@ AS := $(AS) --undeclared-regs endif -# -# Uncomment the first CFLAGS if you are doing kgdb source level -# debugging of the kernel to get the proper debugging information. - -#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 ifneq ($(NEW_GCC),y) CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \ -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare @@ -51,25 +46,6 @@ -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare \ $(CC_UNDECL) AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL) -endif - -# Uncomment this to get spinlock/rwlock debugging on SMP. -# DEBUG_SPINLOCK = 1 - -ifdef CONFIG_SMP - ifdef DEBUG_SPINLOCK - CFLAGS += -DSPIN_LOCK_DEBUG - AFLAGS += -DSPIN_LOCK_DEBUG - endif -endif - -# Uncomment this to keep track of how often flush_dcache_page -# actually flushes the caches, output via /proc/cpuinfo -# -# DEBUG_DCACHE_FLUSH = 1 -ifdef DEBUG_DCACHE_FLUSH - CFLAGS += -DDCFLUSH_DEBUG - AFLAGS += -DDCFLUSH_DEBUG endif LINKFLAGS = -T arch/sparc64/vmlinux.lds diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/config.in linux-2.5/arch/sparc64/config.in --- linux-2.5.1/arch/sparc64/config.in Tue Nov 13 17:16:05 2001 +++ linux-2.5/arch/sparc64/config.in Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.152 2001/11/12 10:20:47 davem Exp $ +# $Id: config.in,v 1.156 2001/11/30 00:17:32 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -31,6 +31,8 @@ # Identify this as a Sparc64 build define_bool CONFIG_SPARC64 y +bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + # Global things across all Sun machines. define_bool CONFIG_HAVE_DEC_LOCK y define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n @@ -89,7 +91,6 @@ mainmenu_option next_comment comment 'Console drivers' bool 'PROM console' CONFIG_PROM_CONSOLE -bool 'Support Frame buffer devices' CONFIG_FB source drivers/video/Config.in endmenu @@ -191,21 +192,21 @@ if [ "$CONFIG_SCSI_SYM53C8XX_2" != "y" ]; then dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI - fi - if [ "$CONFIG_SCSI_NCR53C8XX" != "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 10 - bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE - if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then - bool ' include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS + if [ "$CONFIG_SCSI_NCR53C8XX" != "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 10 + bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE + if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then + bool ' include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS + fi + if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then + bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' assume boards are SYMBIOS compatible (EXPERIMENTAL)' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT + fi fi - if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then - bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' assume boards are SYMBIOS compatible (EXPERIMENTAL)' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT - fi fi dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI @@ -295,6 +296,13 @@ mainmenu_option next_comment comment 'Kernel hacking' -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ -#bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL +if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then + bool ' Debug memory allocations' CONFIG_DEBUG_SLAB + bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ + bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK + bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE + bool ' D-cache flush debugging' CONFIG_DEBUG_DCFLUSH +fi + endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/defconfig linux-2.5/arch/sparc64/defconfig --- linux-2.5.1/arch/sparc64/defconfig Tue Nov 13 17:16:05 2001 +++ linux-2.5/arch/sparc64/defconfig Thu Dec 13 16:32:35 2001 @@ -22,6 +22,7 @@ CONFIG_VT_CONSOLE=y CONFIG_SMP=y CONFIG_SPARC64=y +CONFIG_HOTPLUG=y CONFIG_HAVE_DEC_LOCK=y # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y @@ -84,7 +85,6 @@ # Console drivers # CONFIG_PROM_CONSOLE=y -CONFIG_FB=y # # Frame-buffer support @@ -158,15 +158,16 @@ # # 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_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set -# CONFIG_BLK_DEV_RAM is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_MD_MULTIPATH=m +CONFIG_BLK_DEV_LVM=m +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=4096 # CONFIG_BLK_DEV_INITRD is not set # @@ -174,8 +175,6 @@ # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y CONFIG_NETLINK_DEV=y # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -354,15 +353,11 @@ CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 CONFIG_AIC7XXX_OLD_PROC_STATS=y -# CONFIG_SCSI_SYM53C8XX_2 is not set -CONFIG_SCSI_NCR53C8XX=m -CONFIG_SCSI_SYM53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 -CONFIG_SCSI_NCR53C8XX_SYNC=40 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set -# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set -# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set CONFIG_SCSI_QLOGIC_ISP=m CONFIG_SCSI_QLOGIC_FC=y CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y @@ -493,6 +488,7 @@ CONFIG_SUNDANCE=m # CONFIG_TLAN is not set CONFIG_VIA_RHINE=m +# CONFIG_VIA_RHINE_MMIO is not set CONFIG_WINBOND_840=m # CONFIG_NET_POCKET is not set @@ -539,7 +535,7 @@ CONFIG_NET_FC=y # CONFIG_IPHASE5526 is not set # CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set +CONFIG_SHAPER=m # # Wan interfaces @@ -861,4 +857,9 @@ # # Kernel hacking # -# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_DCFLUSH is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/Makefile linux-2.5/arch/sparc64/kernel/Makefile --- linux-2.5.1/arch/sparc64/kernel/Makefile Wed May 16 17:31:27 2001 +++ linux-2.5/arch/sparc64/kernel/Makefile Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.67 2001/05/11 04:31:55 davem Exp $ +# $Id: Makefile,v 1.69 2001/11/19 04:09:53 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -68,7 +68,7 @@ @echo "#include <linux/config.h>" > tmp.c @echo "#undef CONFIG_SMP" >> tmp.c @echo "#include <linux/sched.h>" >> tmp.c - $(CPP) $(CPPFLAGS) tmp.c -o tmp.i + $(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm_data.c @echo "#include <linux/config.h>" >> check_asm_data.c @echo "#undef CONFIG_SMP" >> check_asm_data.c @@ -95,12 +95,12 @@ ./check_asm >> asm_offsets.h @rm -f check_asm check_asm.c @echo -e "\n#else /* CONFIG_SMP */\n" >> asm_offsets.h - @echo -e "#ifndef SPIN_LOCK_DEBUG\n" >>asm_offsets.h + @echo -e "#ifndef CONFIG_DEBUG_SPINLOCK\n" >>asm_offsets.h @echo "#include <linux/config.h>" > tmp.c @echo "#undef CONFIG_SMP" >> tmp.c @echo "#define CONFIG_SMP 1" >> tmp.c @echo "#include <linux/sched.h>" >> tmp.c - $(CPP) $(CPPFLAGS) tmp.c -o tmp.i + $(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm_data.c @echo "#include <linux/config.h>" >> check_asm_data.c @echo "#undef CONFIG_SMP" >> check_asm_data.c @@ -127,9 +127,9 @@ $(HOSTCC) -o check_asm check_asm.c ./check_asm >> asm_offsets.h @rm -f check_asm check_asm.c - @echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h + @echo -e "\n#else /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h @echo "#include <linux/sched.h>" > tmp.c - $(CPP) $(CPPFLAGS) -DSPIN_LOCK_DEBUG tmp.c -o tmp.i + $(CPP) $(CPPFLAGS) -P -DCONFIG_DEBUG_SPINLOCK tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm_data.c @echo "#include <linux/config.h>" >> check_asm_data.c @echo "#undef CONFIG_SMP" >> check_asm_data.c @@ -140,7 +140,7 @@ $(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c $(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c @echo '};' >> check_asm_data.c - $(CC) $(CPPFLAGS) -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c + $(CC) $(CPPFLAGS) -DCONFIG_DEBUG_SPINLOCK $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c @echo "/* Automatically generated. Do not edit. */" > check_asm.c @echo 'extern int printf(const char *fmt, ...);' >>check_asm.c @echo 'unsigned int check_asm_data[] = {' >> check_asm.c @@ -156,7 +156,7 @@ $(HOSTCC) -o check_asm check_asm.c ./check_asm >> asm_offsets.h @rm -f check_asm check_asm.c - @echo -e "#endif /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h + @echo -e "#endif /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h @echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h @echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h @if test -r $(HPATH)/asm/asm_offsets.h; then \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/entry.S linux-2.5/arch/sparc64/kernel/entry.S --- linux-2.5.1/arch/sparc64/kernel/entry.S Sun Oct 21 17:36:54 2001 +++ linux-2.5/arch/sparc64/kernel/entry.S Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.137 2001/10/18 09:06:36 davem Exp $ +/* $Id: entry.S,v 1.141 2001/12/05 23:56:32 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -483,7 +483,11 @@ ldxa [%g7 + %g0] ASI_INTR_R, %g7 stxa %g0, [%g0] ASI_INTR_RECEIVE membar #Sync - jmpl %g3, %g0 + ba,pt %xcc, 1f + nop + + .align 32 +1: jmpl %g3, %g0 nop do_ivec_spurious: @@ -657,15 +661,15 @@ stx %g5, [%g1 + %lo(pdma_size)] sethi %hi(auxio_register), %g1 ldx [%g1 + %lo(auxio_register)], %g7 - ldub [%g7], %g5 + lduba [%g7] ASI_PHYS_BYPASS_EC_E, %g5 or %g5, 0xc2, %g5 - stb %g5, [%g7] + stba %g5, [%g7] ASI_PHYS_BYPASS_EC_E andn %g5, 0x02, %g5 nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; - stb %g5, [%g7] + stba %g5, [%g7] ASI_PHYS_BYPASS_EC_E sethi %hi(doing_pdma), %g1 b,pt %xcc, floppy_dosoftint st %g0, [%g1 + %lo(doing_pdma)] @@ -678,7 +682,12 @@ sethi %hi(irq_action), %g1 or %g1, %lo(irq_action), %g1 ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq] - ldx [%g3 + 0x10], %g4 ! action->mask == ino_bucket ptr + ldx [%g3 + 0x08], %g4 ! action->flags>>48==ino + sethi %hi(ivector_table), %g3 + srlx %g4, 48, %g4 + or %g3, %lo(ivector_table), %g3 + sllx %g4, 5, %g4 + ldx [%g3 + %g4], %g4 ! &ivector_table[ino] ldx [%g4 + 0x10], %g4 ! bucket->iclr stwa %g0, [%g4] ASI_PHYS_BYPASS_EC_E ! ICLR_IDLE membar #Sync ! probably not needed... @@ -1615,6 +1624,11 @@ * * Note with time_t changes to the timeval type, I must now use * nucleus atomic quad 128-bit loads. + * + * If xtime was stored recently, I've seen crap from the + * quad load on Cheetah. Putting a membar SYNC before + * the quad load seems to make the problem go away. -DaveM + * (we should nop out workarounds like this on spitfire) */ sethi %hi(timer_tick_offset), %g3 sethi %hi(xtime), %g2 @@ -1626,6 +1640,7 @@ sethi %hi(0x003e0014), %o1 srlx %o2, 32, %o2 or %o1, %lo(0x003e0014), %o1 + membar #Sync ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o4 cmp %o2, %o1 bne,pt %xcc, 2f @@ -1634,6 +1649,7 @@ rd %asr24, %o1 2: rd %tick, %o1 3: ldx [%g1], %g7 + membar #Sync ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o2 xor %o4, %o2, %o2 xor %o5, %o3, %o3 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/head.S linux-2.5/arch/sparc64/kernel/head.S --- linux-2.5.1/arch/sparc64/kernel/head.S Sat Oct 6 15:50:28 2001 +++ linux-2.5/arch/sparc64/kernel/head.S Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.82 2001/10/04 23:37:04 davem Exp $ +/* $Id: head.S,v 1.86 2001/12/05 01:02:16 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -201,7 +201,7 @@ add %l0, (1 << 3), %l0 /* Now lock the TTE we created into ITLB-0 and DTLB-0, - * entry 15. + * entry 15 (and maybe 14 too). */ sethi %hi(KERNBASE), %g3 set (0 << 16) | (15 << 3), %g7 @@ -215,6 +215,29 @@ membar #Sync flush %g3 membar #Sync + sethi %hi(_end), %g3 /* Check for bigkernel case */ + or %g3, %lo(_end), %g3 + srl %g3, 23, %g3 /* Check if _end > 8M */ + brz,pt %g3, 1f + sethi %hi(KERNBASE), %g3 /* Restore for fixup code below */ + sethi %hi(0x400000), %g3 + or %g3, %lo(0x400000), %g3 + add %g5, %g3, %g5 /* New tte data */ + andn %g5, (_PAGE_G), %g5 + sethi %hi(KERNBASE+0x400000), %g3 + or %g3, %lo(KERNBASE+0x400000), %g3 + set (0 << 16) | (14 << 3), %g7 + stxa %g3, [%l7] ASI_DMMU + membar #Sync + stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS + membar #Sync + stxa %g3, [%l7] ASI_IMMU + membar #Sync + stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS + membar #Sync + flush %g3 + membar #Sync + sethi %hi(KERNBASE), %g3 /* Restore for fixup code below */ ba,pt %xcc, 1f nop @@ -345,7 +368,7 @@ /* PROM never puts any TLB entries into the MMU with the lock bit - * set. So we gladly use tlb entry 63 for KERNBASE. + * set. So we gladly use tlb entry 63 for KERNBASE. And maybe 62 too. */ sethi %hi(KERNBASE), %g3 @@ -358,7 +381,28 @@ membar #Sync flush %g3 membar #Sync - ba,pt %xcc, 1f + sethi %hi(_end), %g3 /* Check for bigkernel case */ + or %g3, %lo(_end), %g3 + srl %g3, 23, %g3 /* Check if _end > 8M */ + brz,pt %g3, 2f + sethi %hi(KERNBASE), %g3 /* Restore for fixup code below */ + sethi %hi(0x400000), %g3 + or %g3, %lo(0x400000), %g3 + add %g5, %g3, %g5 /* New tte data */ + andn %g5, (_PAGE_G), %g5 + sethi %hi(KERNBASE+0x400000), %g3 + or %g3, %lo(KERNBASE+0x400000), %g3 + mov (62 << 3), %g7 + stxa %g3, [%l7] ASI_DMMU + stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS + membar #Sync + stxa %g3, [%l7] ASI_IMMU + stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS + membar #Sync + flush %g3 + membar #Sync + sethi %hi(KERNBASE), %g3 /* Restore for fixup code below */ +2: ba,pt %xcc, 1f nop 1: set sun4u_init, %g2 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/ioctl32.c linux-2.5/arch/sparc64/kernel/ioctl32.c --- linux-2.5.1/arch/sparc64/kernel/ioctl32.c Tue Nov 13 17:16:05 2001 +++ linux-2.5/arch/sparc64/kernel/ioctl32.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.132 2001/11/07 05:56:19 davem Exp $ +/* $Id: ioctl32.c,v 1.133 2001/11/14 06:14:29 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -2421,6 +2421,7 @@ u32 pv[ABS_MAX_PV + 1]; u32 lv[ABS_MAX_LV + 1]; uint8_t vg_uuid[UUID_LEN+1]; /* volume group UUID */ + uint8_t dummy1[200]; } vg32_t; typedef struct { @@ -2462,7 +2463,7 @@ } lv_status_byindex_req32_t; typedef struct { - dev_t dev; + __kernel_dev_t32 dev; u32 lv; } lv_status_bydev_req32_t; @@ -2535,7 +2536,8 @@ lv_block_exception32_t *lbe32; lv_block_exception_t *lbe; lv32_t *ul = (lv32_t *)A(p); - lv_t *l = (lv_t *)kmalloc(sizeof(lv_t), GFP_KERNEL); + lv_t *l = (lv_t *) kmalloc(sizeof(lv_t), GFP_KERNEL); + if (!l) { *errp = -ENOMEM; return NULL; @@ -2565,12 +2567,11 @@ if (l->lv_block_exception) { lbe32 = (lv_block_exception32_t *)A(ptr2); memset(lbe, 0, size); - for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) { - err |= get_user(lbe->rsector_org, &lbe32->rsector_org); - err |= __get_user(lbe->rdev_org, &lbe32->rdev_org); - err |= __get_user(lbe->rsector_new, &lbe32->rsector_new); - err |= __get_user(lbe->rdev_new, &lbe32->rdev_new); - + for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) { + err |= get_user(lbe->rsector_org, &lbe32->rsector_org); + err |= __get_user(lbe->rdev_org, &lbe32->rdev_org); + err |= __get_user(lbe->rsector_new, &lbe32->rsector_new); + err |= __get_user(lbe->rdev_new, &lbe32->rdev_new); } } } @@ -2608,7 +2609,7 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { - vg_t *v; + vg_t *v = NULL; union { lv_req_t lv_req; le_remap_req_t le_remap; @@ -2626,17 +2627,22 @@ switch (cmd) { case VG_STATUS: v = kmalloc(sizeof(vg_t), GFP_KERNEL); - if (!v) return -ENOMEM; + if (!v) + return -ENOMEM; karg = v; break; + + case VG_CREATE_OLD: case VG_CREATE: v = kmalloc(sizeof(vg_t), GFP_KERNEL); - if (!v) return -ENOMEM; - if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc) || - __get_user(v->proc, &((vg32_t *)arg)->proc)) { + if (!v) + return -ENOMEM; + if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc)) { kfree(v); return -EFAULT; } + /* 'proc' field is unused, just NULL it out. */ + v->proc = NULL; if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) { kfree(v); return -EFAULT; @@ -2648,39 +2654,46 @@ return -EPERM; for (i = 0; i < v->pv_max; i++) { err = __get_user(ptr, &((vg32_t *)arg)->pv[i]); - if (err) break; + if (err) + break; if (ptr) { v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL); if (!v->pv[i]) { err = -ENOMEM; break; } - err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1); + err = copy_from_user(v->pv[i], (void *)A(ptr), + sizeof(pv32_t) - 8 - UUID_LEN+1); if (err) { err = -EFAULT; break; } - err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1); + err = copy_from_user(v->pv[i]->pv_uuid, + ((pv32_t *)A(ptr))->pv_uuid, + UUID_LEN+1); if (err) { err = -EFAULT; break; } - - v->pv[i]->pe = NULL; v->pv[i]->inode = NULL; + v->pv[i]->pe = NULL; + v->pv[i]->bd = NULL; } } if (!err) { for (i = 0; i < v->lv_max; i++) { err = __get_user(ptr, &((vg32_t *)arg)->lv[i]); - if (err) break; + if (err) + break; if (ptr) { v->lv[i] = get_lv_t(ptr, &err); - if (err) break; + if (err) + break; } } } break; + case LV_CREATE: case LV_EXTEND: case LV_REDUCE: @@ -2688,54 +2701,70 @@ case LV_RENAME: case LV_STATUS_BYNAME: err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name)); - if (err) return -EFAULT; + if (err) + return -EFAULT; if (cmd != LV_REMOVE) { err = __get_user(ptr, &((lv_req32_t *)arg)->lv); - if (err) return err; + if (err) + return err; u.lv_req.lv = get_lv_t(ptr, &err); } else u.lv_req.lv = NULL; break; - case LV_STATUS_BYINDEX: - err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index); + err = get_user(u.lv_byindex.lv_index, + &((lv_status_byindex_req32_t *)arg)->lv_index); err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv); - if (err) return err; + if (err) + return err; u.lv_byindex.lv = get_lv_t(ptr, &err); break; + case LV_STATUS_BYDEV: err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev); + err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv); + if (err) + return err; u.lv_bydev.lv = get_lv_t(ptr, &err); - if (err) return err; - u.lv_bydev.lv = &p; - p.pe = NULL; p.inode = NULL; - break; + break; + case VG_EXTEND: err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1); - if (err) return -EFAULT; + if (err) + return -EFAULT; err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1); - if (err) return -EFAULT; - p.pe = NULL; p.inode = NULL; + if (err) + return -EFAULT; + p.pe = NULL; + p.bd = NULL; karg = &p; break; + case PV_CHANGE: case PV_STATUS: err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name)); - if (err) return -EFAULT; + if (err) + return -EFAULT; err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv); - if (err) return err; + if (err) + return err; u.pv_status.pv = &p; if (cmd == PV_CHANGE) { - err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1); - if (err) return -EFAULT; - p.pe = NULL; p.inode = NULL; + err = copy_from_user(&p, (void *)A(ptr), + sizeof(pv32_t) - 8 - UUID_LEN+1); + if (err) + return -EFAULT; + p.pe = NULL; + p.bd = NULL; } break; - } + }; + old_fs = get_fs(); set_fs (KERNEL_DS); err = sys_ioctl (fd, cmd, (unsigned long)karg); set_fs (old_fs); + switch (cmd) { case VG_STATUS: if (!err) { @@ -2748,42 +2777,60 @@ } kfree(v); break; + + case VG_CREATE_OLD: case VG_CREATE: - for (i = 0; i < v->pv_max; i++) - if (v->pv[i]) kfree(v->pv[i]); - for (i = 0; i < v->lv_max; i++) - if (v->lv[i]) put_lv_t(v->lv[i]); + for (i = 0; i < v->pv_max; i++) { + if (v->pv[i]) + kfree(v->pv[i]); + } + for (i = 0; i < v->lv_max; i++) { + if (v->lv[i]) + put_lv_t(v->lv[i]); + } kfree(v); break; + case LV_STATUS_BYNAME: - if (!err && u.lv_req.lv) err = copy_lv_t(ptr, u.lv_req.lv); + if (!err && u.lv_req.lv) + err = copy_lv_t(ptr, u.lv_req.lv); /* Fall through */ + case LV_CREATE: case LV_EXTEND: case LV_REDUCE: - if (u.lv_req.lv) put_lv_t(u.lv_req.lv); + if (u.lv_req.lv) + put_lv_t(u.lv_req.lv); break; + case LV_STATUS_BYINDEX: if (u.lv_byindex.lv) { - if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv); + if (!err) + err = copy_lv_t(ptr, u.lv_byindex.lv); put_lv_t(u.lv_byindex.lv); } break; + + case LV_STATUS_BYDEV: + if (u.lv_bydev.lv) { + if (!err) + err = copy_lv_t(ptr, u.lv_bydev.lv); + put_lv_t(u.lv_byindex.lv); + } + break; + case PV_STATUS: if (!err) { err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1); - if (err) return -EFAULT; + if (err) + return -EFAULT; err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1); - if (err) return -EFAULT; + if (err) + return -EFAULT; } break; - case LV_STATUS_BYDEV: - if (!err) { - if (!err) err = copy_lv_t(ptr, u.lv_bydev.lv); - put_lv_t(u.lv_byindex.lv); - } - break; - } + }; + return err; } #endif @@ -4666,6 +4713,7 @@ HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl) +HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl) HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl) HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl) HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl) @@ -4675,6 +4723,7 @@ HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl) HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl) HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl) +HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl) HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl) HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl) #endif /* LVM */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/irq.c linux-2.5/arch/sparc64/kernel/irq.c --- linux-2.5.1/arch/sparc64/kernel/irq.c Wed Nov 28 21:22:26 2001 +++ linux-2.5/arch/sparc64/kernel/irq.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.109 2001/11/12 22:22:37 davem Exp $ +/* $Id: irq.c,v 1.112 2001/11/16 00:04:54 kanoj Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -35,6 +35,7 @@ #include <asm/softirq.h> #include <asm/starfire.h> #include <asm/uaccess.h> +#include <asm/cache.h> #ifdef CONFIG_SMP static void distribute_irqs(void); @@ -53,10 +54,10 @@ * at the same time. */ -struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (64))); +struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES))); #ifndef CONFIG_SMP -unsigned int __up_workvec[16] __attribute__ ((aligned (64))); +unsigned int __up_workvec[16] __attribute__ ((aligned (SMP_CACHE_BYTES))); #define irq_work(__cpu, __pil) &(__up_workvec[(void)(__cpu), (__pil)]) #else #define irq_work(__cpu, __pil) &(cpu_data[(__cpu)].irq_worklists[(__pil)]) @@ -822,6 +823,11 @@ irq_enter(cpu, irq); kstat.irqs[cpu][irq]++; + +#ifdef CONFIG_PCI + if (irq == 9) + kbd_pt_regs = regs; +#endif /* Sliiiick... */ #ifndef CONFIG_SMP diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/pci_psycho.c linux-2.5/arch/sparc64/kernel/pci_psycho.c --- linux-2.5.1/arch/sparc64/kernel/pci_psycho.c Fri Oct 12 22:35:53 2001 +++ linux-2.5/arch/sparc64/kernel/pci_psycho.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.29 2001/10/11 00:44:38 davem Exp $ +/* $Id: pci_psycho.c,v 1.30 2001/11/14 13:17:56 davem Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -371,6 +371,7 @@ case PCI_BASE_CLASS_MULTIMEDIA: case PCI_BASE_CLASS_MEMORY: case PCI_BASE_CLASS_BRIDGE: + case PCI_BASE_CLASS_SERIAL: ret = 10; break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/pci_sabre.c linux-2.5/arch/sparc64/kernel/pci_sabre.c --- linux-2.5.1/arch/sparc64/kernel/pci_sabre.c Fri Oct 12 22:35:53 2001 +++ linux-2.5/arch/sparc64/kernel/pci_sabre.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.40 2001/10/11 00:44:38 davem Exp $ +/* $Id: pci_sabre.c,v 1.41 2001/11/14 13:17:56 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -589,6 +589,11 @@ { int ret; + if (pdev && + pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_RIO_USB) + return 9; + ret = sabre_pil_table[ino]; if (ret == 0 && pdev == NULL) { ret = 1; @@ -609,6 +614,7 @@ case PCI_BASE_CLASS_MULTIMEDIA: case PCI_BASE_CLASS_MEMORY: case PCI_BASE_CLASS_BRIDGE: + case PCI_BASE_CLASS_SERIAL: ret = 10; break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/pci_schizo.c linux-2.5/arch/sparc64/kernel/pci_schizo.c --- linux-2.5.1/arch/sparc64/kernel/pci_schizo.c Fri Oct 12 22:35:53 2001 +++ linux-2.5/arch/sparc64/kernel/pci_schizo.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_schizo.c,v 1.22 2001/10/11 00:44:38 davem Exp $ +/* $Id: pci_schizo.c,v 1.23 2001/11/14 13:17:56 davem Exp $ * pci_schizo.c: SCHIZO specific PCI controller support. * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -337,6 +337,11 @@ { int ret; + if (pdev && + pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_RIO_USB) + return 9; + ret = schizo_pil_table[ino]; if (ret == 0 && pdev == NULL) { ret = 1; @@ -357,6 +362,7 @@ case PCI_BASE_CLASS_MULTIMEDIA: case PCI_BASE_CLASS_MEMORY: case PCI_BASE_CLASS_BRIDGE: + case PCI_BASE_CLASS_SERIAL: ret = 10; break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/process.c linux-2.5/arch/sparc64/kernel/process.c --- linux-2.5.1/arch/sparc64/kernel/process.c Sun Oct 21 17:36:54 2001 +++ linux-2.5/arch/sparc64/kernel/process.c Thu Dec 27 22:10:28 2001 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.122 2001/10/18 09:06:36 davem Exp $ +/* $Id: process.c,v 1.125 2001/11/17 00:10:48 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -54,7 +54,6 @@ /* endless idle loop with no priority at all */ current->nice = 20; - current->counter = -100; init_idle(); for (;;) { @@ -84,7 +83,6 @@ int cpu_idle(void) { current->nice = 20; - current->counter = -100; init_idle(); while(1) { @@ -276,7 +274,12 @@ #ifdef CONFIG_SMP unsigned long flags; - spin_lock_irqsave(®dump_lock, flags); + /* Protect against xcall ipis which might lead to livelock on the lock */ + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" + : "=r" (flags) + : "i" (PSTATE_IE)); + spin_lock(®dump_lock); printk("CPU[%d]: local_irq_count[%u] irqs_running[%d]\n", smp_processor_id(), local_irq_count(smp_processor_id()), @@ -298,7 +301,9 @@ regs->u_regs[15]); show_regwindow(regs); #ifdef CONFIG_SMP - spin_unlock_irqrestore(®dump_lock, flags); + spin_unlock(®dump_lock); + __asm__ __volatile__("wrpr %0, 0, %%pstate" + : : "r" (flags)); #endif } @@ -583,6 +588,11 @@ { struct thread_struct *t = &p->thread; char *child_trap_frame; + +#ifdef CONFIG_DEBUG_SPINLOCK + t->smp_lock_count = 0; + t->smp_lock_pc = 0; +#endif /* Calculate offset to stack_frame & pt_regs */ child_trap_frame = ((char *)p) + (THREAD_SIZE - (TRACEREG_SZ+REGWIN_SZ)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/rtrap.S linux-2.5/arch/sparc64/kernel/rtrap.S --- linux-2.5.1/arch/sparc64/kernel/rtrap.S Wed Oct 17 21:16:39 2001 +++ linux-2.5/arch/sparc64/kernel/rtrap.S Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.56 2001/10/13 00:14:34 kanoj Exp $ +/* $Id: rtrap.S,v 1.57 2001/12/06 00:16:11 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -18,14 +18,13 @@ #define RTRAP_PSTATE_IRQOFF (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV) #define RTRAP_PSTATE_AG_IRQOFF (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG) -#if 0 -#define RTRAP_CHECK call rtrap_check; add %sp, (STACK_BIAS+REGWIN_SZ), %o0; -#else -#define RTRAP_CHECK -#endif + /* Register %l6 keeps track of whether we are returning + * from a system call or not. It is cleared if we call + * do_signal, and it must not be otherwise modified until + * we fully commit to returning to userspace. + */ .text - .align 32 __handle_softirq: call do_softirq @@ -34,42 +33,101 @@ nop __handle_preemption: call schedule - nop + wrpr %g0, RTRAP_PSTATE, %pstate ba,pt %xcc, __handle_preemption_continue - nop + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate + __handle_user_windows: - wrpr %g0, RTRAP_PSTATE, %pstate call fault_in_user_windows - nop + wrpr %g0, RTRAP_PSTATE, %pstate ba,pt %xcc, __handle_user_windows_continue + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate + /* Redo sched+sig checks */ + ldx [%g6 + AOFF_task_need_resched], %l0 + brz,pt %l0, 1f + nop + call schedule + + wrpr %g0, RTRAP_PSTATE, %pstate + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate +1: lduw [%g6 + AOFF_task_sigpending], %l0 + brz,pt %l0, __handle_user_windows_continue nop + clr %o0 + mov %l5, %o2 + mov %l6, %o3 + + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + call do_signal + wrpr %g0, RTRAP_PSTATE, %pstate + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate + clr %l6 + /* Signal delivery can modify pt_regs tstate, so we must + * reload it. + */ + ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 + sethi %hi(0xf << 20), %l4 + and %l1, %l4, %l4 + + ba,pt %xcc, __handle_user_windows_continue + andn %l1, %l4, %l1 __handle_perfctrs: - /* Don't forget to preserve user window invariants. */ - wrpr %g0, RTRAP_PSTATE, %pstate call update_perfctrs - nop + wrpr %g0, RTRAP_PSTATE, %pstate wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2 - brz,pt %o2, __handle_perfctrs_continue - sethi %hi(TSTATE_PEF), %l6 - wrpr %g0, RTRAP_PSTATE, %pstate + brz,pt %o2, 1f + nop + /* Redo userwin+sched+sig checks */ call fault_in_user_windows + wrpr %g0, RTRAP_PSTATE, %pstate + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate +1: ldx [%g6 + AOFF_task_need_resched], %l0 + brz,pt %l0, 1f nop + call schedule + wrpr %g0, RTRAP_PSTATE, %pstate + + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate +1: lduw [%g6 + AOFF_task_sigpending], %l0 + brz,pt %l0, __handle_perfctrs_continue + sethi %hi(TSTATE_PEF), %o0 + clr %o0 + mov %l5, %o2 + mov %l6, %o3 + add %sp, STACK_BIAS + REGWIN_SZ, %o1 + + call do_signal + wrpr %g0, RTRAP_PSTATE, %pstate + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate + clr %l6 + /* Signal delivery can modify pt_regs tstate, so we must + * reload it. + */ + ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 + sethi %hi(0xf << 20), %l4 + and %l1, %l4, %l4 + andn %l1, %l4, %l1 + ba,pt %xcc, __handle_perfctrs_continue - nop + sethi %hi(TSTATE_PEF), %o0 __handle_userfpu: rd %fprs, %l5 andcc %l5, FPRS_FEF, %g0 + sethi %hi(TSTATE_PEF), %o0 be,a,pn %icc, __handle_userfpu_continue - andn %l1, %l6, %l1 + andn %l1, %o0, %l1 ba,a,pt %xcc, __handle_userfpu_continue + __handle_signal: clr %o0 mov %l5, %o2 mov %l6, %o3 + add %sp, STACK_BIAS + REGWIN_SZ, %o1 call do_signal - add %sp, STACK_BIAS + REGWIN_SZ, %o1 + wrpr %g0, RTRAP_PSTATE, %pstate + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate clr %l6 /* Signal delivery can modify pt_regs tstate, so we must @@ -99,29 +157,43 @@ and %l1, %l4, %l4 bne,pn %icc, to_kernel andn %l1, %l4, %l1 -to_user: ldx [%g6 + AOFF_task_need_resched], %l0 - brnz,pn %l0, __handle_preemption + /* We must hold IRQs off and atomically test schedule+signal + * state, then hold them off all the way back to userspace. + * If we are returning to kernel, none of this matters. + * + * If we do not do this, there is a window where we would do + * the tests, later the signal/resched event arrives but we do + * not process it since we are still in kernel mode. It would + * take until the next local IRQ before the signal/resched + * event would be handled. + * + * This also means that if we have to deal with performance + * counters or user windows, we have to redo all of these + * sched+signal checks with IRQs disabled. + */ +to_user: wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate __handle_preemption_continue: + ldx [%g6 + AOFF_task_need_resched], %l0 + brnz,pn %l0, __handle_preemption lduw [%g6 + AOFF_task_sigpending], %l0 brnz,pn %l0, __handle_signal nop __handle_signal_continue: -check_user_wins: - wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2 brnz,pn %o2, __handle_user_windows - sethi %hi(TSTATE_PEF), %l6 - + nop __handle_user_windows_continue: - RTRAP_CHECK ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %l5 andcc %l5, SPARC_FLAG_PERFCTR, %g0 + sethi %hi(TSTATE_PEF), %o0 bne,pn %xcc, __handle_perfctrs __handle_perfctrs_continue: - andcc %l1, %l6, %g0 + andcc %l1, %o0, %g0 + + /* This fpdepth clear is neccessary for non-syscall rtraps only */ bne,pn %xcc, __handle_userfpu - stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only + stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] __handle_userfpu_continue: rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/semaphore.c linux-2.5/arch/sparc64/kernel/semaphore.c --- linux-2.5.1/arch/sparc64/kernel/semaphore.c Sun May 20 18:32:07 2001 +++ linux-2.5/arch/sparc64/kernel/semaphore.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: semaphore.c,v 1.8 2001/05/18 08:01:35 davem Exp $ +/* $Id: semaphore.c,v 1.9 2001/11/18 00:12:56 davem Exp $ * semaphore.c: Sparc64 semaphore implementation. * * This is basically the PPC semaphore scheme ported to use @@ -31,7 +31,7 @@ " cas [%3], %0, %1\n" " cmp %0, %1\n" " bne,pn %%icc, 1b\n" -" nop\n" +" membar #StoreLoad | #StoreStore\n" : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) : "r" (&sem->count), "r" (incr), "m" (sem->count) : "cc"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/smp.c linux-2.5/arch/sparc64/kernel/smp.c --- linux-2.5.1/arch/sparc64/kernel/smp.c Wed Nov 21 18:31:09 2001 +++ linux-2.5/arch/sparc64/kernel/smp.c Thu Dec 13 16:32:35 2001 @@ -17,6 +17,7 @@ #include <linux/spinlock.h> #include <linux/fs.h> #include <linux/seq_file.h> +#include <linux/cache.h> #include <asm/head.h> #include <asm/ptrace.h> @@ -39,17 +40,17 @@ extern void calibrate_delay(void); extern unsigned prom_cpu_nodes[]; -struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64))); +cpuinfo_sparc cpu_data[NR_CPUS]; -volatile int __cpu_number_map[NR_CPUS] __attribute__ ((aligned (64))); -volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (64))); +volatile int __cpu_number_map[NR_CPUS] __attribute__ ((aligned (SMP_CACHE_BYTES))); +volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (SMP_CACHE_BYTES))); /* Please don't make this stuff initdata!!! --DaveM */ static unsigned char boot_cpu_id = 0; static int smp_activated = 0; /* Kernel spinlock */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; volatile int smp_processors_ready = 0; unsigned long cpu_present_map = 0; @@ -137,6 +138,15 @@ { int cpuid = hard_smp_processor_id(); unsigned long pstate; + extern int bigkernel; + extern unsigned long kern_locked_tte_data; + + if (bigkernel) { + prom_dtlb_load(sparc64_highest_locked_tlbent()-1, + kern_locked_tte_data + 0x400000, KERNBASE + 0x400000); + prom_itlb_load(sparc64_highest_locked_tlbent()-1, + kern_locked_tte_data + 0x400000, KERNBASE + 0x400000); + } inherit_locked_prom_mappings(0); @@ -223,7 +233,6 @@ { trap_init(); init_IRQ(); - smp_callin(); return cpu_idle(); } @@ -276,7 +285,7 @@ init_tasks[cpucount] = p; p->processor = i; - p->cpus_runnable = 1 << i; /* we schedule the first task manually */ + p->cpus_runnable = 1UL << i; /* we schedule the first task manually */ del_from_runqueue(p); unhash_process(p); @@ -482,7 +491,7 @@ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); - if ((stuck & ~(0x5555555555555555UL)) == 0) { + if ((dispatch_stat & ~(0x5555555555555555UL)) == 0) { /* Busy bits will not clear, continue instead * of freezing up on this cpu. */ @@ -542,6 +551,9 @@ int wait; }; +static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; +static struct call_data_struct *call_data; + extern unsigned long xcall_call_function; int smp_call_function(void (*func)(void *info), void *info, @@ -549,6 +561,7 @@ { struct call_data_struct data; int cpus = smp_num_cpus - 1; + long timeout; if (!cpus) return 0; @@ -558,19 +571,36 @@ atomic_set(&data.finished, 0); data.wait = wait; - smp_cross_call(&xcall_call_function, - 0, (u64) &data, 0); + spin_lock_bh(&call_lock); + + call_data = &data; + + smp_cross_call(&xcall_call_function, 0, 0, 0); + /* * Wait for other cpus to complete function or at * least snap the call data. */ - while (atomic_read(&data.finished) != cpus) + timeout = 1000000; + while (atomic_read(&data.finished) != cpus) { + if (--timeout <= 0) + goto out_timeout; barrier(); + udelay(1); + } + + spin_unlock_bh(&call_lock); + + return 0; +out_timeout: + spin_unlock_bh(&call_lock); + printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n", + smp_num_cpus - 1, atomic_read(&data.finished)); return 0; } -void smp_call_function_client(struct call_data_struct *call_data) +void smp_call_function_client(void) { void (*func) (void *info) = call_data->func; void *info = call_data->info; @@ -597,7 +627,7 @@ extern unsigned long xcall_flush_dcache_page_cheetah; extern unsigned long xcall_flush_dcache_page_spitfire; -#ifdef DCFLUSH_DEBUG +#ifdef CONFIG_DEBUG_DCFLUSH extern atomic_t dcpage_flushes; extern atomic_t dcpage_flushes_xcall; #endif @@ -620,7 +650,7 @@ if (smp_processors_ready) { unsigned long mask = 1UL << cpu; -#ifdef DCFLUSH_DEBUG +#ifdef CONFIG_DEBUG_DCFLUSH atomic_inc(&dcpage_flushes); #endif if (cpu == smp_processor_id()) { @@ -642,7 +672,7 @@ __pa(page->virtual), 0, mask); } -#ifdef DCFLUSH_DEBUG +#ifdef CONFIG_DEBUG_DCFLUSH atomic_inc(&dcpage_flushes_xcall); #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/sparc64_ksyms.c linux-2.5/arch/sparc64/kernel/sparc64_ksyms.c --- linux-2.5.1/arch/sparc64/kernel/sparc64_ksyms.c Tue Oct 30 23:08:11 2001 +++ linux-2.5/arch/sparc64/kernel/sparc64_ksyms.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.116 2001/10/26 15:49:21 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.119 2001/11/30 01:04:10 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -98,7 +98,7 @@ #ifdef CONFIG_SMP extern spinlock_t kernel_flag; extern int smp_num_cpus; -#ifdef SPIN_LOCK_DEBUG +#ifdef CONFIG_DEBUG_SPINLOCK extern void _do_spin_lock (spinlock_t *lock, char *str); extern void _do_spin_unlock (spinlock_t *lock); extern int _spin_trylock (spinlock_t *lock); @@ -113,7 +113,7 @@ /* used by various drivers */ #ifdef CONFIG_SMP -#ifndef SPIN_LOCK_DEBUG +#ifndef CONFIG_DEBUG_SPINLOCK /* Out of line rw-locking implementation. */ EXPORT_SYMBOL(__read_lock); EXPORT_SYMBOL(__read_unlock); @@ -145,7 +145,7 @@ EXPORT_SYMBOL(__cpu_logical_map); /* Spinlock debugging library, optional. */ -#ifdef SPIN_LOCK_DEBUG +#ifdef CONFIG_DEBUG_SPINLOCK EXPORT_SYMBOL(_do_spin_lock); EXPORT_SYMBOL(_do_spin_unlock); EXPORT_SYMBOL(_spin_trylock); @@ -319,7 +319,6 @@ EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(_clear_page); -EXPORT_SYMBOL(_copy_page); EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(copy_user_page); EXPORT_SYMBOL(__bzero); @@ -354,4 +353,8 @@ void VISenter(void); /* RAID code needs this */ -EXPORT_SYMBOL(VISenter); +EXPORT_SYMBOL_NOVERS(VISenter); + +#ifdef CONFIG_DEBUG_BUGVERBOSE +EXPORT_SYMBOL(do_BUG); +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/sunos_ioctl32.c linux-2.5/arch/sparc64/kernel/sunos_ioctl32.c --- linux-2.5.1/arch/sparc64/kernel/sunos_ioctl32.c Sat Aug 5 01:16:11 2000 +++ linux-2.5/arch/sparc64/kernel/sunos_ioctl32.c Mon Jan 14 22:39:45 2002 @@ -100,8 +100,12 @@ if(fd >= SUNOS_NR_OPEN) goto out; - if(!fcheck(fd)) + read_lock(¤t->files->file_lock); + if(!fcheck(fd)) { + read_unlock(¤t->files->file_lock); goto out; + } + read_unlock(¤t->files->file_lock); if(cmd == TIOCSETD) { mm_segment_t old_fs = get_fs(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/sys_sparc.c linux-2.5/arch/sparc64/kernel/sys_sparc.c --- linux-2.5.1/arch/sparc64/kernel/sys_sparc.c Tue Oct 30 23:08:11 2001 +++ linux-2.5/arch/sparc64/kernel/sys_sparc.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.54 2001/10/28 20:49:13 davem Exp $ +/* $Id: sys_sparc.c,v 1.55 2001/11/29 22:52:03 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -255,27 +255,15 @@ asmlinkage int sparc64_personality(unsigned long personality) { - unsigned long ret, trying, orig_ret; + int ret; - trying = ret = personality; - - if (current->personality == PER_LINUX32 && - trying == PER_LINUX) - trying = ret = PER_LINUX32; - - /* For PER_LINUX32 we want to retain &default_exec_domain. */ - if (trying == PER_LINUX32) + if (current->personality == PER_LINUX32 && personality == PER_LINUX) + personality = PER_LINUX32; + ret = sys_personality(personality); + if (ret == PER_LINUX32) ret = PER_LINUX; - orig_ret = ret; - ret = sys_personality(ret); - - if (orig_ret == PER_LINUX && trying == PER_LINUX32) { - current->personality = PER_LINUX32; - ret = PER_LINUX; - } - - return (int) ret; + return ret; } /* Linux version of mmap */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/time.c linux-2.5/arch/sparc64/kernel/time.c --- linux-2.5.1/arch/sparc64/kernel/time.c Thu Sep 20 21:11:57 2001 +++ linux-2.5/arch/sparc64/kernel/time.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.40 2001/09/06 02:44:28 davem Exp $ +/* $Id: time.c,v 1.41 2001/11/20 18:24:55 kanoj Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -609,7 +609,6 @@ unsigned long clock; init_timers(timer_interrupt, &clock); - timer_tick_offset = clock / HZ; timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020)); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/trampoline.S linux-2.5/arch/sparc64/kernel/trampoline.S --- linux-2.5.1/arch/sparc64/kernel/trampoline.S Thu Sep 20 21:11:57 2001 +++ linux-2.5/arch/sparc64/kernel/trampoline.S Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.22 2001/09/07 21:04:40 kanoj Exp $ +/* $Id: trampoline.S,v 1.24 2001/11/16 21:59:20 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/traps.c linux-2.5/arch/sparc64/kernel/traps.c --- linux-2.5.1/arch/sparc64/kernel/traps.c Mon Oct 1 16:19:56 2001 +++ linux-2.5/arch/sparc64/kernel/traps.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.79 2001/09/21 02:14:39 kanoj Exp $ +/* $Id: traps.c,v 1.82 2001/11/18 00:12:56 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -38,16 +38,19 @@ void bad_trap (struct pt_regs *regs, long lvl) { + char buffer[32]; siginfo_t info; if (lvl < 0x100) { - char buffer[24]; - - sprintf (buffer, "Bad hw trap %lx at tl0\n", lvl); + sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl); + die_if_kernel(buffer, regs); + } + + lvl -= 0x100; + if (regs->tstate & TSTATE_PRIV) { + sprintf(buffer, "Kernel bad sw trap %lx", lvl); die_if_kernel (buffer, regs); } - if (regs->tstate & TSTATE_PRIV) - die_if_kernel ("Kernel bad trap", regs); if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { regs->tpc &= 0xffffffff; regs->tnpc &= 0xffffffff; @@ -56,7 +59,7 @@ info.si_errno = 0; info.si_code = ILL_ILLTRP; info.si_addr = (void *)regs->tpc; - info.si_trapno = lvl - 0x100; + info.si_trapno = lvl; force_sig_info(SIGILL, &info, current); } @@ -68,6 +71,14 @@ die_if_kernel (buffer, regs); } +#ifdef CONFIG_DEBUG_BUGVERBOSE +void do_BUG(const char *file, int line) +{ + bust_spinlocks(1); + printk("kernel BUG at %s:%d!\n", file, line); +} +#endif + void instruction_access_exception (struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) { @@ -947,6 +958,7 @@ __asm__ __volatile__("ldxa [%0] %3, %%g0\n\t" "ldxa [%1] %3, %%g0\n\t" "casxa [%2] %3, %%g0, %%g0\n\t" + "membar #StoreLoad | #StoreStore\n\t" "ldxa [%0] %3, %%g0\n\t" "ldxa [%1] %3, %%g0\n\t" "membar #Sync" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/kernel/ttable.S linux-2.5/arch/sparc64/kernel/ttable.S --- linux-2.5.1/arch/sparc64/kernel/ttable.S Mon Oct 1 16:19:56 2001 +++ linux-2.5/arch/sparc64/kernel/ttable.S Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.35 2001/09/21 02:14:39 kanoj Exp $ +/* $Id: ttable.S,v 1.36 2001/11/28 23:32:16 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions. * * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu) @@ -15,11 +15,13 @@ sparc64_ttable_tl0: tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7) -tl0_iax: TRAP_NOSAVE(__do_instruction_access_exception) +tl0_iax: membar #Sync + TRAP_NOSAVE_7INSNS(__do_instruction_access_exception) tl0_resv009: BTRAP(0x9) tl0_iae: TRAP(do_iae) tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf) -tl0_ill: TRAP(do_illegal_instruction) +tl0_ill: membar #Sync + TRAP_7INSNS(do_illegal_instruction) tl0_privop: TRAP(do_privop) tl0_resv012: BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17) tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/lib/atomic.S linux-2.5/arch/sparc64/lib/atomic.S --- linux-2.5.1/arch/sparc64/lib/atomic.S Thu Mar 16 19:40:17 2000 +++ linux-2.5/arch/sparc64/lib/atomic.S Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: atomic.S,v 1.3 2000/03/16 16:44:37 davem Exp $ +/* $Id: atomic.S,v 1.4 2001/11/18 00:12:56 davem Exp $ * atomic.S: These things are too big to do inline. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -19,7 +19,7 @@ cas [%o1], %g5, %g7 cmp %g5, %g7 bne,pn %icc, __atomic_add - nop + membar #StoreLoad | #StoreStore retl add %g7, %o0, %o0 @@ -30,7 +30,7 @@ cas [%o1], %g5, %g7 cmp %g5, %g7 bne,pn %icc, __atomic_sub - nop + membar #StoreLoad | #StoreStore retl sub %g7, %o0, %o0 atomic_impl_end: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/lib/bitops.S linux-2.5/arch/sparc64/lib/bitops.S --- linux-2.5.1/arch/sparc64/lib/bitops.S Sat Apr 14 03:15:55 2001 +++ linux-2.5/arch/sparc64/lib/bitops.S Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: bitops.S,v 1.2 2001/04/14 01:12:02 davem Exp $ +/* $Id: bitops.S,v 1.3 2001/11/18 00:12:56 davem Exp $ * bitops.S: Sparc64 atomic bit operations. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -28,7 +28,7 @@ bne,a,pn %xcc, 1b ldx [%o1], %g7 2: retl - nop + membar #StoreLoad | #StoreStore .globl ___test_and_clear_bit ___test_and_clear_bit: /* %o0=nr, %o1=addr */ @@ -47,7 +47,7 @@ bne,a,pn %xcc, 1b ldx [%o1], %g7 2: retl - nop + membar #StoreLoad | #StoreStore .globl ___test_and_change_bit ___test_and_change_bit: /* %o0=nr, %o1=addr */ @@ -65,7 +65,7 @@ bne,a,pn %xcc, 1b ldx [%o1], %g7 2: retl - nop + membar #StoreLoad | #StoreStore nop .globl ___test_and_set_le_bit @@ -85,7 +85,7 @@ bne,a,pn %icc, 1b lduwa [%o1] ASI_PL, %g7 2: retl - nop + membar #StoreLoad | #StoreStore .globl ___test_and_clear_le_bit ___test_and_clear_le_bit: /* %o0=nr, %o1=addr */ @@ -104,7 +104,7 @@ bne,a,pn %icc, 1b lduwa [%o1] ASI_PL, %g7 2: retl - nop + membar #StoreLoad | #StoreStore .globl __bitops_end __bitops_end: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/lib/blockops.S linux-2.5/arch/sparc64/lib/blockops.S --- linux-2.5.1/arch/sparc64/lib/blockops.S Mon Oct 1 16:19:56 2001 +++ linux-2.5/arch/sparc64/lib/blockops.S Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.36 2001/09/24 21:44:03 davem Exp $ +/* $Id: blockops.S,v 1.41 2001/12/05 06:05:35 davem Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com) @@ -17,10 +17,9 @@ fmovd %reg4, %f56; fmovd %reg5, %f58; \ fmovd %reg6, %f60; fmovd %reg7, %f62; -#define TLBTEMP_BASE (8 * 1024 * 1024) #define DCACHE_SIZE (PAGE_SIZE * 2) -#define TLBTEMP_ENT1 (61 << 3) -#define TLBTEMP_ENT2 (62 << 3) +#define TLBTEMP_ENT1 (60 << 3) +#define TLBTEMP_ENT2 (61 << 3) #define TLBTEMP_ENTSZ (1 << 3) #if (PAGE_SHIFT == 13) || (PAGE_SHIFT == 19) @@ -34,64 +33,6 @@ .text .align 32 - .globl _copy_page - .type _copy_page,@function -_copy_page: /* %o0=dest, %o1=src */ - VISEntry - membar #LoadStore | #StoreStore | #StoreLoad - ldda [%o1] ASI_BLK_P, %f0 - add %o1, 0x40, %o1 - ldda [%o1] ASI_BLK_P, %f16 - add %o1, 0x40, %o1 - sethi %hi(PAGE_SIZE), %o2 -1: TOUCH(f0, f2, f4, f6, f8, f10, f12, f14) - ldda [%o1] ASI_BLK_P, %f32 - stda %f48, [%o0] ASI_BLK_P - add %o1, 0x40, %o1 - sub %o2, 0x40, %o2 - add %o0, 0x40, %o0 - TOUCH(f16, f18, f20, f22, f24, f26, f28, f30) - ldda [%o1] ASI_BLK_P, %f0 - stda %f48, [%o0] ASI_BLK_P - add %o1, 0x40, %o1 - sub %o2, 0x40, %o2 - add %o0, 0x40, %o0 - TOUCH(f32, f34, f36, f38, f40, f42, f44, f46) - ldda [%o1] ASI_BLK_P, %f16 - stda %f48, [%o0] ASI_BLK_P - sub %o2, 0x40, %o2 - add %o1, 0x40, %o1 - cmp %o2, PAGE_SIZE_REM - bne,pt %xcc, 1b - add %o0, 0x40, %o0 -#if (PAGE_SHIFT == 16) || (PAGE_SHIFT == 22) - TOUCH(f0, f2, f4, f6, f8, f10, f12, f14) - ldda [%o1] ASI_BLK_P, %f32 - stda %f48, [%o0] ASI_BLK_P - add %o1, 0x40, %o1 - sub %o2, 0x40, %o2 - add %o0, 0x40, %o0 - TOUCH(f16, f18, f20, f22, f24, f26, f28, f30) - ldda [%o1] ASI_BLK_P, %f0 - stda %f48, [%o0] ASI_BLK_P - add %o1, 0x40, %o1 - sub %o2, 0x40, %o2 - add %o0, 0x40, %o0 - membar #Sync - stda %f32, [%o0] ASI_BLK_P - add %o0, 0x40, %o0 - stda %f0, [%o0] ASI_BLK_P -#else - membar #Sync - stda %f0, [%o0] ASI_BLK_P - add %o0, 0x40, %o0 - stda %f16, [%o0] ASI_BLK_P -#endif - membar #Sync - VISExit - retl - nop - .globl copy_user_page .type copy_user_page,@function copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ @@ -110,7 +51,7 @@ or %g2, %g3, %g2 add %o0, %o3, %o0 add %o0, %o1, %o1 -#define FIX_INSN_1 0x96102068 /* mov (13 << 3), %o3 */ +#define FIX_INSN_1 0x96102060 /* mov (12 << 3), %o3 */ cheetah_patch_1: mov TLBTEMP_ENT1, %o3 rdpr %pstate, %g3 @@ -134,6 +75,7 @@ stxa %g0, [%o5] ASI_DMMU membar #Sync + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g0 ldxa [%o3] ASI_DTLB_DATA_ACCESS, %o5 stxa %o0, [%o2] ASI_DMMU stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS @@ -152,6 +94,7 @@ stxa %g0, [%g7] ASI_DMMU membar #Sync + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g0 ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 stxa %o1, [%o2] ASI_DMMU stxa %g2, [%o3] ASI_DTLB_DATA_ACCESS @@ -169,9 +112,10 @@ nop cheetah_copy_user_page: - mov 121, %o2 ! A0 Group + sethi %hi((PAGE_SIZE/64)-7), %o2 ! A0 Group prefetch [%o1 + 0x000], #one_read ! MS - prefetch [%o1 + 0x040], #one_read ! MS Group + or %o2, %lo((PAGE_SIZE/64)-7), %o2 ! A1 Group + prefetch [%o1 + 0x040], #one_read ! MS prefetch [%o1 + 0x080], #one_read ! MS Group prefetch [%o1 + 0x0c0], #one_read ! MS Group ldd [%o1 + 0x000], %f0 ! MS Group @@ -402,7 +346,7 @@ or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3 or %g1, %g3, %g1 add %o0, %o3, %o0 -#define FIX_INSN_2 0x96102070 /* mov (14 << 3), %o3 */ +#define FIX_INSN_2 0x96102068 /* mov (13 << 3), %o3 */ cheetah_patch_2: mov TLBTEMP_ENT2, %o3 rdpr %pstate, %g3 @@ -420,6 +364,7 @@ stxa %g0, [%g7] ASI_DMMU membar #Sync + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g0 ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 stxa %o0, [%o2] ASI_DMMU stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS @@ -430,8 +375,9 @@ clear_page_common: membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group fzero %f0 ! FPA Group - mov PAGE_SIZE/256, %o1 ! IEU0 + sethi %hi(PAGE_SIZE/256), %o1 ! IEU0 fzero %f2 ! FPA Group + or %o1, %lo(PAGE_SIZE/256), %o1 ! IEU0 faddd %f0, %f2, %f4 ! FPA Group fmuld %f0, %f2, %f6 ! FPM faddd %f0, %f2, %f8 ! FPA Group diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/lib/debuglocks.c linux-2.5/arch/sparc64/lib/debuglocks.c --- linux-2.5.1/arch/sparc64/lib/debuglocks.c Fri Apr 27 05:17:25 2001 +++ linux-2.5/arch/sparc64/lib/debuglocks.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: debuglocks.c,v 1.6 2001/04/24 01:09:12 davem Exp $ +/* $Id: debuglocks.c,v 1.9 2001/11/17 00:10:48 davem Exp $ * debuglocks.c: Debugging versions of SMP locking primitives. * * Copyright (C) 1998 David S. Miller (davem@redhat.com) @@ -10,10 +10,7 @@ #include <linux/spinlock.h> #include <asm/system.h> -#ifdef CONFIG_SMP - -/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */ -#ifdef SPIN_LOCK_DEBUG +#if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK) #define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC)) @@ -56,6 +53,7 @@ unsigned long caller, val; int stuck = INIT_STUCK; int cpu = smp_processor_id(); + int shown = 0; GET_CALLER(caller); again: @@ -67,7 +65,8 @@ if (val) { while (lock->lock) { if (!--stuck) { - show(str, lock, caller); + if (shown++ <= 2) + show(str, lock, caller); stuck = INIT_STUCK; } membar("#LoadLoad"); @@ -76,6 +75,8 @@ } lock->owner_pc = ((unsigned int)caller); lock->owner_cpu = cpu; + current->thread.smp_lock_count++; + current->thread.smp_lock_pc = ((unsigned int)caller); } int _spin_trylock(spinlock_t *lock) @@ -92,6 +93,8 @@ if (!val) { lock->owner_pc = ((unsigned int)caller); lock->owner_cpu = cpu; + current->thread.smp_lock_count++; + current->thread.smp_lock_pc = ((unsigned int)caller); } return val == 0; } @@ -102,6 +105,7 @@ lock->owner_cpu = NO_PROC_ID; membar("#StoreStore | #LoadStore"); lock->lock = 0; + current->thread.smp_lock_count--; } /* Keep INIT_STUCK the same... */ @@ -111,13 +115,15 @@ unsigned long caller, val; int stuck = INIT_STUCK; int cpu = smp_processor_id(); + int shown = 0; GET_CALLER(caller); wlock_again: /* Wait for any writer to go away. */ while (((long)(rw->lock)) < 0) { if (!--stuck) { - show_read(str, rw, caller); + if (shown++ <= 2) + show_read(str, rw, caller); stuck = INIT_STUCK; } membar("#LoadLoad"); @@ -137,6 +143,8 @@ if (val) goto wlock_again; rw->reader_pc[cpu] = ((unsigned int)caller); + current->thread.smp_lock_count++; + current->thread.smp_lock_pc = ((unsigned int)caller); } void _do_read_unlock (rwlock_t *rw, char *str) @@ -144,11 +152,13 @@ unsigned long caller, val; int stuck = INIT_STUCK; int cpu = smp_processor_id(); + int shown = 0; GET_CALLER(caller); /* Drop our identity _first_. */ rw->reader_pc[cpu] = 0; + current->thread.smp_lock_count--; runlock_again: /* Spin trying to decrement the counter using casx. */ __asm__ __volatile__( @@ -162,7 +172,8 @@ : "g5", "g7", "memory"); if (val) { if (!--stuck) { - show_read(str, rw, caller); + if (shown++ <= 2) + show_read(str, rw, caller); stuck = INIT_STUCK; } goto runlock_again; @@ -174,13 +185,15 @@ unsigned long caller, val; int stuck = INIT_STUCK; int cpu = smp_processor_id(); + int shown = 0; GET_CALLER(caller); wlock_again: /* Spin while there is another writer. */ while (((long)rw->lock) < 0) { if (!--stuck) { - show_write(str, rw, caller); + if (shown++ <= 2) + show_write(str, rw, caller); stuck = INIT_STUCK; } membar("#LoadLoad"); @@ -204,7 +217,8 @@ if (val) { /* We couldn't get the write bit. */ if (!--stuck) { - show_write(str, rw, caller); + if (shown++ <= 2) + show_write(str, rw, caller); stuck = INIT_STUCK; } goto wlock_again; @@ -214,7 +228,8 @@ * lock, spin, and try again. */ if (!--stuck) { - show_write(str, rw, caller); + if (shown++ <= 2) + show_write(str, rw, caller); stuck = INIT_STUCK; } __asm__ __volatile__( @@ -231,7 +246,8 @@ : "g3", "g5", "g7", "cc", "memory"); while(rw->lock != 0) { if (!--stuck) { - show_write(str, rw, caller); + if (shown++ <= 2) + show_write(str, rw, caller); stuck = INIT_STUCK; } membar("#LoadLoad"); @@ -242,18 +258,22 @@ /* We have it, say who we are. */ rw->writer_pc = ((unsigned int)caller); rw->writer_cpu = cpu; + current->thread.smp_lock_count++; + current->thread.smp_lock_pc = ((unsigned int)caller); } void _do_write_unlock(rwlock_t *rw) { unsigned long caller, val; int stuck = INIT_STUCK; + int shown = 0; GET_CALLER(caller); /* Drop our identity _first_ */ rw->writer_pc = 0; rw->writer_cpu = NO_PROC_ID; + current->thread.smp_lock_count--; wlock_again: __asm__ __volatile__( " mov 1, %%g3\n" @@ -268,12 +288,21 @@ : "g3", "g5", "g7", "memory"); if (val) { if (!--stuck) { - show_write("write_unlock", rw, caller); + if (shown++ <= 2) + show_write("write_unlock", rw, caller); stuck = INIT_STUCK; } goto wlock_again; } } -#endif /* SPIN_LOCK_DEBUG */ -#endif /* CONFIG_SMP */ +int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) +{ + spin_lock(lock); + if (atomic_dec_and_test(atomic)) + return 1; + spin_unlock(lock); + return 0; +} + +#endif /* CONFIG_SMP && CONFIG_DEBUG_SPINLOCK */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/lib/dec_and_lock.S linux-2.5/arch/sparc64/lib/dec_and_lock.S --- linux-2.5.1/arch/sparc64/lib/dec_and_lock.S Sun Aug 13 19:01:54 2000 +++ linux-2.5/arch/sparc64/lib/dec_and_lock.S Thu Dec 13 16:32:35 2001 @@ -1,10 +1,12 @@ -/* $Id: dec_and_lock.S,v 1.2 2000/08/13 18:24:12 davem Exp $ +/* $Id: dec_and_lock.S,v 1.5 2001/11/18 00:12:56 davem Exp $ * dec_and_lock.S: Sparc64 version of "atomic_dec_and_lock()" * using cas and ldstub instructions. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) */ +#include <linux/config.h> +#ifndef CONFIG_DEBUG_SPINLOCK .text .align 64 @@ -34,13 +36,15 @@ bne,pn %icc, loop1 mov 0, %g1 -out: retl +out: + membar #StoreLoad | #StoreStore + retl mov %g1, %o0 -to_zero:ldstub [%o1], %g3 +to_zero: + ldstub [%o1], %g3 brnz,pn %g3, spin_on_lock membar #StoreLoad | #StoreStore loop2: cas [%o0], %g5, %g7 /* ASSERT(g7 == 0) */ - nop cmp %g5, %g7 be,pt %icc, out @@ -61,3 +65,5 @@ ba,pt %xcc, to_zero nop nop + +#endif /* !(CONFIG_DEBUG_SPINLOCK) */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/mm/extable.c linux-2.5/arch/sparc64/mm/extable.c --- linux-2.5.1/arch/sparc64/mm/extable.c Tue Aug 7 15:30:50 2001 +++ linux-2.5/arch/sparc64/mm/extable.c Thu Dec 13 16:32:35 2001 @@ -11,35 +11,49 @@ static unsigned long search_one_table(const struct exception_table_entry *start, - const struct exception_table_entry *last, + const struct exception_table_entry *end, unsigned long value, unsigned long *g2) { - const struct exception_table_entry *first = start; - const struct exception_table_entry *mid; - long diff = 0; - while (first <= last) { - mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) { - if (!mid->fixup) { - *g2 = 0; - return (mid + 1)->fixup; - } else - return mid->fixup; - } else if (diff < 0) - first = mid+1; - else - last = mid-1; - } - if (last->insn < value && !last->fixup && last[1].insn > value) { - *g2 = (value - last->insn)/4; - return last[1].fixup; - } - if (first > start && first[-1].insn < value - && !first[-1].fixup && first->insn < value) { - *g2 = (value - first[-1].insn)/4; - return first->fixup; - } + const struct exception_table_entry *walk; + + /* Single insn entries are encoded as: + * word 1: insn address + * word 2: fixup code address + * + * Range entries are encoded as: + * word 1: first insn address + * word 2: 0 + * word 3: last insn address + 4 bytes + * word 4: fixup code address + * + * See asm/uaccess.h for more details. + */ + + /* 1. Try to find an exact match. */ + for (walk = start; walk <= end; walk++) { + if (walk->fixup == 0) { + /* A range entry, skip both parts. */ + walk++; + continue; + } + + if (walk->insn == value) + return walk->fixup; + } + + /* 2. Try to find a range match. */ + for (walk = start; walk <= (end - 1); walk++) { + if (walk->fixup) + continue; + + if (walk[0].insn <= value && + walk[1].insn > value) { + *g2 = (value - walk[0].insn) / 4; + return walk[1].fixup; + } + walk++; + } + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/mm/init.c linux-2.5/arch/sparc64/mm/init.c --- linux-2.5.1/arch/sparc64/mm/init.c Tue Nov 13 17:16:05 2001 +++ linux-2.5/arch/sparc64/mm/init.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.202 2001/11/13 00:49:28 davem Exp $ +/* $Id: init.c,v 1.207 2001/11/30 06:55:39 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -63,6 +63,8 @@ struct page *mem_map_zero; +int bigkernel = 0; + int do_check_pgt_cache(int low, int high) { int freed = 0; @@ -111,7 +113,7 @@ extern void __update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t); -#ifdef DCFLUSH_DEBUG +#ifdef CONFIG_DEBUG_DCFLUSH atomic_t dcpage_flushes = ATOMIC_INIT(0); #ifdef CONFIG_SMP atomic_t dcpage_flushes_xcall = ATOMIC_INIT(0); @@ -120,7 +122,7 @@ __inline__ void flush_dcache_page_impl(struct page *page) { -#ifdef DCFLUSH_DEBUG +#ifdef CONFIG_DEBUG_DCFLUSH atomic_inc(&dcpage_flushes); #endif @@ -152,7 +154,7 @@ "casx [%2], %%g7, %%g5\n\t" "cmp %%g7, %%g5\n\t" "bne,pn %%xcc, 1b\n\t" - " nop" + " membar #StoreLoad | #StoreStore" : /* no outputs */ : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags) : "g5", "g7"); @@ -172,7 +174,7 @@ "casx [%2], %%g7, %%g5\n\t" "cmp %%g7, %%g5\n\t" "bne,pn %%xcc, 1b\n\t" - " nop\n" + " membar #StoreLoad | #StoreStore\n" "2:" : /* no outputs */ : "r" (cpu), "r" (mask), "r" (&page->flags) @@ -261,14 +263,14 @@ else seq_printf(m, "MMU Type\t: ???\n"); -#ifdef DCFLUSH_DEBUG +#ifdef CONFIG_DEBUG_DCFLUSH seq_printf(m, "DCPageFlushes\t: %d\n", atomic_read(&dcpage_flushes)); #ifdef CONFIG_SMP seq_printf(m, "DCPageFlushesXC\t: %d\n", atomic_read(&dcpage_flushes_xcall)); #endif /* CONFIG_SMP */ -#endif /* DCFLUSH_DEBUG */ +#endif /* CONFIG_DEBUG_DCFLUSH */ } struct linux_prom_translation { @@ -505,6 +507,10 @@ (unsigned long) KERNBASE, prom_get_mmu_ihandle()); + if (bigkernel) + remap_func(((tte_data + 0x400000) & _PAGE_PADDR), + (unsigned long) KERNBASE + 0x400000, prom_get_mmu_ihandle()); + /* Flush out that temporary mapping. */ spitfire_flush_dtlb_nucleus_page(0x0); spitfire_flush_itlb_nucleus_page(0x0); @@ -512,6 +518,12 @@ /* Now lock us back into the TLBs via OBP. */ prom_dtlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr); prom_itlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr); + if (bigkernel) { + prom_dtlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000, + tte_vaddr + 0x400000); + prom_itlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000, + tte_vaddr + 0x400000); + } /* Re-read translations property. */ if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) { @@ -528,6 +540,8 @@ unsigned long avoid_start = (unsigned long) KERNBASE; unsigned long avoid_end = avoid_start + (4 * 1024 * 1024); + if (bigkernel) + avoid_end += (4 * 1024 * 1024); if (vaddr < avoid_start) { unsigned long top = vaddr + size; @@ -714,7 +728,8 @@ } } if (tlb_type == spitfire) { - for (i = 0; i < SPITFIRE_HIGHEST_LOCKED_TLBENT; i++) { + int high = SPITFIRE_HIGHEST_LOCKED_TLBENT - bigkernel; + for (i = 0; i < high; i++) { unsigned long data; /* Spitfire Errata #32 workaround */ @@ -752,7 +767,7 @@ } } - for (i = 0; i < SPITFIRE_HIGHEST_LOCKED_TLBENT; i++) { + for (i = 0; i < high; i++) { unsigned long data; /* Spitfire Errata #32 workaround */ @@ -790,7 +805,9 @@ } } } else if (tlb_type == cheetah) { - for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) { + int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel; + + for (i = 0; i < high; i++) { unsigned long data; data = cheetah_get_ldtlb_data(i); @@ -814,7 +831,7 @@ } } - for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) { + for (i = 0; i < high; i++) { unsigned long data; data = cheetah_get_litlb_data(i); @@ -1282,6 +1299,8 @@ set_bit(0, mmu_context_bmap); real_end = (unsigned long)&_end; + if ((real_end > ((unsigned long)KERNBASE + 0x400000))) + bigkernel = 1; #ifdef CONFIG_BLK_DEV_INITRD if (sparc_ramdisk_image) real_end = (PAGE_ALIGN(real_end) + PAGE_ALIGN(sparc_ramdisk_size)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/mm/modutil.c linux-2.5/arch/sparc64/mm/modutil.c --- linux-2.5.1/arch/sparc64/mm/modutil.c Tue Aug 28 14:09:44 2001 +++ linux-2.5/arch/sparc64/mm/modutil.c Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: modutil.c,v 1.9 2001/08/14 22:10:56 davem Exp $ +/* $Id: modutil.c,v 1.11 2001/12/05 06:05:35 davem Exp $ * arch/sparc64/mm/modutil.c * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -10,10 +10,6 @@ #include <asm/uaccess.h> #include <asm/system.h> - -#define MODULES_VADDR 0x0000000001000000ULL /* Where to map modules */ -#define MODULES_LEN 0x000000007f000000ULL -#define MODULES_END 0x0000000080000000ULL static struct vm_struct * modvmlist = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/mm/ultra.S linux-2.5/arch/sparc64/mm/ultra.S --- linux-2.5.1/arch/sparc64/mm/ultra.S Tue Nov 13 17:16:05 2001 +++ linux-2.5/arch/sparc64/mm/ultra.S Thu Dec 13 16:32:35 2001 @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.68 2001/11/09 14:59:19 davem Exp $ +/* $Id: ultra.S,v 1.70 2001/11/29 16:42:10 kanoj Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com) @@ -117,7 +117,7 @@ wrpr %g1, PSTATE_IE, %pstate mov TLB_TAG_ACCESS, %g3 /* XXX Spitfire dependency... */ - mov (62 << 3), %g2 + mov ((SPITFIRE_HIGHEST_LOCKED_TLBENT-1) << 3), %g2 /* Spitfire Errata #32 workaround. */ mov 0x8, %o4 @@ -642,7 +642,7 @@ stx %g0, [%g4 + %lo(errata32_hwbug)] 2: add %g2, 1, %g2 - cmp %g2, 63 + cmp %g2, SPITFIRE_HIGHEST_LOCKED_TLBENT ble,pt %icc, 1b sll %g2, 3, %g3 flush %g6 @@ -679,20 +679,15 @@ .globl xcall_call_function xcall_call_function: - mov TLB_TAG_ACCESS, %g5 ! wheee... - stxa %g1, [%g5] ASI_IMMU ! save call_data here for a bit - membar #Sync rdpr %pstate, %g2 wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate - mov TLB_TAG_ACCESS, %g2 - ldxa [%g2] ASI_IMMU, %g5 rdpr %pil, %g2 wrpr %g0, 15, %pil sethi %hi(109f), %g7 b,pt %xcc, etrap_irq 109: or %g7, %lo(109b), %g7 call smp_call_function_client - mov %l5, %o0 + nop b,pt %xcc, rtrap clr %l6 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/solaris/ioctl.c linux-2.5/arch/sparc64/solaris/ioctl.c --- linux-2.5.1/arch/sparc64/solaris/ioctl.c Wed Nov 29 05:53:44 2000 +++ linux-2.5/arch/sparc64/solaris/ioctl.c Mon Jan 14 22:39:45 2002 @@ -289,11 +289,15 @@ { struct inode *ino; /* I wonder which of these tests are superfluous... --patrik */ + read_lock(¤t->files->file_lock); if (! current->files->fd[fd] || ! current->files->fd[fd]->f_dentry || ! (ino = current->files->fd[fd]->f_dentry->d_inode) || - ! ino->i_sock) + ! ino->i_sock) { + read_unlock(¤t->files->file_lock); return TBADF; + } + read_unlock(¤t->files->file_lock); switch (cmd & 0xff) { case 109: /* SI_SOCKPARAMS */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/arch/sparc64/solaris/timod.c linux-2.5/arch/sparc64/solaris/timod.c --- linux-2.5.1/arch/sparc64/solaris/timod.c Mon Dec 10 21:52:53 2001 +++ linux-2.5/arch/sparc64/solaris/timod.c Mon Jan 14 22:39:45 2002 @@ -149,7 +149,9 @@ struct socket *sock; SOLD("wakeing socket"); + read_lock(¤t->files->file_lock); sock = ¤t->files->fd[fd]->f_dentry->d_inode->u.socket_i; + read_unlock(¤t->files->file_lock); wake_up_interruptible(&sock->wait); read_lock(&sock->sk->callback_lock); if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) @@ -163,7 +165,9 @@ struct sol_socket_struct *sock; SOLD("queuing primsg"); + read_lock(¤t->files->file_lock); sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + read_unlock(¤t->files->file_lock); it->next = sock->pfirst; sock->pfirst = it; if (!sock->plast) @@ -177,7 +181,9 @@ struct sol_socket_struct *sock; SOLD("queuing primsg at end"); + read_lock(¤t->files->file_lock); sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + read_unlock(¤t->files->file_lock); it->next = NULL; if (sock->plast) sock->plast->next = it; @@ -355,7 +361,11 @@ (int (*)(int, unsigned long *))SYS(socketcall); int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) = (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto); - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (!filp) + return -EBADF; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLD("entry"); @@ -636,7 +646,11 @@ SOLD("entry"); SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p)); - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (!filp) + return -EBADF; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL)); @@ -847,7 +861,9 @@ lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); if(!filp) goto out; ino = filp->f_dentry->d_inode; @@ -914,7 +930,9 @@ lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); if(!filp) goto out; ino = filp->f_dentry->d_inode; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acorn/block/mfmhd.c linux-2.5/drivers/acorn/block/mfmhd.c --- linux-2.5.1/drivers/acorn/block/mfmhd.c Thu Oct 25 20:58:35 2001 +++ linux-2.5/drivers/acorn/block/mfmhd.c Mon Jan 7 23:36:27 2002 @@ -746,7 +746,7 @@ /* Yep - a partial access */ /* and issue the remainder */ - issue_request(MINOR(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); + issue_request(minor(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); return; } @@ -929,7 +929,7 @@ DBG("mfm_request: before arg extraction\n"); - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; #ifdef DEBUG @@ -1187,10 +1187,10 @@ if (!inode || !(dev = inode->i_rdev)) return -EINVAL; - major = MAJOR(dev); - minor = MINOR(dev); + major = major(dev); + minor = minor(dev); - device = DEVICE_NR(MINOR(inode->i_rdev)), err; + device = DEVICE_NR(minor(inode->i_rdev)), err; if (device >= mfm_drives) return -EINVAL; @@ -1242,7 +1242,7 @@ static int mfm_open(struct inode *inode, struct file *file) { - int dev = DEVICE_NR(MINOR(inode->i_rdev)); + int dev = DEVICE_NR(minor(inode->i_rdev)); if (dev >= mfm_drives) return -ENODEV; @@ -1260,7 +1260,7 @@ */ static int mfm_release(struct inode *inode, struct file *file) { - mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--; + mfm_info[DEVICE_NR(minor(inode->i_rdev))].access_count--; return 0; } @@ -1281,7 +1281,7 @@ void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads, unsigned long discsize, unsigned int secsize) { - int drive = MINOR(dev) >> 6; + int drive = minor(dev) >> 6; if (mfm_info[drive].cylinders == 1) { mfm_info[drive].sectors = secsptrack; @@ -1311,10 +1311,8 @@ major: MAJOR_NR, major_name: "mfm", minor_shift: 6, - max_p: 1 << 6, part: mfm, sizes: mfm_sizes, - real_devices: (void *)mfm_info, }; static struct block_device_operations mfm_fops = @@ -1351,7 +1349,7 @@ for (i = 0; i < mfm_drives; i++) { mfm_geometry (i); - register_disk(&mfm_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6, + register_disk(&mfm_gendisk, mk_kdev(MAJOR_NR,i<<6), 1<<6, &mfm_fops, mfm_info[i].cylinders * mfm_info[i].heads * mfm_info[i].sectors / 2); @@ -1462,7 +1460,7 @@ */ static int mfm_reread_partitions(kdev_t dev) { - unsigned int start, i, maxp, target = DEVICE_NR(MINOR(dev)); + unsigned int start, i, maxp, target = DEVICE_NR(minor(dev)); unsigned long flags; save_flags_cli(flags); @@ -1473,12 +1471,12 @@ mfm_info[target].busy = 1; restore_flags (flags); - maxp = mfm_gendisk.max_p; + maxp = 1 << mfm_gendisk.minor_shift; start = target << mfm_gendisk.minor_shift; for (i = maxp - 1; i >= 0; i--) { int minor = start + i; - invalidate_device (MKDEV(MAJOR_NR, minor), 1); + invalidate_device (mk_kdev(MAJOR_NR, minor), 1); mfm_gendisk.part[minor].start_sect = 0; mfm_gendisk.part[minor].nr_sects = 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acorn/scsi/acornscsi.c linux-2.5/drivers/acorn/scsi/acornscsi.c --- linux-2.5.1/drivers/acorn/scsi/acornscsi.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/drivers/acorn/scsi/acornscsi.c Thu Dec 27 22:10:28 2001 @@ -3142,18 +3142,17 @@ static int __init acornscsi_init(void) { - acornscsi_template.module = THIS_MODULE; - scsi_register_module(MODULE_SCSI_HA, &acornscsi_template); + scsi_register_host(&acornscsi_template); if (acornscsi_template.present) return 0; - scsi_unregister_module(MODULE_SCSI_HA, &acornscsi_template); + scsi_unregister_host(&acornscsi_template); return -ENODEV; } static void __exit acornscsi_exit(void) { - scsi_unregister_module(MODULE_SCSI_HA, &acornscsi_template); + scsi_unregister_host(&acornscsi_template); } module_init(acornscsi_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acorn/scsi/arxescsi.c linux-2.5/drivers/acorn/scsi/arxescsi.c --- linux-2.5.1/drivers/acorn/scsi/arxescsi.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/drivers/acorn/scsi/arxescsi.c Thu Dec 27 22:10:28 2001 @@ -423,17 +423,17 @@ static int __init init_arxe_scsi_driver(void) { arxescsi_template.module = THIS_MODULE; - scsi_register_module(MODULE_SCSI_HA, &arxescsi_template); + scsi_register_host(&arxescsi_template); if (arxescsi_template.present) return 0; - scsi_unregister_module(MODULE_SCSI_HA, &arxescsi_template); + scsi_unregister_host(&arxescsi_template); return -ENODEV; } static void __exit exit_arxe_scsi_driver(void) { - scsi_unregister_module(MODULE_SCSI_HA, &arxescsi_template); + scsi_unregister_host(&arxescsi_template); } module_init(init_arxe_scsi_driver); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acorn/scsi/cumana_1.c linux-2.5/drivers/acorn/scsi/cumana_1.c --- linux-2.5.1/drivers/acorn/scsi/cumana_1.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/acorn/scsi/cumana_1.c Thu Dec 27 22:10:28 2001 @@ -409,17 +409,17 @@ static int __init cumanascsi_init(void) { - scsi_register_module(MODULE_SCSI_HA, &cumanascsi_template); + scsi_register_host(&cumanascsi_template); if (cumanascsi_template.present) return 0; - scsi_unregister_module(MODULE_SCSI_HA, &cumanascsi_template); + scsi_unregister_host(&cumanascsi_template); return -ENODEV; } static void __exit cumanascsi_exit(void) { - scsi_unregister_module(MODULE_SCSI_HA, &cumanascsi_template); + scsi_unregister_host(&cumanascsi_template); } module_init(cumanascsi_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acorn/scsi/cumana_2.c linux-2.5/drivers/acorn/scsi/cumana_2.c --- linux-2.5.1/drivers/acorn/scsi/cumana_2.c Wed Nov 28 18:22:26 2001 +++ linux-2.5/drivers/acorn/scsi/cumana_2.c Thu Dec 27 22:10:28 2001 @@ -579,17 +579,17 @@ static int __init cumanascsi2_init(void) { - scsi_register_module(MODULE_SCSI_HA, &cumanascsi2_template); + scsi_register_host(&cumanascsi2_template); if (cumanascsi2_template.present) return 0; - scsi_unregister_module(MODULE_SCSI_HA, &cumanascsi2_template); + scsi_unregister_host(&cumanascsi2_template); return -ENODEV; } static void __exit cumanascsi2_exit(void) { - scsi_unregister_module(MODULE_SCSI_HA, &cumanascsi2_template); + scsi_unregister_host(&cumanascsi2_template); } module_init(cumanascsi2_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acorn/scsi/ecoscsi.c linux-2.5/drivers/acorn/scsi/ecoscsi.c --- linux-2.5.1/drivers/acorn/scsi/ecoscsi.c Thu Oct 25 20:53:46 2001 +++ linux-2.5/drivers/acorn/scsi/ecoscsi.c Thu Dec 27 22:10:28 2001 @@ -276,17 +276,17 @@ static int __init ecoscsi_init(void) { - scsi_register_module(MODULE_SCSI_HA, &ecoscsi_template); + scsi_register_host(&ecoscsi_template); if (ecoscsi_template.present) return 0; - scsi_unregister_module(MODULE_SCSI_HA, &ecoscsi_template); + scsi_unregister_host(&ecoscsi_template); return -ENODEV; } static void __exit ecoscsi_exit(void) { - scsi_unregister_module(MODULE_SCSI_HA, &ecoscsi_template); + scsi_unregister_host(&ecoscsi_template); } module_init(ecoscsi_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acorn/scsi/eesox.c linux-2.5/drivers/acorn/scsi/eesox.c --- linux-2.5.1/drivers/acorn/scsi/eesox.c Wed Nov 28 18:22:27 2001 +++ linux-2.5/drivers/acorn/scsi/eesox.c Thu Dec 27 22:10:28 2001 @@ -581,17 +581,17 @@ static int __init eesox_init(void) { - scsi_register_module(MODULE_SCSI_HA, &eesox_template); + scsi_register_host(&eesox_template); if (eesox_template.present) return 0; - scsi_unregister_module(MODULE_SCSI_HA, &eesox_template); + scsi_unregister_host(&eesox_template); return -ENODEV; } static void __exit eesox_exit(void) { - scsi_unregister_module(MODULE_SCSI_HA, &eesox_template); + scsi_unregister_host(&eesox_template); } module_init(eesox_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acorn/scsi/oak.c linux-2.5/drivers/acorn/scsi/oak.c --- linux-2.5.1/drivers/acorn/scsi/oak.c Thu Oct 11 16:04:57 2001 +++ linux-2.5/drivers/acorn/scsi/oak.c Thu Dec 27 22:10:28 2001 @@ -270,17 +270,17 @@ static int __init oakscsi_init(void) { - scsi_register_module(MODULE_SCSI_HA, &oakscsi_template); + scsi_register_host(&oakscsi_template); if (oakscsi_template.present) return 0; - scsi_unregister_module(MODULE_SCSI_HA, &oakscsi_template); + scsi_unregister_host(&oakscsi_template); return -ENODEV; } static void __exit oakscsi_exit(void) { - scsi_unregister_module(MODULE_SCSI_HA, &oakscsi_template); + scsi_unregister_host(&oakscsi_template); } module_init(oakscsi_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acorn/scsi/powertec.c linux-2.5/drivers/acorn/scsi/powertec.c --- linux-2.5.1/drivers/acorn/scsi/powertec.c Wed Nov 28 18:22:27 2001 +++ linux-2.5/drivers/acorn/scsi/powertec.c Thu Dec 27 22:10:28 2001 @@ -481,17 +481,17 @@ static int __init powertecscsi_init(void) { - scsi_register_module(MODULE_SCSI_HA, &powertecscsi_template); + scsi_register_host(&powertecscsi_template); if (powertecscsi_template.present) return 0; - scsi_unregister_module(MODULE_SCSI_HA, &powertecscsi_template); + scsi_unregister_host(&powertecscsi_template); return -ENODEV; } static void __exit powertecscsi_exit(void) { - scsi_unregister_module(MODULE_SCSI_HA, &powertecscsi_template); + scsi_unregister_host(&powertecscsi_template); } module_init(powertecscsi_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acpi/ospm/ac_adapter/ac_osl.c linux-2.5/drivers/acpi/ospm/ac_adapter/ac_osl.c --- linux-2.5.1/drivers/acpi/ospm/ac_adapter/ac_osl.c Wed Oct 24 21:06:22 2001 +++ linux-2.5/drivers/acpi/ospm/ac_adapter/ac_osl.c Sun Dec 16 03:58:15 2001 @@ -35,6 +35,7 @@ MODULE_AUTHOR("Andrew Grover"); MODULE_DESCRIPTION("ACPI Component Architecture (CA) - AC Adapter Driver"); +MODULE_LICENSE("GPL"); #define AC_PROC_ROOT "ac_adapter" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acpi/ospm/battery/bt_osl.c linux-2.5/drivers/acpi/ospm/battery/bt_osl.c --- linux-2.5.1/drivers/acpi/ospm/battery/bt_osl.c Wed Oct 24 21:06:22 2001 +++ linux-2.5/drivers/acpi/ospm/battery/bt_osl.c Sun Dec 16 03:58:15 2001 @@ -44,6 +44,7 @@ MODULE_AUTHOR("Andrew Grover"); MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Control Method Battery Driver"); +MODULE_LICENSE("GPL"); #define BT_PROC_ROOT "battery" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acpi/ospm/busmgr/bm_osl.c linux-2.5/drivers/acpi/ospm/busmgr/bm_osl.c --- linux-2.5.1/drivers/acpi/ospm/busmgr/bm_osl.c Wed Oct 24 21:06:22 2001 +++ linux-2.5/drivers/acpi/ospm/busmgr/bm_osl.c Sun Dec 16 03:58:15 2001 @@ -38,6 +38,7 @@ MODULE_AUTHOR("Andrew Grover"); MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI Bus Manager"); +MODULE_LICENSE("GPL"); /***************************************************************************** diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acpi/ospm/button/bn_osl.c linux-2.5/drivers/acpi/ospm/button/bn_osl.c --- linux-2.5.1/drivers/acpi/ospm/button/bn_osl.c Wed Oct 24 21:06:22 2001 +++ linux-2.5/drivers/acpi/ospm/button/bn_osl.c Sun Dec 16 03:58:15 2001 @@ -35,6 +35,7 @@ MODULE_AUTHOR("Andrew Grover"); MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Button Driver"); +MODULE_LICENSE("GPL"); #define BN_PROC_ROOT "button" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acpi/ospm/ec/ec_osl.c linux-2.5/drivers/acpi/ospm/ec/ec_osl.c --- linux-2.5.1/drivers/acpi/ospm/ec/ec_osl.c Wed Oct 24 21:06:22 2001 +++ linux-2.5/drivers/acpi/ospm/ec/ec_osl.c Sun Dec 16 03:58:15 2001 @@ -36,6 +36,7 @@ MODULE_AUTHOR("Andrew Grover"); MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Embedded Controller Driver"); +MODULE_LICENSE("GPL"); extern struct proc_dir_entry *bm_proc_root; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acpi/ospm/processor/pr_osl.c linux-2.5/drivers/acpi/ospm/processor/pr_osl.c --- linux-2.5.1/drivers/acpi/ospm/processor/pr_osl.c Fri Nov 9 21:58:02 2001 +++ linux-2.5/drivers/acpi/ospm/processor/pr_osl.c Sun Dec 16 03:58:15 2001 @@ -37,6 +37,7 @@ MODULE_AUTHOR("Andrew Grover"); MODULE_DESCRIPTION("ACPI Component Architecture (CA) - IA32 Processor Driver"); +MODULE_LICENSE("GPL"); #define PR_PROC_ROOT "processor" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acpi/ospm/system/sm_osl.c linux-2.5/drivers/acpi/ospm/system/sm_osl.c --- linux-2.5.1/drivers/acpi/ospm/system/sm_osl.c Wed Oct 24 21:06:22 2001 +++ linux-2.5/drivers/acpi/ospm/system/sm_osl.c Sun Dec 16 03:58:15 2001 @@ -42,6 +42,7 @@ MODULE_AUTHOR("Andrew Grover"); MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI System Driver"); +MODULE_LICENSE("GPL"); #define SM_PROC_INFO "info" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acpi/ospm/thermal/tz_osl.c linux-2.5/drivers/acpi/ospm/thermal/tz_osl.c --- linux-2.5.1/drivers/acpi/ospm/thermal/tz_osl.c Wed Oct 24 21:06:22 2001 +++ linux-2.5/drivers/acpi/ospm/thermal/tz_osl.c Sun Dec 16 03:58:15 2001 @@ -35,6 +35,7 @@ MODULE_AUTHOR("Andrew Grover"); MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Thermal Zone Driver"); +MODULE_LICENSE("GPL"); int TZP = 0; MODULE_PARM(TZP, "i"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/acpi/ospm/thermal/tzpolicy.c linux-2.5/drivers/acpi/ospm/thermal/tzpolicy.c --- linux-2.5.1/drivers/acpi/ospm/thermal/tzpolicy.c Wed Oct 24 21:06:22 2001 +++ linux-2.5/drivers/acpi/ospm/thermal/tzpolicy.c Sun Dec 30 20:14:04 2001 @@ -31,6 +31,7 @@ #include <linux/proc_fs.h> #include <linux/sysctl.h> #include <linux/pm.h> +#include <linux/sched.h> #include <acpi.h> #include <bm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/atm/eni.c linux-2.5/drivers/atm/eni.c --- linux-2.5.1/drivers/atm/eni.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/atm/eni.c Thu Dec 13 16:32:35 2001 @@ -2310,7 +2310,7 @@ name: DEV_LABEL, id_table: eni_pci_tbl, probe: eni_init_one, - remove: eni_remove_one, + remove: __devexit_p(eni_remove_one), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/atm/firestream.c linux-2.5/drivers/atm/firestream.c --- linux-2.5.1/drivers/atm/firestream.c Fri Nov 9 21:58:03 2001 +++ linux-2.5/drivers/atm/firestream.c Thu Dec 13 16:32:35 2001 @@ -2102,7 +2102,7 @@ name: "firestream", id_table: firestream_pci_tbl, probe: firestream_init_one, - remove: firestream_remove_one, + remove: __devexit_p(firestream_remove_one), }; static int __init firestream_init_module (void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/atm/fore200e.c linux-2.5/drivers/atm/fore200e.c --- linux-2.5.1/drivers/atm/fore200e.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/atm/fore200e.c Sun Dec 30 21:17:30 2001 @@ -39,7 +39,6 @@ #include <linux/atm_suni.h> #include <asm/io.h> #include <asm/string.h> -#include <asm/segment.h> #include <asm/page.h> #include <asm/irq.h> #include <asm/dma.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/atm/idt77252.c linux-2.5/drivers/atm/idt77252.c --- linux-2.5.1/drivers/atm/idt77252.c Tue Nov 20 23:46:21 2001 +++ linux-2.5/drivers/atm/idt77252.c Thu Dec 13 16:32:35 2001 @@ -1,8 +1,8 @@ /******************************************************************* - * ident "$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $" + * ident "$Id: idt77252.c,v 1.3 2001/11/17 00:30:19 ecd Exp $" * * $Author: ecd $ - * $Date: 2001/11/11 08:13:54 $ + * $Date: 2001/11/17 00:30:19 $ * * Copyright (c) 2000 ATecoM GmbH * @@ -30,7 +30,7 @@ * *******************************************************************/ static char const rcsid[] = -"$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $"; +"$Id: idt77252.c,v 1.3 2001/11/17 00:30:19 ecd Exp $"; #include <linux/module.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/atm/iphase.c linux-2.5/drivers/atm/iphase.c --- linux-2.5.1/drivers/atm/iphase.c Tue Sep 18 05:52:34 2001 +++ linux-2.5/drivers/atm/iphase.c Mon Jan 14 22:39:45 2002 @@ -1777,8 +1777,9 @@ memset((caddr_t)ia_vcc, 0, sizeof(*ia_vcc)); if (vcc->qos.txtp.max_sdu > (iadev->tx_buf_sz - sizeof(struct cpcs_trailer))){ - printk("IA: SDU size over the configured SDU size %d\n", - iadev->tx_buf_sz); + printk("IA: SDU size over (%d) the configured SDU size %d\n", + vcc->qos.txtp.max_sdu,iadev->tx_buf_sz); + INPH_IA_VCC(vcc) = NULL; kfree(ia_vcc); return -EINVAL; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/DAC960.c linux-2.5/drivers/block/DAC960.c --- linux-2.5.1/drivers/block/DAC960.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/DAC960.c Mon Jan 7 19:43:05 2002 @@ -45,7 +45,6 @@ #include <linux/pci.h> #include <linux/init.h> #include <asm/io.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include "DAC960.h" @@ -1974,9 +1973,7 @@ Controller->GenericDiskInfo.major = MajorNumber; Controller->GenericDiskInfo.major_name = "rd"; Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits; - Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions; Controller->GenericDiskInfo.nr_real = DAC960_MaxLogicalDrives; - Controller->GenericDiskInfo.real_devices = Controller; Controller->GenericDiskInfo.next = NULL; Controller->GenericDiskInfo.fops = &DAC960_BlockDeviceOperations; /* @@ -2025,10 +2022,9 @@ Information Partition Sector Counts and Block Sizes. */ -static void DAC960_ComputeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo) +static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller) { - DAC960_Controller_T *Controller = - (DAC960_Controller_T *) GenericDiskInfo->real_devices; + GenericDiskInfo_T *GenericDiskInfo = &Controller->GenericDiskInfo; int LogicalDriveNumber, i; for (LogicalDriveNumber = 0; LogicalDriveNumber < DAC960_MaxLogicalDrives; @@ -2659,7 +2655,7 @@ int LogicalDriveNumber; if (Controller == NULL) continue; DAC960_InitializeController(Controller); - DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo); + DAC960_ComputeGenericDiskInfo(Controller); for (LogicalDriveNumber = 0; LogicalDriveNumber < DAC960_MaxLogicalDrives; LogicalDriveNumber++) @@ -3162,7 +3158,7 @@ Controller->ControllerNumber, LogicalDriveNumber); Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives; - DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo); + DAC960_ComputeGenericDiskInfo(Controller); } if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount) { @@ -3174,7 +3170,7 @@ Controller->ControllerNumber, LogicalDriveNumber); Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives; - DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo); + DAC960_ComputeGenericDiskInfo(Controller); } if (NewEnquiry->StatusFlags.DeferredWriteError != OldEnquiry->StatusFlags.DeferredWriteError) @@ -4514,7 +4510,7 @@ { memset(LogicalDeviceInfo, 0, sizeof(DAC960_V2_LogicalDeviceInfo_T)); - DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo); + DAC960_ComputeGenericDiskInfo(Controller); } } if (LogicalDeviceInfo != NULL) @@ -4631,7 +4627,7 @@ kfree(LogicalDeviceInfo); Controller->LogicalDriveInitiallyAccessible [LogicalDriveNumber] = false; - DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo); + DAC960_ComputeGenericDiskInfo(Controller); } Controller->V2.NeedLogicalDeviceInformation = false; } @@ -5300,10 +5296,10 @@ if (!Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber]) { Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true; - DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo); + DAC960_ComputeGenericDiskInfo(Controller); DAC960_RegisterDisk(Controller, LogicalDriveNumber); } - if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0) + if (Controller->GenericDiskInfo.sizes[minor(Inode->i_rdev)] == 0) return -ENXIO; /* Increment Controller and Logical Drive Usage Counts. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/DAC960.h linux-2.5/drivers/block/DAC960.h --- linux-2.5.1/drivers/block/DAC960.h Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/block/DAC960.h Mon Jan 7 19:15:30 2002 @@ -2054,13 +2054,13 @@ */ #define DAC960_ControllerNumber(Device) \ - (MAJOR(Device) - DAC960_MAJOR) + (major(Device) - DAC960_MAJOR) #define DAC960_LogicalDriveNumber(Device) \ - (MINOR(Device) >> DAC960_MaxPartitionsBits) + (minor(Device) >> DAC960_MaxPartitionsBits) #define DAC960_PartitionNumber(Device) \ - (MINOR(Device) & (DAC960_MaxPartitions - 1)) + (minor(Device) & (DAC960_MaxPartitions - 1)) #define DAC960_MajorNumber(ControllerNumber) \ (DAC960_MAJOR + (ControllerNumber)) @@ -2074,7 +2074,7 @@ #define DAC960_KernelDevice(ControllerNumber, \ LogicalDriveNumber, \ PartitionNumber) \ - MKDEV(DAC960_MajorNumber(ControllerNumber), \ + mk_kdev(DAC960_MajorNumber(ControllerNumber), \ DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/acsi.c linux-2.5/drivers/block/acsi.c --- linux-2.5.1/drivers/block/acsi.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/acsi.c Mon Jan 7 23:35:33 2002 @@ -784,7 +784,7 @@ status = acsi_getstatus(); if (status != 0) { - int dev = DEVICE_NR(MINOR(CURRENT->rq_dev)); + int dev = DEVICE_NR(minor(CURRENT->rq_dev)); printk( KERN_ERR "ad%c: ", dev+'a' ); if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, acsi_info[dev].lun)) @@ -815,7 +815,7 @@ status = acsi_getstatus(); if (status != 0) { - int dev = DEVICE_NR(MINOR(CURRENT->rq_dev)); + int dev = DEVICE_NR(minor(CURRENT->rq_dev)); printk( KERN_ERR "ad%c: ", dev+'a' ); if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, acsi_info[dev].lun)) @@ -993,7 +993,7 @@ panic(DEVICE_NAME ": block not locked"); } - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; if (DEVICE_NR(dev) >= NDevices || block+CURRENT->nr_sectors >= acsi_part[dev].nr_sects) { @@ -1111,7 +1111,7 @@ if (!inode) return -EINVAL; - dev = DEVICE_NR(MINOR(inode->i_rdev)); + dev = DEVICE_NR(minor(inode->i_rdev)); if (dev >= NDevices) return -EINVAL; switch (cmd) { @@ -1174,7 +1174,7 @@ int device; struct acsi_info_struct *aip; - device = DEVICE_NR(MINOR(inode->i_rdev)); + device = DEVICE_NR(minor(inode->i_rdev)); if (device >= NDevices) return -ENXIO; aip = &acsi_info[device]; @@ -1212,7 +1212,7 @@ static int acsi_release( struct inode * inode, struct file * file ) { - int device = DEVICE_NR(MINOR(inode->i_rdev)); + int device = DEVICE_NR(minor(inode->i_rdev)); if (--access_count[device] == 0 && acsi_info[device].removable) acsi_prevent_removal(device, 0); return( 0 ); @@ -1240,7 +1240,7 @@ static int acsi_media_change (dev_t dev) { - int device = DEVICE_NR(MINOR(dev)); + int device = DEVICE_NR(minor(dev)); struct acsi_info_struct *aip; aip = &acsi_info[device]; @@ -1386,10 +1386,8 @@ major: MAJOR_NR, major_name: "ad", minor_shift: 4, - max_p: 1 << 4, part: acsi_part, sizes: acsi_sizes, - real_devices: (void *)acsi_info, fops: &acsi_fops, }; @@ -1744,7 +1742,7 @@ acsi_blocksizes[i] = 1024; blksize_size[MAJOR_NR] = acsi_blocksizes; for( i = 0; i < NDevices; ++i ) - register_disk(&acsi_gendisk, MKDEV(MAJOR_NR,i<<4), + register_disk(&acsi_gendisk, mk_kdev(MAJOR_NR,i<<4), (acsi_info[i].type==HARDDISK)?1<<4:1, &acsi_fops, acsi_info[i].size); @@ -1856,7 +1854,7 @@ int res; struct acsi_info_struct *aip; - device = DEVICE_NR(MINOR(dev)); + device = DEVICE_NR(minor(dev)); aip = &acsi_info[device]; gdev = &GENDISK_STRUCT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/ataflop.c linux-2.5/drivers/block/ataflop.c --- linux-2.5.1/drivers/block/ataflop.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/ataflop.c Mon Jan 7 23:38:10 2002 @@ -659,7 +659,7 @@ unsigned char *p; int sect, nsect; unsigned long flags; - int type, drive = MINOR(device) & 3; + int type, drive = minor(device) & 3; DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n", drive, desc->track, desc->head, desc->sect_offset )); @@ -672,7 +672,7 @@ atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */ restore_flags(flags); - type = MINOR(device) >> 2; + type = minor(device) >> 2; if (type) { if (--type >= NUM_DISK_MINORS || minor2disktype[type].drive_types > DriveType) { @@ -1367,9 +1367,9 @@ static int check_floppy_change (kdev_t dev) { - unsigned int drive = MINOR(dev) & 0x03; + unsigned int drive = minor(dev) & 0x03; - if (MAJOR(dev) != MAJOR_NR) { + if (major(dev) != MAJOR_NR) { printk(KERN_ERR "floppy_changed: not a floppy\n"); return 0; } @@ -1394,7 +1394,7 @@ static int floppy_revalidate (kdev_t dev) { - int drive = MINOR(dev) & 3; + int drive = minor(dev) & 3; if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change) || @@ -1466,13 +1466,13 @@ if (QUEUE_EMPTY) goto the_end; - if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + if (major(CURRENT->rq_dev) != MAJOR_NR) panic(DEVICE_NAME ": request list destroyed"); if (CURRENT->bh && !buffer_locked(CURRENT->bh)) panic(DEVICE_NAME ": block not locked"); - device = MINOR(CURRENT_DEVICE); + device = minor(CURRENT_DEVICE); drive = device & 3; type = device >> 2; @@ -1553,7 +1553,7 @@ { /* invalidate the buffer track to force a reread */ BufferDrive = -1; - set_bit(MINOR(rdev) & 3, &fake_change); + set_bit(minor(rdev) & 3, &fake_change); check_disk_change(rdev); return 0; } @@ -1578,7 +1578,7 @@ case BLKFLSBUF: return blk_ioctl(device, cmd, param); } - drive = MINOR (device); + drive = minor (device); type = drive >> 2; drive &= 3; switch (cmd) { @@ -1898,15 +1898,15 @@ return -EIO; } - drive = MINOR(inode->i_rdev) & 3; - type = MINOR(inode->i_rdev) >> 2; + drive = minor(inode->i_rdev) & 3; + type = minor(inode->i_rdev) >> 2; DPRINT(("fd_open: type=%d\n",type)); if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS) return -ENXIO; old_dev = fd_device[drive]; - if (fd_ref[drive] && old_dev != MINOR(inode->i_rdev)) + if (fd_ref[drive] && old_dev != minor(inode->i_rdev)) return -EBUSY; if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) @@ -1917,10 +1917,10 @@ else fd_ref[drive]++; - fd_device[drive] = MINOR(inode->i_rdev); + fd_device[drive] = minor(inode->i_rdev); - if (old_dev && old_dev != MINOR(inode->i_rdev)) - invalidate_buffers(MKDEV(FLOPPY_MAJOR, old_dev)); + if (old_dev && old_dev != minor(inode->i_rdev)) + invalidate_buffers(mk_kdev(FLOPPY_MAJOR, old_dev)); if (filp->f_flags & O_NDELAY) return 0; @@ -1941,7 +1941,7 @@ static int floppy_release( struct inode * inode, struct file * filp ) { - int drive = MINOR(inode->i_rdev) & 3; + int drive = minor(inode->i_rdev) & 3; if (fd_ref[drive] < 0) fd_ref[drive] = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/blkpg.c linux-2.5/drivers/block/blkpg.c --- linux-2.5.1/drivers/block/blkpg.c Thu Dec 6 22:02:56 2001 +++ linux-2.5/drivers/block/blkpg.c Tue Jan 1 23:42:41 2002 @@ -85,14 +85,16 @@ return -ENXIO; /* existing drive? */ - drive = (MINOR(dev) >> g->minor_shift); + drive = (minor(dev) >> g->minor_shift); first_minor = (drive << g->minor_shift); - end_minor = first_minor + g->max_p; + end_minor = first_minor + (1 << g->minor_shift); if (drive >= g->nr_real) return -ENXIO; /* drive and partition number OK? */ - if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p) + if (first_minor != minor(dev)) + return -EINVAL; + if (p->pno <= 0 || p->pno >= (1 << g->minor_shift)) return -EINVAL; /* partition number in use? */ @@ -136,10 +138,13 @@ return -ENXIO; /* drive and partition number OK? */ - drive = (MINOR(dev) >> g->minor_shift); + drive = (minor(dev) >> g->minor_shift); first_minor = (drive << g->minor_shift); - if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p) + + if (first_minor != minor(dev)) return -EINVAL; + if (p->pno <= 0 || p->pno >= (1 << g->minor_shift)) + return -EINVAL; /* existing drive and partition? */ minor = first_minor + p->pno; @@ -147,7 +152,7 @@ return -ENXIO; /* partition in use? Incomplete check for now. */ - devp = MKDEV(MAJOR(dev), minor); + devp = mk_kdev(major(dev), minor); if (is_mounted(devp) || is_swap_partition(devp)) return -EBUSY; @@ -201,8 +206,9 @@ struct gendisk *g; u64 ullval = 0; int intval, *iptr; + unsigned short usval; - if (!dev) + if (kdev_none(dev)) return -EINVAL; intval = block_ioctl(dev, cmd, arg); @@ -226,30 +232,33 @@ return -EACCES; if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(dev)] = arg; + read_ahead[major(dev)] = arg; return 0; case BLKRAGET: if (!arg) return -EINVAL; - return put_user(read_ahead[MAJOR(dev)], (long *) arg); + return put_user(read_ahead[major(dev)], (long *) arg); case BLKFRASET: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!(iptr = max_readahead[MAJOR(dev)])) + if (!(iptr = max_readahead[major(dev)])) return -EINVAL; - iptr[MINOR(dev)] = arg; + iptr[minor(dev)] = arg; return 0; case BLKFRAGET: - if (!(iptr = max_readahead[MAJOR(dev)])) + if (!(iptr = max_readahead[major(dev)])) return -EINVAL; - return put_user(iptr[MINOR(dev)], (long *) arg); + return put_user(iptr[minor(dev)], (long *) arg); case BLKSECTGET: - if ((q = blk_get_queue(dev))) - return put_user(q->max_sectors, (unsigned short *)arg); - return -EINVAL; + if ((q = blk_get_queue(dev)) == NULL) + return -EINVAL; + + usval = q->max_sectors; + blk_put_queue(q); + return put_user(usval, (unsigned short *)arg); case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) @@ -267,7 +276,7 @@ case BLKGETSIZE64: g = get_gendisk(dev); if (g) - ullval = g->part[MINOR(dev)].nr_sects; + ullval = g->part[minor(dev)].nr_sects; if (cmd == BLKGETSIZE) return put_user((unsigned long)ullval, (unsigned long *)arg); @@ -291,9 +300,7 @@ case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */ - intval = BLOCK_SIZE; - if (blksize_size[MAJOR(dev)]) - intval = blksize_size[MAJOR(dev)][MINOR(dev)]; + intval = block_size(dev); return put_user(intval, (int *) arg); case BLKBSZSET: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/block_ioctl.c linux-2.5/drivers/block/block_ioctl.c --- linux-2.5.1/drivers/block/block_ioctl.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/block_ioctl.c Thu Dec 27 22:10:28 2001 @@ -35,7 +35,7 @@ DECLARE_COMPLETION(wait); int err = 0; - rq->flags |= REQ_BARRIER; + rq->flags |= REQ_NOMERGE; rq->waiting = &wait; elv_add_request(q, rq, 1); generic_unplug_device(q); @@ -76,8 +76,8 @@ err = -ENOTTY; } -#if 0 blk_put_queue(q); -#endif return err; } + +EXPORT_SYMBOL(block_ioctl); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/cciss.c linux-2.5/drivers/block/cciss.c --- linux-2.5.1/drivers/block/cciss.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/cciss.c Thu Jan 3 23:04:39 2002 @@ -317,8 +317,8 @@ */ static int cciss_open(struct inode *inode, struct file *filep) { - int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; - int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + int ctlr = major(inode->i_rdev) - MAJOR_NR; + int dsk = minor(inode->i_rdev) >> NWD_SHIFT; #ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk); @@ -327,7 +327,7 @@ if (ctlr > MAX_CTLR || hba[ctlr] == NULL) return -ENXIO; - if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0) + if (!suser() && hba[ctlr]->sizes[minor(inode->i_rdev)] == 0) return -ENXIO; /* @@ -337,8 +337,8 @@ * for "raw controller". */ if (suser() - && (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) - && (MINOR(inode->i_rdev)!= 0)) + && (hba[ctlr]->sizes[minor(inode->i_rdev)] == 0) + && (minor(inode->i_rdev)!= 0)) return -ENXIO; hba[ctlr]->drv[dsk].usage_count++; @@ -350,8 +350,8 @@ */ static int cciss_release(struct inode *inode, struct file *filep) { - int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; - int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + int ctlr = major(inode->i_rdev) - MAJOR_NR; + int dsk = minor(inode->i_rdev) >> NWD_SHIFT; #ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk); @@ -370,8 +370,8 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg) { - int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; - int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + int ctlr = major(inode->i_rdev) - MAJOR_NR; + int dsk = minor(inode->i_rdev) >> NWD_SHIFT; #ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg); @@ -696,8 +696,8 @@ unsigned long flags; int res; - target = MINOR(dev) >> NWD_SHIFT; - ctlr = MAJOR(dev) - MAJOR_NR; + target = minor(dev) >> NWD_SHIFT; + ctlr = major(dev) - MAJOR_NR; gdev = &(hba[ctlr]->gendisk); spin_lock_irqsave(CCISS_LOCK(ctlr), flags); @@ -746,8 +746,8 @@ int ctlr, i; unsigned long flags; - ctlr = MAJOR(dev) - MAJOR_NR; - if (MINOR(dev) != 0) + ctlr = major(dev) - MAJOR_NR; + if (minor(dev) != 0) return -ENXIO; spin_lock_irqsave(CCISS_LOCK(ctlr), flags); @@ -781,9 +781,11 @@ hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_ON); cciss_geninit(ctlr); - for(i=0; i<NWD; i++) + for(i=0; i<NWD; i++) { + kdev_t kdev = mk_kdev(major(dev), i << NWD_SHIFT); if (hba[ctlr]->sizes[ i<<NWD_SHIFT ]) - revalidate_logvol(dev+(i<<NWD_SHIFT), 2); + revalidate_logvol(kdev, 2); + } hba[ctlr]->usage_count--; return 0; @@ -1205,7 +1207,6 @@ ctlr_info_t *h= q->queuedata; CommandList_struct *c; int log_unit, start_blk, seg; - struct list_head *queue_head = &q->queue_head; struct request *creq; u64bit temp64; struct scatterlist tmp_sg[MAXSGENTRIES]; @@ -1215,17 +1216,17 @@ goto startio; queue: - if (list_empty(queue_head)) + if (blk_queue_empty(q)) goto startio; creq = elv_next_request(q); if (creq->nr_phys_segments > MAXSGENTRIES) BUG(); - if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) + if (h->ctlr != major(creq->rq_dev)-MAJOR_NR ) { printk(KERN_WARNING "doreq cmd for %d, %x at %p\n", - h->ctlr, creq->rq_dev, creq); + h->ctlr, major(creq->rq_dev), creq); blkdev_dequeue_request(creq); complete_buffers(creq->bio, 0); end_that_request_last(creq); @@ -1243,7 +1244,7 @@ c->rq = creq; /* fill in the request */ - log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; + log_unit = minor(creq->rq_dev) >> NWD_SHIFT; c->Header.ReplyQueue = 0; // unused in simple mode c->Header.Tag.lower = c->busaddr; // use the physical address the cmd block for tag c->Header.LUN.LogDev.VolId= hba[h->ctlr]->drv[log_unit].LunID; @@ -1886,7 +1887,6 @@ hba[i]->gendisk.major = MAJOR_NR + i; hba[i]->gendisk.major_name = "cciss"; hba[i]->gendisk.minor_shift = NWD_SHIFT; - hba[i]->gendisk.max_p = MAX_PART; hba[i]->gendisk.part = hba[i]->hd; hba[i]->gendisk.sizes = hba[i]->sizes; hba[i]->gendisk.nr_real = hba[i]->num_luns; @@ -1897,7 +1897,7 @@ cciss_geninit(i); for(j=0; j<NWD; j++) register_disk(&(hba[i]->gendisk), - MKDEV(MAJOR_NR+i, j <<4), + mk_kdev(MAJOR_NR+i, j <<4), MAX_PART, &cciss_fops, hba[i]->drv[j].nr_blocks); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/cciss.h linux-2.5/drivers/block/cciss.h --- linux-2.5.1/drivers/block/cciss.h Wed Dec 12 21:41:03 2001 +++ linux-2.5/drivers/block/cciss.h Mon Jan 7 19:11:53 2002 @@ -8,7 +8,7 @@ #define NWD 16 #define NWD_SHIFT 4 -#define MAX_PART 16 +#define MAX_PART (1 << NWD_SHIFT) #define IO_OK 0 #define IO_ERROR 1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/cciss_cmd.h linux-2.5/drivers/block/cciss_cmd.h --- linux-2.5.1/drivers/block/cciss_cmd.h Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/block/cciss_cmd.h Thu Jan 3 23:04:39 2002 @@ -7,7 +7,7 @@ //general boundary defintions #define SENSEINFOBYTES 32//note that this value may vary between host implementations -#define MAXSGENTRIES 32 +#define MAXSGENTRIES 31 #define MAXREPLYQS 256 //Command Status value diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/cpqarray.c linux-2.5/drivers/block/cpqarray.c --- linux-2.5.1/drivers/block/cpqarray.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/cpqarray.c Fri Jan 4 16:55:04 2002 @@ -483,7 +483,6 @@ ida_gendisk[i].major = MAJOR_NR + i; ida_gendisk[i].major_name = "ida"; ida_gendisk[i].minor_shift = NWD_SHIFT; - ida_gendisk[i].max_p = 16; ida_gendisk[i].part = ida + (i*256); ida_gendisk[i].sizes = ida_sizes + (i*256); ida_gendisk[i].nr_real = 0; @@ -500,7 +499,7 @@ ida_geninit(i); for(j=0; j<NWD; j++) register_disk(&ida_gendisk[i], - MKDEV(MAJOR_NR+i,j<<4), + mk_kdev(MAJOR_NR+i,j<<4), 16, &ida_fops, hba[i]->drv[j].nr_blks); } @@ -777,15 +776,15 @@ */ static int ida_open(struct inode *inode, struct file *filep) { - int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; - int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + int ctlr = major(inode->i_rdev) - MAJOR_NR; + int dsk = minor(inode->i_rdev) >> NWD_SHIFT; DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) ); if (ctlr > MAX_CTLR || hba[ctlr] == NULL) return -ENXIO; if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) + - MINOR(inode->i_rdev)] == 0) + minor(inode->i_rdev)] == 0) return -ENXIO; /* @@ -795,8 +794,8 @@ * for "raw controller". */ if (suser() - && ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0 - && MINOR(inode->i_rdev) != 0) + && ida_sizes[(ctlr << CTLR_SHIFT) + minor(inode->i_rdev)] == 0 + && minor(inode->i_rdev) != 0) return -ENXIO; hba[ctlr]->drv[dsk].usage_count++; @@ -809,8 +808,8 @@ */ static int ida_release(struct inode *inode, struct file *filep) { - int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; - int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + int ctlr = major(inode->i_rdev) - MAJOR_NR; + int dsk = minor(inode->i_rdev) >> NWD_SHIFT; DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) ); @@ -858,7 +857,6 @@ { ctlr_info_t *h = q->queuedata; cmdlist_t *c; - struct list_head * queue_head = &q->queue_head; struct request *creq; struct scatterlist tmp_sg[SG_MAX]; int i, dir, seg; @@ -867,17 +865,17 @@ goto startio; queue_next: - if (list_empty(queue_head)) + if (blk_queue_empty(q)) goto startio; creq = elv_next_request(q); if (creq->nr_phys_segments > SG_MAX) BUG(); - if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR || h->ctlr > nr_ctlr) + if (h->ctlr != major(creq->rq_dev)-MAJOR_NR || h->ctlr > nr_ctlr) { printk(KERN_WARNING "doreq cmd for %d, %x at %p\n", - h->ctlr, creq->rq_dev, creq); + h->ctlr, kdev_t_to_nr(creq->rq_dev), creq); blkdev_dequeue_request(creq); complete_buffers(creq->bio, 0); end_that_request_last(creq); @@ -892,7 +890,7 @@ spin_unlock_irq(q->queue_lock); c->ctlr = h->ctlr; - c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT; + c->hdr.unit = minor(creq->rq_dev) >> NWD_SHIFT; c->hdr.size = sizeof(rblk_t) >> 2; c->size += sizeof(rblk_t); @@ -1110,8 +1108,8 @@ */ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg) { - int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; - int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + int ctlr = major(inode->i_rdev) - MAJOR_NR; + int dsk = minor(inode->i_rdev) >> NWD_SHIFT; int error; int diskinfo[4]; struct hd_geometry *geo = (struct hd_geometry *)arg; @@ -1490,12 +1488,14 @@ */ static int revalidate_allvol(kdev_t dev) { - int ctlr, i; + int ctlr, i, maj; unsigned long flags; - ctlr = MAJOR(dev) - MAJOR_NR; - if (MINOR(dev) != 0) + ctlr = major(dev) - MAJOR_NR; + if (minor(dev) != 0) return -ENXIO; + maj = major(dev); + ctlr = major(dev) - MAJOR_NR; spin_lock_irqsave(IDA_LOCK(ctlr), flags); if (hba[ctlr]->usage_count > 1) { @@ -1527,9 +1527,11 @@ hba[ctlr]->access.set_intr_mask(hba[ctlr], FIFO_NOT_EMPTY); ida_geninit(ctlr); - for(i=0; i<NWD; i++) + for(i=0; i<NWD; i++) { + kdev_t kdev = mk_kdev(major(dev), i << NWD_SHIFT); if (ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)]) - revalidate_logvol(dev+(i<<NWD_SHIFT), 2); + revalidate_logvol(kdev, 2); + } hba[ctlr]->usage_count--; return 0; @@ -1544,7 +1546,7 @@ int res; target = DEVICE_NR(dev); - ctlr = MAJOR(dev) - MAJOR_NR; + ctlr = major(dev) - MAJOR_NR; gdev = &ida_gendisk[ctlr]; spin_lock_irqsave(IDA_LOCK(ctlr), flags); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/elevator.c linux-2.5/drivers/block/elevator.c --- linux-2.5.1/drivers/block/elevator.c Sat Dec 8 00:32:26 2001 +++ linux-2.5/drivers/block/elevator.c Thu Jan 3 23:04:39 2002 @@ -53,7 +53,7 @@ * if .next is a valid request */ next = rq->queuelist.next; - if (next == head) + if (unlikely(next == head)) return 0; next_rq = list_entry(next, struct request, queuelist); @@ -70,7 +70,7 @@ * if the device is different (not a normal case) just check if * bio is after rq */ - if (next_rq->rq_dev != rq->rq_dev) + if (!kdev_same(next_rq->rq_dev, rq->rq_dev)) return bio->bi_sector > rq->sector; /* @@ -101,7 +101,7 @@ */ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio) { - if (!(rq->flags & REQ_CMD)) + if (!rq_mergeable(rq)) return 0; /* @@ -109,61 +109,92 @@ */ if (bio_data_dir(bio) != rq_data_dir(rq)) return 0; - if (rq->flags & REQ_NOMERGE) - return 0; /* * same device and no special stuff set, merge is ok */ - if (rq->rq_dev == bio->bi_dev && !rq->waiting && !rq->special) + if (kdev_same(rq->rq_dev, bio->bi_dev) && !rq->waiting && !rq->special) return 1; return 0; } -int elevator_linus_merge(request_queue_t *q, struct request **req, - struct list_head *head, struct bio *bio) +inline int elv_try_merge(struct request *__rq, struct bio *bio) { - unsigned int count = bio_sectors(bio); - struct list_head *entry = &q->queue_head; int ret = ELEVATOR_NO_MERGE; + + /* + * we can merge and sequence is ok, check if it's possible + */ + if (elv_rq_merge_ok(__rq, bio)) { + if (__rq->sector + __rq->nr_sectors == bio->bi_sector) + ret = ELEVATOR_BACK_MERGE; + else if (__rq->sector - bio_sectors(bio) == bio->bi_sector) + ret = ELEVATOR_FRONT_MERGE; + } + + return ret; +} + +inline int elv_try_last_merge(request_queue_t *q, struct request **req, + struct bio *bio) +{ + int ret = ELEVATOR_NO_MERGE; + + /* + * give a one-shot try to merging with the last touched + * request + */ + if (q->last_merge) { + struct request *__rq = list_entry_rq(q->last_merge); + BUG_ON(__rq->flags & REQ_STARTED); + + if ((ret = elv_try_merge(__rq, bio))) + *req = __rq; + } + + return ret; +} + +/* + * elevator_linux starts here + */ +int elevator_linus_merge(request_queue_t *q, struct request **req, + struct bio *bio) +{ + struct list_head *entry; struct request *__rq; + int ret; + + if ((ret = elv_try_last_merge(q, req, bio))) + return ret; entry = &q->queue_head; - while ((entry = entry->prev) != head) { + ret = ELEVATOR_NO_MERGE; + while ((entry = entry->prev) != &q->queue_head) { __rq = list_entry_rq(entry); - prefetch(list_entry_rq(entry->prev)); + if (__rq->flags & (REQ_BARRIER | REQ_STARTED)) + break; /* * simply "aging" of requests in queue */ - if (__rq->elevator_sequence-- <= 0) - break; - if (__rq->flags & (REQ_BARRIER | REQ_STARTED)) + if (elv_linus_sequence(__rq)-- <= 0) break; if (!(__rq->flags & REQ_CMD)) continue; + if (elv_linus_sequence(__rq) < bio_sectors(bio)) + break; if (!*req && bio_rq_in_between(bio, __rq, &q->queue_head)) *req = __rq; - if (!elv_rq_merge_ok(__rq, bio)) - continue; - if (__rq->elevator_sequence < count) - break; - - /* - * we can merge and sequence is ok, check if it's possible - */ - if (__rq->sector + __rq->nr_sectors == bio->bi_sector) { - ret = ELEVATOR_BACK_MERGE; - *req = __rq; - break; - } else if (__rq->sector - count == bio->bi_sector) { - ret = ELEVATOR_FRONT_MERGE; - __rq->elevator_sequence -= count; + if ((ret = elv_try_merge(__rq, bio))) { + if (ret == ELEVATOR_FRONT_MERGE) + elv_linus_sequence(__rq) -= bio_sectors(bio); *req = __rq; + q->last_merge = &__rq->queuelist; break; } } @@ -183,56 +214,76 @@ entry = &req->queuelist; while ((entry = entry->next) != &q->queue_head) { struct request *tmp; - prefetch(list_entry_rq(entry->next)); tmp = list_entry_rq(entry); - tmp->elevator_sequence -= count; + elv_linus_sequence(tmp) -= count; } } void elevator_linus_merge_req(struct request *req, struct request *next) { - if (next->elevator_sequence < req->elevator_sequence) - req->elevator_sequence = next->elevator_sequence; + if (elv_linus_sequence(next) < elv_linus_sequence(req)) + elv_linus_sequence(req) = elv_linus_sequence(next); } -void elv_add_request_fn(request_queue_t *q, struct request *rq, - struct list_head *insert_here) +void elevator_linus_add_request(request_queue_t *q, struct request *rq, + struct list_head *insert_here) { + elevator_t *e = &q->elevator; + int lat = 0, *latency = e->elevator_data; + + if (!(rq->flags & REQ_BARRIER)) + lat = latency[rq_data_dir(rq)]; + + elv_linus_sequence(rq) = lat; + list_add(&rq->queuelist, insert_here); + + /* + * new merges must not precede this barrier + */ + if (rq->flags & REQ_BARRIER) + q->last_merge = NULL; + else if (!q->last_merge) + q->last_merge = &rq->queuelist; } -struct request *elv_next_request_fn(request_queue_t *q) +int elevator_linus_init(request_queue_t *q, elevator_t *e) { - if (!blk_queue_empty(q)) - return list_entry(q->queue_head.next, struct request, queuelist); + int *latency; - return NULL; -} + latency = kmalloc(2 * sizeof(int), GFP_KERNEL); + if (!latency) + return -ENOMEM; -int elv_linus_init(request_queue_t *q, elevator_t *e) -{ + latency[READ] = 8192; + latency[WRITE] = 16384; + + e->elevator_data = latency; return 0; } -void elv_linus_exit(request_queue_t *q, elevator_t *e) +void elevator_linus_exit(request_queue_t *q, elevator_t *e) { + kfree(e->elevator_data); } /* + * elevator noop + * * See if we can find a request that this buffer can be coalesced with. */ int elevator_noop_merge(request_queue_t *q, struct request **req, - struct list_head *head, struct bio *bio) + struct bio *bio) { - unsigned int count = bio_sectors(bio); struct list_head *entry = &q->queue_head; struct request *__rq; + int ret; - entry = &q->queue_head; - while ((entry = entry->prev) != head) { - __rq = list_entry_rq(entry); + if ((ret = elv_try_last_merge(q, req, bio))) + return ret; - prefetch(list_entry_rq(entry->prev)); + while ((entry = entry->prev) != &q->queue_head) { + __rq = list_entry_rq(entry); if (__rq->flags & (REQ_BARRIER | REQ_STARTED)) break; @@ -240,33 +291,47 @@ if (!(__rq->flags & REQ_CMD)) continue; - if (!elv_rq_merge_ok(__rq, bio)) - continue; - - /* - * we can merge and sequence is ok, check if it's possible - */ - if (__rq->sector + __rq->nr_sectors == bio->bi_sector) { - *req = __rq; - return ELEVATOR_BACK_MERGE; - } else if (__rq->sector - count == bio->bi_sector) { + if ((ret = elv_try_merge(__rq, bio))) { *req = __rq; - return ELEVATOR_FRONT_MERGE; + q->last_merge = &__rq->queuelist; + return ret; } } return ELEVATOR_NO_MERGE; } -void elevator_noop_merge_cleanup(request_queue_t *q, struct request *req, int count) {} +void elevator_noop_add_request(request_queue_t *q, struct request *rq, + struct list_head *insert_here) +{ + list_add_tail(&rq->queuelist, &q->queue_head); -void elevator_noop_merge_req(struct request *req, struct request *next) {} + /* + * new merges must not precede this barrier + */ + if (rq->flags & REQ_BARRIER) + q->last_merge = NULL; + else if (!q->last_merge) + q->last_merge = &rq->queuelist; +} +struct request *elevator_noop_next_request(request_queue_t *q) +{ + if (!blk_queue_empty(q)) + return list_entry_rq(q->queue_head.next); + + return NULL; +} + +/* + * general block -> elevator interface starts here + */ int elevator_init(request_queue_t *q, elevator_t *e, elevator_t type) { *e = type; INIT_LIST_HEAD(&q->queue_head); + q->last_merge = NULL; if (e->elevator_init_fn) return e->elevator_init_fn(q, e); @@ -285,4 +350,77 @@ return 0; } +void elv_merge_cleanup(request_queue_t *q, struct request *rq, + int nr_sectors) +{ + elevator_t *e = &q->elevator; + + if (e->elevator_merge_cleanup_fn) + e->elevator_merge_cleanup_fn(q, rq, nr_sectors); +} + +int elv_merge(request_queue_t *q, struct request **rq, struct bio *bio) +{ + elevator_t *e = &q->elevator; + + if (e->elevator_merge_fn) + return e->elevator_merge_fn(q, rq, bio); + + return ELEVATOR_NO_MERGE; +} + +void elv_merge_requests(request_queue_t *q, struct request *rq, + struct request *next) +{ + elevator_t *e = &q->elevator; + + if (e->elevator_merge_req_fn) + e->elevator_merge_req_fn(rq, next); +} + +/* + * add_request and next_request are required to be supported, naturally + */ +void __elv_add_request(request_queue_t *q, struct request *rq, + struct list_head *insert_here) +{ + q->elevator.elevator_add_req_fn(q, rq, insert_here); +} + +struct request *__elv_next_request(request_queue_t *q) +{ + return q->elevator.elevator_next_req_fn(q); +} + +void elv_remove_request(request_queue_t *q, struct request *rq) +{ + elevator_t *e = &q->elevator; + + if (e->elevator_remove_req_fn) + e->elevator_remove_req_fn(q, rq); +} + +elevator_t elevator_linus = { + elevator_merge_fn: elevator_linus_merge, + elevator_merge_cleanup_fn: elevator_linus_merge_cleanup, + elevator_merge_req_fn: elevator_linus_merge_req, + elevator_next_req_fn: elevator_noop_next_request, + elevator_add_req_fn: elevator_linus_add_request, + elevator_init_fn: elevator_linus_init, + elevator_exit_fn: elevator_linus_exit, +}; + +elevator_t elevator_noop = { + elevator_merge_fn: elevator_noop_merge, + elevator_next_req_fn: elevator_noop_next_request, + elevator_add_req_fn: elevator_noop_add_request, +}; + module_init(elevator_global_init); + +EXPORT_SYMBOL(elevator_linus); +EXPORT_SYMBOL(elevator_noop); + +EXPORT_SYMBOL(__elv_add_request); +EXPORT_SYMBOL(__elv_next_request); +EXPORT_SYMBOL(elv_remove_request); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/floppy.c linux-2.5/drivers/block/floppy.c --- linux-2.5.1/drivers/block/floppy.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/drivers/block/floppy.c Tue Jan 1 23:42:41 2002 @@ -270,10 +270,10 @@ static int initialising=1; static inline int TYPE(kdev_t x) { - return (MINOR(x)>>2) & 0x1f; + return (minor(x)>>2) & 0x1f; } static inline int DRIVE(kdev_t x) { - return (MINOR(x)&0x03) | ((MINOR(x)&0x80) >> 5); + return (minor(x)&0x03) | ((minor(x)&0x80) >> 5); } #define ITYPE(x) (((x)>>2) & 0x1f) #define TOMINOR(x) ((x & 3) | ((x & 4) << 5)) @@ -2906,7 +2906,7 @@ unlock_fdc(); return; } - if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + if (major(CURRENT->rq_dev) != MAJOR_NR) panic(DEVICE_NAME ": request list destroyed"); device = CURRENT->rq_dev; @@ -3332,7 +3332,7 @@ if (ITYPE(drive_state[cnt].fd_device) == type && drive_state[cnt].fd_ref) check_disk_change( - MKDEV(FLOPPY_MAJOR, + mk_kdev(FLOPPY_MAJOR, drive_state[cnt].fd_device)); } } else { @@ -3717,7 +3717,7 @@ if (TYPE(inode->i_rdev) >= NUMBER(floppy_type)) return -ENXIO; old_dev = UDRS->fd_device; - if (UDRS->fd_ref && old_dev != MINOR(inode->i_rdev)) + if (UDRS->fd_ref && old_dev != minor(inode->i_rdev)) return -EBUSY; if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){ @@ -3768,11 +3768,11 @@ } } - UDRS->fd_device = MINOR(inode->i_rdev); - if (old_dev != -1 && old_dev != MINOR(inode->i_rdev)) { + UDRS->fd_device = minor(inode->i_rdev); + if (old_dev != -1 && old_dev != minor(inode->i_rdev)) { if (buffer_drive == drive) buffer_track = -1; - invalidate_buffers(MKDEV(FLOPPY_MAJOR,old_dev)); + invalidate_buffers(mk_kdev(FLOPPY_MAJOR,old_dev)); } /* Allow ioctls if we have write-permissions even if read-only open. @@ -3806,7 +3806,7 @@ { int drive = DRIVE(dev); - if (MAJOR(dev) != MAJOR_NR) { + if (major(dev) != MAJOR_NR) { DPRINT("check_floppy_change: not a floppy\n"); return 0; } @@ -3868,7 +3868,7 @@ UDRS->generation++; if (NO_GEOM){ /* auto-sensing */ - int size = floppy_blocksizes[MINOR(dev)]; + int size = floppy_blocksizes[minor(dev)]; if (!size) size = 1024; if (!(bh = getblk(dev,0,size))){ @@ -4275,7 +4275,7 @@ if (fdc_state[FDC(drive)].version == FDC_NONE) continue; for (i = 0; i<NUMBER(floppy_type); i++) - register_disk(NULL, MKDEV(MAJOR_NR,TOMINOR(drive)+i*4), + register_disk(NULL, mk_kdev(MAJOR_NR,TOMINOR(drive)+i*4), 1, &floppy_fops, 0); } return have_no_fdc; @@ -4480,3 +4480,5 @@ __setup ("floppy=", floppy_setup); module_init(floppy_init) #endif + +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/genhd.c linux-2.5/drivers/block/genhd.c --- linux-2.5.1/drivers/block/genhd.c Sat Dec 8 17:49:52 2001 +++ linux-2.5/drivers/block/genhd.c Tue Jan 1 23:42:41 2002 @@ -103,7 +103,7 @@ get_gendisk(kdev_t dev) { struct gendisk *gp = NULL; - int maj = MAJOR(dev); + int maj = major(dev); read_lock(&gendisk_lock); for (gp = gendisk_head; gp; gp = gp->next) @@ -124,7 +124,7 @@ gp = get_gendisk(dev); if (gp) - return gp->part[MINOR(dev)].start_sect; + return gp->part[minor(dev)].start_sect; return 0; } @@ -137,7 +137,7 @@ gp = get_gendisk(dev); if (gp) - return gp->part[MINOR(dev)].nr_sects; + return gp->part[minor(dev)].nr_sects; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/ll_rw_blk.c linux-2.5/drivers/block/ll_rw_blk.c --- linux-2.5.1/drivers/block/ll_rw_blk.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/ll_rw_blk.c Mon Jan 14 23:52:46 2002 @@ -109,12 +109,17 @@ **/ inline request_queue_t *blk_get_queue(kdev_t dev) { - struct blk_dev_struct *bdev = blk_dev + MAJOR(dev); + struct blk_dev_struct *bdev = blk_dev + major(dev); if (bdev->queue) return bdev->queue(dev); else - return &blk_dev[MAJOR(dev)].request_queue; + return &blk_dev[major(dev)].request_queue; +} + +void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn) +{ + q->prep_rq_fn = pfn; } /** @@ -150,6 +155,11 @@ blk_queue_max_sectors(q, MAX_SECTORS); blk_queue_hardsect_size(q, 512); + /* + * by default assume old behaviour and bounce for any highmem page + */ + blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); + init_waitqueue_head(&q->queue_wait); } @@ -179,7 +189,6 @@ if (dma_addr == BLK_BOUNCE_ISA) { init_emergency_isa_pool(); q->bounce_gfp = GFP_NOIO | GFP_DMA; - printk("isa pfn %lu, max low %lu, max %lu\n", bounce_pfn, blk_max_low_pfn, blk_max_pfn); } else q->bounce_gfp = GFP_NOHIGHIO; @@ -300,7 +309,7 @@ { int bit; - printk("%s: dev %x: ", msg, rq->rq_dev); + printk("%s: dev %02x:%02x: ", msg, major(rq->rq_dev), minor(rq->rq_dev)); bit = 0; do { if (rq->flags & (1 << bit)) @@ -319,7 +328,7 @@ /* * standard prep_rq_fn that builds 10 byte cmds */ -static int ll_10byte_cmd_build(request_queue_t *q, struct request *rq) +int ll_10byte_cmd_build(request_queue_t *q, struct request *rq) { int hard_sect = get_hardsect_size(rq->rq_dev); sector_t block = rq->hard_sector / (hard_sect >> 9); @@ -477,7 +486,7 @@ sg[nsegs - 1].length += nbytes; } else { new_segment: - sg[nsegs].address = NULL; + memset(&sg[nsegs],0,sizeof(struct scatterlist)); sg[nsegs].page = bvec->bv_page; sg[nsegs].length = nbytes; sg[nsegs].offset = bvec->bv_offset; @@ -504,6 +513,7 @@ if (req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) { req->flags |= REQ_NOMERGE; + q->last_merge = NULL; return 0; } @@ -520,9 +530,12 @@ struct bio *bio) { int nr_hw_segs = bio_hw_segments(q, bio); + int nr_phys_segs = bio_phys_segments(q, bio); - if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments) { + if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments + || req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) { req->flags |= REQ_NOMERGE; + q->last_merge = NULL; return 0; } @@ -531,7 +544,7 @@ * counters. */ req->nr_hw_segments += nr_hw_segs; - req->nr_phys_segments += bio_phys_segments(q, bio); + req->nr_phys_segments += nr_phys_segs; return 1; } @@ -540,11 +553,11 @@ { if (req->nr_sectors + bio_sectors(bio) > q->max_sectors) { req->flags |= REQ_NOMERGE; + q->last_merge = NULL; return 0; } - if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), - __BVEC_START(bio))) + if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio))) return ll_new_mergeable(q, req, bio); return ll_new_hw_segment(q, req, bio); @@ -555,11 +568,11 @@ { if (req->nr_sectors + bio_sectors(bio) > q->max_sectors) { req->flags |= REQ_NOMERGE; + q->last_merge = NULL; return 0; } - if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), - __BVEC_START(req->bio))) + if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(req->bio))) return ll_new_mergeable(q, req, bio); return ll_new_hw_segment(q, req, bio); @@ -568,7 +581,7 @@ static int ll_merge_requests_fn(request_queue_t *q, struct request *req, struct request *next) { - int total_phys_segments = req->nr_phys_segments + next->nr_phys_segments; + int total_phys_segments = req->nr_phys_segments +next->nr_phys_segments; int total_hw_segments = req->nr_hw_segments + next->nr_hw_segments; /* @@ -790,7 +803,7 @@ if (blk_init_free_list(q)) return -ENOMEM; - if ((ret = elevator_init(q, &q->elevator, ELEVATOR_LINUS))) { + if ((ret = elevator_init(q, &q->elevator, elevator_linus))) { blk_cleanup_queue(q); return ret; } @@ -799,22 +812,21 @@ q->back_merge_fn = ll_back_merge_fn; q->front_merge_fn = ll_front_merge_fn; q->merge_requests_fn = ll_merge_requests_fn; - q->prep_rq_fn = ll_10byte_cmd_build; + q->prep_rq_fn = NULL; q->plug_tq.sync = 0; q->plug_tq.routine = &generic_unplug_device; q->plug_tq.data = q; q->queue_flags = (1 << QUEUE_FLAG_CLUSTER); q->queue_lock = lock; + q->last_merge = NULL; - /* - * by default assume old behaviour and bounce for any highmem page - */ - blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); - blk_queue_segment_boundary(q, 0xffffffff); blk_queue_make_request(q, __make_request); blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE); + + blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS); + blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS); return 0; } @@ -874,11 +886,19 @@ BUG_ON(rw != READ && rw != WRITE); + spin_lock_irq(q->queue_lock); rq = get_request(q, rw); + spin_unlock_irq(q->queue_lock); if (!rq && (gfp_mask & __GFP_WAIT)) rq = get_request_wait(q, rw); + if (rq) { + rq->flags = 0; + rq->buffer = NULL; + rq->bio = rq->biotail = NULL; + rq->waiting = NULL; + } return rq; } @@ -895,8 +915,8 @@ { int minor,major; - major = MAJOR(dev); - minor = MINOR(dev); + major = major(dev); + minor = minor(dev); if (major < 0 || major >= MAX_BLKDEV) return 0; return ro_bits[major][minor >> 5] & (1 << (minor & 31)); } @@ -905,8 +925,8 @@ { int minor,major; - major = MAJOR(dev); - minor = MINOR(dev); + major = major(dev); + minor = minor(dev); if (major < 0 || major >= MAX_BLKDEV) return; if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31); else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31)); @@ -914,7 +934,7 @@ void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) { - unsigned int major = MAJOR(rq->rq_dev); + unsigned int major = major(rq->rq_dev); int rw = rq_data_dir(rq); unsigned int index; @@ -944,19 +964,16 @@ drive_stat_acct(req, req->nr_sectors, 1); /* - * debug stuff... + * it's a bug to let this rq preempt an already started request */ - if (insert_here == &q->queue_head) { - struct request *__rq = __elv_next_request(q); - - BUG_ON(__rq && (__rq->flags & REQ_STARTED)); - } + if (insert_here->next != &q->queue_head) + BUG_ON(list_entry_rq(insert_here->next)->flags & REQ_STARTED); /* * elevator indicated where it wants this request to be * inserted at elevator_merge time */ - q->elevator.elevator_add_req_fn(q, req, insert_here); + __elv_add_request(q, req, insert_here); } /* @@ -965,11 +982,17 @@ void blkdev_release_request(struct request *req) { struct request_list *rl = req->rl; + request_queue_t *q = req->q; req->rq_status = RQ_INACTIVE; req->q = NULL; req->rl = NULL; + if (q) { + if (q->last_merge == &req->queuelist) + q->last_merge = NULL; + } + /* * Request may not have originated from ll_rw_blk. if not, * it didn't come out of our reserved rq pools @@ -985,14 +1008,10 @@ /* * Has to be called with the request spinlock acquired */ -static void attempt_merge(request_queue_t *q, struct request *req) +static void attempt_merge(request_queue_t *q, struct request *req, + struct request *next) { - struct request *next = blkdev_next_request(req); - - /* - * not a rw command - */ - if (!(next->flags & REQ_CMD)) + if (!rq_mergeable(req) || !rq_mergeable(next)) return; /* @@ -1001,26 +1020,20 @@ if (req->sector + req->nr_sectors != next->sector) return; - /* - * don't touch NOMERGE rq, or one that has been started by driver - */ - if (next->flags & (REQ_NOMERGE | REQ_STARTED)) - return; - if (rq_data_dir(req) != rq_data_dir(next) - || req->rq_dev != next->rq_dev + || !kdev_same(req->rq_dev, next->rq_dev) || req->nr_sectors + next->nr_sectors > q->max_sectors || next->waiting || next->special) return; /* - * If we are not allowed to merge these requests, then - * return. If we are allowed to merge, then the count - * will have been updated to the appropriate number, - * and we shouldn't do it here too. + * If we are allowed to merge, then append bio list + * from next to rq and release next. merge_requests_fn + * will have updated segment counts, update sector + * counts here. */ if (q->merge_requests_fn(q, req, next)) { - q->elevator.elevator_merge_req_fn(req, next); + elv_merge_requests(q, req, next); blkdev_dequeue_request(next); @@ -1035,24 +1048,18 @@ static inline void attempt_back_merge(request_queue_t *q, struct request *rq) { - if (&rq->queuelist != q->queue_head.prev) - attempt_merge(q, rq); + struct list_head *next = rq->queuelist.next; + + if (next != &q->queue_head) + attempt_merge(q, rq, list_entry_rq(next)); } -static inline void attempt_front_merge(request_queue_t *q, - struct list_head *head, - struct request *rq) +static inline void attempt_front_merge(request_queue_t *q, struct request *rq) { struct list_head *prev = rq->queuelist.prev; - if (prev != head) - attempt_merge(q, blkdev_entry_to_request(prev)); -} - -static inline void __blk_attempt_remerge(request_queue_t *q, struct request *rq) -{ - if (rq->queuelist.next != &q->queue_head) - attempt_merge(q, rq); + if (prev != &q->queue_head) + attempt_merge(q, list_entry_rq(prev), rq); } /** @@ -1073,16 +1080,15 @@ unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); - __blk_attempt_remerge(q, rq); + attempt_back_merge(q, rq); spin_unlock_irqrestore(q->queue_lock, flags); } static int __make_request(request_queue_t *q, struct bio *bio) { struct request *req, *freereq = NULL; - int el_ret, latency = 0, rw, nr_sectors, cur_nr_sectors, barrier; - struct list_head *head, *insert_here; - elevator_t *elevator = &q->elevator; + int el_ret, rw, nr_sectors, cur_nr_sectors, barrier; + struct list_head *insert_here; sector_t sector; sector = bio->bi_sector; @@ -1099,35 +1105,26 @@ spin_lock_prefetch(q->queue_lock); - latency = elevator_request_latency(elevator, rw); barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw); + spin_lock_irq(q->queue_lock); again: req = NULL; - head = &q->queue_head; + insert_here = q->queue_head.prev; - spin_lock_irq(q->queue_lock); - - insert_here = head->prev; if (blk_queue_empty(q) || barrier) { blk_plug_device(q); goto get_rq; - } else if ((req = __elv_next_request(q))) { - if (req->flags & REQ_STARTED) - head = head->next; - - req = NULL; } - el_ret = elevator->elevator_merge_fn(q, &req, head, bio); + el_ret = elv_merge(q, &req, bio); switch (el_ret) { case ELEVATOR_BACK_MERGE: - BUG_ON(req->flags & REQ_STARTED); - BUG_ON(req->flags & REQ_NOMERGE); + BUG_ON(!rq_mergeable(req)); if (!q->back_merge_fn(q, req, bio)) break; - elevator->elevator_merge_cleanup_fn(q, req, nr_sectors); + elv_merge_cleanup(q, req, nr_sectors); req->biotail->bi_next = bio; req->biotail = bio; @@ -1137,12 +1134,11 @@ goto out; case ELEVATOR_FRONT_MERGE: - BUG_ON(req->flags & REQ_STARTED); - BUG_ON(req->flags & REQ_NOMERGE); + BUG_ON(!rq_mergeable(req)); if (!q->front_merge_fn(q, req, bio)) break; - elevator->elevator_merge_cleanup_fn(q, req, nr_sectors); + elv_merge_cleanup(q, req, nr_sectors); bio->bi_next = req->bio; req->bio = bio; @@ -1157,7 +1153,7 @@ req->sector = req->hard_sector = sector; req->nr_sectors = req->hard_nr_sectors += nr_sectors; drive_stat_acct(req, nr_sectors, 0); - attempt_front_merge(q, head, req); + attempt_front_merge(q, req); goto out; /* @@ -1188,7 +1184,6 @@ req = freereq; freereq = NULL; } else if ((req = get_request(q, rw)) == NULL) { - spin_unlock_irq(q->queue_lock); /* @@ -1200,15 +1195,11 @@ } freereq = get_request_wait(q, rw); + spin_lock_irq(q->queue_lock); goto again; } /* - * fill up the request-info, and add it to the queue - */ - req->elevator_sequence = latency; - - /* * first three bits are identical in rq->flags and bio->bi_rw, * see bio.h and blkdev.h */ @@ -1252,14 +1243,14 @@ struct gendisk *g; kdev_t dev0; - major = MAJOR(bio->bi_dev); + major = major(bio->bi_dev); if ((g = get_gendisk(bio->bi_dev))) { - minor = MINOR(bio->bi_dev); + minor = minor(bio->bi_dev); drive = (minor >> g->minor_shift); minor0 = (drive << g->minor_shift); /* whole disk device */ /* that is, minor0 = (minor & ~((1<<g->minor_shift)-1)); */ - dev0 = MKDEV(major, minor0); - if (dev0 != bio->bi_dev) { + dev0 = mk_kdev(major, minor0); + if (!kdev_same(dev0, bio->bi_dev)) { bio->bi_dev = dev0; bio->bi_sector += g->part[minor].start_sect; } @@ -1294,11 +1285,11 @@ * */ void generic_make_request(struct bio *bio) { - int major = MAJOR(bio->bi_dev); - int minor = MINOR(bio->bi_dev); + int major = major(bio->bi_dev); + int minor = minor(bio->bi_dev); request_queue_t *q; sector_t minorsize = 0; - int nr_sectors = bio_sectors(bio); + int ret, nr_sectors = bio_sectors(bio); /* Test device or partition size, when known. */ if (blk_size[major]) @@ -1352,7 +1343,10 @@ */ blk_partition_remap(bio); - } while (q->make_request_fn(q, bio)); + ret = q->make_request_fn(q, bio); + blk_put_queue(q); + + } while (ret); } /* @@ -1481,7 +1475,7 @@ if (!nr) return; - major = MAJOR(bhs[0]->b_dev); + major = major(bhs[0]->b_dev); /* Determine correct block size for this device. */ correct_size = get_hardsect_size(bhs[0]->b_dev); @@ -1572,21 +1566,23 @@ inline void blk_recalc_rq_sectors(struct request *rq, int nsect) { - rq->hard_sector += nsect; - rq->hard_nr_sectors -= nsect; - rq->sector = rq->hard_sector; - rq->nr_sectors = rq->hard_nr_sectors; + if (rq->flags & REQ_CMD) { + rq->hard_sector += nsect; + rq->hard_nr_sectors -= nsect; + rq->sector = rq->hard_sector; + rq->nr_sectors = rq->hard_nr_sectors; - rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9; - rq->hard_cur_sectors = rq->current_nr_sectors; + rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9; + rq->hard_cur_sectors = rq->current_nr_sectors; - /* - * if total number of sectors is less than the first segment - * size, something has gone terribly wrong - */ - if (rq->nr_sectors < rq->current_nr_sectors) { - printk("blk: request botched\n"); - rq->nr_sectors = rq->current_nr_sectors; + /* + * if total number of sectors is less than the first segment + * size, something has gone terribly wrong + */ + if (rq->nr_sectors < rq->current_nr_sectors) { + printk("blk: request botched\n"); + rq->nr_sectors = rq->current_nr_sectors; + } } } @@ -1715,7 +1711,11 @@ printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests); blk_max_low_pfn = max_low_pfn; +#ifdef CONFIG_HIGHMEM blk_max_pfn = max_pfn; +#else + blk_max_pfn = max_low_pfn; +#endif #if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE) ide_init(); /* this MUST precede hd_init */ @@ -1755,3 +1755,6 @@ EXPORT_SYMBOL(blk_queue_assign_lock); EXPORT_SYMBOL(blk_phys_contig_segment); EXPORT_SYMBOL(blk_hw_contig_segment); + +EXPORT_SYMBOL(ll_10byte_cmd_build); +EXPORT_SYMBOL(blk_queue_prep_rq); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/loop.c linux-2.5/drivers/block/loop.c --- linux-2.5.1/drivers/block/loop.c Fri Nov 30 16:33:50 2001 +++ linux-2.5/drivers/block/loop.c Tue Jan 8 00:44:24 2002 @@ -155,8 +155,8 @@ { if (S_ISREG(lo_dentry->d_inode->i_mode)) return (lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS; - if (blk_size[MAJOR(lodev)]) - return blk_size[MAJOR(lodev)][MINOR(lodev)] - + if (blk_size[major(lodev)]) + return blk_size[major(lodev)][minor(lodev)] - (lo->lo_offset >> BLOCK_SIZE_BITS); return MAX_DISK_SIZE; } @@ -284,14 +284,7 @@ static inline int loop_get_bs(struct loop_device *lo) { - int bs = 0; - - if (blksize_size[MAJOR(lo->lo_device)]) - bs = blksize_size[MAJOR(lo->lo_device)][MINOR(lo->lo_device)]; - if (!bs) - bs = BLOCK_SIZE; - - return bs; + return block_size(lo->lo_device); } static inline unsigned long loop_get_iv(struct loop_device *lo, @@ -386,7 +379,7 @@ */ static int loop_end_io_transfer(struct bio *bio, int nr_sectors) { - struct loop_device *lo = &loop_dev[MINOR(bio->bi_dev)]; + struct loop_device *lo = &loop_dev[minor(bio->bi_dev)]; int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); if (!uptodate || bio_rw(bio) == WRITE) { @@ -436,10 +429,10 @@ unsigned long IV; int rw = bio_rw(rbh); - if (MINOR(rbh->bi_dev) >= max_loop) + if (minor(rbh->bi_dev) >= max_loop) goto out; - lo = &loop_dev[MINOR(rbh->bi_dev)]; + lo = &loop_dev[minor(rbh->bi_dev)]; spin_lock_irq(&lo->lo_lock); if (lo->lo_state != Lo_bound) goto inactive; @@ -525,7 +518,7 @@ ret = do_bio_blockbacked(lo, bio, rbh); - bio_endio(rbh, !ret, bio_sectors(bio)); + bio_endio(rbh, !ret, bio_sectors(rbh)); loop_put_buffer(bio); } } @@ -551,14 +544,15 @@ flush_signals(current); spin_unlock_irq(¤t->sigmask_lock); - current->policy = SCHED_OTHER; - current->nice = -20; + set_user_nice(current, -20); spin_lock_irq(&lo->lo_lock); lo->lo_state = Lo_bound; atomic_inc(&lo->lo_pending); spin_unlock_irq(&lo->lo_lock); + current->flags |= PF_NOIO; + /* * up sem, we are running */ @@ -600,7 +594,6 @@ kdev_t lo_device; int lo_flags = 0; int error; - int bs; MOD_INC_USE_COUNT; @@ -621,6 +614,10 @@ if (S_ISBLK(inode->i_mode)) { lo_device = inode->i_rdev; + if (kdev_same(lo_device, dev)) { + error = -EBUSY; + goto out; + } } else if (S_ISREG(inode->i_mode)) { struct address_space_operations *aops = inode->i_mapping->a_ops; /* @@ -656,13 +653,7 @@ lo->old_gfp_mask = inode->i_mapping->gfp_mask; inode->i_mapping->gfp_mask = GFP_NOIO; - bs = 0; - if (blksize_size[MAJOR(lo_device)]) - bs = blksize_size[MAJOR(lo_device)][MINOR(lo_device)]; - if (!bs) - bs = BLOCK_SIZE; - - set_blocksize(dev, bs); + set_blocksize(dev, block_size(lo_device)); lo->lo_bio = lo->lo_biotail = NULL; kernel_thread(loop_thread, lo, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); @@ -733,7 +724,7 @@ loop_release_xfer(lo); lo->transfer = NULL; lo->ioctl = NULL; - lo->lo_device = 0; + lo->lo_device = NODEV; lo->lo_encrypt_type = 0; lo->lo_offset = 0; lo->lo_encrypt_key_size = 0; @@ -826,12 +817,12 @@ if (!inode) return -EINVAL; - if (MAJOR(inode->i_rdev) != MAJOR_NR) { + if (major(inode->i_rdev) != MAJOR_NR) { printk(KERN_WARNING "lo_ioctl: pseudo-major != %d\n", MAJOR_NR); return -ENODEV; } - dev = MINOR(inode->i_rdev); + dev = minor(inode->i_rdev); if (dev >= max_loop) return -ENODEV; lo = &loop_dev[dev]; @@ -881,11 +872,11 @@ if (!inode) return -EINVAL; - if (MAJOR(inode->i_rdev) != MAJOR_NR) { + if (major(inode->i_rdev) != MAJOR_NR) { printk(KERN_WARNING "lo_open: pseudo-major != %d\n", MAJOR_NR); return -ENODEV; } - dev = MINOR(inode->i_rdev); + dev = minor(inode->i_rdev); if (dev >= max_loop) return -ENODEV; @@ -908,12 +899,12 @@ if (!inode) return 0; - if (MAJOR(inode->i_rdev) != MAJOR_NR) { + if (major(inode->i_rdev) != MAJOR_NR) { printk(KERN_WARNING "lo_release: pseudo-major != %d\n", MAJOR_NR); return 0; } - dev = MINOR(inode->i_rdev); + dev = minor(inode->i_rdev); if (dev >= max_loop) return 0; @@ -1007,6 +998,7 @@ goto out_mem; blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), loop_make_request); + blk_queue_bounce_limit(BLK_DEFAULT_QUEUE(MAJOR_NR), BLK_BOUNCE_HIGH); for (i = 0; i < max_loop; i++) { struct loop_device *lo = &loop_dev[i]; @@ -1023,7 +1015,7 @@ blk_size[MAJOR_NR] = loop_sizes; blksize_size[MAJOR_NR] = loop_blksizes; for (i = 0; i < max_loop; i++) - register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &lo_fops, 0); + register_disk(NULL, mk_kdev(MAJOR_NR, i), 1, &lo_fops, 0); printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/nbd.c linux-2.5/drivers/block/nbd.c --- linux-2.5.1/drivers/block/nbd.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/nbd.c Fri Jan 4 22:46:50 2002 @@ -45,7 +45,6 @@ #include <linux/devfs_fs_kernel.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <asm/types.h> @@ -79,7 +78,7 @@ if (!inode) return -EINVAL; - dev = MINOR(inode->i_rdev); + dev = minor(inode->i_rdev); if (dev >= MAX_NBD) return -ENODEV; @@ -254,7 +253,7 @@ if (req != blkdev_entry_prev_request(&lo->queue_head)) { printk(KERN_ALERT "NBD: I have problem...\n"); } - if (lo != &nbd_dev[MINOR(req->rq_dev)]) { + if (lo != &nbd_dev[minor(req->rq_dev)]) { printk(KERN_ALERT "NBD: request corrupted!\n"); continue; } @@ -292,7 +291,7 @@ printk( KERN_ALERT "NBD: panic, panic, panic\n" ); break; } - if (lo != &nbd_dev[MINOR(req->rq_dev)]) { + if (lo != &nbd_dev[minor(req->rq_dev)]) { printk(KERN_ALERT "NBD: request corrupted when clearing!\n"); continue; } @@ -327,9 +326,9 @@ req = CURRENT; #ifdef PARANOIA if (!req) - FAIL("que not empty but no request?"); + FAIL("queue not empty but no request?"); #endif - dev = MINOR(req->rq_dev); + dev = minor(req->rq_dev); #ifdef PARANOIA if (dev >= MAX_NBD) FAIL("Minor too big."); /* Probably can not happen */ @@ -382,7 +381,7 @@ return -EPERM; if (!inode) return -EINVAL; - dev = MINOR(inode->i_rdev); + dev = minor(inode->i_rdev); if (dev >= MAX_NBD) return -ENODEV; @@ -474,7 +473,7 @@ if (!inode) return -ENODEV; - dev = MINOR(inode->i_rdev); + dev = minor(inode->i_rdev); if (dev >= MAX_NBD) return -ENODEV; lo = &nbd_dev[dev]; @@ -529,7 +528,7 @@ nbd_blksize_bits[i] = 10; nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */ nbd_sizes[i] = nbd_bytesizes[i] >> BLOCK_SIZE_BITS; - register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops, + register_disk(NULL, mk_kdev(MAJOR_NR,i), 1, &nbd_fops, nbd_bytesizes[i]>>9); } devfs_handle = devfs_mk_dir (NULL, "nbd", NULL); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/paride/Config.in linux-2.5/drivers/block/paride/Config.in --- linux-2.5.1/drivers/block/paride/Config.in Thu Oct 25 07:07:39 2001 +++ linux-2.5/drivers/block/paride/Config.in Thu Dec 13 16:32:35 2001 @@ -29,7 +29,7 @@ dep_tristate ' Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE if [ "$CONFIG_PARIDE_EPAT" != "n" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Support c7/c8 chips (EXPERIMENTAL)' CONFIG_PARIDE_EPATC8 $CONFIG_PARIDE + bool ' Support c7/c8 chips (EXPERIMENTAL)' CONFIG_PARIDE_EPATC8 fi fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/paride/pcd.c linux-2.5/drivers/block/paride/pcd.c --- linux-2.5.1/drivers/block/paride/pcd.c Wed Dec 12 21:51:57 2001 +++ linux-2.5/drivers/block/paride/pcd.c Sat Jan 5 16:38:08 2002 @@ -182,7 +182,7 @@ #define MAJOR_NR major #define DEVICE_NAME "PCD" #define DEVICE_REQUEST do_pcd_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #define DEVICE_ON(device) #define DEVICE_OFF(device) @@ -325,7 +325,7 @@ PCD.info.ops = &pcd_dops; PCD.info.handle = NULL; - PCD.info.dev = MKDEV(major,unit); + PCD.info.dev = mk_kdev(major,unit); PCD.info.speed = 0; PCD.info.capacity = 1; PCD.info.mask = 0; @@ -771,7 +771,7 @@ if (QUEUE_EMPTY || (CURRENT->rq_status == RQ_INACTIVE)) return; INIT_REQUEST; if (rq_data_dir(CURRENT) == READ) { - unit = MINOR(CURRENT->rq_dev); + unit = minor(CURRENT->rq_dev); if (unit != pcd_unit) { pcd_bufblk = -1; pcd_unit = unit; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/paride/pd.c linux-2.5/drivers/block/paride/pd.c --- linux-2.5.1/drivers/block/paride/pd.c Sun Dec 16 23:38:31 2001 +++ linux-2.5/drivers/block/paride/pd.c Sat Jan 5 16:38:08 2002 @@ -206,7 +206,7 @@ #define MAJOR_NR major #define DEVICE_NAME "PD" #define DEVICE_REQUEST do_pd_request -#define DEVICE_NR(device) (MINOR(device)>>PD_BITS) +#define DEVICE_NR(device) (minor(device)>>PD_BITS) #define DEVICE_ON(device) #define DEVICE_OFF(device) @@ -347,7 +347,6 @@ major: PD_MAJOR, major_name: PD_NAME, minor_shift: PD_BITS, - max_p: PD_PARTNS, part: pd_hd, sizes: pd_sizes, fops: &pd_fops, @@ -446,7 +445,7 @@ struct hd_geometry *geo = (struct hd_geometry *) arg; int err, unit; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; unit = DEVICE_NR(inode->i_rdev); if (!PD.present) @@ -815,7 +814,7 @@ } else pi_release(PI); } for (unit=0;unit<PD_UNITS;unit++) - register_disk(&pd_gendisk,MKDEV(MAJOR_NR,unit<<PD_BITS), + register_disk(&pd_gendisk,mk_kdev(MAJOR_NR,unit<<PD_BITS), PD_PARTNS,&pd_fops, PD.present?PD.capacity:0); @@ -848,7 +847,7 @@ if (QUEUE_EMPTY || (CURRENT->rq_status == RQ_INACTIVE)) return; INIT_REQUEST; - pd_dev = MINOR(CURRENT->rq_dev); + pd_dev = minor(CURRENT->rq_dev); pd_unit = unit = DEVICE_NR(CURRENT->rq_dev); pd_block = CURRENT->sector; pd_run = CURRENT->nr_sectors; @@ -887,7 +886,7 @@ if (QUEUE_EMPTY || (rq_data_dir(CURRENT) != pd_cmd) || - (MINOR(CURRENT->rq_dev) != pd_dev) || + (minor(CURRENT->rq_dev) != pd_dev) || (CURRENT->rq_status == RQ_INACTIVE) || (CURRENT->sector != pd_block)) printk("%s: OUCH: request list changed unexpectedly\n", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/paride/pf.c linux-2.5/drivers/block/paride/pf.c --- linux-2.5.1/drivers/block/paride/pf.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/paride/pf.c Sat Jan 5 16:38:08 2002 @@ -202,7 +202,7 @@ #define MAJOR_NR major #define DEVICE_NAME "PF" #define DEVICE_REQUEST do_pf_request -#define DEVICE_NR(device) MINOR(device) +#define DEVICE_NR(device) minor(device) #define DEVICE_ON(device) #define DEVICE_OFF(device) @@ -368,7 +368,7 @@ for (i=0;i<PF_UNITS;i++) pf_blocksizes[i] = 1024; blksize_size[MAJOR_NR] = pf_blocksizes; for (i=0;i<PF_UNITS;i++) - register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &pf_fops, 0); + register_disk(NULL, mk_kdev(MAJOR_NR, i), 1, &pf_fops, 0); return 0; } @@ -399,7 +399,7 @@ { int err, unit; struct hd_geometry *geo = (struct hd_geometry *) arg; - if ((!inode) || (!inode->i_rdev)) return -EINVAL; + if ((!inode) || kdev_none(inode->i_rdev)) return -EINVAL; unit = DEVICE_NR(inode->i_rdev); if (unit >= PF_UNITS) return -EINVAL; if (!PF.present) return -ENODEV; @@ -684,7 +684,8 @@ for (k=0;k<len;k++) if((buf[k+offs]!=0x20)||(buf[k+offs]!=l)) l=targ[j++]=buf[k+offs]; - if (l==0x20) j--; targ[j]=0; + if (l==0x20) j--; + targ[j]=0; } static int xl( char *buf, int offs ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/paride/pg.c linux-2.5/drivers/block/paride/pg.c --- linux-2.5.1/drivers/block/paride/pg.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/block/paride/pg.c Sat Jan 5 16:38:08 2002 @@ -491,7 +491,8 @@ for (k=0;k<len;k++) if((buf[k+offs]!=0x20)||(buf[k+offs]!=l)) l=targ[j++]=buf[k+offs]; - if (l==0x20) j--; targ[j]=0; + if (l==0x20) j--; + targ[j]=0; } static int pg_identify( int unit, int log ) @@ -565,7 +566,7 @@ return -1; } -#define DEVICE_NR(dev) (MINOR(dev) % 128) +#define DEVICE_NR(dev) (minor(dev) & 0x7F) static int pg_open (struct inode *inode, struct file *file) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/paride/pseudo.h linux-2.5/drivers/block/paride/pseudo.h --- linux-2.5.1/drivers/block/paride/pseudo.h Sun Feb 4 18:05:29 2001 +++ linux-2.5/drivers/block/paride/pseudo.h Mon Jan 7 18:58:40 2002 @@ -102,7 +102,7 @@ spin_unlock_irqrestore(&ps_spinlock,flags); return; } - if (!ps_ready || ps_ready() || (jiffies >= ps_timeout)) { + if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) { ps_continuation = NULL; spin_unlock_irqrestore(&ps_spinlock,flags); con(); @@ -131,7 +131,7 @@ spin_unlock_irqrestore(&ps_spinlock,flags); return; } - if (!ps_ready || ps_ready() || (jiffies >= ps_timeout)) { + if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) { ps_continuation = NULL; spin_unlock_irqrestore(&ps_spinlock,flags); con(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/paride/pt.c linux-2.5/drivers/block/paride/pt.c --- linux-2.5.1/drivers/block/paride/pt.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/block/paride/pt.c Sat Jan 5 16:38:08 2002 @@ -577,7 +577,8 @@ for (k=0;k<len;k++) if((buf[k+offs]!=0x20)||(buf[k+offs]!=l)) l=targ[j++]=buf[k+offs]; - if (l==0x20) j--; targ[j]=0; + if (l==0x20) j--; + targ[j]=0; } static int xn( char *buf, int offs, int size ) @@ -688,7 +689,7 @@ return -1; } -#define DEVICE_NR(dev) (MINOR(dev) % 128) +#define DEVICE_NR(dev) (minor(dev) & 0x7F) static int pt_open (struct inode *inode, struct file *file) @@ -713,7 +714,7 @@ return -EROFS; } - if (!(MINOR(inode->i_rdev) & 128)) + if (!(minor(inode->i_rdev) & 128)) PT.flags |= PT_REWIND; PT.bufptr = kmalloc(PT_BUFSIZE,GFP_KERNEL); @@ -732,7 +733,7 @@ int unit; struct mtop mtop; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; unit = DEVICE_NR(inode->i_rdev); if (unit >= PT_UNITS) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/ps2esdi.c linux-2.5/drivers/block/ps2esdi.c --- linux-2.5.1/drivers/block/ps2esdi.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/ps2esdi.c Mon Jan 7 19:11:32 2002 @@ -51,7 +51,6 @@ #include <asm/system.h> #include <asm/io.h> -#include <asm/segment.h> #include <asm/dma.h> #include <asm/mca_dma.h> #include <asm/uaccess.h> @@ -161,10 +160,8 @@ major: MAJOR_NR, major_name: "ed", minor_shift: 6, - max_p: 1 << 6, part: ps2esdi, sizes: ps2esdi_sizes, - real_devices: (void *)ps2esdi_info, fops: &ps2esdi_fops, }; @@ -425,7 +422,7 @@ blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 128); for (i = 0; i < ps2esdi_drives; i++) { - register_disk(&ps2esdi_gendisk,MKDEV(MAJOR_NR,i<<6),1<<6, + register_disk(&ps2esdi_gendisk,mk_kdev(MAJOR_NR,i<<6),1<<6, &ps2esdi_fops, ps2esdi_info[i].head * ps2esdi_info[i].sect * ps2esdi_info[i].cyl); @@ -484,7 +481,7 @@ } /* check for above 16Mb dmas */ else if ((CURRENT_DEV < ps2esdi_drives) && (CURRENT->sector + CURRENT->current_nr_sectors <= - ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects) && + ps2esdi[minor(CURRENT->rq_dev)].nr_sects) && CURRENT->flags & REQ_CMD) { #if 0 printk("%s:got request. device : %d minor : %d command : %d sector : %ld count : %ld\n", @@ -513,7 +510,7 @@ /* is request is valid */ else { printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives, - CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects); + CURRENT->sector, ps2esdi[minor(CURRENT->rq_dev)].nr_sects); end_request(FAIL); } @@ -953,10 +950,10 @@ break; } if(ending != -1) { - spin_lock_irqsave(ps2esdi_LOCK, flags); + spin_lock_irqsave(&ps2esdi_lock, flags); end_request(ending); do_ps2esdi_request(BLK_DEFAULT_QUEUE(MAJOR_NR)); - spin_unlock_irqrestore(ps2esdi_LOCK, flags); + spin_unlock_irqrestore(&ps2esdi_lock, flags); } } /* handle interrupts */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/rd.c linux-2.5/drivers/block/rd.c --- linux-2.5.1/drivers/block/rd.c Wed Dec 12 17:28:27 2001 +++ linux-2.5/drivers/block/rd.c Sun Jan 13 22:56:03 2002 @@ -43,26 +43,12 @@ */ #include <linux/config.h> -#include <linux/sched.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/hdreg.h> #include <linux/string.h> -#include <linux/mm.h> -#include <linux/mman.h> #include <linux/slab.h> -#include <linux/ioctl.h> -#include <linux/fd.h> #include <linux/module.h> #include <linux/init.h> #include <linux/devfs_fs_kernel.h> -#include <linux/smp_lock.h> - -#include <asm/system.h> #include <asm/uaccess.h> -#include <asm/byteorder.h> - -extern void wait_for_keypress(void); /* * 35 has been officially registered as the RAMDISK major number, but @@ -79,6 +65,8 @@ #ifdef CONFIG_BLK_DEV_INITRD static int initrd_users; static spinlock_t initrd_users_lock = SPIN_LOCK_UNLOCKED; +unsigned long initrd_start, initrd_end; +int initrd_below_start_ok; #endif /* Various static variables go here. Most are used only in the RAM disk code. @@ -99,7 +87,7 @@ */ int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */ /* - * It would be very desiderable to have a soft-blocksize (that in the case + * It would be very desirable to have a soft-blocksize (that in the case * of the ramdisk driver is also the hardblocksize ;) of PAGE_SIZE because * doing that we'll achieve a far better MM footprint. Using a rd_blocksize of * BLOCK_SIZE in the worst case we'll make PAGE_SIZE/BLOCK_SIZE buffer-pages @@ -111,95 +99,49 @@ */ int rd_blocksize = BLOCK_SIZE; /* blocksize of the RAM disks */ -#ifndef MODULE - -int rd_doload; /* 1 = load RAM disk, 0 = don't load */ -int rd_prompt = 1; /* 1 = prompt for RAM disk, 0 = don't prompt */ -int rd_image_start; /* starting block # of image */ -#ifdef CONFIG_BLK_DEV_INITRD -unsigned long initrd_start, initrd_end; -int mount_initrd = 1; /* zero if initrd should not be mounted */ -int initrd_below_start_ok; - -static int __init no_initrd(char *str) -{ - mount_initrd = 0; - return 1; -} - -__setup("noinitrd", no_initrd); - -#endif - -static int __init ramdisk_start_setup(char *str) -{ - rd_image_start = simple_strtol(str,NULL,0); - return 1; -} - -static int __init load_ramdisk(char *str) -{ - rd_doload = simple_strtol(str,NULL,0) & 3; - return 1; -} - -static int __init prompt_ramdisk(char *str) -{ - rd_prompt = simple_strtol(str,NULL,0) & 1; - return 1; -} - -static int __init ramdisk_size(char *str) -{ - rd_size = simple_strtol(str,NULL,0); - return 1; -} - -static int __init ramdisk_size2(char *str) -{ - return ramdisk_size(str); -} - -static int __init ramdisk_blocksize(char *str) -{ - rd_blocksize = simple_strtol(str,NULL,0); - return 1; -} - -__setup("ramdisk_start=", ramdisk_start_setup); -__setup("load_ramdisk=", load_ramdisk); -__setup("prompt_ramdisk=", prompt_ramdisk); -__setup("ramdisk=", ramdisk_size); -__setup("ramdisk_size=", ramdisk_size2); -__setup("ramdisk_blocksize=", ramdisk_blocksize); - -#endif - /* * Copyright (C) 2000 Linus Torvalds. * 2000 Transmeta Corp. * aops copied from ramfs. */ -static int ramdisk_readpage(struct file *file, struct page * page) +static void ramdisk_updatepage(struct page * page, int need_kmap) { if (!Page_Uptodate(page)) { - memset(kmap(page), 0, PAGE_CACHE_SIZE); - kunmap(page); + struct buffer_head *bh = page->buffers; + void * address; + + if (need_kmap) + kmap(page); + address = page_address(page); + if (bh) { + struct buffer_head *tmp = bh; + do { + if (!buffer_uptodate(tmp)) { + memset(address, 0, tmp->b_size); + mark_buffer_uptodate(tmp, 1); + } + address += tmp->b_size; + tmp = tmp->b_this_page; + } while (tmp != bh); + } else + memset(address, 0, PAGE_CACHE_SIZE); + if (need_kmap) + kunmap(page); flush_dcache_page(page); SetPageUptodate(page); } +} + +static int ramdisk_readpage(struct file *file, struct page * page) +{ + ramdisk_updatepage(page, 1); UnlockPage(page); return 0; } static int ramdisk_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { - if (!Page_Uptodate(page)) { - void *addr = page_address(page); - memset(addr, 0, PAGE_CACHE_SIZE); - flush_dcache_page(page); - SetPageUptodate(page); - } + ramdisk_updatepage(page, 0); SetPageDirty(page); return 0; } @@ -226,40 +168,37 @@ err = 0; mapping = rd_bdev[minor]->bd_inode->i_mapping; + /* writing a buffer cache not uptodate must not clear it */ + if (sbh->b_page->mapping == mapping) { + if (rw == WRITE) { + mark_buffer_uptodate(sbh, 1); + SetPageDirty(sbh->b_page); + } + goto out; + } + index = sector >> (PAGE_CACHE_SHIFT - 9); offset = (sector << 9) & ~PAGE_CACHE_MASK; size = vec->bv_len; do { int count; - struct page ** hash; struct page * page; char * src, * dst; - int unlock = 0; count = PAGE_CACHE_SIZE - offset; if (count > size) count = size; size -= count; - hash = page_hash(mapping, index); - page = __find_get_page(mapping, index, hash); + page = grab_cache_page(mapping, index); if (!page) { - page = grab_cache_page(mapping, index); err = -ENOMEM; - if (!page) - goto out; - err = 0; - - if (!Page_Uptodate(page)) { - memset(kmap(page), 0, PAGE_CACHE_SIZE); - kunmap(page); - SetPageUptodate(page); - } - - unlock = 1; + goto out; } + ramdisk_updatepage(page, 1); + index++; if (rw == READ) { @@ -283,8 +222,7 @@ } else { SetPageDirty(page); } - if (unlock) - UnlockPage(page); + UnlockPage(page); __free_page(page); } while (size); @@ -322,7 +260,7 @@ unsigned long offset, len; int rw = sbh->bi_rw; - minor = MINOR(sbh->bi_dev); + minor = minor(sbh->bi_dev); if (minor >= NUM_RAMDISKS) goto fail; @@ -356,10 +294,10 @@ int error = -EINVAL; unsigned int minor; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) goto out; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); switch (cmd) { case BLKFLSBUF: @@ -483,7 +421,7 @@ rd_bdev[i] = NULL; if (bdev) blkdev_put(bdev, BDEV_FILE); - destroy_buffers(MKDEV(MAJOR_NR, i)); + destroy_buffers(mk_kdev(MAJOR_NR, i)); } devfs_unregister (devfs_handle); @@ -492,7 +430,7 @@ } /* This is the registration and initialization section of the RAM disk driver */ -int __init rd_init (void) +static int __init rd_init (void) { int i; @@ -525,11 +463,11 @@ &rd_bd_op, NULL); for (i = 0; i < NUM_RAMDISKS; i++) - register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &rd_bd_op, rd_size<<1); + register_disk(NULL, mk_kdev(MAJOR_NR,i), 1, &rd_bd_op, rd_size<<1); #ifdef CONFIG_BLK_DEV_INITRD /* We ought to separate initrd operations here */ - register_disk(NULL, MKDEV(MAJOR_NR,INITRD_MINOR), 1, &rd_bd_op, rd_size<<1); + register_disk(NULL, mk_kdev(MAJOR_NR,INITRD_MINOR), 1, &rd_bd_op, rd_size<<1); devfs_register(devfs_handle, "initrd", DEVFS_FL_DEFAULT, MAJOR_NR, INITRD_MINOR, S_IFBLK | S_IRUSR, &rd_bd_op, NULL); #endif @@ -548,7 +486,28 @@ module_init(rd_init); module_exit(rd_cleanup); -/* loadable module support */ +/* options - nonmodular */ +#ifndef MODULE +static int __init ramdisk_size(char *str) +{ + rd_size = simple_strtol(str,NULL,0); + return 1; +} +static int __init ramdisk_size2(char *str) /* kludge */ +{ + return ramdisk_size(str); +} +static int __init ramdisk_blocksize(char *str) +{ + rd_blocksize = simple_strtol(str,NULL,0); + return 1; +} +__setup("ramdisk=", ramdisk_size); +__setup("ramdisk_size=", ramdisk_size2); +__setup("ramdisk_blocksize=", ramdisk_blocksize); +#endif + +/* options - modular */ MODULE_PARM (rd_size, "1i"); MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes."); MODULE_PARM (rd_blocksize, "i"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/swim3.c linux-2.5/drivers/block/swim3.c --- linux-2.5.1/drivers/block/swim3.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/drivers/block/swim3.c Thu Dec 27 16:32:31 2001 @@ -29,14 +29,15 @@ #include <asm/prom.h> #include <asm/uaccess.h> #include <asm/mediabay.h> -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #define MAJOR_NR FLOPPY_MAJOR #include <linux/blk.h> #include <linux/devfs_fs_kernel.h> static int floppy_blocksizes[2] = {512,512}; -static int floppy_sizes[2] = {2880,2880}; +static int floppy_sizes[2] = {1440,1440}; #define MAX_FLOPPIES 2 @@ -445,9 +446,9 @@ ++cp; init_dma(cp, OUTPUT_MORE, CURRENT->buffer, 512); ++cp; - init_dma(cp, OUTPUT_MORE, write_postamble, sizeof(write_postamble)); + init_dma(cp, OUTPUT_LAST, write_postamble, sizeof(write_postamble)); } else { - init_dma(cp, INPUT_MORE, CURRENT->buffer, n * 512); + init_dma(cp, INPUT_LAST, CURRENT->buffer, n * 512); } ++cp; out_le16(&cp->command, DBDMA_STOP); @@ -679,7 +680,10 @@ break; dr = fs->dma; cp = fs->dma_cmd; - st_le32(&dr->control, RUN << 16); + /* We must wait a bit for dbdma to complete */ + for (n=0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++) + udelay(10); + DBDMA_DO_STOP(dr); out_8(&sw->intr_enable, 0); out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); @@ -1061,9 +1065,14 @@ return -EINVAL; } + if (!request_OF_resource(swim, 0, NULL)) { + printk(KERN_INFO "swim3: can't request IO resource !\n"); + return -EINVAL; + } + mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ? swim->parent : NULL; if (mediabay == NULL) - feature_set(swim, FEATURE_SWIM3_enable); + pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1); memset(fs, 0, sizeof(*fs)); fs->state = idle; @@ -1085,14 +1094,14 @@ if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) { printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr); - feature_clear(swim, FEATURE_SWIM3_enable); + pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0); return -EBUSY; } /* if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) { printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA", fs->dma_intr); - feature_clear(swim, FEATURE_SWIM3_enable); + pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0); return -EBUSY; } */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/block/xd.c linux-2.5/drivers/block/xd.c --- linux-2.5.1/drivers/block/xd.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/block/xd.c Sat Jan 5 16:38:08 2002 @@ -130,10 +130,8 @@ major: MAJOR_NR, major_name: "xd", minor_shift: 6, - max_p: 1 << 6, part: xd_struct, sizes: xd_sizes, - real_devices: (void *)xd_info, fops: &xd_fops, }; @@ -251,7 +249,8 @@ for (i = 0; i < xd_drives; i++) { xd_valid[i] = 1; - register_disk(&xd_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6, &xd_fops, + register_disk(&xd_gendisk, mk_kdev(MAJOR_NR,i<<6), 1<<6, + &xd_fops, xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors); } @@ -289,8 +288,9 @@ INIT_REQUEST; /* do some checking on the request structure */ if (CURRENT_DEV < xd_drives + && (CURRENT->flags & REQ_CMD) && CURRENT->sector + CURRENT->nr_sectors - <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) { + <= xd_struct[minor(CURRENT->rq_dev)].nr_sects) { block = CURRENT->sector; count = CURRENT->nr_sectors; @@ -314,7 +314,7 @@ { int dev; - if ((!inode) || !(inode->i_rdev)) + if ((!inode) || kdev_none(inode->i_rdev)) return -EINVAL; dev = DEVICE_NR(inode->i_rdev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/bluetooth/hci_usb.c linux-2.5/drivers/bluetooth/hci_usb.c --- linux-2.5.1/drivers/bluetooth/hci_usb.c Fri Sep 7 16:28:38 2001 +++ linux-2.5/drivers/bluetooth/hci_usb.c Tue Jan 8 00:44:24 2002 @@ -437,18 +437,18 @@ static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb) { struct urb *urb = husb->ctrl_urb; - devrequest *dr = &husb->dev_req; + struct usb_ctrlrequest *dr = &husb->dev_req; int pipe, status; DBG("%s len %d", husb->hdev.name, skb->len); pipe = usb_sndctrlpipe(husb->udev, 0); - dr->requesttype = HCI_CTRL_REQ; - dr->request = 0; - dr->index = 0; - dr->value = 0; - dr->length = cpu_to_le16(skb->len); + dr->bRequestType = HCI_CTRL_REQ; + dr->bRequest = 0; + dr->wIndex = 0; + dr->wValue = 0; + dr->wLength = cpu_to_le16(skb->len); FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len, hci_usb_ctrl, skb); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/aztcd.c linux-2.5/drivers/cdrom/aztcd.c --- linux-2.5.1/drivers/cdrom/aztcd.c Thu Oct 25 20:58:35 2001 +++ linux-2.5/drivers/cdrom/aztcd.c Sat Jan 5 16:38:08 2002 @@ -229,7 +229,7 @@ #endif #define CURRENT_VALID \ - (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \ + (!QUEUE_EMPTY && major(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \ && CURRENT -> sector != -1) #define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA) @@ -309,6 +309,8 @@ static unsigned long aztTimeOutCount; static int aztCmd = 0; +static spinlock_t aztSpin = SPIN_LOCK_UNLOCKED; + /*########################################################################### Function Prototypes ########################################################################### @@ -1599,10 +1601,6 @@ } azt_transfer_is_active = 1; while (CURRENT_VALID) { - if (CURRENT->bh) { - if (!buffer_locked(CURRENT->bh)) - panic(DEVICE_NAME ": block not locked"); - } azt_transfer(); if (CURRENT->nr_sectors == 0) { end_request(1); @@ -1927,10 +1925,10 @@ MAJOR_NR); return -EIO; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &aztSpin); blksize_size[MAJOR_NR] = aztcd_blocksizes; read_ahead[MAJOR_NR] = 4; - register_disk(NULL, MKDEV(MAJOR_NR, 0), 1, &azt_fops, 0); + register_disk(NULL, mk_kdev(MAJOR_NR, 0), 1, &azt_fops, 0); if ((azt_port == 0x1f0) || (azt_port == 0x170)) request_region(azt_port, 8, "aztcd"); /*IDE-interface */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/cdrom.c linux-2.5/drivers/cdrom/cdrom.c --- linux-2.5.1/drivers/cdrom/cdrom.c Thu Dec 6 22:02:56 2001 +++ linux-2.5/drivers/cdrom/cdrom.c Tue Jan 1 23:42:41 2002 @@ -266,7 +266,6 @@ #include <linux/init.h> #include <asm/fcntl.h> -#include <asm/segment.h> #include <asm/uaccess.h> /* used to tell the module to turn on full debugging messages */ @@ -338,7 +337,7 @@ int register_cdrom(struct cdrom_device_info *cdi) { static char banner_printed; - int major = MAJOR(cdi->dev); + int major = major(cdi->dev); struct cdrom_device_ops *cdo = cdi->ops; int *change_capability = (int *)&cdo->capability; /* hack */ @@ -409,7 +408,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) { struct cdrom_device_info *cdi, *prev; - int major = MAJOR(unreg->dev); + int major = major(unreg->dev); cdinfo(CD_OPEN, "entering unregister_cdrom\n"); @@ -418,7 +417,7 @@ prev = NULL; cdi = topCdromPtr; - while (cdi != NULL && cdi->dev != unreg->dev) { + while (cdi != NULL && !kdev_same(cdi->dev, unreg->dev)) { prev = cdi; cdi = cdi->next; } @@ -441,7 +440,7 @@ struct cdrom_device_info *cdi; cdi = topCdromPtr; - while (cdi != NULL && cdi->dev != dev) + while (cdi != NULL && !kdev_same(cdi->dev, dev)) cdi = cdi->next; return cdi; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/cdu31a.c linux-2.5/drivers/cdrom/cdu31a.c --- linux-2.5.1/drivers/cdrom/cdu31a.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/cdrom/cdu31a.c Sat Jan 5 16:38:08 2002 @@ -237,6 +237,7 @@ static volatile unsigned short sony_cd_read_reg; static volatile unsigned short sony_cd_fifost_reg; +static spinlock_t cdu31a_lock = SPIN_LOCK_UNLOCKED; /* queue lock */ static int sony_spun_up = 0; /* Has the drive been spun up? */ @@ -1586,7 +1587,7 @@ /* * jens: driver has lots of races */ - spin_unlock_irq(&q->queue_lock); + spin_unlock_irq(q->queue_lock); /* Make sure the timer is cancelled. */ del_timer(&cdu31a_abort_timer); @@ -1605,17 +1606,7 @@ scd_spinup(); } - /* I don't use INIT_REQUEST because it calls return, which would - return without unlocking the device. It shouldn't matter, - but just to be safe... */ - if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) { - panic(DEVICE_NAME ": request list destroyed"); - } - if (CURRENT->bh) { - if (!buffer_locked(CURRENT->bh)) { - panic(DEVICE_NAME ": block not locked"); - } - } + INIT_REQUEST; block = CURRENT->sector; nblock = CURRENT->nr_sectors; @@ -1626,114 +1617,107 @@ goto cdu31a_request_startover; } - switch (CURRENT->cmd) { - case READ: - /* - * If the block address is invalid or the request goes beyond the end of - * the media, return an error. - */ -#if 0 - if ((block / 4) < sony_toc.start_track_lba) { - printk - ("CDU31A: Request before beginning of media\n"); - end_request(0); - goto cdu31a_request_startover; - } -#endif - if ((block / 4) >= sony_toc.lead_out_start_lba) { - printk - ("CDU31A: Request past end of media\n"); - end_request(0); - goto cdu31a_request_startover; - } - if (((block + nblock) / 4) >= - sony_toc.lead_out_start_lba) { - printk - ("CDU31A: Request past end of media\n"); - end_request(0); - goto cdu31a_request_startover; - } - - num_retries = 0; - - try_read_again: - while (handle_sony_cd_attention()); - - if (!sony_toc_read) { - printk("CDU31A: TOC not read\n"); - end_request(0); - goto cdu31a_request_startover; - } - - /* If no data is left to be read from the drive, start the - next request. */ - if (sony_blocks_left == 0) { - if (start_request - (block / 4, CDU31A_READAHEAD / 4, 0)) { - end_request(0); - goto cdu31a_request_startover; - } - } - /* If the requested block is not the next one waiting in - the driver, abort the current operation and start a - new one. */ - else if (block != sony_next_block) { -#if DEBUG - printk - ("CDU31A Warning: Read for block %d, expected %d\n", - block, sony_next_block); -#endif - abort_read(); - if (!sony_toc_read) { - printk("CDU31A: TOC not read\n"); + if(CURRENT->flags & REQ_CMD) { + switch (rq_data_dir(CURRENT)) { + case READ: + /* + * If the block address is invalid or the request goes beyond the end of + * the media, return an error. + */ + if ((block / 4) >= sony_toc.lead_out_start_lba) { + printk + ("CDU31A: Request past end of media\n"); end_request(0); goto cdu31a_request_startover; } - if (start_request - (block / 4, CDU31A_READAHEAD / 4, 0)) { + if (((block + nblock) / 4) >= + sony_toc.lead_out_start_lba) { printk - ("CDU31a: start request failed\n"); + ("CDU31A: Request past end of media\n"); end_request(0); goto cdu31a_request_startover; } - } - read_data_block(CURRENT->buffer, block, nblock, - res_reg, &res_size); - if (res_reg[0] == 0x20) { - if (num_retries > MAX_CDU31A_RETRIES) { + num_retries = 0; + + try_read_again: + while (handle_sony_cd_attention()); + + if (!sony_toc_read) { + printk("CDU31A: TOC not read\n"); end_request(0); goto cdu31a_request_startover; } - num_retries++; - if (res_reg[1] == SONY_NOT_SPIN_ERR) { - do_sony_cd_cmd(SONY_SPIN_UP_CMD, - NULL, 0, res_reg, - &res_size); - } else { + /* If no data is left to be read from the drive, start the + next request. */ + if (sony_blocks_left == 0) { + if (start_request + (block / 4, CDU31A_READAHEAD / 4, 0)) { + end_request(0); + goto cdu31a_request_startover; + } + } + /* If the requested block is not the next one waiting in + the driver, abort the current operation and start a + new one. */ + else if (block != sony_next_block) { +#if DEBUG printk - ("CDU31A: %s error for block %d, nblock %d\n", - translate_error(res_reg[1]), - block, nblock); + ("CDU31A Warning: Read for block %d, expected %d\n", + block, sony_next_block); +#endif + abort_read(); + if (!sony_toc_read) { + printk("CDU31A: TOC not read\n"); + end_request(0); + goto cdu31a_request_startover; + } + if (start_request + (block / 4, CDU31A_READAHEAD / 4, 0)) { + printk + ("CDU31a: start request failed\n"); + end_request(0); + goto cdu31a_request_startover; + } } - goto try_read_again; - } else { - end_request(1); - } - break; - case WRITE: - end_request(0); - break; + read_data_block(CURRENT->buffer, block, nblock, + res_reg, &res_size); + if (res_reg[0] == 0x20) { + if (num_retries > MAX_CDU31A_RETRIES) { + end_request(0); + goto cdu31a_request_startover; + } - default: - panic("CDU31A: Unknown cmd"); + num_retries++; + if (res_reg[1] == SONY_NOT_SPIN_ERR) { + do_sony_cd_cmd(SONY_SPIN_UP_CMD, + NULL, 0, res_reg, + &res_size); + } else { + printk + ("CDU31A: %s error for block %d, nblock %d\n", + translate_error(res_reg[1]), + block, nblock); + } + goto try_read_again; + } else { + end_request(1); + } + break; + + case WRITE: + end_request(0); + break; + + default: + panic("CDU31A: Unknown cmd"); + } } } - end_do_cdu31a_request: - spin_lock_irq(&q->queue_lock); + spin_lock_irq(q->queue_lock); #if 0 /* After finished, cancel any pending operations. */ abort_read(); @@ -3456,7 +3440,8 @@ strcmp("CD-ROM CDU31A", drive_config.product_id) == 0; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), - DEVICE_REQUEST); + DEVICE_REQUEST, + &cdu31a_lock); read_ahead[MAJOR_NR] = CDU31A_READAHEAD; cdu31a_block_size = 1024; /* 1kB default block size */ /* use 'mount -o block=2048' */ @@ -3465,7 +3450,7 @@ init_timer(&cdu31a_abort_timer); cdu31a_abort_timer.function = handle_abort_timeout; - scd_info.dev = MKDEV(MAJOR_NR, 0); + scd_info.dev = mk_kdev(MAJOR_NR, 0); scd_info.mask = deficiency; strncpy(scd_info.name, "cdu31a", sizeof(scd_info.name)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/cm206.c linux-2.5/drivers/cdrom/cm206.c --- linux-2.5.1/drivers/cdrom/cm206.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/cdrom/cm206.c Sat Jan 5 16:38:08 2002 @@ -302,6 +302,7 @@ #define PLAY_TO cd->toc[0] /* toc[0] records end-time in play */ static struct cm206_struct *cd; /* the main memory structure */ +static spinlock_t cm206_lock = SPIN_LOCK_UNLOCKED; /* First, we define some polling functions. These are actually only being used in the initialization. */ @@ -866,7 +867,7 @@ end_request(0); continue; } - spin_unlock_irq(&q->queue_lock); + spin_unlock_irq(q->queue_lock); error = 0; for (i = 0; i < CURRENT->nr_sectors; i++) { int e1, e2; @@ -893,7 +894,7 @@ debug(("cm206_request: %d %d\n", e1, e2)); } } - spin_lock_irq(&q->queue_lock); + spin_lock_irq(q->queue_lock); end_request(!error); } } @@ -1491,7 +1492,7 @@ cleanup(3); return -EIO; } - cm206_info.dev = MKDEV(MAJOR_NR, 0); + cm206_info.dev = mk_kdev(MAJOR_NR, 0); if (register_cdrom(&cm206_info) != 0) { printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR); @@ -1499,7 +1500,8 @@ return -EIO; } devfs_plain_cdrom(&cm206_info, &cm206_bdops); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, + &cm206_lock); blksize_size[MAJOR_NR] = cm206_blocksizes; read_ahead[MAJOR_NR] = 16; /* reads ahead what? */ init_bh(CM206_BH, cm206_bh); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/gscd.c linux-2.5/drivers/cdrom/gscd.c --- linux-2.5.1/drivers/cdrom/gscd.c Thu Oct 25 20:58:35 2001 +++ linux-2.5/drivers/cdrom/gscd.c Sat Jan 5 16:38:08 2002 @@ -162,6 +162,7 @@ static int AudioEnd_f; static struct timer_list gscd_timer; +static spinlock_t gscd_lock = SPIN_LOCK_UNLOCKED; static struct block_device_operations gscd_fops = { owner:THIS_MODULE, @@ -180,7 +181,7 @@ int target; - target = MINOR(full_dev); + target = minor(full_dev); if (target > 0) { printk @@ -283,7 +284,7 @@ if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE) goto out; INIT_REQUEST; - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; @@ -296,7 +297,7 @@ goto repeat; } - if (MINOR(CURRENT->rq_dev) != 0) { + if (dev != 0) { printk("GSCD: this version supports only one device\n"); end_request(0); goto repeat; @@ -1019,7 +1020,7 @@ devfs_register(NULL, "gscd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUGO | S_IWUGO, &gscd_fops, NULL); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &gscd_lock); blksize_size[MAJOR_NR] = gscd_blocksizes; read_ahead[MAJOR_NR] = 4; @@ -1027,7 +1028,7 @@ gscdPresent = 1; request_region(gscd_port, 4, "gscd"); - register_disk(NULL, MKDEV(MAJOR_NR, 0), 1, &gscd_fops, 0); + register_disk(NULL, mk_kdev(MAJOR_NR, 0), 1, &gscd_fops, 0); printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n"); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/mcd.c linux-2.5/drivers/cdrom/mcd.c --- linux-2.5.1/drivers/cdrom/mcd.c Thu Oct 25 20:58:35 2001 +++ linux-2.5/drivers/cdrom/mcd.c Sat Jan 5 16:38:08 2002 @@ -123,7 +123,7 @@ #define QUICK_LOOP_COUNT 20 #define CURRENT_VALID \ -(!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \ +(!QUEUE_EMPTY && major(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \ && CURRENT -> sector != -1) #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA) @@ -185,6 +185,7 @@ static void mcd_release(struct cdrom_device_info *cdi); static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr); static int mcd_tray_move(struct cdrom_device_info *cdi, int position); +static spinlock_t mcd_spinlock = SPIN_LOCK_UNLOCKED; int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg); int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr); @@ -617,10 +618,6 @@ mcd_transfer_is_active = 1; while (CURRENT_VALID) { - if (CURRENT->bh) { - if (!buffer_locked(CURRENT->bh)) - panic(DEVICE_NAME ": block not locked"); - } mcd_transfer(); if (CURRENT->nr_sectors == 0) { end_request(1); @@ -1076,7 +1073,8 @@ } blksize_size[MAJOR_NR] = mcd_blocksizes; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, + &mcd_spinlock); read_ahead[MAJOR_NR] = 4; /* check for card */ @@ -1150,7 +1148,7 @@ mcd_invalidate_buffers(); mcdPresent = 1; - mcd_info.dev = MKDEV(MAJOR_NR, 0); + mcd_info.dev = mk_kdev(MAJOR_NR, 0); if (register_cdrom(&mcd_info) != 0) { printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/mcdx.c linux-2.5/drivers/cdrom/mcdx.c --- linux-2.5.1/drivers/cdrom/mcdx.c Thu Oct 25 20:58:35 2001 +++ linux-2.5/drivers/cdrom/mcdx.c Sat Jan 5 16:38:08 2002 @@ -291,6 +291,7 @@ static struct s_drive_stuff *mcdx_irq_map[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static spinlock_t mcdx_lock = SPIN_LOCK_UNLOCKED; MODULE_PARM(mcdx, "1-4i"); static struct cdrom_device_ops mcdx_dops = { @@ -318,7 +319,7 @@ static int mcdx_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) { - struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)]; + struct s_drive_stuff *stuffp = mcdx_stuffp[minor(cdi->dev)]; if (!stuffp->present) return -ENXIO; @@ -575,7 +576,7 @@ INIT_REQUEST; - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); stuffp = mcdx_stuffp[dev]; if ((dev < 0) @@ -598,14 +599,13 @@ xtrace(REQUEST, "do_request() (%lu + %lu)\n", CURRENT->sector, CURRENT->nr_sectors); - switch (CURRENT->cmd) { - case WRITE: - xwarn("do_request(): attempt to write to cd!!\n"); + if (CURRENT->cmd != READ) { + xwarn("do_request(): non-read command to cd!!\n"); xtrace(REQUEST, "end_request(0): write\n"); end_request(0); return; - - case READ: + } + else { stuffp->status = 0; while (CURRENT->nr_sectors) { int i; @@ -628,11 +628,6 @@ xtrace(REQUEST, "end_request(1)\n"); end_request(1); - break; - - default: - panic(MCDX "do_request: unknown command.\n"); - break; } goto again; @@ -642,7 +637,7 @@ { struct s_drive_stuff *stuffp; xtrace(OPENCLOSE, "open()\n"); - stuffp = mcdx_stuffp[MINOR(cdi->dev)]; + stuffp = mcdx_stuffp[minor(cdi->dev)]; if (!stuffp->present) return -ENXIO; @@ -791,7 +786,7 @@ xtrace(OPENCLOSE, "close()\n"); - stuffp = mcdx_stuffp[MINOR(cdi->dev)]; + stuffp = mcdx_stuffp[minor(cdi->dev)]; --stuffp->users; } @@ -805,7 +800,7 @@ xinfo("mcdx_media_changed called for device %s\n", kdevname(cdi->dev)); - stuffp = mcdx_stuffp[MINOR(cdi->dev)]; + stuffp = mcdx_stuffp[minor(cdi->dev)]; mcdx_getstatus(stuffp, 1); if (stuffp->yyy == 0) @@ -1187,7 +1182,8 @@ return 1; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, + &mcdx_lock); read_ahead[MAJOR_NR] = READ_AHEAD; blksize_size[MAJOR_NR] = mcdx_blocksizes; @@ -1228,7 +1224,7 @@ stuffp->wreg_data, stuffp->irq, version.code, version.ver); mcdx_stuffp[drive] = stuffp; xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); - mcdx_info.dev = MKDEV(MAJOR_NR, 0); + mcdx_info.dev = mk_kdev(MAJOR_NR, 0); if (register_cdrom(&mcdx_info) != 0) { printk("Cannot register Mitsumi CD-ROM!\n"); release_region((unsigned long) stuffp->wreg_data, @@ -1698,7 +1694,7 @@ static int mcdx_tray_move(struct cdrom_device_info *cdi, int position) { - struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)]; + struct s_drive_stuff *stuffp = mcdx_stuffp[minor(cdi->dev)]; if (!stuffp->present) return -ENXIO; @@ -1888,7 +1884,7 @@ static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock) { - struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)]; + struct s_drive_stuff *stuffp = mcdx_stuffp[minor(cdi->dev)]; char cmd[2] = { 0xfe }; if (!(stuffp->present & DOOR)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/optcd.c linux-2.5/drivers/cdrom/optcd.c --- linux-2.5.1/drivers/cdrom/optcd.c Thu Oct 25 20:58:35 2001 +++ linux-2.5/drivers/cdrom/optcd.c Sat Jan 5 16:38:08 2002 @@ -109,7 +109,6 @@ #endif static int blksize = 2048; -static int hsecsize = 2048; /* Drive hardware/firmware characteristics @@ -267,6 +266,7 @@ static DECLARE_WAIT_QUEUE_HEAD(waitq); static void sleep_timer(unsigned long data); static struct timer_list delay_timer = {function: sleep_timer}; +spinlock_t optcd_lock = SPIN_LOCK_UNLOCKED; /* Timer routine: wake up when desired flag goes low, @@ -977,7 +977,7 @@ #define CURRENT_VALID \ - (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \ + (!QUEUE_EMPTY && major(CURRENT -> rq_dev) == MAJOR_NR \ && CURRENT -> cmd == READ && CURRENT -> sector != -1) @@ -1371,10 +1371,6 @@ transfer_is_active = 1; while (CURRENT_VALID) { - if (CURRENT->bh) { - if (!buffer_locked(CURRENT->bh)) - panic(DEVICE_NAME ": block not locked"); - } transfer(); /* First try to transfer block from buffers */ if (CURRENT -> nr_sectors == 0) { end_request(1); @@ -2063,12 +2059,12 @@ } devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL); - hardsect_size[MAJOR_NR] = &hsecsize; blksize_size[MAJOR_NR] = &blksize; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, + &optcd_lock); read_ahead[MAJOR_NR] = 4; request_region(optcd_port, 4, "optcd"); - register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &opt_fops, 0); + register_disk(NULL, mk_kdev(MAJOR_NR,0), 1, &opt_fops, 0); printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/sbpcd.c linux-2.5/drivers/cdrom/sbpcd.c --- linux-2.5.1/drivers/cdrom/sbpcd.c Sun Dec 9 04:02:47 2001 +++ linux-2.5/drivers/cdrom/sbpcd.c Sun Jan 6 01:38:26 2002 @@ -2057,7 +2057,7 @@ static int sbpcd_select_speed(struct cdrom_device_info *cdi, int speed) { - int i = MINOR(cdi->dev); + int i = minor(cdi->dev); if (i != d) switch_drive(i); @@ -2095,7 +2095,7 @@ static int sbpcd_reset(struct cdrom_device_info *cdi) { - int i = MINOR(cdi->dev); + int i = minor(cdi->dev); if (i != d) switch_drive(i); @@ -2376,7 +2376,7 @@ { int i; int retval=0; - i = MINOR(cdi->dev); + i = minor(cdi->dev); switch_drive(i); /* DUH! --AJK */ if(D_S[d].CD_changed != 0xFF) { @@ -4061,13 +4061,13 @@ msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); #if 0 - if (!(D_S[MINOR(cdi->dev)].status_bits & p_door_closed)) return CDS_TRAY_OPEN; - if (D_S[MINOR(cdi->dev)].status_bits & p_disk_ok) return CDS_DISC_OK; - if (D_S[MINOR(cdi->dev)].status_bits & p_disk_in) return CDS_DRIVE_NOT_READY; + if (!(D_S[minor(cdi->dev)].status_bits & p_door_closed)) return CDS_TRAY_OPEN; + if (D_S[minor(cdi->dev)].status_bits & p_disk_ok) return CDS_DISC_OK; + if (D_S[minor(cdi->dev)].status_bits & p_disk_in) return CDS_DRIVE_NOT_READY; return CDS_NO_DISC; #else - if (D_S[MINOR(cdi->dev)].status_bits & p_spinning) return CDS_DISC_OK; + if (D_S[minor(cdi->dev)].status_bits & p_spinning) return CDS_DISC_OK; /* return CDS_TRAY_OPEN; */ return CDS_NO_DISC; @@ -4203,8 +4203,8 @@ static int sbpcd_get_last_session(struct cdrom_device_info *cdi, struct cdrom_multisession *ms_infp) { ms_infp->addr_format = CDROM_LBA; - ms_infp->addr.lba = D_S[MINOR(cdi->dev)].lba_multi; - if (D_S[MINOR(cdi->dev)].f_multisession) + ms_infp->addr.lba = D_S[minor(cdi->dev)].lba_multi; + if (D_S[minor(cdi->dev)].f_multisession) ms_infp->xa_flag=1; /* valid redirection address */ else ms_infp->xa_flag=0; /* invalid redirection address */ @@ -4223,8 +4223,8 @@ int i; msg(DBG_IO2,"ioctl(%d, 0x%08lX, 0x%08lX)\n", - MINOR(cdi->dev), cmd, arg); - i=MINOR(cdi->dev); + minor(cdi->dev), cmd, arg); + i=minor(cdi->dev); if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1)) { msg(DBG_INF, "ioctl: bad device: %04X\n", cdi->dev); @@ -4533,9 +4533,9 @@ case BLKRASET: if(!capable(CAP_SYS_ADMIN)) RETURN_UP(-EACCES); - if(!(cdi->dev)) RETURN_UP(-EINVAL); + if(kdev_none(cdi->dev)) RETURN_UP(-EINVAL); if(arg > 0xff) RETURN_UP(-EINVAL); - read_ahead[MAJOR(cdi->dev)] = arg; + read_ahead[major(cdi->dev)] = arg; RETURN_UP(0); default: msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd); @@ -4549,8 +4549,8 @@ int i, st, j; msg(DBG_IO2,"ioctl(%d, 0x%08lX, 0x%08p)\n", - MINOR(cdi->dev), cmd, arg); - i=MINOR(cdi->dev); + minor(cdi->dev), cmd, arg); + i=minor(cdi->dev); if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1)) { msg(DBG_INF, "ioctl: bad device: %04X\n", cdi->dev); @@ -4930,7 +4930,7 @@ sbpcd_end_request(req, 0); if (req -> sector == -1) sbpcd_end_request(req, 0); - spin_unlock_irq(&q->queue_lock); + spin_unlock_irq(q->queue_lock); down(&ioctl_read_sem); if (req->cmd != READ) @@ -4938,7 +4938,7 @@ msg(DBG_INF, "bad cmd %d\n", req->cmd); goto err_done; } - i = MINOR(req->rq_dev); + i = minor(req->rq_dev); if ( (i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1)) { msg(DBG_INF, "do_request: bad device: %s\n", @@ -4970,7 +4970,7 @@ xnr, req, req->sector, req->nr_sectors, jiffies); #endif up(&ioctl_read_sem); - spin_lock_irq(&q->queue_lock); + spin_lock_irq(q->queue_lock); sbpcd_end_request(req, 1); goto request_loop; } @@ -5011,7 +5011,7 @@ xnr, req, req->sector, req->nr_sectors, jiffies); #endif up(&ioctl_read_sem); - spin_lock_irq(&q->queue_lock); + spin_lock_irq(q->queue_lock); sbpcd_end_request(req, 1); goto request_loop; } @@ -5027,7 +5027,7 @@ #endif up(&ioctl_read_sem); sbp_sleep(0); /* wait a bit, try again */ - spin_lock_irq(&q->queue_lock); + spin_lock_irq(q->queue_lock); sbpcd_end_request(req, 0); goto request_loop; } @@ -5435,7 +5435,7 @@ { int i; - i = MINOR(cdi->dev); + i = minor(cdi->dev); down(&ioctl_read_sem); switch_drive(i); @@ -5474,7 +5474,7 @@ { int i; - i = MINOR(cdi->dev); + i = minor(cdi->dev); if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1)) { msg(DBG_INF, "release: bad device: %04X\n", cdi->dev); @@ -6003,8 +6003,8 @@ { int i; - msg(DBG_CHK,"media_check (%d) called\n", MINOR(full_dev)); - i=MINOR(full_dev); + i=minor(full_dev); + msg(DBG_CHK,"media_check (%d) called\n", i); if (D_S[i].CD_changed==0xFF) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/sjcd.c linux-2.5/drivers/cdrom/sjcd.c --- linux-2.5.1/drivers/cdrom/sjcd.c Thu Oct 25 20:58:35 2001 +++ linux-2.5/drivers/cdrom/sjcd.c Sun Jan 6 01:38:26 2002 @@ -105,6 +105,7 @@ static volatile unsigned char sjcd_completion_error = 0; static unsigned short sjcd_command_is_in_progress = 0; static unsigned short sjcd_error_reported = 0; +static spinlock_t sjcd_lock = SPIN_LOCK_UNLOCKED; static int sjcd_open_count; @@ -458,7 +459,7 @@ #if 0 printk("SJCD: sjcd_disk_change( 0x%x )\n", full_dev); #endif - if (MINOR(full_dev) > 0) { + if (minor(full_dev) > 0) { printk("SJCD: request error: invalid device minor.\n"); return 0; } @@ -1074,7 +1075,7 @@ */ #define CURRENT_IS_VALID \ - ( !QUEUE_EMPTY && MAJOR( CURRENT->rq_dev ) == MAJOR_NR && \ + ( !QUEUE_EMPTY && major( CURRENT->rq_dev ) == MAJOR_NR && \ CURRENT->cmd == READ && CURRENT->sector != -1 ) static void sjcd_transfer(void) @@ -1497,12 +1498,6 @@ #endif sjcd_transfer_is_active = 1; while (CURRENT_IS_VALID) { - /* - * Who of us are paranoiac? - */ - if (CURRENT->bh && !buffer_locked(CURRENT->bh)) - panic(DEVICE_NAME ": block not locked"); - sjcd_transfer(); if (CURRENT->nr_sectors == 0) end_request(1); @@ -1664,7 +1659,6 @@ }; static int blksize = 2048; -static int secsize = 2048; /* * Following stuff is intended for initialization of the cdrom. It @@ -1692,7 +1686,6 @@ printk("SJCD: sjcd=0x%x: ", sjcd_base); #endif - hardsect_size[MAJOR_NR] = &secsize; blksize_size[MAJOR_NR] = &blksize; if (devfs_register_blkdev(MAJOR_NR, "sjcd", &sjcd_fops) != 0) { @@ -1701,9 +1694,9 @@ return (-EIO); } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST,&sjcd_lock); read_ahead[MAJOR_NR] = 4; - register_disk(NULL, MKDEV(MAJOR_NR, 0), 1, &sjcd_fops, 0); + register_disk(NULL, mk_kdev(MAJOR_NR, 0), 1, &sjcd_fops, 0); if (check_region(sjcd_base, 4)) { printk diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/cdrom/sonycd535.c linux-2.5/drivers/cdrom/sonycd535.c --- linux-2.5.1/drivers/cdrom/sonycd535.c Thu Oct 25 20:58:35 2001 +++ linux-2.5/drivers/cdrom/sonycd535.c Sun Jan 6 01:38:26 2002 @@ -217,6 +217,8 @@ static unsigned short read_status_reg; static unsigned short data_reg; +static spinlock_t sonycd535_lock = SPIN_LOCK_UNLOCKED; /* queue lock */ + static int initialized; /* Has the drive been initialized? */ static int sony_disc_changed = 1; /* Has the disk been changed since the last check? */ @@ -279,7 +281,7 @@ { int retval; - if (MINOR(full_dev) != 0) { + if (minor(full_dev) != 0) { printk(CDU535_MESSAGE_NAME " request error: invalid device.\n"); return 0; } @@ -808,130 +810,131 @@ return; } INIT_REQUEST; - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; if (dev != 0) { end_request(0); continue; } - switch (CURRENT->cmd) { - case READ: - /* - * If the block address is invalid or the request goes beyond the end of - * the media, return an error. - */ - - if (sony_toc->lead_out_start_lba <= (block / 4)) { - end_request(0); - return; - } - if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) { - end_request(0); - return; - } - while (0 < nsect) { + if(CURRENT->flags & REQ_CMD) { + switch (rq_data_dir(CURRENT)) { + case READ: /* - * If the requested sector is not currently in the read-ahead buffer, - * it must be read in. + * If the block address is invalid or the request goes beyond the end of + * the media, return an error. */ - if ((block < sony_first_block) || (sony_last_block < block)) { - sony_first_block = (block / 4) * 4; - log_to_msf(block / 4, params); - - /* - * If the full read-ahead would go beyond the end of the media, trim - * it back to read just till the end of the media. - */ - if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) { - sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1; - read_size = sony_toc->lead_out_start_lba - (block / 4); - } else { - sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1; - read_size = sony_buffer_sectors; - } - size_to_buf(read_size, ¶ms[3]); - + + if (sony_toc->lead_out_start_lba <= (block / 4)) { + end_request(0); + return; + } + if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) { + end_request(0); + return; + } + while (0 < nsect) { /* - * Read the data. If the drive was not spinning, - * spin it up and try some more. + * If the requested sector is not currently in the read-ahead buffer, + * it must be read in. */ - for (spin_up_retry=0 ;; ++spin_up_retry) { - /* This loop has been modified to support the Sony - * CDU-510/515 series, thanks to Claudio Porfiri - * <C.Porfiri@nisms.tei.ericsson.se>. - */ + if ((block < sony_first_block) || (sony_last_block < block)) { + sony_first_block = (block / 4) * 4; + log_to_msf(block / 4, params); + /* - * This part is to deal with very slow hardware. We - * try at most MAX_SPINUP_RETRY times to read the same - * block. A check for seek_and_read_N_blocks' result is - * performed; if the result is wrong, the CDROM's engine - * is restarted and the operation is tried again. + * If the full read-ahead would go beyond the end of the media, trim + * it back to read just till the end of the media. */ + if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) { + sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1; + read_size = sony_toc->lead_out_start_lba - (block / 4); + } else { + sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1; + read_size = sony_buffer_sectors; + } + size_to_buf(read_size, ¶ms[3]); + /* - * 1995-06-01: The system got problems when downloading - * from Slackware CDROM, the problem seems to be: - * seek_and_read_N_blocks returns BAD_STATUS and we - * should wait for a while before retrying, so a new - * part was added to discriminate the return value from - * seek_and_read_N_blocks for the various cases. + * Read the data. If the drive was not spinning, + * spin it up and try some more. */ - int readStatus = seek_and_read_N_blocks(params, read_size, - status, sony_buffer, (read_size * CDU535_BLOCK_SIZE)); - if (0 <= readStatus) /* Good data; common case, placed first */ - break; - if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) { - /* give up */ - if (readStatus == NO_ROOM) - printk(CDU535_MESSAGE_NAME " No room to read from CD\n"); - else - printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n", - status[0]); - sony_first_block = -1; - sony_last_block = -1; - end_request(0); - return; - } - if (readStatus == BAD_STATUS) { - /* Sleep for a while, then retry */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10); - } + for (spin_up_retry=0 ;; ++spin_up_retry) { + /* This loop has been modified to support the Sony + * CDU-510/515 series, thanks to Claudio Porfiri + * <C.Porfiri@nisms.tei.ericsson.se>. + */ + /* + * This part is to deal with very slow hardware. We + * try at most MAX_SPINUP_RETRY times to read the same + * block. A check for seek_and_read_N_blocks' result is + * performed; if the result is wrong, the CDROM's engine + * is restarted and the operation is tried again. + */ + /* + * 1995-06-01: The system got problems when downloading + * from Slackware CDROM, the problem seems to be: + * seek_and_read_N_blocks returns BAD_STATUS and we + * should wait for a while before retrying, so a new + * part was added to discriminate the return value from + * seek_and_read_N_blocks for the various cases. + */ + int readStatus = seek_and_read_N_blocks(params, read_size, + status, sony_buffer, (read_size * CDU535_BLOCK_SIZE)); + if (0 <= readStatus) /* Good data; common case, placed first */ + break; + if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) { + /* give up */ + if (readStatus == NO_ROOM) + printk(CDU535_MESSAGE_NAME " No room to read from CD\n"); + else + printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n", + status[0]); + sony_first_block = -1; + sony_last_block = -1; + end_request(0); + return; + } + if (readStatus == BAD_STATUS) { + /* Sleep for a while, then retry */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10); + } #if DEBUG > 0 - printk(CDU535_MESSAGE_NAME - " debug: calling spin up when reading data!\n"); + printk(CDU535_MESSAGE_NAME + " debug: calling spin up when reading data!\n"); #endif - cmd[0] = SONY535_SPIN_UP; - do_sony_cmd(cmd, 1, status, NULL, 0, 0); + cmd[0] = SONY535_SPIN_UP; + do_sony_cmd(cmd, 1, status, NULL, 0, 0); + } } + /* + * The data is in memory now, copy it to the buffer and advance to the + * next block to read. + */ + copyoff = block - sony_first_block; + memcpy(CURRENT->buffer, + sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512); + + block += 1; + nsect -= 1; + CURRENT->buffer += 512; } - /* - * The data is in memory now, copy it to the buffer and advance to the - * next block to read. - */ - copyoff = block - sony_first_block; - memcpy(CURRENT->buffer, - sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512); - - block += 1; - nsect -= 1; - CURRENT->buffer += 512; - } - - end_request(1); - break; - case WRITE: - end_request(0); - break; - - default: - panic("Unknown SONY CD cmd"); + end_request(1); + break; + + case WRITE: + end_request(0); + break; + + default: + panic("Unknown SONY CD cmd"); + } } } } - /* * Read the table of contents from the drive and set sony_toc_read if * successful. @@ -1086,7 +1089,7 @@ if (!inode) { return -EINVAL; } - dev = MINOR(inode->i_rdev) >> 6; + dev = minor(inode->i_rdev) >> 6; if (dev != 0) { return -EINVAL; } @@ -1593,7 +1596,7 @@ MAJOR_NR, CDU535_MESSAGE_NAME); return -EIO; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &sonycd535_lock); blksize_size[MAJOR_NR] = &sonycd535_block_size; read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ @@ -1641,7 +1644,7 @@ return -EIO; } request_region(sony535_cd_base_io, 4, CDU535_HANDLE); - register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &cdu_fops, 0); + register_disk(NULL, mk_kdev(MAJOR_NR,0), 1, &cdu_fops, 0); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/Config.in linux-2.5/drivers/char/Config.in --- linux-2.5.1/drivers/char/Config.in Mon Nov 12 17:34:16 2001 +++ linux-2.5/drivers/char/Config.in Thu Dec 27 15:14:59 2001 @@ -16,7 +16,7 @@ tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL fi fi -if [ "$CONFIG_ACPI" = "y" ]; then +if [ "$CONFIG_ACPI" = "y" -a "$CONFIG_IA64" = "y" ]; then bool ' Support for serial ports defined by ACPI tables' CONFIG_SERIAL_ACPI fi dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/acquirewdt.c linux-2.5/drivers/char/acquirewdt.c --- linux-2.5.1/drivers/char/acquirewdt.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/acquirewdt.c Sun Jan 13 22:15:01 2002 @@ -17,6 +17,9 @@ * * (c) Copyright 1995 Alan Cox <alan@redhat.com> * + * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Can't add timeout - driver doesn't allow changing value */ #include <linux/config.h> @@ -50,8 +53,14 @@ #define WDT_STOP 0x43 #define WDT_START 0x443 -#define WD_TIMO (100*60) /* 1 minute */ +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); /* * Kernel methods. @@ -117,7 +126,7 @@ static int acq_open(struct inode *inode, struct file *file) { - switch(MINOR(inode->i_rdev)) + switch(minor(inode->i_rdev)) { case WATCHDOG_MINOR: spin_lock(&acq_lock); @@ -126,10 +135,13 @@ spin_unlock(&acq_lock); return -EBUSY; } + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate */ - + acq_is_open=1; inb_p(WDT_START); spin_unlock(&acq_lock); @@ -141,12 +153,12 @@ static int acq_close(struct inode *inode, struct file *file) { - if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) + if(minor(inode->i_rdev)==WATCHDOG_MINOR) { spin_lock(&acq_lock); -#ifndef CONFIG_WATCHDOG_NOWAYOUT - inb_p(WDT_STOP); -#endif + if (!nowayout) { + inb_p(WDT_STOP); + } acq_is_open=0; spin_unlock(&acq_lock); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/advantechwdt.c linux-2.5/drivers/char/advantechwdt.c --- linux-2.5.1/drivers/char/advantechwdt.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/advantechwdt.c Sun Jan 13 22:15:01 2002 @@ -20,6 +20,9 @@ * * (c) Copyright 1995 Alan Cox <alan@redhat.com> * + * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default */ #include <linux/config.h> @@ -56,8 +59,7 @@ * the manual says WDT_STOP is 0x43, not 0x443). * (0x43 is also a write-only control register for the 8254 timer!) * - * TODO: module parameters to set the I/O port addresses and NOWAYOUT - * option at load time. + * TODO: module parameters to set the I/O port addresses */ #define WDT_STOP 0x443 @@ -65,6 +67,19 @@ #define WD_TIMO 60 /* 1 minute */ +static int timeout = WD_TIMO; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * Kernel methods. */ @@ -73,7 +88,7 @@ advwdt_ping(void) { /* Write a watchdog value */ - outb_p(WD_TIMO, WDT_START); + outb_p(timeout, WDT_START); } static ssize_t @@ -128,13 +143,16 @@ static int advwdt_open(struct inode *inode, struct file *file) { - switch (MINOR(inode->i_rdev)) { + switch (minor(inode->i_rdev)) { case WATCHDOG_MINOR: spin_lock(&advwdt_lock); if (advwdt_is_open) { spin_unlock(&advwdt_lock); return -EBUSY; } + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate */ @@ -151,11 +169,11 @@ static int advwdt_close(struct inode *inode, struct file *file) { - if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { + if (minor(inode->i_rdev) == WATCHDOG_MINOR) { spin_lock(&advwdt_lock); -#ifndef CONFIG_WATCHDOG_NOWAYOUT - inb_p(WDT_STOP); -#endif + if (!nowayout) { + inb_p(WDT_STOP); + } advwdt_is_open = 0; spin_unlock(&advwdt_lock); } @@ -207,11 +225,21 @@ 0 }; +static void __init +advwdt_validate_timeout(void) +{ + if (timeout < 1 || timeout > 63) { + timeout = WD_TIMO; + printk(KERN_INFO "advantechwdt: timeout value must be 1 <= x <= 63, using %d\n", timeout); + } +} + static int __init advwdt_init(void) { printk("WDT driver for Advantech single board computer initialising.\n"); + advwdt_validate_timeout(); spin_lock_init(&advwdt_lock); misc_register(&advwdt_miscdev); #if WDT_START != WDT_STOP diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/agp/agp.h linux-2.5/drivers/char/agp/agp.h --- linux-2.5.1/drivers/char/agp/agp.h Wed Nov 28 00:46:57 2001 +++ linux-2.5/drivers/char/agp/agp.h Tue Jan 8 01:17:10 2002 @@ -179,6 +179,9 @@ #ifndef PCI_DEVICE_ID_INTEL_820_0 #define PCI_DEVICE_ID_INTEL_820_0 0x2500 #endif +#ifndef PCI_DEVICE_ID_INTEL_820_UP_0 +#define PCI_DEVICE_ID_INTEL_820_UP_0 0x2501 +#endif #ifndef PCI_DEVICE_ID_INTEL_840_0 #define PCI_DEVICE_ID_INTEL_840_0 0x1a21 #endif @@ -189,7 +192,7 @@ #define PCI_DEVICE_ID_INTEL_850_0 0x2530 #endif #ifndef PCI_DEVICE_ID_INTEL_860_0 -#define PCI_DEVICE_ID_INTEL_860_0 0x2532 +#define PCI_DEVICE_ID_INTEL_860_0 0x2531 #endif #ifndef PCI_DEVICE_ID_INTEL_810_DC100_0 #define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122 @@ -275,6 +278,9 @@ #define I830_RDRAM_CHANNEL_TYPE 0x03010 #define I830_RDRAM_ND(x) (((x) & 0x20) >> 5) #define I830_RDRAM_DDT(x) (((x) & 0x18) >> 3) + +/* This one is for I830MP w. an external graphic card */ +#define INTEL_I830_ERRSTS 0x92 #define INTEL_I830_ERRSTS 0x92 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/agp/agpgart_be.c linux-2.5/drivers/char/agp/agpgart_be.c --- linux-2.5.1/drivers/char/agp/agpgart_be.c Fri Nov 30 16:52:41 2001 +++ linux-2.5/drivers/char/agp/agpgart_be.c Thu Dec 13 16:32:35 2001 @@ -409,8 +409,18 @@ * AGP devices and collect their data. */ - while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, - device)) != NULL) { + + pci_for_each_dev(device) + { + /* + * Enable AGP devices. Most will be VGA display but + * some may be coprocessors on non VGA devices too + */ + + if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) && + (device->class != (PCI_CLASS_PROCESSOR_CO << 8))) + continue; + pci_read_config_dword(device, 0x04, &scratch); if (!(scratch & 0x00100000)) @@ -3307,8 +3317,18 @@ * AGP devices and collect their data. */ - while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, - device)) != NULL) { + + pci_for_each_dev(device) + { + /* + * Enable AGP devices. Most will be VGA display but + * some may be coprocessors on non VGA devices too + */ + + if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) && + (device->class != (PCI_CLASS_PROCESSOR_CO << 8))) + continue; + pci_read_config_dword(device, 0x04, &scratch); if (!(scratch & 0x00100000)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/agp/agpgart_fe.c linux-2.5/drivers/char/agp/agpgart_fe.c --- linux-2.5.1/drivers/char/agp/agpgart_fe.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/agp/agpgart_fe.c Tue Jan 1 23:42:41 2002 @@ -694,7 +694,7 @@ static int agp_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); agp_file_private *priv; agp_client *client; int rc = -ENXIO; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/amiserial.c linux-2.5/drivers/char/amiserial.c --- linux-2.5.1/drivers/char/amiserial.c Mon Sep 17 04:22:56 2001 +++ linux-2.5/drivers/char/amiserial.c Sun Jan 6 01:38:26 2002 @@ -1904,7 +1904,7 @@ unsigned long page; MOD_INC_USE_COUNT; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) { MOD_DEC_USE_COUNT; return -ENODEV; @@ -2143,7 +2143,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -2328,7 +2330,7 @@ static kdev_t serial_console_device(struct console *c) { - return MKDEV(TTY_MAJOR, 64); + return mk_kdev(TTY_MAJOR, 64); } static struct console sercons = { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/busmouse.c linux-2.5/drivers/char/busmouse.c --- linux-2.5.1/drivers/char/busmouse.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/busmouse.c Wed Jan 2 17:23:52 2002 @@ -51,7 +51,7 @@ #define NR_MICE 15 #define FIRST_MOUSE 0 -#define DEV_TO_MOUSE(dev) MINOR_TO_MOUSE(MINOR(dev)) +#define DEV_TO_MOUSE(dev) MINOR_TO_MOUSE(minor(dev)) #define MINOR_TO_MOUSE(minor) ((minor) - FIRST_MOUSE) /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/console.c linux-2.5/drivers/char/console.c --- linux-2.5.1/drivers/char/console.c Mon Oct 15 21:00:43 2001 +++ linux-2.5/drivers/char/console.c Sun Jan 13 20:03:25 2002 @@ -100,6 +100,7 @@ #include <linux/tqueue.h> #include <linux/bootmem.h> #include <linux/pm.h> +#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/system.h> @@ -126,6 +127,7 @@ #define DEFAULT_BELL_DURATION (HZ/8) extern void vcs_make_devfs (unsigned int index, int unregister); +extern void console_map_init(void); #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -2171,14 +2173,13 @@ static kdev_t vt_console_device(struct console *c) { - return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1); + return mk_kdev(TTY_MAJOR, c->index ? c->index : fg_console + 1); } struct console vt_console_driver = { name: "tty", write: vt_console_print, device: vt_console_device, - wait_key: keyboard_wait_for_keypress, unblank: unblank_screen, flags: CON_PRINTBUFFER, index: -1, @@ -2326,7 +2327,7 @@ int console_num; if (!tty) return; - console_num = MINOR(tty->device) - (tty->driver.minor_start); + console_num = minor(tty->device) - (tty->driver.minor_start); if (!vc_cons_allocated(console_num)) return; set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); @@ -2341,24 +2342,32 @@ int console_num; if (!tty) return; - console_num = MINOR(tty->device) - (tty->driver.minor_start); + console_num = minor(tty->device) - (tty->driver.minor_start); if (!vc_cons_allocated(console_num)) return; clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); set_leds(); } +/* + * we can race here against con_close, so we grab the bkl + * and check the pointer before calling set_cursor + */ static void con_flush_chars(struct tty_struct *tty) { - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; + struct vt_struct *vt; if (in_interrupt()) /* from flush_to_ldisc */ return; pm_access(pm_con); + lock_kernel(); acquire_console_sem(); - set_cursor(vt->vc_num); + vt = (struct vt_struct *)tty->driver_data; + if (vt) + set_cursor(vt->vc_num); release_console_sem(); + unlock_kernel(); } /* @@ -2369,7 +2378,7 @@ unsigned int currcons; int i; - currcons = MINOR(tty->device) - tty->driver.minor_start; + currcons = minor(tty->device) - tty->driver.minor_start; i = vc_allocate(currcons); if (i) @@ -2377,6 +2386,7 @@ vt_cons[currcons]->vc_num = currcons; tty->driver_data = vt_cons[currcons]; + vc_cons[currcons].d->vc_tty = tty; if (!tty->winsize.ws_row && !tty->winsize.ws_col) { tty->winsize.ws_row = video_num_lines; @@ -2392,7 +2402,7 @@ if (!tty) return; if (tty->count != 1) return; - vcs_make_devfs (MINOR (tty->device) - tty->driver.minor_start, 1); + vcs_make_devfs (minor(tty->device) - tty->driver.minor_start, 1); tty->driver_data = 0; } @@ -2441,42 +2451,6 @@ return; } - memset(&console_driver, 0, sizeof(struct tty_driver)); - console_driver.magic = TTY_DRIVER_MAGIC; - console_driver.name = "vc/%d"; - console_driver.name_base = 1; - console_driver.major = TTY_MAJOR; - console_driver.minor_start = 1; - console_driver.num = MAX_NR_CONSOLES; - console_driver.type = TTY_DRIVER_TYPE_CONSOLE; - console_driver.init_termios = tty_std_termios; - console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - /* Tell tty_register_driver() to skip consoles because they are - * registered before kmalloc() is ready. We'll patch them in later. - * See comments at console_init(); see also con_init_devfs(). - */ - console_driver.flags |= 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.write_room = con_write_room; - console_driver.put_char = con_put_char; - console_driver.flush_chars = con_flush_chars; - console_driver.chars_in_buffer = con_chars_in_buffer; - console_driver.ioctl = vt_ioctl; - console_driver.stop = con_stop; - console_driver.start = con_start; - console_driver.throttle = con_throttle; - console_driver.unthrottle = con_unthrottle; - - if (tty_register_driver(&console_driver)) - panic("Couldn't register console driver\n"); - init_timer(&console_timer); console_timer.function = blank_screen; if (blankinterval) { @@ -2515,6 +2489,47 @@ #endif } +int __init vty_init(void) +{ + memset(&console_driver, 0, sizeof(struct tty_driver)); + console_driver.magic = TTY_DRIVER_MAGIC; + console_driver.name = "vc/%d"; + console_driver.name_base = 1; + console_driver.major = TTY_MAJOR; + console_driver.minor_start = 1; + console_driver.num = MAX_NR_CONSOLES; + console_driver.type = TTY_DRIVER_TYPE_CONSOLE; + console_driver.init_termios = tty_std_termios; + console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; + console_driver.refcount = &console_refcount; + console_driver.table = console_table; + console_driver.termios = console_termios; + console_driver.termios_locked = console_termios_locked; +#ifdef CONFIG_VT_CONSOLE + console_driver.console = &vt_console_driver; +#endif + console_driver.open = con_open; + console_driver.close = con_close; + console_driver.write = con_write; + console_driver.write_room = con_write_room; + console_driver.put_char = con_put_char; + console_driver.flush_chars = con_flush_chars; + console_driver.chars_in_buffer = con_chars_in_buffer; + console_driver.ioctl = vt_ioctl; + console_driver.stop = con_stop; + console_driver.start = con_start; + console_driver.throttle = con_throttle; + console_driver.unthrottle = con_unthrottle; + + if (tty_register_driver(&console_driver)) + panic("Couldn't register console driver\n"); + + kbd_init(); + console_map_init(); + vcs_init(); + return 0; +} + #ifndef VT_SINGLE_DRIVER static void clear_buffer_attributes(int currcons) @@ -2599,23 +2614,10 @@ static void set_vesa_blanking(unsigned long arg) { - char *argp = (char *)arg + 1; - unsigned int mode; - get_user(mode, argp); - vesa_blank_mode = (mode < 4) ? mode : 0; -} - -/* We can't register the console with devfs during con_init(), because it - * is called before kmalloc() works. This function is called later to - * do the registration. - */ -void __init con_init_devfs (void) -{ - int i; - - for (i = 0; i < console_driver.num; i++) - tty_register_devfs (&console_driver, DEVFS_FL_AOPEN_NOTIFY, - console_driver.minor_start + i); + char *argp = (char *)arg + 1; + unsigned int mode; + get_user(mode, argp); + vesa_blank_mode = (mode < 4) ? mode : 0; } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/cyclades.c linux-2.5/drivers/char/cyclades.c --- linux-2.5.1/drivers/char/cyclades.c Fri Sep 14 21:04:07 2001 +++ linux-2.5/drivers/char/cyclades.c Sun Jan 6 01:38:26 2002 @@ -2591,7 +2591,7 @@ unsigned long page; MOD_INC_USE_COUNT; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if ((line < 0) || (NR_PORTS <= line)){ MOD_DEC_USE_COUNT; return -ENODEV; @@ -4965,6 +4965,8 @@ uclong Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0; uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS]; unsigned char Ze_irq[NR_CARDS]; + struct resource *resource; + unsigned long res_start, res_len; for (i = 0; i < NR_CARDS; i++) { /* look for a Cyclades card by vendor and device id */ @@ -5012,7 +5014,15 @@ /* Although we don't use this I/O region, we should request it from the kernel anyway, to avoid problems with other drivers accessing it. */ - request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y"); + resource = request_region(cy_pci_phys1, + CyPCI_Yctl, "Cyclom-Y"); + if (resource == NULL) { + printk(KERN_ERR "cyclades: failed to allocate IO " + "resource at 0x%lx\n", cy_pci_phys1); + continue; + } + res_start = cy_pci_phys1; + res_len = CyPCI_Yctl; #if defined(__alpha__) if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ @@ -5083,7 +5093,11 @@ cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; cy_card[j].num_chips = cy_pci_nchan/4; - + cy_card[j].resource = resource; + cy_card[j].res_start = res_start; + cy_card[j].res_len = res_len; + resource = NULL; /* For next card */ + /* enable interrupts in the PCI interface */ plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f; switch (plx_ver) { @@ -5162,8 +5176,16 @@ /* Although we don't use this I/O region, we should request it from the kernel anyway, to avoid problems with other drivers accessing it. */ - request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z"); - + resource = request_region(cy_pci_phys1, + CyPCI_Zctl, "Cyclades-Z"); + if (resource == NULL) { + printk(KERN_ERR "cyclades: failed ot allocate IO resource " + "at 0x%lx\n", cy_pci_phys1); + continue; + } + res_start = cy_pci_phys1; + res_len = CyPCI_Zctl; + if (mailbox == ZE_V1) { cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win); if (ZeIndex == NR_CARDS) { @@ -5261,6 +5283,10 @@ cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; cy_card[j].num_chips = -1; + cy_card[j].resource = resource; + cy_card[j].res_start = res_start; + cy_card[j].res_len = res_len; + resource = NULL; /* For next card */ /* print message */ #ifdef CONFIG_CYZ_INTR @@ -5279,7 +5305,7 @@ printk("%d channels starting from port %d.\n", cy_pci_nchan,cy_next_channel); cy_next_channel += cy_pci_nchan; - } + } } for (; ZeIndex != 0 && i < NR_CARDS; i++) { @@ -5787,6 +5813,8 @@ #endif /* CONFIG_CYZ_INTR */ ) free_irq(cy_card[i].irq, &cy_card[i]); + if (cy_card[i].resource) + release_region(cy_card[i].res_start, cy_card[i].res_len); } } if (tmp_buf) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/Config.in linux-2.5/drivers/char/drm/Config.in --- linux-2.5.1/drivers/char/drm/Config.in Wed Aug 8 16:42:10 2001 +++ linux-2.5/drivers/char/drm/Config.in Thu Dec 13 16:32:35 2001 @@ -13,4 +13,5 @@ dep_tristate ' ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP dep_tristate ' Intel I810' CONFIG_DRM_I810 $CONFIG_AGP dep_tristate ' Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP + dep_tristate ' SiS' CONFIG_DRM_SIS $CONFIG_AGP fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/Makefile linux-2.5/drivers/char/drm/Makefile --- linux-2.5.1/drivers/char/drm/Makefile Thu Aug 9 21:09:38 2001 +++ linux-2.5/drivers/char/drm/Makefile Thu Dec 13 16:32:35 2001 @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. O_TARGET := drm.o -list-multi := gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o +list-multi := gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o sis.o gamma-objs := gamma_drv.o gamma_dma.o tdfx-objs := tdfx_drv.o @@ -12,6 +12,7 @@ i810-objs := i810_drv.o i810_dma.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o ffb-objs := ffb_drv.o ffb_context.o +sis-objs := sis_drv.o sis_ds.o sis_mm.o obj-$(CONFIG_DRM_GAMMA) += gamma.o obj-$(CONFIG_DRM_TDFX) += tdfx.o @@ -20,6 +21,7 @@ obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o obj-$(CONFIG_DRM_FFB) += ffb.o +obj-$(CONFIG_DRM_SIS) += sis.o include $(TOPDIR)/Rules.make @@ -43,3 +45,6 @@ ffb.o: $(ffb-objs) $(lib) $(LD) -r -o $@ $(ffb-objs) $(lib) + +sis.o: $(sis-objs) $(lib) + $(LD) -r -o $@ $(sis-objs) $(lib) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/drm.h linux-2.5/drivers/char/drm/drm.h --- linux-2.5.1/drivers/char/drm/drm.h Wed Aug 8 16:52:17 2001 +++ linux-2.5/drivers/char/drm/drm.h Mon Jan 14 14:35:11 2002 @@ -104,7 +104,7 @@ #include "i810_drm.h" #include "r128_drm.h" #include "radeon_drm.h" -#ifdef CONFIG_DRM_SIS +#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE) #include "sis_drm.h" #endif @@ -483,7 +483,7 @@ #define DRM_IOCTL_RADEON_INDIRECT DRM_IOWR(0x4d, drm_radeon_indirect_t) #define DRM_IOCTL_RADEON_TEXTURE DRM_IOWR(0x4e, drm_radeon_texture_t) -#ifdef CONFIG_DRM_SIS +#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE) /* SiS specific ioctls */ #define SIS_IOCTL_FB_ALLOC DRM_IOWR(0x44, drm_sis_mem_t) #define SIS_IOCTL_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/drm_context.h linux-2.5/drivers/char/drm/drm_context.h --- linux-2.5.1/drivers/char/drm/drm_context.h Sun Dec 16 23:43:58 2001 +++ linux-2.5/drivers/char/drm/drm_context.h Mon Jan 14 14:35:11 2002 @@ -27,6 +27,10 @@ * Authors: * Rickard E. (Rik) Faith <faith@valinux.com> * Gareth Hughes <gareth@valinux.com> + * ChangeLog: + * 2001-11-16 Torsten Duwe <duwe@caldera.de> + * added context constructor/destructor hooks, + * needed by SiS driver's memory management. */ #define __NO_VERSION__ @@ -316,6 +320,10 @@ /* Should this return -EBUSY instead? */ return -ENOMEM; } +#ifdef DRIVER_CTX_CTOR + if ( ctx.handle != DRM_KERNEL_CONTEXT ) + DRIVER_CTX_CTOR(ctx.handle); /* XXX: also pass dev ? */ +#endif if ( copy_to_user( (drm_ctx_t *)arg, &ctx, sizeof(ctx) ) ) return -EFAULT; @@ -390,6 +398,9 @@ priv->remove_auth_on_close = 1; } if ( ctx.handle != DRM_KERNEL_CONTEXT ) { +#ifdef DRIVER_CTX_DTOR + DRIVER_CTX_DTOR(ctx.handle); /* XXX: also pass dev ? */ +#endif DRM(ctxbitmap_free)( dev, ctx.handle ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/drm_drv.h linux-2.5/drivers/char/drm/drm_drv.h --- linux-2.5.1/drivers/char/drm/drm_drv.h Sun Oct 21 17:40:36 2001 +++ linux-2.5/drivers/char/drm/drm_drv.h Tue Jan 1 23:42:41 2002 @@ -719,7 +719,7 @@ int i; for (i = 0; i < DRM(numdevs); i++) { - if (MINOR(inode->i_rdev) == DRM(minor)[i]) { + if (minor(inode->i_rdev) == DRM(minor)[i]) { dev = &(DRM(device)[i]); break; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/drm_fops.h linux-2.5/drivers/char/drm/drm_fops.h --- linux-2.5.1/drivers/char/drm/drm_fops.h Sun Dec 16 23:43:58 2001 +++ linux-2.5/drivers/char/drm/drm_fops.h Mon Jan 14 14:35:11 2002 @@ -38,7 +38,7 @@ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) { - kdev_t minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); drm_file_t *priv; if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/drm_stub.h linux-2.5/drivers/char/drm/drm_stub.h --- linux-2.5.1/drivers/char/drm/drm_stub.h Sun Dec 16 23:43:58 2001 +++ linux-2.5/drivers/char/drm/drm_stub.h Mon Jan 14 14:35:11 2002 @@ -53,7 +53,7 @@ static int DRM(stub_open)(struct inode *inode, struct file *filp) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); int err = -ENODEV; struct file_operations *old_fops; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/sis.h linux-2.5/drivers/char/drm/sis.h --- linux-2.5.1/drivers/char/drm/sis.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,56 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.1 2001/05/19 18:29:22 dawes Exp $ */ + +#ifndef __SIS_H__ +#define __SIS_H__ + +/* This remains constant for all DRM template files. + * Name it sisdrv_##x as there's a conflict with sis_free/malloc in the kernel + * that's used for fb devices + */ +#define DRM(x) sisdrv_##x + +/* General customization: + */ +#define __HAVE_AGP 1 +#define __MUST_HAVE_AGP 0 +#define __HAVE_MTRR 1 +#define __HAVE_CTX_BITMAP 1 + +/* Buffer customization: + */ +#define DRIVER_AGP_BUFFERS_MAP( dev ) \ + ((drm_sis_private_t *)((dev)->dev_private))->buffers + +extern int sis_init_context(int context); +extern int sis_final_context(int context); + +#define DRIVER_CTX_CTOR sis_init_context +#define DRIVER_CTX_DTOR sis_final_context + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/sis_drm.h linux-2.5/drivers/char/drm/sis_drm.h --- linux-2.5.1/drivers/char/drm/sis_drm.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_drm.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,36 @@ + +#ifndef _sis_drm_public_h_ +#define _sis_drm_public_h_ + +typedef struct { + int context; + unsigned int offset; + unsigned int size; + unsigned int free; +} drm_sis_mem_t; + +typedef struct { + unsigned int offset, size; +} drm_sis_agp_t; + +typedef struct { + unsigned int left, right; +} drm_sis_flip_t; + +#ifdef __KERNEL__ + +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); + +int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); + +#endif + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/sis_drv.c linux-2.5/drivers/char/drm/sis_drv.c --- linux-2.5.1/drivers/char/drm/sis_drv.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_drv.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,74 @@ +/* sis.c -- sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include <linux/config.h> +#include "sis.h" +#include "drmP.h" +#include "sis_drm.h" +#include "sis_drv.h" + +#define DRIVER_AUTHOR "SIS" +#define DRIVER_NAME "sis" +#define DRIVER_DESC "SIS 300/630/540" +#define DRIVER_DATE "20010503" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + +#define DRIVER_IOCTLS \ + [DRM_IOCTL_NR(SIS_IOCTL_FB_ALLOC)] = { sis_fb_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_FB_FREE)] = { sis_fb_free, 1, 0 }, \ + /* AGP Memory Management */ \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_INIT)] = { sisp_agp_init, 1, 0 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_ALLOC)] = { sisp_agp_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_FREE)] = { sisp_agp_free, 1, 0 } +#if 0 /* these don't appear to be defined */ + /* SIS Stereo */ + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { sis_control, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP)] = { sis_flip, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP_INIT)] = { sis_flip_init, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP_FINAL)] = { sis_flip_final, 1, 1 } +#endif + +#define __HAVE_COUNTERS 5 + +#include "drm_auth.h" +#include "drm_agpsupport.h" +#include "drm_bufs.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_drawable.h" +#include "drm_drv.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lists.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/sis_drv.h linux-2.5/drivers/char/drm/sis_drv.h --- linux-2.5.1/drivers/char/drm/sis_drv.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_drv.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,45 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _SIS_DRV_H_ +#define _SIS_DRV_H_ + +typedef struct drm_sis_private { + drm_map_t *buffers; +} drm_sis_private_t; + +/* Stereo ? - this was never committed */ + +int sis_flip(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_flip_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_flip_final(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +void flip_final(void); + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/sis_ds.c linux-2.5/drivers/char/drm/sis_ds.c --- linux-2.5.1/drivers/char/drm/sis_ds.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_ds.c Thu Dec 13 16:32:35 2001 @@ -0,0 +1,406 @@ +/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin <sclin@sis.com.tw> + * + */ + +#define __NO_VERSION__ +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/poll.h> +#include <asm/io.h> +#include <linux/pci.h> + +#include "sis_ds.h" + +/* Set Data Structure, not check repeated value + * temporarily used + */ + +set_t *setInit(void) +{ + int i; + set_t *set; + + set = (set_t *)MALLOC(sizeof(set_t)); + for(i = 0; i < SET_SIZE; i++){ + set->list[i].free_next = i+1; + set->list[i].alloc_next = -1; + } + set->list[SET_SIZE-1].free_next = -1; + set->free = 0; + set->alloc = -1; + set->trace = -1; + + return set; +} + +int setAdd(set_t *set, ITEM_TYPE item) +{ + int free = set->free; + + if(free != -1){ + set->list[free].val = item; + set->free = set->list[free].free_next; + } + else{ + return 0; + } + + set->list[free].alloc_next = set->alloc; + set->alloc = free; + set->list[free].free_next = -1; + + return 1; +} + +int setDel(set_t *set, ITEM_TYPE item) +{ + int alloc = set->alloc; + int prev = -1; + + while(alloc != -1){ + if(set->list[alloc].val == item){ + if(prev != -1) + set->list[prev].alloc_next = set->list[alloc].alloc_next; + else + set->alloc = set->list[alloc].alloc_next; + break; + } + prev = alloc; + alloc = set->list[alloc].alloc_next; + } + + if(alloc == -1) + return 0; + + set->list[alloc].free_next = set->free; + set->free = alloc; + set->list[alloc].alloc_next = -1; + + return 1; +} + +/* setFirst -> setAdd -> setNext is wrong */ + +int setFirst(set_t *set, ITEM_TYPE *item) +{ + if(set->alloc == -1) + return 0; + + *item = set->list[set->alloc].val; + set->trace = set->list[set->alloc].alloc_next; + + return 1; +} + +int setNext(set_t *set, ITEM_TYPE *item) +{ + if(set->trace == -1) + return 0; + + *item = set->list[set->trace].val; + set->trace = set->list[set->trace].alloc_next; + + return 1; +} + +int setDestroy(set_t *set) +{ + FREE(set); + + return 1; +} + +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Keith Whitwell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define ISFREE(bptr) ((bptr)->free) + +#define PRINTF(fmt, arg...) do{}while(0) +#define fprintf(fmt, arg...) do{}while(0) + +static void *calloc(size_t nmemb, size_t size) +{ + void *addr; + addr = kmalloc(nmemb*size, GFP_KERNEL); + memset(addr, 0, nmemb*size); + return addr; +} +#define free(n) kfree(n) + +void mmDumpMemInfo( memHeap_t *heap ) +{ + TMemBlock *p; + + PRINTF ("Memory heap %p:\n", heap); + if (heap == 0) { + PRINTF (" heap == 0\n"); + } else { + p = (TMemBlock *)heap; + while (p) { + PRINTF (" Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size, + p->free ? '.':'U', + p->reserved ? 'R':'.'); + p = p->next; + } + } + PRINTF ("End of memory blocks\n"); +} + +memHeap_t *mmInit(int ofs, + int size) +{ + PMemBlock blocks; + + if (size <= 0) { + return 0; + } + blocks = (TMemBlock *) calloc(1,sizeof(TMemBlock)); + if (blocks) { + blocks->ofs = ofs; + blocks->size = size; + blocks->free = 1; + return (memHeap_t *)blocks; + } else + return 0; +} + +/* Kludgey workaround for existing i810 server. Remove soon. + */ +memHeap_t *mmAddRange( memHeap_t *heap, + int ofs, + int size ) +{ + PMemBlock blocks; + blocks = (TMemBlock *) calloc(2,sizeof(TMemBlock)); + if (blocks) { + blocks[0].size = size; + blocks[0].free = 1; + blocks[0].ofs = ofs; + blocks[0].next = &blocks[1]; + + /* Discontinuity - stops JoinBlock from trying to join non-adjacent + * ranges. + */ + blocks[1].size = 0; + blocks[1].free = 0; + blocks[1].ofs = ofs+size; + blocks[1].next = (PMemBlock) heap; + return (memHeap_t *)blocks; + } + else + return heap; +} + +static TMemBlock* SliceBlock(TMemBlock *p, + int startofs, int size, + int reserved, int alignment) +{ + TMemBlock *newblock; + + /* break left */ + if (startofs > p->ofs) { + newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock)); + newblock->ofs = startofs; + newblock->size = p->size - (startofs - p->ofs); + newblock->free = 1; + newblock->next = p->next; + p->size -= newblock->size; + p->next = newblock; + p = newblock; + } + + /* break right */ + if (size < p->size) { + newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock)); + newblock->ofs = startofs + size; + newblock->size = p->size - size; + newblock->free = 1; + newblock->next = p->next; + p->size = size; + p->next = newblock; + } + + /* p = middle block */ + p->align = alignment; + p->free = 0; + p->reserved = reserved; + return p; +} + +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch) +{ + int mask,startofs,endofs; + TMemBlock *p; + + if (!heap || align2 < 0 || size <= 0) + return NULL; + mask = (1 << align2)-1; + startofs = 0; + p = (TMemBlock *)heap; + while (p) { + if (ISFREE(p)) { + startofs = (p->ofs + mask) & ~mask; + if ( startofs < startSearch ) { + startofs = startSearch; + } + endofs = startofs+size; + if (endofs <= (p->ofs+p->size)) + break; + } + p = p->next; + } + if (!p) + return NULL; + p = SliceBlock(p,startofs,size,0,mask+1); + p->heap = heap; + return p; +} + +static __inline__ int Join2Blocks(TMemBlock *p) +{ + if (p->free && p->next && p->next->free) { + TMemBlock *q = p->next; + p->size += q->size; + p->next = q->next; + free(q); + return 1; + } + return 0; +} + +int mmFreeMem(PMemBlock b) +{ + TMemBlock *p,*prev; + + if (!b) + return 0; + if (!b->heap) { + fprintf(stderr, "no heap\n"); + return -1; + } + p = b->heap; + prev = NULL; + while (p && p != b) { + prev = p; + p = p->next; + } + if (!p || p->free || p->reserved) { + if (!p) + fprintf(stderr, "block not found in heap\n"); + else if (p->free) + fprintf(stderr, "block already free\n"); + else + fprintf(stderr, "block is reserved\n"); + return -1; + } + p->free = 1; + Join2Blocks(p); + if (prev) + Join2Blocks(prev); + return 0; +} + +int mmReserveMem(memHeap_t *heap, int offset,int size) +{ + int endofs; + TMemBlock *p; + + if (!heap || size <= 0) + return -1; + endofs = offset+size; + p = (TMemBlock *)heap; + while (p && p->ofs <= offset) { + if (ISFREE(p) && endofs <= (p->ofs+p->size)) { + SliceBlock(p,offset,size,1,1); + return 0; + } + p = p->next; + } + return -1; +} + +int mmFreeReserved(memHeap_t *heap, int offset) +{ + TMemBlock *p,*prev; + + if (!heap) + return -1; + p = (TMemBlock *)heap; + prev = NULL; + while (p && p->ofs != offset) { + prev = p; + p = p->next; + } + if (!p || !p->reserved) + return -1; + p->free = 1; + p->reserved = 0; + Join2Blocks(p); + if (prev) + Join2Blocks(prev); + return 0; +} + +void mmDestroy(memHeap_t *heap) +{ + TMemBlock *p,*q; + + if (!heap) + return; + p = (TMemBlock *)heap; + while (p) { + q = p->next; + free(p); + p = q; + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/sis_ds.h linux-2.5/drivers/char/drm/sis_ds.h --- linux-2.5.1/drivers/char/drm/sis_ds.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_ds.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,163 @@ +/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin <sclin@sis.com.tw> + * + */ + +#ifndef _sis_ds_h_ +#define _sis_ds_h_ + +/* Set Data Structure */ + +#define SET_SIZE 5000 +#define MALLOC(s) kmalloc(s, GFP_KERNEL) +#define FREE(s) kfree(s) + +typedef unsigned int ITEM_TYPE; + +typedef struct { + ITEM_TYPE val; + int alloc_next, free_next; +} list_item_t; + +typedef struct { + int alloc; + int free; + int trace; + list_item_t list[SET_SIZE]; +} set_t; + +set_t *setInit(void); +int setAdd(set_t *set, ITEM_TYPE item); +int setDel(set_t *set, ITEM_TYPE item); +int setFirst(set_t *set, ITEM_TYPE *item); +int setNext(set_t *set, ITEM_TYPE *item); +int setDestroy(set_t *set); + +#endif + +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Keith Whitwell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef MM_INC +#define MM_INC + +struct mem_block_t { + struct mem_block_t *next; + struct mem_block_t *heap; + int ofs,size; + int align; + int free:1; + int reserved:1; +}; +typedef struct mem_block_t TMemBlock; +typedef struct mem_block_t *PMemBlock; + +/* a heap is just the first block in a chain */ +typedef struct mem_block_t memHeap_t; + +static __inline__ int mmBlockSize(PMemBlock b) +{ return b->size; } + +static __inline__ int mmOffset(PMemBlock b) +{ return b->ofs; } + +static __inline__ void mmMarkReserved(PMemBlock b) +{ b->reserved = 1; } + +/* + * input: total size in bytes + * return: a heap pointer if OK, NULL if error + */ +memHeap_t *mmInit( int ofs, int size ); + + + +memHeap_t *mmAddRange( memHeap_t *heap, + int ofs, + int size ); + + +/* + * Allocate 'size' bytes with 2^align2 bytes alignment, + * restrict the search to free memory after 'startSearch' + * depth and back buffers should be in different 4mb banks + * to get better page hits if possible + * input: size = size of block + * align2 = 2^align2 bytes alignment + * startSearch = linear offset from start of heap to begin search + * return: pointer to the allocated block, 0 if error + */ +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch ); + +/* + * Free block starts at offset + * input: pointer to a block + * return: 0 if OK, -1 if error + */ +int mmFreeMem( PMemBlock b ); + +/* + * Reserve 'size' bytes block start at offset + * This is used to prevent allocation of memory already used + * by the X server for the front buffer, pixmaps, and cursor + * input: size, offset + * output: 0 if OK, -1 if error + */ +int mmReserveMem( memHeap_t *heap, int offset,int size ); +int mmFreeReserved( memHeap_t *heap, int offset ); + +/* + * destroy MM + */ +void mmDestroy( memHeap_t *mmInit ); + +/* For debuging purpose. */ +void mmDumpMemInfo( memHeap_t *mmInit ); + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/drm/sis_mm.c linux-2.5/drivers/char/drm/sis_mm.c --- linux-2.5.1/drivers/char/drm/sis_mm.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_mm.c Thu Dec 13 16:32:35 2001 @@ -0,0 +1,307 @@ +/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin <sclin@sis.com.tw> + * + */ + +#define __NO_VERSION__ +#include "sis.h" +#include <linux/sisfb.h> +#include "drmP.h" +#include "sis_drm.h" +#include "sis_drv.h" +#include "sis_ds.h" + +#define MAX_CONTEXT 100 +#define VIDEO_TYPE 0 +#define AGP_TYPE 1 + +typedef struct { + int used; + int context; + set_t *sets[2]; /* 0 for video, 1 for AGP */ +} sis_context_t; + +static sis_context_t global_ppriv[MAX_CONTEXT]; + +static int add_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + + for(i = 0; i < MAX_CONTEXT; i++) + if(global_ppriv[i].used && global_ppriv[i].context == context){ + retval = setAdd(global_ppriv[i].sets[type], val); + break; + } + return retval; +} + +static int del_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + for(i = 0; i < MAX_CONTEXT; i++) + if(global_ppriv[i].used && global_ppriv[i].context == context){ + retval = setDel(global_ppriv[i].sets[type], val); + break; + } + return retval; +} + +/* fb management via fb device */ +#if 1 +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t fb; + struct sis_memreq req; + int retval = 0; + + if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb))) + return -EFAULT; + + req.size = fb.size; + sis_malloc(&req); + if(req.offset){ + /* TODO */ + fb.offset = req.offset; + fb.free = req.offset; + if(!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)){ + DRM_DEBUG("adding to allocation set fails\n"); + sis_free(req.offset); + retval = -1; + } + } + else{ + fb.offset = 0; + fb.size = 0; + fb.free = 0; + } + + if (copy_to_user((drm_sis_mem_t *)arg, &fb, sizeof(fb))) return -EFAULT; + + DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset); + + return retval; +} + +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t fb; + int retval = 0; + + if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb))) + return -EFAULT; + + if(!fb.free){ + return -1; + } + + sis_free(fb.free); + if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) + retval = -1; + + DRM_DEBUG("free fb, offset = %d\n", fb.free); + + return retval; +} + +#else + +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return -1; +} + +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +#endif + +/* agp memory management */ +#if 1 + +static memHeap_t *AgpHeap = NULL; + +int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_agp_t agp; + + if (copy_from_user(&agp, (drm_sis_agp_t *)arg, sizeof(agp))) + return -EFAULT; + + AgpHeap = mmInit(agp.offset, agp.size); + + DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); + + return 0; +} + +int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t agp; + PMemBlock block; + int retval = 0; + + if(!AgpHeap) + return -1; + + if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp))) + return -EFAULT; + + block = mmAllocMem(AgpHeap, agp.size, 0, 0); + if(block){ + /* TODO */ + agp.offset = block->ofs; + agp.free = (unsigned int)block; + if(!add_alloc_set(agp.context, AGP_TYPE, agp.free)){ + DRM_DEBUG("adding to allocation set fails\n"); + mmFreeMem((PMemBlock)agp.free); + retval = -1; + } + } + else{ + agp.offset = 0; + agp.size = 0; + agp.free = 0; + } + + if (copy_to_user((drm_sis_mem_t *)arg, &agp, sizeof(agp))) return -EFAULT; + + DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset); + + return retval; +} + +int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t agp; + int retval = 0; + + if(!AgpHeap) + return -1; + + if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp))) + return -EFAULT; + + if(!agp.free){ + return -1; + } + + mmFreeMem((PMemBlock)agp.free); + if(!del_alloc_set(agp.context, AGP_TYPE, agp.free)) + retval = -1; + + DRM_DEBUG("free agp, free = %d\n", agp.free); + + return retval; +} + +#endif + +int sis_init_context(int context) +{ + int i; + + for(i = 0; i < MAX_CONTEXT ; i++) + if(global_ppriv[i].used && (global_ppriv[i].context == context)) + break; + + if(i >= MAX_CONTEXT){ + for(i = 0; i < MAX_CONTEXT ; i++){ + if(!global_ppriv[i].used){ + global_ppriv[i].context = context; + global_ppriv[i].used = 1; + global_ppriv[i].sets[0] = setInit(); + global_ppriv[i].sets[1] = setInit(); + DRM_DEBUG("init allocation set, socket=%d, context = %d\n", + i, context); + break; + } + } + if((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || + (global_ppriv[i].sets[1] == NULL)){ + return 0; + } + } + + return 1; +} + +int sis_final_context(int context) +{ + int i; + + for(i=0; i<MAX_CONTEXT; i++) + if(global_ppriv[i].used && (global_ppriv[i].context == context)) + break; + + if(i < MAX_CONTEXT){ + set_t *set; + unsigned int item; + int retval; + + DRM_DEBUG("find socket %d, context = %d\n", i, context); + + /* Video Memory */ + set = global_ppriv[i].sets[0]; + retval = setFirst(set, &item); + while(retval){ + DRM_DEBUG("free video memory 0x%x\n", item); + sis_free(item); + retval = setNext(set, &item); + } + setDestroy(set); + + /* AGP Memory */ + set = global_ppriv[i].sets[1]; + retval = setFirst(set, &item); + while(retval){ + DRM_DEBUG("free agp memory 0x%x\n", item); + mmFreeMem((PMemBlock)item); + retval = setNext(set, &item); + } + setDestroy(set); + + global_ppriv[i].used = 0; + } + + /* turn-off auto-flip */ + /* TODO */ +#if defined(SIS_STEREO) + flip_final(); +#endif + + return 1; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/dsp56k.c linux-2.5/drivers/char/dsp56k.c --- linux-2.5.1/drivers/char/dsp56k.c Mon Sep 10 15:06:32 2001 +++ linux-2.5/drivers/char/dsp56k.c Sun Jan 6 01:38:26 2002 @@ -37,7 +37,6 @@ #include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> -#include <asm/segment.h> #include <asm/atarihw.h> #include <asm/traps.h> #include <asm/uaccess.h> /* For put_user and get_user */ @@ -208,7 +207,7 @@ loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; - int dev = MINOR(inode->i_rdev) & 0x0f; + int dev = minor(inode->i_rdev) & 0x0f; switch(dev) { @@ -271,7 +270,7 @@ loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; - int dev = MINOR(inode->i_rdev) & 0x0f; + int dev = minor(inode->i_rdev) & 0x0f; switch(dev) { @@ -332,7 +331,7 @@ static int dsp56k_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int dev = MINOR(inode->i_rdev) & 0x0f; + int dev = minor(inode->i_rdev) & 0x0f; switch(dev) { @@ -425,7 +424,7 @@ #if 0 static unsigned int dsp56k_poll(struct file *file, poll_table *wait) { - int dev = MINOR(file->f_dentry->d_inode->i_rdev) & 0x0f; + int dev = minor(file->f_dentry->d_inode->i_rdev) & 0x0f; switch(dev) { @@ -442,7 +441,7 @@ static int dsp56k_open(struct inode *inode, struct file *file) { - int dev = MINOR(inode->i_rdev) & 0x0f; + int dev = minor(inode->i_rdev) & 0x0f; switch(dev) { @@ -473,7 +472,7 @@ static int dsp56k_release(struct inode *inode, struct file *file) { - int dev = MINOR(inode->i_rdev) & 0x0f; + int dev = minor(inode->i_rdev) & 0x0f; switch(dev) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/dtlk.c linux-2.5/drivers/char/dtlk.c --- linux-2.5.1/drivers/char/dtlk.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/dtlk.c Sun Jan 6 01:38:26 2002 @@ -57,7 +57,6 @@ #include <linux/errno.h> /* for -EBUSY */ #include <linux/ioport.h> /* for check_region, request_region */ #include <linux/delay.h> /* for loops_per_jiffy */ -#include <asm/segment.h> /* for put_user_byte */ #include <asm/io.h> /* for inb_p, outb_p, inb, outb, etc. */ #include <asm/uaccess.h> /* for get_user, etc. */ #include <linux/wait.h> /* for wait_queue */ @@ -126,7 +125,7 @@ static ssize_t dtlk_read(struct file *file, char *buf, size_t count, loff_t * ppos) { - unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + unsigned int minor = minor(file->f_dentry->d_inode->i_rdev); char ch; int i = 0, retries; @@ -186,7 +185,7 @@ if (ppos != &file->f_pos) return -ESPIPE; - if (MINOR(file->f_dentry->d_inode->i_rdev) != DTLK_MINOR) + if (minor(file->f_dentry->d_inode->i_rdev) != DTLK_MINOR) return -EINVAL; while (1) { @@ -305,7 +304,7 @@ { TRACE_TEXT("(dtlk_open"); - switch (MINOR(inode->i_rdev)) { + switch (minor(inode->i_rdev)) { case DTLK_MINOR: if (dtlk_busy) return -EBUSY; @@ -320,7 +319,7 @@ { TRACE_TEXT("(dtlk_release"); - switch (MINOR(inode->i_rdev)) { + switch (minor(inode->i_rdev)) { case DTLK_MINOR: break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/dz.c linux-2.5/drivers/char/dz.c --- linux-2.5.1/drivers/char/dz.c Sun Sep 9 17:43:02 2001 +++ linux-2.5/drivers/char/dz.c Sun Jan 6 01:38:26 2002 @@ -67,7 +67,7 @@ extern int (*prom_printf) (char *,...); #endif - +struct console dz_sercons; #include "dz.h" @@ -75,7 +75,6 @@ DECLARE_TASK_QUEUE(tq_serial); -extern wait_queue_head_t keypress_wait; static struct dz_serial *lines[4]; static unsigned char tmp_buffer[256]; @@ -228,8 +227,6 @@ if (info->is_console) { if (ch == 0) return; /* it's a break ... */ - - wake_up (&keypress_wait); /* It is a 'keyboard interrupt' ;-) */ } #endif @@ -1276,7 +1273,7 @@ struct dz_serial *info; int retval, line; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; /* * The dz lines for the mouse/keyboard must be opened using their @@ -1356,7 +1353,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &dz_sercons; +#endif serial_driver.open = dz_open; serial_driver.close = dz_close; serial_driver.write = dz_write; @@ -1509,14 +1508,9 @@ } } -static int dz_console_wait_key(struct console *co) -{ - return 0; -} - static kdev_t dz_console_device(struct console *c) { - return MKDEV(TTY_MAJOR, 64 + c->index); + return mk_kdev(TTY_MAJOR, 64 + c->index); } static int __init dz_console_setup(struct console *co, char *options) @@ -1614,7 +1608,6 @@ name: "ttyS", write: dz_console_print, device: dz_console_device, - wait_key: dz_console_wait_key, setup: dz_console_setup, flags: CON_CONSDEV | CON_PRINTBUFFER, index: CONSOLE_LINE, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/epca.c linux-2.5/drivers/char/epca.c --- linux-2.5.1/drivers/char/epca.c Fri Oct 12 20:48:42 2001 +++ linux-2.5/drivers/char/epca.c Sun Jan 6 01:38:26 2002 @@ -897,7 +897,6 @@ inline void copy_from_user(void * to, const void * from, unsigned long count); - You must include <asm/segment.h> I also think (Check hackers guide) that optimization must be turned ON. (Which sounds strange to me...) @@ -1385,7 +1384,7 @@ return (0) ; } - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if (line < 0 || line >= nbdevs) { printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n"); @@ -2896,7 +2895,7 @@ if (bc->orun) { bc->orun = 0; - printk(KERN_WARNING "overrun! DigiBoard device minor = %d\n",MINOR(tty->device)); + printk(KERN_WARNING "overrun! DigiBoard device minor = %d\n",minor(tty->device)); } rxwinon(ch); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/esp.c linux-2.5/drivers/char/esp.c --- linux-2.5.1/drivers/char/esp.c Fri Nov 9 22:01:21 2001 +++ linux-2.5/drivers/char/esp.c Sun Jan 6 01:38:26 2002 @@ -60,7 +60,6 @@ #include <asm/system.h> #include <asm/io.h> -#include <asm/segment.h> #include <asm/bitops.h> #include <asm/dma.h> @@ -2355,7 +2354,7 @@ struct esp_struct *info; int retval, line; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/eurotechwdt.c linux-2.5/drivers/char/eurotechwdt.c --- linux-2.5.1/drivers/char/eurotechwdt.c Thu Oct 25 20:53:47 2001 +++ linux-2.5/drivers/char/eurotechwdt.c Sun Jan 13 22:15:01 2002 @@ -20,6 +20,10 @@ * "AS-IS" and at no charge. * * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>* + * + * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default */ #include <linux/config.h> @@ -45,7 +49,6 @@ #include <linux/smp_lock.h> static int eurwdt_is_open; -static int eurwdt_timeout; static spinlock_t eurwdt_lock; /* @@ -58,6 +61,18 @@ static char *ev = "int"; #define WDT_TIMEOUT 60 /* 1 minute */ +static int timeout = WDT_TIMEOUT; + +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Eurotech WDT timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); /* @@ -116,6 +131,15 @@ * Programming support */ +static void __init eurwdt_validate_timeout(void) +{ + if (timeout < 0 || timeout > 255) { + timeout = WDT_TIMEOUT; + printk(KERN_INFO "eurwdt: timeout must be 0 < x < 255, using %d\n", + timeout); + } +} + static inline void eurwdt_write_reg(u8 index, u8 data) { outb(index, io); @@ -189,7 +213,7 @@ static void eurwdt_ping(void) { /* Write the watchdog default value */ - eurwdt_set_timeout(eurwdt_timeout); + eurwdt_set_timeout(timeout); } /** @@ -263,7 +287,7 @@ if (time < 0 || time > 255) return -EINVAL; - eurwdt_timeout = time; + timeout = time; eurwdt_set_timeout(time); return 0; } @@ -280,16 +304,18 @@ static int eurwdt_open(struct inode *inode, struct file *file) { - switch (MINOR(inode->i_rdev)) { + switch (minor(inode->i_rdev)) { case WATCHDOG_MINOR: spin_lock(&eurwdt_lock); if (eurwdt_is_open) { spin_unlock(&eurwdt_lock); return -EBUSY; } + if (nowayout) { + MOD_INC_USE_COUNT; + } eurwdt_is_open = 1; - eurwdt_timeout = WDT_TIMEOUT; /* initial timeout */ /* Activate the WDT */ eurwdt_activate_timer(); @@ -322,13 +348,13 @@ static int eurwdt_release(struct inode *inode, struct file *file) { - if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - eurwdt_disable_timer(); -#endif - eurwdt_is_open = 0; + if (minor(inode->i_rdev) == WATCHDOG_MINOR) { + if (!nowayout) { + eurwdt_disable_timer(); + } + eurwdt_is_open = 0; - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; } return 0; @@ -422,7 +448,8 @@ static int __init eurwdt_init(void) { int ret; - + + eurwdt_validate_timeout(); ret = misc_register(&eurwdt_miscdev); if (ret) { printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ftape/lowlevel/ftape-buffer.c linux-2.5/drivers/char/ftape/lowlevel/ftape-buffer.c --- linux-2.5.1/drivers/char/ftape/lowlevel/ftape-buffer.c Fri Feb 9 19:30:22 2001 +++ linux-2.5/drivers/char/ftape/lowlevel/ftape-buffer.c Sun Dec 30 21:17:30 2001 @@ -24,7 +24,6 @@ * buffer. */ -#include <asm/segment.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/mman.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ftape/lowlevel/ftape-io.c linux-2.5/drivers/char/ftape/lowlevel/ftape-io.c --- linux-2.5.1/drivers/char/ftape/lowlevel/ftape-io.c Mon Oct 16 19:58:51 2000 +++ linux-2.5/drivers/char/ftape/lowlevel/ftape-io.c Sun Dec 30 21:17:30 2001 @@ -29,7 +29,6 @@ #include <linux/errno.h> #include <linux/sched.h> #include <linux/mm.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/ioctl.h> #include <linux/mtio.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ftape/lowlevel/ftape-read.c linux-2.5/drivers/char/ftape/lowlevel/ftape-read.c --- linux-2.5.1/drivers/char/ftape/lowlevel/ftape-read.c Tue Nov 25 22:45:27 1997 +++ linux-2.5/drivers/char/ftape/lowlevel/ftape-read.c Sun Dec 30 21:17:30 2001 @@ -29,7 +29,6 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/mm.h> -#include <asm/segment.h> #include <linux/ftape.h> #include <linux/qic117.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ftape/lowlevel/ftape-setup.c linux-2.5/drivers/char/ftape/lowlevel/ftape-setup.c --- linux-2.5.1/drivers/char/ftape/lowlevel/ftape-setup.c Thu Aug 12 18:53:22 1999 +++ linux-2.5/drivers/char/ftape/lowlevel/ftape-setup.c Sun Dec 30 21:17:30 2001 @@ -29,7 +29,6 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/mm.h> -#include <asm/segment.h> #include <linux/ftape.h> #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,16) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ftape/lowlevel/ftape-write.c linux-2.5/drivers/char/ftape/lowlevel/ftape-write.c --- linux-2.5.1/drivers/char/ftape/lowlevel/ftape-write.c Mon Oct 16 19:58:51 2000 +++ linux-2.5/drivers/char/ftape/lowlevel/ftape-write.c Sun Dec 30 21:17:30 2001 @@ -28,7 +28,6 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/mm.h> -#include <asm/segment.h> #include <linux/ftape.h> #include <linux/qic117.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ftape/zftape/zftape-buffers.c linux-2.5/drivers/char/ftape/zftape/zftape-buffers.c --- linux-2.5.1/drivers/char/ftape/zftape/zftape-buffers.c Fri Feb 9 19:30:22 2001 +++ linux-2.5/drivers/char/ftape/zftape/zftape-buffers.c Sun Dec 30 21:17:30 2001 @@ -27,7 +27,6 @@ #include <linux/errno.h> #include <linux/mm.h> #include <linux/slab.h> -#include <asm/segment.h> #include <linux/zftape.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ftape/zftape/zftape-init.c linux-2.5/drivers/char/ftape/zftape/zftape-init.c --- linux-2.5.1/drivers/char/ftape/zftape/zftape-init.c Fri Nov 30 20:33:17 2001 +++ linux-2.5/drivers/char/ftape/zftape/zftape-init.c Sun Jan 6 01:38:26 2002 @@ -25,7 +25,6 @@ #include <linux/errno.h> #include <linux/version.h> #include <linux/fs.h> -#include <asm/segment.h> #include <linux/kernel.h> #include <linux/signal.h> #include <linux/major.h> @@ -113,11 +112,11 @@ int result; TRACE_FUN(ft_t_flow); - TRACE(ft_t_flow, "called for minor %d", MINOR(ino->i_rdev)); + TRACE(ft_t_flow, "called for minor %d", minor(ino->i_rdev)); if ( test_and_set_bit(0,&busy_flag) ) { TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy"); } - if ((MINOR(ino->i_rdev) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND)) + if ((minor(ino->i_rdev) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND)) > FTAPE_SEL_D) { clear_bit(0,&busy_flag); @@ -125,7 +124,7 @@ } orig_sigmask = current->blocked; sigfillset(¤t->blocked); - result = _zft_open(MINOR(ino->i_rdev), filep->f_flags & O_ACCMODE); + result = _zft_open(minor(ino->i_rdev), filep->f_flags & O_ACCMODE); if (result < 0) { current->blocked = orig_sigmask; /* restore mask */ clear_bit(0,&busy_flag); @@ -147,7 +146,7 @@ int result; TRACE_FUN(ft_t_flow); - if ( !test_bit(0,&busy_flag) || MINOR(ino->i_rdev) != zft_unit) { + if ( !test_bit(0,&busy_flag) || minor(ino->i_rdev) != zft_unit) { TRACE(ft_t_err, "failed: not busy or wrong unit"); TRACE_EXIT 0; } @@ -170,7 +169,7 @@ sigset_t old_sigmask; TRACE_FUN(ft_t_flow); - if ( !test_bit(0,&busy_flag) || MINOR(ino->i_rdev) != zft_unit || ft_failure) { + if ( !test_bit(0,&busy_flag) || minor(ino->i_rdev) != zft_unit || ft_failure) { TRACE_ABORT(-EIO, ft_t_err, "failed: not busy, failure or wrong unit"); } @@ -191,7 +190,7 @@ TRACE_FUN(ft_t_flow); if ( !test_bit(0,&busy_flag) || - MINOR(filep->f_dentry->d_inode->i_rdev) != zft_unit || + minor(filep->f_dentry->d_inode->i_rdev) != zft_unit || ft_failure) { TRACE_ABORT(-EIO, ft_t_err, @@ -220,7 +219,7 @@ TRACE_FUN(ft_t_flow); TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len); - if (!test_bit(0,&busy_flag) || MINOR(ino->i_rdev) != zft_unit || ft_failure) { + if (!test_bit(0,&busy_flag) || minor(ino->i_rdev) != zft_unit || ft_failure) { TRACE_ABORT(-EIO, ft_t_err, "failed: not busy, failure or wrong unit"); } @@ -243,7 +242,7 @@ TRACE_FUN(ft_t_flow); TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len); - if (!test_bit(0,&busy_flag) || MINOR(ino->i_rdev) != zft_unit || ft_failure) { + if (!test_bit(0,&busy_flag) || minor(ino->i_rdev) != zft_unit || ft_failure) { TRACE_ABORT(-EIO, ft_t_err, "failed: not busy, failure or wrong unit"); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ftape/zftape/zftape-rw.c linux-2.5/drivers/char/ftape/zftape/zftape-rw.c --- linux-2.5.1/drivers/char/ftape/zftape/zftape-rw.c Mon Oct 16 19:58:51 2000 +++ linux-2.5/drivers/char/ftape/zftape/zftape-rw.c Sun Dec 30 21:17:30 2001 @@ -27,7 +27,6 @@ #include <linux/config.h> /* for CONFIG_ZFT_DFLT_BLK_SZ */ #include <linux/errno.h> #include <linux/mm.h> -#include <asm/segment.h> #include <linux/zftape.h> #include "../zftape/zftape-init.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ftape/zftape/zftape-vtbl.c linux-2.5/drivers/char/ftape/zftape/zftape-vtbl.c --- linux-2.5.1/drivers/char/ftape/zftape/zftape-vtbl.c Fri Apr 6 17:42:55 2001 +++ linux-2.5/drivers/char/ftape/zftape/zftape-vtbl.c Sun Dec 30 21:17:30 2001 @@ -31,7 +31,6 @@ #include <linux/errno.h> #include <linux/mm.h> #include <linux/slab.h> -#include <asm/segment.h> #include <linux/zftape.h> #include "../zftape/zftape-init.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/generic_serial.c linux-2.5/drivers/char/generic_serial.c --- linux-2.5.1/drivers/char/generic_serial.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/char/generic_serial.c Fri Dec 28 01:15:11 2001 @@ -143,7 +143,12 @@ /* Can't copy more? break out! */ if (c <= 0) break; if (from_user) - copy_from_user (port->xmit_buf + port->xmit_head, buf, c); + if (copy_from_user (port->xmit_buf + port->xmit_head, + buf, c)) { + up (& port->port_write_sem); + return -EFAULT; + } + else memcpy (port->xmit_buf + port->xmit_head, buf, c); @@ -214,8 +219,13 @@ while (1) { c = count; - /* This is safe because we "OWN" the "head". Noone else can - change the "head": we own the port_write_sem. */ + /* Note: This part can be done without + * interrupt routine protection since + * the interrupt routines may only modify + * shared variables in safe ways, in the worst + * case causing us to loop twice in the code + * below. See comments below. */ + /* Don't overrun the end of the buffer */ t = SERIAL_XMIT_SIZE - port->xmit_head; if (t < c) c = t; @@ -506,7 +516,7 @@ void gs_shutdown_port (struct gs_port *port) { - long flags; + unsigned long flags; func_enter(); @@ -589,6 +599,7 @@ int do_clocal = 0; int CD; struct tty_struct *tty; + unsigned long flags; func_enter (); @@ -604,7 +615,7 @@ * until it's done, and then try again. */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&port->close_wait); + interruptible_sleep_on(&port->close_wait); if (port->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else @@ -668,10 +679,11 @@ add_wait_queue(&port->open_wait, &wait); gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); + save_flags(flags); cli(); if (!tty_hung_up_p(filp)) port->count--; - sti(); + restore_flags(flags); port->blocked_open++; while (1) { CD = port->rd->get_CD (port); @@ -1003,7 +1015,8 @@ { struct serial_struct sio; - copy_from_user(&sio, sp, sizeof(struct serial_struct)); + if (copy_from_user(&sio, sp, sizeof(struct serial_struct))) + return(-EFAULT); if (!capable(CAP_SYS_ADMIN)) { if ((sio.baud_base != port->baud_base) || @@ -1033,7 +1046,7 @@ * Generate the serial struct info. */ -void gs_getserial(struct gs_port *port, struct serial_struct *sp) +int gs_getserial(struct gs_port *port, struct serial_struct *sp) { struct serial_struct sio; @@ -1055,7 +1068,10 @@ if (port->rd->getserial) port->rd->getserial (port, &sio); - copy_to_user(sp, &sio, sizeof(struct serial_struct)); + if (copy_to_user(sp, &sio, sizeof(struct serial_struct))) + return -EFAULT; + return 0; + } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/h8.c linux-2.5/drivers/char/h8.c --- linux-2.5.1/drivers/char/h8.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/char/h8.c Sun Dec 30 21:17:30 2001 @@ -14,7 +14,6 @@ #include <linux/module.h> #include <asm/system.h> -#include <asm/segment.h> #include <asm/io.h> #include <linux/types.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/i810-tco.c linux-2.5/drivers/char/i810-tco.c --- linux-2.5.1/drivers/char/i810-tco.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/char/i810-tco.c Sun Jan 13 22:15:01 2002 @@ -1,5 +1,5 @@ /* - * i810-tco 0.02: TCO timer driver for i810 chipsets + * i810-tco 0.03: TCO timer driver for i810 chipsets * * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved. * http://www.kernelconcepts.de @@ -28,6 +28,9 @@ * Initial Version 0.01 * 20000728 Nils Faerber * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups + * 20011214 Matt Domsch <Matt_Domsch@dell.com> + * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Didn't add timeout option as i810_margin already exists. */ #include <linux/module.h> @@ -60,6 +63,18 @@ static int i810_margin = TIMER_MARGIN; /* steps of 0.6sec */ MODULE_PARM (i810_margin, "i"); +MODULE_PARM_DESC(i810_margin, "Watchdog timeout in steps of 0.6sec, 2<n<64. Default = 50 (30 seconds)"); + + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * Timer active flag @@ -167,6 +182,9 @@ if (timer_alive) return -EBUSY; + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Reload and activate timer */ @@ -181,10 +199,10 @@ /* * Shut off the timer. */ -#ifdef CONFIG_WATCHDOG_NOWAYOUT - tco_timer_stop (); - timer_alive = 0; -#endif + if (nowayout) { + tco_timer_stop (); + timer_alive = 0; + } return 0; } @@ -342,8 +360,8 @@ tco_timer_reload (); printk (KERN_INFO - "i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n", - (int) (i810_margin * 6 / 10), TCOBASE); + "i810 TCO timer: V0.03, timer margin: %d sec (0x%04x), nowayout: %d\n", + (int) (i810_margin * 6 / 10), TCOBASE, nowayout); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/i8k.c linux-2.5/drivers/char/i8k.c --- linux-2.5.1/drivers/char/i8k.c Sat Nov 3 01:46:47 2001 +++ linux-2.5/drivers/char/i8k.c Thu Dec 13 16:32:35 2001 @@ -1,5 +1,7 @@ /* - * i8k.c -- Linux driver for accessing the SMM BIOS on Dell I8000 laptops + * i8k.c -- Linux driver for accessing the SMM BIOS on Dell laptops. + * See http://www.debian.org/~dz/i8k/ for more information + * and for latest version of this driver. * * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org> * @@ -19,15 +21,13 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/proc_fs.h> -#include <asm/io.h> +#include <linux/apm_bios.h> #include <asm/uaccess.h> +#include <asm/io.h> #include <linux/i8k.h> -#define I8K_VERSION "1.1 02/11/2001" -#define I8K_BIOS_SIGNATURE "Dell System Inspiron 8000" -#define I8K_BIOS_SIGNATURE_ADDR 0x000ec000 -#define I8K_BIOS_VERSION_OFFSET 32 +#define I8K_VERSION "1.7 21/11/2001" #define I8K_SMM_FN_STATUS 0x0025 #define I8K_SMM_POWER_STATUS 0x0069 @@ -35,31 +35,47 @@ #define I8K_SMM_GET_FAN 0x00a3 #define I8K_SMM_GET_SPEED 0x02a3 #define I8K_SMM_GET_TEMP 0x10a3 +#define I8K_SMM_GET_DELL_SIG 0xffa3 #define I8K_SMM_BIOS_VERSION 0x00a6 #define I8K_FAN_MULT 30 #define I8K_MAX_TEMP 127 -#define I8K_FN_NONE 0x08 -#define I8K_FN_UP 0x09 -#define I8K_FN_DOWN 0x0a -#define I8K_FN_MUTE 0x0c +#define I8K_FN_NONE 0x00 +#define I8K_FN_UP 0x01 +#define I8K_FN_DOWN 0x02 +#define I8K_FN_MUTE 0x04 +#define I8K_FN_MASK 0x07 +#define I8K_FN_SHIFT 8 #define I8K_POWER_AC 0x05 #define I8K_POWER_BATTERY 0x01 #define I8K_TEMPERATURE_BUG 1 -static char bios_version[4] = "?"; -static char bios_machine_id[16] = "?"; +#define DELL_SIGNATURE "Dell Computer" + +static char *supported_models[] = { + "Inspiron", + "Latitude", + NULL +}; + +static char system_vendor[48] = "?"; +static char product_name [48] = "?"; +static char bios_version [4] = "?"; +static char serial_number[16] = "?"; int force = 0; +int power_status = 0; MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); -MODULE_DESCRIPTION("Driver for accessing the SMM BIOS on Dell I8000 laptops"); +MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); MODULE_LICENSE("GPL"); MODULE_PARM(force, "i"); -MODULE_PARM_DESC(force, "Force loading without checking for an Inspiron 8000"); +MODULE_PARM(power_status, "i"); +MODULE_PARM_DESC(force, "Force loading without checking for supported models"); +MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); static ssize_t i8k_read(struct file *, char *, size_t, loff_t *); static int i8k_ioctl(struct inode *, struct file *, unsigned int, @@ -79,12 +95,19 @@ unsigned int edi __attribute__ ((packed)); } SMMRegisters; +typedef struct { + u8 type; + u8 length; + u16 handle; +} DMIHeader; + /* - * Call the System Management Mode BIOS. + * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard. */ static int i8k_smm(SMMRegisters *regs) { int rc; + int eax = regs->eax; asm("pushl %%eax\n\t" \ "movl 0(%%eax),%%edx\n\t" \ @@ -112,7 +135,7 @@ : "a" (regs) : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); - if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff)) { + if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) { return -EINVAL; } @@ -137,11 +160,12 @@ } /* - * Read the machine id. Not yet implemented. + * Read the machine id. */ -static int i8k_get_machine_id(unsigned char *buff) +static int i8k_get_serial_number(unsigned char *buff) { - return -EINVAL; + strncpy(buff, serial_number, 16); + return 0; } /* @@ -157,7 +181,7 @@ return rc; } - switch ((regs.eax & 0xff00) >> 8) { + switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { case I8K_FN_UP: return I8K_VOL_UP; case I8K_FN_DOWN: @@ -281,6 +305,23 @@ return temp; } +static int i8k_get_dell_signature(void) +{ + SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; + int rc; + + regs.eax = I8K_SMM_GET_DELL_SIG; + if ((rc=i8k_smm(®s)) < 0) { + return rc; + } + + if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) { + return 0; + } else { + return -1; + } +} + static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { @@ -299,7 +340,7 @@ case I8K_MACHINE_ID: memset(buff, 0, 16); - val = i8k_get_machine_id(buff); + val = i8k_get_serial_number(buff); break; case I8K_FN_STATUS: @@ -375,13 +416,17 @@ int n, fn_key, cpu_temp, ac_power; int left_fan, right_fan, left_speed, right_speed; - cpu_temp = i8k_get_cpu_temp(); - left_fan = i8k_get_fan_status(I8K_FAN_LEFT); - right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); - left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); - right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); - ac_power = i8k_get_power_status(); - fn_key = i8k_get_fn_status(); + cpu_temp = i8k_get_cpu_temp(); /* 11100 µs */ + left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ + right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ + left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ + right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ + fn_key = i8k_get_fn_status(); /* 750 µs */ + if (power_status) { + ac_power = i8k_get_power_status(); /* 14700 µs */ + } else { + ac_power = -1; + } /* * Info: @@ -400,7 +445,7 @@ n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n", I8K_PROC_FMT, bios_version, - bios_machine_id, + serial_number, cpu_temp, left_fan, right_fan, @@ -438,76 +483,253 @@ return len; } +static char* __init string_trim(char *s, int size) +{ + int len; + char *p; + + if ((len = strlen(s)) > size) { + len = size; + } + + for (p=s+len-1; len && (*p==' '); len--,p--) { + *p = '\0'; + } + + return s; +} + +/* DMI code, stolen from arch/i386/kernel/dmi_scan.c */ + /* - * Probe for the presence of an Inspiron I8000. + * |<-- dmi->length -->| + * | | + * |dmi header s=N | string1,\0, ..., stringN,\0, ..., \0 + * | | + * +-----------------------+ */ -static int i8k_probe(void) +static char* __init dmi_string(DMIHeader *dmi, u8 s) { - unsigned char *buff, *p; - unsigned char bios_vers[4]; - int version; + u8 *p; + + if (!s) { + return ""; + } + s--; + + p = (u8 *)dmi + dmi->length; + while (s > 0) { + p += strlen(p); + p++; + s--; + } + + return p; +} + +static void __init dmi_decode(DMIHeader *dmi) +{ + u8 *data = (u8 *) dmi; + char *p; + +#ifdef I8K_DEBUG + int i; + printk("%08x ", (int)data); + for (i=0; i<data[1] && i<64; i++) { + printk("%02x ", data[i]); + } + printk("\n"); +#endif + + switch (dmi->type) { + case 0: /* BIOS Information */ + p = dmi_string(dmi,data[5]); + if (*p) { + strncpy(bios_version, p, sizeof(bios_version)); + string_trim(bios_version, sizeof(bios_version)); + } + break; + case 1: /* System Information */ + p = dmi_string(dmi,data[4]); + if (*p) { + strncpy(system_vendor, p, sizeof(system_vendor)); + string_trim(system_vendor, sizeof(system_vendor)); + } + p = dmi_string(dmi,data[5]); + if (*p) { + strncpy(product_name, p, sizeof(product_name)); + string_trim(product_name, sizeof(product_name)); + } + p = dmi_string(dmi,data[7]); + if (*p) { + strncpy(serial_number, p, sizeof(serial_number)); + string_trim(serial_number, sizeof(serial_number)); + } + break; + } +} + +static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*)) +{ + u8 *buf; + u8 *data; + DMIHeader *dmi; + int i = 1; + + buf = ioremap(base, len); + if (buf == NULL) { + return -1; + } + data = buf; /* - * Until Dell tell us how to reliably check for an Inspiron system - * look for a signature at a fixed location in the BIOS memory. - * Ugly but safe. + * Stop when we see al the items the table claimed to have + * or we run off the end of the table (also happens) */ - if (!force) { - buff = ioremap(I8K_BIOS_SIGNATURE_ADDR, I8K_BIOS_VERSION_OFFSET+4); - if (buff == NULL) { - printk("i8k: ioremap failed\n"); - return -ENODEV; + while ((i<num) && ((data-buf) < len)) { + dmi = (DMIHeader *)data; + /* + * Avoid misparsing crud if the length of the last + * record is crap + */ + if ((data-buf+dmi->length) >= len) { + break; + } + fn(dmi); + data += dmi->length; + /* + * Don't go off the end of the data if there is + * stuff looking like string fill past the end + */ + while (((data-buf) < len) && (*data || data[1])) { + data++; } - if (strncmp(buff,I8K_BIOS_SIGNATURE,sizeof(I8K_BIOS_SIGNATURE)) != 0) { - printk("i8k: Inspiron 8000 BIOS signature not found\n"); - iounmap(buff); - return -ENODEV; + data += 2; + i++; + } + iounmap(buf); + + return 0; +} + +static int __init dmi_iterate(void (*decode)(DMIHeader *)) +{ + unsigned char buf[20]; + long fp = 0x000e0000L; + fp -= 16; + + while (fp < 0x000fffffL) { + fp += 16; + isa_memcpy_fromio(buf, fp, 20); + if (memcmp(buf, "_DMI_", 5)==0) { + u16 num = buf[13]<<8 | buf[12]; + u16 len = buf [7]<<8 | buf [6]; + u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]; +#ifdef I8K_DEBUG + printk(KERN_INFO "DMI %d.%d present.\n", + buf[14]>>4, buf[14]&0x0F); + printk(KERN_INFO "%d structures occupying %d bytes.\n", + buf[13]<<8 | buf[12], + buf [7]<<8 | buf[6]); + printk(KERN_INFO "DMI table at 0x%08X.\n", + buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]); +#endif + if (dmi_table(base, len, num, decode)==0) { + return 0; + } } - strncpy(bios_vers, buff+I8K_BIOS_VERSION_OFFSET, 3); - bios_vers[3] = '\0'; - iounmap(buff); - } - if (force >= 2) { - buff = ioremap(0x000c0000, 0x00100000-0x000c0000); - if (buff == NULL) { - printk("i8k: ioremap failed\n"); + } + return -1; +} +/* end of DMI code */ + +/* + * Get DMI information. + */ +static int __init i8k_dmi_probe(void) +{ + char **p; + + if (dmi_iterate(dmi_decode) != 0) { + printk(KERN_INFO "i8k: unable to get DMI information\n"); + return -ENODEV; + } + + if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) { + printk(KERN_INFO "i8k: not running on a Dell system\n"); + return -ENODEV; + } + + for (p=supported_models; ; p++) { + if (!*p) { + printk(KERN_INFO "i8k: unsupported model: %s\n", product_name); return -ENODEV; } - for (p=buff; (p-buff)<(0x00100000-0x000c0000); p+=16) { - if (strncmp(p,I8K_BIOS_SIGNATURE,sizeof(I8K_BIOS_SIGNATURE))==0) { - printk("i8k: Inspiron 8000 BIOS signature found at %08x\n", - 0x000c0000+(p-buff)); - break; - } + if (strncmp(product_name,*p,strlen(*p)) == 0) { + break; } - iounmap(buff); } + return 0; +} + +/* + * Probe for the presence of a supported laptop. + */ +static int __init i8k_probe(void) +{ + char buff[4]; + int version; + int smm_found = 0; + /* - * Next try to get the BIOS version with an SMM call. If this - * fails SMM can't be reliably used on this system. + * Get DMI information */ - version = i8k_get_bios_version(); - if (version <= 0) { - printk("i8k: unable to get BIOS version\n"); - return -ENODEV; + if (i8k_dmi_probe() != 0) { + printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n", + system_vendor, product_name, bios_version); } - bios_version[0] = (version >> 16) & 0xff; - bios_version[1] = (version >> 8) & 0xff; - bios_version[2] = (version) & 0xff; - bios_version[3] = '\0'; /* - * Finally check if the two versions match. + * Get SMM Dell signature */ - if (!force) { - if (strncmp(bios_version,bios_vers,sizeof(bios_version)) != 0) { - printk("i8k: BIOS version mismatch: %s != %s\n", - bios_version, bios_vers); - return -ENODEV; + if (i8k_get_dell_signature() != 0) { + printk(KERN_INFO "i8k: unable to get SMM Dell signature\n"); + } else { + smm_found = 1; + } + + /* + * Get SMM BIOS version. + */ + version = i8k_get_bios_version(); + if (version <= 0) { + printk(KERN_INFO "i8k: unable to get SMM BIOS version\n"); + } else { + smm_found = 1; + buff[0] = (version >> 16) & 0xff; + buff[1] = (version >> 8) & 0xff; + buff[2] = (version) & 0xff; + buff[3] = '\0'; + /* + * If DMI BIOS version is unknown use SMM BIOS version. + */ + if (bios_version[0] == '?') { + strcpy(bios_version, buff); + } + /* + * Check if the two versions match. + */ + if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) { + printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n", + buff, bios_version); } } + if (!smm_found && !force) { + return -ENODEV; + } + return 0; } @@ -518,7 +740,7 @@ { struct proc_dir_entry *proc_i8k; - /* Are we running on an Inspiron 8000 laptop? */ + /* Are we running on an supported laptop? */ if (i8k_probe() != 0) { return -ENODEV; } @@ -532,7 +754,7 @@ SET_MODULE_OWNER(proc_i8k); printk(KERN_INFO - "Inspiron 8000 SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", + "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", I8K_VERSION); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ib700wdt.c linux-2.5/drivers/char/ib700wdt.c --- linux-2.5.1/drivers/char/ib700wdt.c Thu Oct 11 16:07:00 2001 +++ linux-2.5/drivers/char/ib700wdt.c Sun Jan 13 22:15:01 2002 @@ -25,6 +25,10 @@ * * (c) Copyright 1995 Alan Cox <alan@redhat.com> * + * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default + * */ #include <linux/config.h> @@ -92,15 +96,36 @@ #define WD_TIMO 0 /* 30 seconds +/- 20%, from table */ +static int timeout_val = WD_TIMO; /* value in table */ +static int timeout = 30; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, 0 < n < 30, must be even (default=30)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * Kernel methods. */ +static void __init +ibwdt_validate_timeout(void) +{ + timeout_val = (30 - timeout) / 2; + if (timeout_val < 0 || timeout_val > 0xF) timeout_val = WD_TIMO; +} + static void ibwdt_ping(void) { /* Write a watchdog value */ - outb_p(WD_TIMO, WDT_START); + outb_p(timeout_val, WDT_START); } static ssize_t @@ -155,13 +180,16 @@ static int ibwdt_open(struct inode *inode, struct file *file) { - switch (MINOR(inode->i_rdev)) { + switch (minor(inode->i_rdev)) { case WATCHDOG_MINOR: spin_lock(&ibwdt_lock); if (ibwdt_is_open) { spin_unlock(&ibwdt_lock); return -EBUSY; } + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate */ @@ -179,11 +207,11 @@ ibwdt_close(struct inode *inode, struct file *file) { lock_kernel(); - if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { + if (minor(inode->i_rdev) == WATCHDOG_MINOR) { spin_lock(&ibwdt_lock); -#ifndef CONFIG_WATCHDOG_NOWAYOUT - outb_p(WD_TIMO, WDT_STOP); -#endif + if (!nowayout) { + outb_p(timeout_val, WDT_STOP); + } ibwdt_is_open = 0; spin_unlock(&ibwdt_lock); } @@ -201,7 +229,7 @@ { if (code == SYS_DOWN || code == SYS_HALT) { /* Turn the WDT off */ - outb_p(WD_TIMO, WDT_STOP); + outb_p(timeout_val, WDT_STOP); } return NOTIFY_DONE; } @@ -241,6 +269,7 @@ { printk("WDT driver for IB700 single board computer initialising.\n"); + ibwdt_validate_timeout(); spin_lock_init(&ibwdt_lock); misc_register(&ibwdt_miscdev); #if WDT_START != WDT_STOP diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ip2/i2cmd.c linux-2.5/drivers/char/ip2/i2cmd.c --- linux-2.5.1/drivers/char/ip2/i2cmd.c Wed Oct 24 19:05:18 2001 +++ linux-2.5/drivers/char/ip2/i2cmd.c Thu Dec 13 16:32:35 2001 @@ -139,7 +139,7 @@ //static UCHAR ct86[]={ 2, BTH, 0x56,0 }; // RCV_ENABLE static UCHAR ct87[] = { 1, BYP, 0x57 }; // HW_TEST //static UCHAR ct88[]={ 3, BTH, 0x58,0,0 }; // RCV_THRESHOLD -static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW +//static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW //static UCHAR ct90[]={ 3, BYP, 0x5A,0,0 }; // Set SILO //static UCHAR ct91[]={ 2, BYP, 0x5B,0 }; // timed break diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ip2.c linux-2.5/drivers/char/ip2.c --- linux-2.5.1/drivers/char/ip2.c Wed Oct 24 19:05:18 2001 +++ linux-2.5/drivers/char/ip2.c Thu Dec 13 16:32:35 2001 @@ -33,9 +33,10 @@ */ static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 }; static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; -static int poll_only = 0; #ifdef MODULE + +static int poll_only = 0; # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) MODULE_AUTHOR("Doug McNash"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ip2main.c linux-2.5/drivers/char/ip2main.c --- linux-2.5.1/drivers/char/ip2main.c Sat Nov 3 01:26:17 2001 +++ linux-2.5/drivers/char/ip2main.c Sun Jan 6 01:38:26 2002 @@ -142,7 +142,6 @@ // so blame them. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,4) -# include <asm/segment.h> # define GET_USER(error,value,addr) error = get_user(value,addr) # define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 # define PUT_USER(error,value,addr) error = put_user(value,addr) @@ -1590,9 +1589,9 @@ wait_queue_t wait; int rc = 0; int do_clocal = 0; - i2ChanStrPtr pCh = DevTable[MINOR(tty->device)]; + i2ChanStrPtr pCh = DevTable[minor(tty->device)]; - ip2trace (MINOR(tty->device), ITRC_OPEN, ITRC_ENTER, 0 ); + ip2trace (minor(tty->device), ITRC_OPEN, ITRC_ENTER, 0 ); if ( pCh == NULL ) { return -ENODEV; @@ -1605,7 +1604,7 @@ #ifdef IP2DEBUG_OPEN printk(KERN_DEBUG \ "IP2:open(tty=%p,pFile=%p):dev=%x,maj=%d,min=%d,ch=%d,idx=%d\n", - tty, pFile, tty->device, MAJOR(tty->device), MINOR(tty->device), + tty, pFile, tty->device, major(tty->device), minor(tty->device), pCh->infl.hd.i2sChannel, pCh->port_index); open_sanity_check ( pCh, pCh->pMyBord ); #endif @@ -1797,7 +1796,7 @@ ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 ); #ifdef IP2DEBUG_OPEN - printk(KERN_DEBUG "IP2:close ttyF%02X:\n",MINOR(tty->device)); + printk(KERN_DEBUG "IP2:close ttyF%02X:\n",minor(tty->device)); #endif if ( tty_hung_up_p ( pFile ) ) { @@ -2206,7 +2205,7 @@ static void ip2_start ( PTTY tty ) { - i2ChanStrPtr pCh = DevTable[MINOR(tty->device)]; + i2ChanStrPtr pCh = DevTable[minor(tty->device)]; i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME); i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND); @@ -2219,7 +2218,7 @@ static void ip2_stop ( PTTY tty ) { - i2ChanStrPtr pCh = DevTable[MINOR(tty->device)]; + i2ChanStrPtr pCh = DevTable[minor(tty->device)]; i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND); #ifdef IP2DEBUG_WRITE @@ -2247,7 +2246,7 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg ) { wait_queue_t wait; - i2ChanStrPtr pCh = DevTable[MINOR(tty->device)]; + i2ChanStrPtr pCh = DevTable[minor(tty->device)]; struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct *p_cuser; /* user space */ int rc = 0; @@ -3011,12 +3010,12 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) int ip2_ipl_read(struct inode *pInode, char *pData, size_t count, loff_t *off ) - unsigned int minor = MINOR( pInode->i_rdev ); + unsigned int minor = minor( pInode->i_rdev ); #else ssize_t ip2_ipl_read(struct file *pFile, char *pData, size_t count, loff_t *off ) { - unsigned int minor = MINOR( pFile->f_dentry->d_inode->i_rdev ); + unsigned int minor = minor( pFile->f_dentry->d_inode->i_rdev ); #endif int rc = 0; @@ -3147,7 +3146,7 @@ static int ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg ) { - unsigned int iplminor = MINOR(pInode->i_rdev); + unsigned int iplminor = minor(pInode->i_rdev); int rc = 0; ULONG *pIndex = (ULONG*)arg; i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4]; @@ -3282,7 +3281,7 @@ static int ip2_ipl_open( struct inode *pInode, struct file *pFile ) { - unsigned int iplminor = MINOR(pInode->i_rdev); + unsigned int iplminor = minor(pInode->i_rdev); i2eBordStrPtr pB; i2ChanStrPtr pCh; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/isicom.c linux-2.5/drivers/char/isicom.c --- linux-2.5.1/drivers/char/isicom.c Fri Nov 9 22:01:21 2001 +++ linux-2.5/drivers/char/isicom.c Sun Jan 6 01:38:26 2002 @@ -51,7 +51,6 @@ #include <linux/timer.h> #include <linux/ioport.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/system.h> @@ -1022,7 +1021,7 @@ #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: open start!!!.\n"); #endif - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; #ifdef ISICOM_DEBUG printk(KERN_DEBUG "line = %d.\n", line); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/istallion.c linux-2.5/drivers/char/istallion.c --- linux-2.5.1/drivers/char/istallion.c Thu Oct 25 20:53:47 2001 +++ linux-2.5/drivers/char/istallion.c Sun Jan 6 01:38:26 2002 @@ -1034,7 +1034,7 @@ (int) filp, tty->device); #endif - minordev = MINOR(tty->device); + minordev = minor(tty->device); brdnr = MINOR2BRD(minordev); if (brdnr >= stli_nrbrds) return(-ENODEV); @@ -4859,7 +4859,7 @@ (int) fp, (int) buf, count, (int) offp); #endif - brdnr = MINOR(fp->f_dentry->d_inode->i_rdev); + brdnr = minor(fp->f_dentry->d_inode->i_rdev); if (brdnr >= stli_nrbrds) return(-ENODEV); brdp = stli_brds[brdnr]; @@ -4910,7 +4910,7 @@ (int) fp, (int) buf, count, (int) offp); #endif - brdnr = MINOR(fp->f_dentry->d_inode->i_rdev); + brdnr = minor(fp->f_dentry->d_inode->i_rdev); if (brdnr >= stli_nrbrds) return(-ENODEV); brdp = stli_brds[brdnr]; @@ -5247,7 +5247,7 @@ * Now handle the board specific ioctls. These all depend on the * minor number of the device they were called from. */ - brdnr = MINOR(ip->i_rdev); + brdnr = minor(ip->i_rdev); if (brdnr >= STL_MAXBRDS) return(-ENODEV); brdp = stli_brds[brdnr]; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ite_gpio.c linux-2.5/drivers/char/ite_gpio.c --- linux-2.5.1/drivers/char/ite_gpio.c Sun Sep 9 17:43:02 2001 +++ linux-2.5/drivers/char/ite_gpio.c Sun Jan 6 01:38:26 2002 @@ -238,7 +238,7 @@ static int ite_gpio_open(struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); if (minor != GPIO_MINOR) return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/joystick/cs461x.c linux-2.5/drivers/char/joystick/cs461x.c --- linux-2.5.1/drivers/char/joystick/cs461x.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/char/joystick/cs461x.c Thu Dec 13 16:32:35 2001 @@ -313,7 +313,7 @@ name: "PCI Gameport", id_table: cs461x_pci_tbl, probe: cs461x_pci_probe, - remove: cs461x_pci_remove, + remove: __devexit_p(cs461x_pci_remove), }; int __init js_cs461x_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/joystick/emu10k1-gp.c linux-2.5/drivers/char/joystick/emu10k1-gp.c --- linux-2.5.1/drivers/char/joystick/emu10k1-gp.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/char/joystick/emu10k1-gp.c Thu Dec 13 16:32:35 2001 @@ -108,7 +108,7 @@ name: "Emu10k1 Gameport", id_table: emu_tbl, probe: emu_probe, - remove: emu_remove, + remove: __devexit_p(emu_remove), }; int __init emu_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/joystick/iforce.c linux-2.5/drivers/char/joystick/iforce.c --- linux-2.5.1/drivers/char/joystick/iforce.c Wed Sep 12 22:34:06 2001 +++ linux-2.5/drivers/char/joystick/iforce.c Tue Jan 8 00:44:24 2002 @@ -134,7 +134,7 @@ #ifdef IFORCE_USB struct usb_device *usbdev; /* USB transfer */ struct urb irq, out, ctrl; - devrequest dr; + struct usb_ctrlrequest dr; #endif /* Force Feedback */ wait_queue_head_t wait; @@ -283,7 +283,7 @@ #ifdef IFORCE_USB case IFORCE_USB: - iforce->dr.request = packet[0]; + iforce->dr.bRequest = packet[0]; iforce->ctrl.dev = iforce->usbdev; set_current_state(TASK_INTERRUPTIBLE); @@ -1027,9 +1027,9 @@ iforce->bus = IFORCE_USB; iforce->usbdev = dev; - iforce->dr.requesttype = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; - iforce->dr.index = 0; - iforce->dr.length = 16; + iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; + iforce->dr.wIndex = 0; + iforce->dr.wLength = 16; FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/joystick/pcigame.c linux-2.5/drivers/char/joystick/pcigame.c --- linux-2.5.1/drivers/char/joystick/pcigame.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/char/joystick/pcigame.c Thu Dec 13 16:32:35 2001 @@ -180,7 +180,7 @@ name: "pcigame", id_table: pcigame_id_table, probe: pcigame_probe, - remove: pcigame_remove, + remove: __devexit_p(pcigame_remove), }; int __init pcigame_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/joystick/serport.c linux-2.5/drivers/char/joystick/serport.c --- linux-2.5.1/drivers/char/joystick/serport.c Wed Sep 12 22:34:06 2001 +++ linux-2.5/drivers/char/joystick/serport.c Wed Jan 2 17:23:52 2002 @@ -149,9 +149,9 @@ char name[32]; #ifdef CONFIG_DEVFS_FS - sprintf(name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start); + sprintf(name, tty->driver.name, minor(tty->device) - tty->driver.minor_start); #else - sprintf(name, "%s%d", tty->driver.name, MINOR(tty->device) - tty->driver.minor_start); + sprintf(name, "%s%d", tty->driver.name, minor(tty->device) - tty->driver.minor_start); #endif serio_register_port(&serport->serio); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/keyboard.c linux-2.5/drivers/char/keyboard.c --- linux-2.5.1/drivers/char/keyboard.c Tue Sep 18 20:39:51 2001 +++ linux-2.5/drivers/char/keyboard.c Sun Jan 13 19:20:26 2002 @@ -36,6 +36,7 @@ #include <asm/keyboard.h> #include <asm/bitops.h> +#include <linux/console_struct.h> #include <linux/kbd_kern.h> #include <linux/kbd_diacr.h> #include <linux/vt_kern.h> @@ -43,8 +44,14 @@ #include <linux/sysrq.h> #include <linux/pm.h> +extern void ctrl_alt_del(void); + #define SIZE(x) (sizeof(x)/sizeof((x)[0])) +/* + * Exported functions/variables + */ + #ifndef KBD_DEFMODE #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) #endif @@ -64,286 +71,121 @@ void (*kbd_ledfunc)(unsigned int led); EXPORT_SYMBOL(handle_scancode); EXPORT_SYMBOL(kbd_ledfunc); - -extern void ctrl_alt_del(void); - -DECLARE_WAIT_QUEUE_HEAD(keypress_wait); -struct console; - -int keyboard_wait_for_keypress(struct console *co) -{ - sleep_on(&keypress_wait); - return 0; -} +/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ +struct pt_regs * kbd_pt_regs; +void compute_shiftstate(void); /* - * global state includes the following, and various static variables - * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next. - * (last_console is now a global variable) + * Handler Tables. */ -/* shift state counters.. */ -static unsigned char k_down[NR_SHIFT]; -/* keyboard key bitmap */ -static unsigned long key_down[256/BITS_PER_LONG]; - -static int dead_key_next; -/* - * In order to retrieve the shift_state (for the mouse server), either - * the variable must be global, or a new procedure must be created to - * return the value. I chose the former way. - */ -int shift_state; -static int npadch = -1; /* -1 or number assembled on pad */ -static unsigned char diacr; -static char rep; /* flag telling character repeat */ -struct kbd_struct kbd_table[MAX_NR_CONSOLES]; -static struct tty_struct **ttytab; -static struct kbd_struct * kbd = kbd_table; -static struct tty_struct * tty; - -void compute_shiftstate(void); - -typedef void (*k_hand)(unsigned char value, char up_flag); -typedef void (k_handfn)(unsigned char value, char up_flag); - -static k_handfn - do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, - do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, - do_ignore; - -static k_hand key_handler[16] = { - do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, - do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, - do_ignore, do_ignore -}; - /* Key types processed even in raw modes */ #define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT)) +#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK)) -typedef void (*void_fnp)(void); -typedef void (void_fn)(void); - -static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, - num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, - SAK, decr_console, incr_console, spawn_console, bare_num; - -static void_fnp spec_fn_table[] = { - do_null, enter, show_ptregs, show_mem, - show_state, send_intr, lastcons, caps_toggle, - num, hold, scroll_forw, scroll_back, - boot_it, caps_on, compose, SAK, - decr_console, incr_console, spawn_console, bare_num -}; +#define K_HANDLERS\ + k_self, k_fn, k_spec, k_pad,\ + k_dead, k_cons, k_cur, k_shift,\ + k_meta, k_ascii, k_lock, k_lowercase,\ + k_slock, k_dead2, k_ignore, k_ignore + +typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, + char up_flag); +static k_handler_fn K_HANDLERS; +static k_handler_fn *k_handler[16] = { K_HANDLERS }; + +#define FN_HANDLERS\ + fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ + fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ + fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ + fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ + fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num + +typedef void (fn_handler_fn)(struct vc_data *vc); +static fn_handler_fn FN_HANDLERS; +static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; -#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK)) +/* + * Variables/functions exported for vt.c + */ /* maximum values each key_handler can handle */ const int max_vals[] = { - 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, - NR_DEAD - 1, 255, 3, NR_SHIFT - 1, - 255, NR_ASCII - 1, NR_LOCK - 1, 255, - NR_LOCK - 1, 255 + 255, SIZE(func_table) - 1, SIZE(fn_handler) - 1, NR_PAD - 1, + NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, + 255, NR_LOCK - 1, 255 }; const int NR_TYPES = SIZE(max_vals); -/* N.B. drivers/macintosh/mac_keyb.c needs to call put_queue */ -void put_queue(int); -static unsigned char handle_diacr(unsigned char); - -/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ -struct pt_regs * kbd_pt_regs; - -#ifdef CONFIG_MAGIC_SYSRQ -static int sysrq_pressed; -#endif - -static struct pm_dev *pm_kbd; - -/* - * Many other routines do put_queue, but I think either - * they produce ASCII, or they produce some user-assigned - * string, and in both cases we might assume that it is - * in utf-8 already. - */ -void to_utf8(ushort c) { - if (c < 0x80) - put_queue(c); /* 0******* */ - else if (c < 0x800) { - put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */ - put_queue(0x80 | (c & 0x3f)); - } else { - put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */ - put_queue(0x80 | ((c >> 6) & 0x3f)); - put_queue(0x80 | (c & 0x3f)); - } - /* UTF-8 is defined for words of up to 31 bits, - but we need only 16 bits here */ -} +int spawnpid, spawnsig; /* * Translation of escaped scancodes to keycodes. * This is now user-settable (for machines were it makes sense). */ - -int setkeycode(unsigned int scancode, unsigned int keycode) -{ - return kbd_setkeycode(scancode, keycode); -} - int getkeycode(unsigned int scancode) { return kbd_getkeycode(scancode); } -void handle_scancode(unsigned char scancode, int down) +int setkeycode(unsigned int scancode, unsigned int keycode) { - unsigned char keycode; - char up_flag = down ? 0 : 0200; - char raw_mode; - - pm_access(pm_kbd); - add_keyboard_randomness(scancode | up_flag); - - tty = ttytab? ttytab[fg_console]: NULL; - if (tty && (!tty->driver_data)) { - /* - * 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 - * it opens it, and clears it when it closes it. - */ - tty = NULL; - } - kbd = kbd_table + fg_console; - if ((raw_mode = (kbd->kbdmode == VC_RAW))) { - put_queue(scancode | up_flag); - /* we do not return yet, because we want to maintain - the key_down array, so that we have the correct - values when finishing RAW mode or when changing VT's */ - } - - /* - * Convert scancode to keycode - */ - if (!kbd_translate(scancode, &keycode, raw_mode)) - goto out; - - /* - * At this point the variable `keycode' contains the keycode. - * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid). - * We keep track of the up/down status of the key, and - * return the keycode if in MEDIUMRAW mode. - */ - - if (up_flag) { - rep = 0; - if(!test_and_clear_bit(keycode, key_down)) - up_flag = kbd_unexpected_up(keycode); - } else - rep = test_and_set_bit(keycode, key_down); - -#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ - if (keycode == SYSRQ_KEY) { - sysrq_pressed = !up_flag; - goto out; - } else if (sysrq_pressed) { - if (!up_flag) { - handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty); - goto out; - } - } -#endif + return kbd_setkeycode(scancode, keycode); +} - if (kbd->kbdmode == VC_MEDIUMRAW) { - /* soon keycodes will require more than one byte */ - put_queue(keycode + up_flag); - raw_mode = 1; /* Most key classes will be ignored */ - } +/* + * Variables/function exported for console.c + */ +int shift_state = 0; - /* - * Small change in philosophy: earlier we defined repetition by - * rep = keycode == prev_keycode; - * prev_keycode = keycode; - * but now by the fact that the depressed key was down already. - * Does this ever make a difference? Yes. - */ +/* + * Internal Data. + */ - /* - * Repeat a key only if the input buffers are empty or the - * characters get echoed locally. This makes key repeat usable - * with slow applications and under heavy loads. - */ - if (!rep || - (vc_kbd_mode(kbd,VC_REPEAT) && tty && - (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { - u_short keysym; - u_char type; +static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */ +static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ +static int dead_key_next; +static int npadch = -1; /* -1 or number assembled on pad */ +static unsigned char diacr; +static char rep; /* flag telling character repeat */ +pm_callback pm_kbd_request_override = NULL; +typedef void (pm_kbd_func) (void); +static struct pm_dev *pm_kbd; - /* the XOR below used to be an OR */ - int shift_final = (shift_state | kbd->slockstate) ^ - kbd->lockstate; - ushort *key_map = key_maps[shift_final]; +static unsigned char ledstate = 0xff; /* undefined */ +static unsigned char ledioctl; - if (key_map != NULL) { - keysym = key_map[keycode]; - type = KTYP(keysym); +static struct ledptr { + unsigned int *addr; + unsigned int mask; + unsigned char valid:1; +} ledptrs[3]; - if (type >= 0xf0) { - type -= 0xf0; - if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) - goto out; - if (type == KT_LETTER) { - type = KT_LATIN; - if (vc_kbd_led(kbd, VC_CAPSLOCK)) { - key_map = key_maps[shift_final ^ (1<<KG_SHIFT)]; - if (key_map) - keysym = key_map[keycode]; - } - } - (*key_handler[type])(keysym & 0xff, up_flag); - if (type != KT_SLOCK) - kbd->slockstate = 0; - } else { - /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ - if (!up_flag && !raw_mode) - to_utf8(keysym); - } - } else { - /* maybe beep? */ - /* we have at least to update shift_state */ -#if 1 /* how? two almost equivalent choices follow */ - compute_shiftstate(); - kbd->slockstate = 0; /* play it safe */ -#else - keysym = U(plain_map[keycode]); - type = KTYP(keysym); - if (type == KT_SHIFT) - (*key_handler[type])(keysym & 0xff, up_flag); +struct kbd_struct kbd_table[MAX_NR_CONSOLES]; +static struct kbd_struct *kbd = kbd_table; +#ifdef CONFIG_MAGIC_SYSRQ +static int sysrq_pressed; #endif - } - } -out: - do_poke_blanked_console = 1; - schedule_console_callback(); -} - -void put_queue(int ch) +/* + * Helper Functions. + */ +void put_queue(struct vc_data *vc, int ch) { - wake_up(&keypress_wait); + struct tty_struct *tty = vc->vc_tty; + if (tty) { tty_insert_flip_char(tty, ch, 0); con_schedule_flip(tty); } } -static void puts_queue(char *cp) +static void puts_queue(struct vc_data *vc, char *cp) { - wake_up(&keypress_wait); + struct tty_struct *tty = vc->vc_tty; + if (!tty) return; @@ -354,48 +196,139 @@ con_schedule_flip(tty); } -static void applkey(int key, char mode) +static void applkey(struct vc_data *vc, int key, char mode) { static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; buf[1] = (mode ? 'O' : '['); buf[2] = key; - puts_queue(buf); + puts_queue(vc, buf); +} + +/* + * Many other routines do put_queue, but I think either + * they produce ASCII, or they produce some user-assigned + * string, and in both cases we might assume that it is + * in utf-8 already. UTF-8 is defined for words of up to 31 bits, + * but we need only 16 bits here + */ +void to_utf8(struct vc_data *vc, ushort c) +{ + if (c < 0x80) + /* 0******* */ + put_queue(vc, c); + else if (c < 0x800) { + /* 110***** 10****** */ + put_queue(vc, 0xc0 | (c >> 6)); + put_queue(vc, 0x80 | (c & 0x3f)); + } else { + /* 1110**** 10****** 10*******/ + put_queue(vc, 0xe0 | (c >> 12)); + put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); + put_queue(vc, 0x80 | (c & 0x3f)); + } +} + +/* called after returning from RAW mode or when changing consoles - + recompute shift_down[] and shift_state from key_down[] */ +/* maybe called when keymap is undefined, so that shiftkey release is seen */ +void compute_shiftstate(void) +{ + int i, j, k, sym, val; + + shift_state = 0; + memset(shift_down, 0, sizeof(shift_down)); + + for (i = 0; i < SIZE(key_down); i++) { + + if (!key_down[i]) + continue; + + k = i*BITS_PER_LONG; + + for (j = 0; j < BITS_PER_LONG; j++, k++) { + + if (!test_bit(k, key_down)) + continue; + + sym = U(plain_map[k]); + if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) + continue; + + val = KVAL(sym); + if (val == KVAL(K_CAPSSHIFT)) + val = KVAL(K_SHIFT); + + shift_down[val]++; + shift_state |= (1<<val); + } + } +} + +/* + * We have a combining character DIACR here, followed by the character CH. + * If the combination occurs in the table, return the corresponding value. + * Otherwise, if CH is a space or equals DIACR, return DIACR. + * Otherwise, conclude that DIACR was not combining after all, + * queue it and return CH. + */ +unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) +{ + int d = diacr; + int i; + + diacr = 0; + + for (i = 0; i < accent_table_size; i++) { + if (accent_table[i].diacr == d && accent_table[i].base == ch) + return accent_table[i].result; + } + + if (ch == ' ' || ch == d) + return d; + + put_queue(vc, d); + return ch; } -static void enter(void) +/* + * Special function handlers + */ +static void fn_enter(struct vc_data *vc) { if (diacr) { - put_queue(diacr); + put_queue(vc, diacr); diacr = 0; } - put_queue(13); - if (vc_kbd_mode(kbd,VC_CRLF)) - put_queue(10); + put_queue(vc, 13); + if (vc_kbd_mode(kbd, VC_CRLF)) + put_queue(vc, 10); } -static void caps_toggle(void) +static void fn_caps_toggle(struct vc_data *vc) { if (rep) return; chg_vc_kbd_led(kbd, VC_CAPSLOCK); } -static void caps_on(void) +static void fn_caps_on(struct vc_data *vc) { if (rep) return; set_vc_kbd_led(kbd, VC_CAPSLOCK); } -static void show_ptregs(void) +static void fn_show_ptregs(struct vc_data *vc) { if (kbd_pt_regs) show_regs(kbd_pt_regs); } -static void hold(void) +static void fn_hold(struct vc_data *vc) { + struct tty_struct *tty = vc->vc_tty; + if (rep || !tty) return; @@ -410,12 +343,12 @@ stop_tty(tty); } -static void num(void) +static void fn_num(struct vc_data *vc) { if (vc_kbd_mode(kbd,VC_APPLIC)) - applkey('P', 1); + applkey(vc, 'P', 1); else - bare_num(); + fn_bare_num(vc); } /* @@ -424,19 +357,19 @@ * Bind this to NumLock if you prefer that the NumLock key always * changes the NumLock flag. */ -static void bare_num(void) +static void fn_bare_num(struct vc_data *vc) { if (!rep) chg_vc_kbd_led(kbd,VC_NUMLOCK); } -static void lastcons(void) +static void fn_lastcons(struct vc_data *vc) { /* switch to the last used console, ChN */ set_console(last_console); } -static void decr_console(void) +static void fn_dec_console(struct vc_data *vc) { int i; @@ -449,7 +382,7 @@ set_console(i); } -static void incr_console(void) +static void fn_inc_console(struct vc_data *vc) { int i; @@ -462,98 +395,112 @@ set_console(i); } -static void send_intr(void) +static void fn_send_intr(struct vc_data *vc) { + struct tty_struct *tty = vc->vc_tty; + if (!tty) return; tty_insert_flip_char(tty, 0, TTY_BREAK); con_schedule_flip(tty); } -static void scroll_forw(void) +static void fn_scroll_forw(struct vc_data *vc) { scrollfront(0); } -static void scroll_back(void) +static void fn_scroll_back(struct vc_data *vc) { scrollback(0); } -static void boot_it(void) +static void fn_show_mem(struct vc_data *vc) +{ + show_mem(); +} + +static void fn_show_state(struct vc_data *vc) +{ + show_state(); +} + +static void fn_boot_it(struct vc_data *vc) { ctrl_alt_del(); } -static void compose(void) +static void fn_compose(struct vc_data *vc) { dead_key_next = 1; } -int spawnpid, spawnsig; - -static void spawn_console(void) +static void fn_spawn_con(struct vc_data *vc) { if (spawnpid) if(kill_proc(spawnpid, spawnsig, 1)) spawnpid = 0; } -static void SAK(void) +static void fn_SAK(struct vc_data *vc) { + struct tty_struct *tty = vc->vc_tty; + /* * SAK should also work in all raw modes and reset * them properly. */ - - do_SAK(tty); + if (tty) + do_SAK(tty); reset_vc(fg_console); #if 0 do_unblank_screen(); /* not in interrupt routine? */ #endif } -static void do_ignore(unsigned char value, char up_flag) +static void fn_null(struct vc_data *vc) { + compute_shiftstate(); } -static void do_null() +/* + * Special key handlers + */ +static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag) { - compute_shiftstate(); } -static void do_spec(unsigned char value, char up_flag) +static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; - if (value >= SIZE(spec_fn_table)) + if (value >= SIZE(fn_handler)) return; if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) && !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value))) return; - spec_fn_table[value](); + fn_handler[value](vc); } -static void do_lowercase(unsigned char value, char up_flag) +static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) { printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n"); } -static void do_self(unsigned char value, char up_flag) +static void k_self(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; /* no action, if this is a key release */ if (diacr) - value = handle_diacr(value); + value = handle_diacr(vc, value); if (dead_key_next) { dead_key_next = 0; diacr = value; return; } - - put_queue(value); + put_queue(vc, value); } #define A_GRAVE '`' @@ -566,10 +513,10 @@ {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL }; /* Obsolete - for backwards compatibility only */ -static void do_dead(unsigned char value, char up_flag) +static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) { value = ret_diacr[value]; - do_dead2(value,up_flag); + k_dead2(vc, value,up_flag); } /* @@ -577,60 +524,33 @@ * dead keys modifying the same character. Very useful * for Vietnamese. */ -static void do_dead2(unsigned char value, char up_flag) +static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; - diacr = (diacr ? handle_diacr(value) : value); + diacr = (diacr ? handle_diacr(vc, value) : value); } - -/* - * We have a combining character DIACR here, followed by the character CH. - * If the combination occurs in the table, return the corresponding value. - * Otherwise, if CH is a space or equals DIACR, return DIACR. - * Otherwise, conclude that DIACR was not combining after all, - * queue it and return CH. - */ -unsigned char handle_diacr(unsigned char ch) -{ - int d = diacr; - int i; - - diacr = 0; - - for (i = 0; i < accent_table_size; i++) { - if (accent_table[i].diacr == d && accent_table[i].base == ch) - return accent_table[i].result; - } - - if (ch == ' ' || ch == d) - return d; - - put_queue(d); - return ch; -} - -static void do_cons(unsigned char value, char up_flag) +static void k_cons(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; set_console(value); } -static void do_fn(unsigned char value, char up_flag) +static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; if (value < SIZE(func_table)) { if (func_table[value]) - puts_queue(func_table[value]); + puts_queue(vc, func_table[value]); } else - printk(KERN_ERR "do_fn called with value=%d\n", value); + printk(KERN_ERR "k_fn called with value=%d\n", value); } -static void do_pad(unsigned char value, char up_flag) +static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) { static const char *pad_chars = "0123456789+-*/\015,.?()"; static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; @@ -639,8 +559,8 @@ return; /* no action, if this is a key release */ /* kludge... shift forces cursor/number keys */ - if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) { - applkey(app_map[value], 1); + if (vc_kbd_mode(kbd,VC_APPLIC) && !shift_down[KG_SHIFT]) { + applkey(vc, app_map[value], 1); return; } @@ -648,55 +568,55 @@ switch (value) { case KVAL(K_PCOMMA): case KVAL(K_PDOT): - do_fn(KVAL(K_REMOVE), 0); + k_fn(vc, KVAL(K_REMOVE), 0); return; case KVAL(K_P0): - do_fn(KVAL(K_INSERT), 0); + k_fn(vc, KVAL(K_INSERT), 0); return; case KVAL(K_P1): - do_fn(KVAL(K_SELECT), 0); + k_fn(vc, KVAL(K_SELECT), 0); return; case KVAL(K_P2): - do_cur(KVAL(K_DOWN), 0); + k_cur(vc, KVAL(K_DOWN), 0); return; case KVAL(K_P3): - do_fn(KVAL(K_PGDN), 0); + k_fn(vc, KVAL(K_PGDN), 0); return; case KVAL(K_P4): - do_cur(KVAL(K_LEFT), 0); + k_cur(vc, KVAL(K_LEFT), 0); return; case KVAL(K_P6): - do_cur(KVAL(K_RIGHT), 0); + k_cur(vc, KVAL(K_RIGHT), 0); return; case KVAL(K_P7): - do_fn(KVAL(K_FIND), 0); + k_fn(vc, KVAL(K_FIND), 0); return; case KVAL(K_P8): - do_cur(KVAL(K_UP), 0); + k_cur(vc, KVAL(K_UP), 0); return; case KVAL(K_P9): - do_fn(KVAL(K_PGUP), 0); + k_fn(vc, KVAL(K_PGUP), 0); return; case KVAL(K_P5): - applkey('G', vc_kbd_mode(kbd, VC_APPLIC)); + applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC)); return; } - put_queue(pad_chars[value]); + put_queue(vc, pad_chars[value]); if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) - put_queue(10); + put_queue(vc, 10); } -static void do_cur(unsigned char value, char up_flag) +static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) { static const char *cur_chars = "BDCA"; + if (up_flag) return; - - applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE)); + applkey(vc, cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE)); } -static void do_shift(unsigned char value, char up_flag) +static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) { int old_state = shift_state; @@ -714,12 +634,12 @@ if (up_flag) { /* handle the case that two shift or control keys are depressed simultaneously */ - if (k_down[value]) - k_down[value]--; + if (shift_down[value]) + shift_down[value]--; } else - k_down[value]++; + shift_down[value]++; - if (k_down[value]) + if (shift_down[value]) shift_state |= (1 << value); else shift_state &= ~ (1 << value); @@ -727,54 +647,26 @@ /* kludge */ if (up_flag && shift_state != old_state && npadch != -1) { if (kbd->kbdmode == VC_UNICODE) - to_utf8(npadch & 0xffff); + to_utf8(vc, npadch & 0xffff); else - put_queue(npadch & 0xff); + put_queue(vc, npadch & 0xff); npadch = -1; } } -/* called after returning from RAW mode or when changing consoles - - recompute k_down[] and shift_state from key_down[] */ -/* maybe called when keymap is undefined, so that shiftkey release is seen */ -void compute_shiftstate(void) -{ - int i, j, k, sym, val; - - shift_state = 0; - for(i=0; i < SIZE(k_down); i++) - k_down[i] = 0; - - for(i=0; i < SIZE(key_down); i++) - if(key_down[i]) { /* skip this word if not a single bit on */ - 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]); - if(KTYP(sym) == KT_SHIFT || KTYP(sym) == KT_SLOCK) { - val = KVAL(sym); - if (val == KVAL(K_CAPSSHIFT)) - val = KVAL(K_SHIFT); - k_down[val]++; - shift_state |= (1<<val); - } - } - } -} - -static void do_meta(unsigned char value, char up_flag) +static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; if (vc_kbd_mode(kbd, VC_META)) { - put_queue('\033'); - put_queue(value); + put_queue(vc, '\033'); + put_queue(vc, value); } else - put_queue(value | 0x80); + put_queue(vc, value | 0x80); } -static void do_ascii(unsigned char value, char up_flag) +static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) { int base; @@ -794,16 +686,16 @@ npadch = npadch * base + value; } -static void do_lock(unsigned char value, char up_flag) +static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag || rep) return; chg_vc_kbd_lock(kbd, value); } -static void do_slock(unsigned char value, char up_flag) +static void k_slock(struct vc_data *vc, unsigned char value, char up_flag) { - do_shift(value,up_flag); + k_shift(vc, value,up_flag); if (up_flag || rep) return; chg_vc_kbd_slock(kbd, value); @@ -819,10 +711,6 @@ * or (ii) whatever pattern of lights people want to show using KDSETLED, * or (iii) specified bits of specified words in kernel memory. */ - -static unsigned char ledstate = 0xff; /* undefined */ -static unsigned char ledioctl; - unsigned char getledstate(void) { return ledstate; } @@ -836,12 +724,6 @@ set_leds(); } -static struct ledptr { - unsigned int *addr; - unsigned int mask; - unsigned char valid:1; -} ledptrs[3]; - void register_leds(int console, unsigned int led, unsigned int *addr, unsigned int mask) { struct kbd_struct *kbd = kbd_table + console; @@ -897,6 +779,7 @@ * used, but this allows for easy and efficient race-condition * prevention later on. */ + static void kbd_bh(unsigned long dummy) { unsigned char leds = getleds(); @@ -911,15 +794,146 @@ EXPORT_SYMBOL(keyboard_tasklet); DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); -typedef void (pm_kbd_func) (void); +void handle_scancode(unsigned char scancode, int down) +{ + struct vc_data *vc = vc_cons[fg_console].d; + char up_flag = down ? 0 : 0200; + struct tty_struct *tty; + unsigned char keycode; + char raw_mode; -pm_callback pm_kbd_request_override = NULL; + pm_access(pm_kbd); + add_keyboard_randomness(scancode | up_flag); + + tty = vc->vc_tty; + + if (tty && (!tty->driver_data)) { + /* + * 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 + * it opens it, and clears it when it closes it. + */ + tty = NULL; + } + kbd = kbd_table + fg_console; + if ((raw_mode = (kbd->kbdmode == VC_RAW))) { + put_queue(vc, scancode | up_flag); + /* we do not return yet, because we want to maintain + the key_down array, so that we have the correct + values when finishing RAW mode or when changing VT's */ + } + + /* + * Convert scancode to keycode + */ + if (!kbd_translate(scancode, &keycode, raw_mode)) + goto out; + + /* + * At this point the variable `keycode' contains the keycode. + * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid). + * We keep track of the up/down status of the key, and + * return the keycode if in MEDIUMRAW mode. + */ + + if (up_flag) { + rep = 0; + if(!test_and_clear_bit(keycode, key_down)) + up_flag = kbd_unexpected_up(keycode); + } else + rep = test_and_set_bit(keycode, key_down); + +#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ + if (keycode == SYSRQ_KEY) { + sysrq_pressed = !up_flag; + goto out; + } else if (sysrq_pressed) { + if (!up_flag) { + handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty); + goto out; + } + } +#endif + + if (kbd->kbdmode == VC_MEDIUMRAW) { + /* soon keycodes will require more than one byte */ + put_queue(vc, keycode + up_flag); + raw_mode = 1; /* Most key classes will be ignored */ + } + + /* + * Small change in philosophy: earlier we defined repetition by + * rep = keycode == prev_keycode; + * prev_keycode = keycode; + * but now by the fact that the depressed key was down already. + * Does this ever make a difference? Yes. + */ + + /* + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and under heavy loads. + */ + if (!rep || + (vc_kbd_mode(kbd,VC_REPEAT) && tty && + (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { + u_short keysym; + u_char type; + + /* the XOR below used to be an OR */ + int shift_final = (shift_state | kbd->slockstate) ^ + kbd->lockstate; + ushort *key_map = key_maps[shift_final]; + + if (key_map != NULL) { + keysym = key_map[keycode]; + type = KTYP(keysym); + + if (type >= 0xf0) { + type -= 0xf0; + if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) + goto out; + if (type == KT_LETTER) { + type = KT_LATIN; + if (vc_kbd_led(kbd, VC_CAPSLOCK)) { + key_map = key_maps[shift_final ^ (1<<KG_SHIFT)]; + if (key_map) + keysym = key_map[keycode]; + } + } + (*k_handler[type])(vc, keysym & 0xff, up_flag); + if (type != KT_SLOCK) + kbd->slockstate = 0; + } else { + /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ + if (!up_flag && !raw_mode) + to_utf8(vc, keysym); + } + } else { + /* maybe beep? */ + /* we have at least to update shift_state */ +#if 1 /* how? two almost equivalent choices follow */ + compute_shiftstate(); + kbd->slockstate = 0; /* play it safe */ +#else + keysym = U(plain_map[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(); +} int __init kbd_init(void) { int i; struct kbd_struct kbd0; - extern struct tty_driver console_driver; kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; kbd0.ledmode = LED_SHOW_FLAGS; @@ -930,8 +944,6 @@ for (i = 0 ; i < MAX_NR_CONSOLES ; i++) kbd_table[i] = kbd0; - - ttytab = console_driver.table; kbd_init_hw(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/lp.c linux-2.5/drivers/char/lp.c --- linux-2.5.1/drivers/char/lp.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/lp.c Tue Jan 8 01:17:10 2002 @@ -294,7 +294,7 @@ static ssize_t lp_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { - unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + unsigned int minor = minor(file->f_dentry->d_inode->i_rdev); struct parport *port = lp_table[minor].dev->port; char *kbuf = lp_table[minor].lp_buffer; ssize_t retv = 0; @@ -403,7 +403,7 @@ static ssize_t lp_read(struct file * file, char * buf, size_t count, loff_t *ppos) { - unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev); + unsigned int minor=minor(file->f_dentry->d_inode->i_rdev); struct parport *port = lp_table[minor].dev->port; ssize_t retval = 0; char *kbuf = lp_table[minor].lp_buffer; @@ -430,7 +430,7 @@ static int lp_open(struct inode * inode, struct file * file) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); if (minor >= LP_NO) return -ENXIO; @@ -488,7 +488,7 @@ static int lp_release(struct inode * inode, struct file * file) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); lp_claim_parport_or_block (&lp_table[minor]); parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT); @@ -503,7 +503,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); int status; int retval = 0; @@ -648,7 +648,7 @@ do { /* Write the data, converting LF->CRLF as we go. */ ssize_t canwrite = count; - char *lf = strchr (s, '\n'); + char *lf = memchr (s, '\n', count); if (lf) canwrite = lf - s; @@ -683,7 +683,7 @@ static kdev_t lp_console_device (struct console *c) { - return MKDEV(LP_MAJOR, CONSOLE_LP); + return mk_kdev(LP_MAJOR, CONSOLE_LP); } static struct console lpcons = { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/machzwd.c linux-2.5/drivers/char/machzwd.c --- linux-2.5.1/drivers/char/machzwd.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/char/machzwd.c Sun Jan 13 22:15:01 2002 @@ -24,6 +24,8 @@ * a system RESET and it starts wd#2 that unconditionaly will RESET * the system when the counter reaches zero. * + * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT */ #include <linux/config.h> @@ -103,6 +105,15 @@ MODULE_PARM(action, "i"); MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + #define PFX "machzwd" static struct watchdog_info zf_info = { @@ -307,23 +318,23 @@ * no need to check for close confirmation * no way to disable watchdog ;) */ -#ifndef CONFIG_WATCHDOG_NOWAYOUT - size_t ofs; - - /* - * note: just in case someone wrote the magic character - * five months ago... - */ - zf_expect_close = 0; - - /* now scan */ - for(ofs = 0; ofs != count; ofs++){ - if(buf[ofs] == 'V'){ - zf_expect_close = 1; - dprintk("zf_expect_close 1\n"); + if (!nowayout) { + size_t ofs; + + /* + * note: just in case someone wrote the magic character + * five months ago... + */ + zf_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++){ + if(buf[ofs] == 'V'){ + zf_expect_close = 1; + dprintk("zf_expect_close 1\n"); + } } } -#endif /* * Well, anyhow someone wrote to us, * we should return that favour @@ -378,7 +389,7 @@ static int zf_open(struct inode *inode, struct file *file) { - switch(MINOR(inode->i_rdev)){ + switch(minor(inode->i_rdev)){ case WATCHDOG_MINOR: spin_lock(&zf_lock); if(zf_is_open){ @@ -386,9 +397,9 @@ return -EBUSY; } -#ifdef CONFIG_WATCHDOG_NOWAYOUT - MOD_INC_USE_COUNT; -#endif + if (nowayout) { + MOD_INC_USE_COUNT; + } zf_is_open = 1; spin_unlock(&zf_lock); @@ -403,7 +414,7 @@ static int zf_close(struct inode *inode, struct file *file) { - if(MINOR(inode->i_rdev) == WATCHDOG_MINOR){ + if(minor(inode->i_rdev) == WATCHDOG_MINOR){ if(zf_expect_close){ zf_timer_off(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/mem.c linux-2.5/drivers/char/mem.c --- linux-2.5.1/drivers/char/mem.c Fri Sep 14 21:04:07 2001 +++ linux-2.5/drivers/char/mem.c Tue Jan 1 23:42:41 2002 @@ -272,6 +272,8 @@ return virtr + read; } +extern long vwrite(char *buf, char *addr, unsigned long count); + /* * This function writes to the *virtual* memory as seen by the kernel. */ @@ -279,12 +281,46 @@ size_t count, loff_t *ppos) { unsigned long p = *ppos; + ssize_t wrote = 0; + ssize_t virtr = 0; + char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ + + if (p < (unsigned long) high_memory) { + wrote = count; + if (count > (unsigned long) high_memory - p) + wrote = (unsigned long) high_memory - p; + + wrote = do_write_mem(file, (void*)p, p, buf, wrote, ppos); + + p += wrote; + buf += wrote; + count -= wrote; + } - if (p >= (unsigned long) high_memory) - return 0; - if (count > (unsigned long) high_memory - p) - count = (unsigned long) high_memory - p; - return do_write_mem(file, (void*)p, p, buf, count, ppos); + if (count > 0) { + kbuf = (char *)__get_free_page(GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + while (count > 0) { + int len = count; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + if (len && copy_from_user(kbuf, buf, len)) { + free_page((unsigned long)kbuf); + return -EFAULT; + } + len = vwrite(kbuf, (char *)p, len); + count -= len; + buf += len; + virtr += len; + p += len; + } + free_page((unsigned long)kbuf); + } + + *ppos = p; + return virtr + wrote; } #if !defined(__mc68000__) @@ -538,7 +574,7 @@ static int memory_open(struct inode * inode, struct file * filp) { - switch (MINOR(inode->i_rdev)) { + switch (minor(inode->i_rdev)) { case 1: filp->f_op = &mem_fops; break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/misc.c linux-2.5/drivers/char/misc.c --- linux-2.5.1/drivers/char/misc.c Sat Nov 3 01:46:47 2001 +++ linux-2.5/drivers/char/misc.c Tue Jan 1 23:42:41 2002 @@ -104,7 +104,7 @@ static int misc_open(struct inode * inode, struct file * file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct miscdevice *c; int err = -ENODEV; struct file_operations *old_fops, *new_fops = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/mixcomwd.c linux-2.5/drivers/char/mixcomwd.c --- linux-2.5.1/drivers/char/mixcomwd.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/mixcomwd.c Sun Jan 13 22:15:01 2002 @@ -27,10 +27,13 @@ * * Version 0.4 (99/11/15): * - support for one more type board + * + * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com> + * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT * */ -#define VERSION "0.4" +#define VERSION "0.5" #include <linux/module.h> #include <linux/config.h> @@ -57,26 +60,30 @@ static long mixcomwd_opened; /* long req'd for setbit --RR */ static int watchdog_port; - -#ifndef CONFIG_WATCHDOG_NOWAYOUT static int mixcomwd_timer_alive; static struct timer_list mixcomwd_timer; + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; #endif +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + static void mixcomwd_ping(void) { outb_p(55,watchdog_port); return; } -#ifndef CONFIG_WATCHDOG_NOWAYOUT static void mixcomwd_timerfun(unsigned long d) { mixcomwd_ping(); mod_timer(&mixcomwd_timer,jiffies+ 5*HZ); } -#endif /* * Allow only one person to hold it open @@ -89,31 +96,32 @@ } mixcomwd_ping(); -#ifndef CONFIG_WATCHDOG_NOWAYOUT - if(mixcomwd_timer_alive) { - del_timer(&mixcomwd_timer); - mixcomwd_timer_alive=0; - } -#endif + if (nowayout) { + MOD_INC_USE_COUNT; + } else { + if(mixcomwd_timer_alive) { + del_timer(&mixcomwd_timer); + mixcomwd_timer_alive=0; + } + } return 0; } static int mixcomwd_release(struct inode *inode, struct file *file) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - if(mixcomwd_timer_alive) { - printk(KERN_ERR "mixcomwd: release called while internal timer alive"); - return -EBUSY; + if (!nowayout) { + if(mixcomwd_timer_alive) { + printk(KERN_ERR "mixcomwd: release called while internal timer alive"); + return -EBUSY; + } + init_timer(&mixcomwd_timer); + mixcomwd_timer.expires=jiffies + 5 * HZ; + mixcomwd_timer.function=mixcomwd_timerfun; + mixcomwd_timer.data=0; + mixcomwd_timer_alive=1; + add_timer(&mixcomwd_timer); } - init_timer(&mixcomwd_timer); - mixcomwd_timer.expires=jiffies + 5 * HZ; - mixcomwd_timer.function=mixcomwd_timerfun; - mixcomwd_timer.data=0; - mixcomwd_timer_alive=1; - add_timer(&mixcomwd_timer); -#endif - clear_bit(0,&mixcomwd_opened); return 0; } @@ -145,9 +153,9 @@ { case WDIOC_GETSTATUS: status=mixcomwd_opened; -#ifndef CONFIG_WATCHDOG_NOWAYOUT - status|=mixcomwd_timer_alive; -#endif + if (!nowayout) { + status|=mixcomwd_timer_alive; + } if (copy_to_user((int *)arg, &status, sizeof(int))) { return -EFAULT; } @@ -252,14 +260,14 @@ static void __exit mixcomwd_exit(void) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - if(mixcomwd_timer_alive) { - printk(KERN_WARNING "mixcomwd: I quit now, hardware will" - " probably reboot!\n"); - del_timer(&mixcomwd_timer); - mixcomwd_timer_alive=0; + if (!nowayout) { + if(mixcomwd_timer_alive) { + printk(KERN_WARNING "mixcomwd: I quit now, hardware will" + " probably reboot!\n"); + del_timer(&mixcomwd_timer); + mixcomwd_timer_alive=0; + } } -#endif release_region(watchdog_port,1); misc_deregister(&mixcomwd_miscdev); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/moxa.c linux-2.5/drivers/char/moxa.c --- linux-2.5.1/drivers/char/moxa.c Thu Oct 25 20:53:47 2001 +++ linux-2.5/drivers/char/moxa.c Sun Jan 6 01:38:26 2002 @@ -53,7 +53,6 @@ #include <asm/system.h> #include <asm/io.h> -#include <asm/segment.h> #include <asm/bitops.h> #include <asm/uaccess.h> @@ -190,7 +189,7 @@ #define WAKEUP_CHARS 256 -#define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start) +#define PORTNO(x) (minor((x)->device) - (x)->driver.minor_start) static int verbose = 0; static int ttymajor = MOXAMAJOR; @@ -649,7 +648,7 @@ } if (--ch->count < 0) { printk("moxa_close: bad serial port count, minor=%d\n", - MINOR(tty->device)); + minor(tty->device)); ch->count = 0; } if (ch->count) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/mwave/mwavedd.c linux-2.5/drivers/char/mwave/mwavedd.c --- linux-2.5.1/drivers/char/mwave/mwavedd.c Thu Oct 11 16:14:32 2001 +++ linux-2.5/drivers/char/mwave/mwavedd.c Tue Jan 8 00:44:24 2002 @@ -279,7 +279,6 @@ pDrvData->IPCs[ipcnum].bIsHere = FALSE; pDrvData->IPCs[ipcnum].bIsEnabled = TRUE; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - current->nice = -20; /* boost to provide priority timing */ #else current->priority = 0x28; /* boost to provide priority timing */ #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/mxser.c linux-2.5/drivers/char/mxser.c --- linux-2.5.1/drivers/char/mxser.c Thu Oct 25 20:53:47 2001 +++ linux-2.5/drivers/char/mxser.c Mon Jan 14 22:39:45 2002 @@ -58,7 +58,6 @@ #include <asm/system.h> #include <asm/io.h> #include <asm/irq.h> -#include <asm/segment.h> #include <asm/bitops.h> #include <asm/uaccess.h> @@ -92,7 +91,7 @@ #define UART_MCR_AFE 0x20 #define UART_LSR_SPECIAL 0x1E -#define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start) +#define PORTNO(x) (minor((x)->device) - (x)->driver.minor_start) #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) @@ -614,38 +613,35 @@ n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1; index = 0; for (b = 0; b < n; b++) { - pdev = pci_find_device(mxser_pcibrds[b].vendor, - mxser_pcibrds[b].device, pdev); - if (!pdev || pci_enable_device(pdev)) - continue; - hwconf.pdev = pdev; - printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", - mxser_brdname[mxser_pcibrds[b].driver_data], - pdev->bus->number, PCI_SLOT(pdev->devfn)); - if (m >= MXSER_BOARDS) { - printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS); - } else { - retval = mxser_get_PCI_conf(pdev, - mxser_pcibrds[b].driver_data, &hwconf); - if (retval < 0) { - if (retval == MXSER_ERR_IRQ) - printk("Invalid interrupt number,board not configured\n"); - else if (retval == MXSER_ERR_IRQ_CONFLIT) - printk("Invalid interrupt number,board not configured\n"); - else if (retval == MXSER_ERR_VECTOR) - printk("Invalid interrupt vector,board not configured\n"); - else if (retval == MXSER_ERR_IOADDR) - printk("Invalid I/O address,board not configured\n"); + while (pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev)) + { + if (pci_enable_device(pdev)) continue; - + hwconf.pdev = pdev; + printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", + mxser_brdname[mxser_pcibrds[b].driver_data], + pdev->bus->number, PCI_SLOT(pdev->devfn)); + if (m >= MXSER_BOARDS) { + printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS); + } else { + retval = mxser_get_PCI_conf(pdev, mxser_pcibrds[b].driver_data, &hwconf); + if (retval < 0) { + if (retval == MXSER_ERR_IRQ) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_IRQ_CONFLIT) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_VECTOR) + printk("Invalid interrupt vector,board not configured\n"); + else if (retval == MXSER_ERR_IOADDR) + printk("Invalid I/O address,board not configured\n"); + continue; + } + if (mxser_initbrd(m, &hwconf) < 0) + continue; + mxser_getcfg(m, &hwconf); + m++; } - if (mxser_initbrd(m, &hwconf) < 0) - continue; - mxser_getcfg(m, &hwconf); - m++; - } - } } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/n_hdlc.c linux-2.5/drivers/char/n_hdlc.c --- linux-2.5.1/drivers/char/n_hdlc.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/char/n_hdlc.c Sun Jan 6 01:38:26 2002 @@ -9,7 +9,7 @@ * Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au> * * Original release 01/11/99 - * $Id: n_hdlc.c,v 3.2 2000/11/06 22:34:38 paul Exp $ + * $Id: n_hdlc.c,v 3.3 2001/11/08 16:16:03 paulkf Exp $ * * This code is released under the GNU General Public License (GPL) * @@ -78,7 +78,7 @@ */ #define HDLC_MAGIC 0x239e -#define HDLC_VERSION "3.2" +#define HDLC_VERSION "$Revision: 3.3 $" #include <linux/version.h> #include <linux/config.h> @@ -112,7 +112,6 @@ #include <linux/kerneld.h> #endif -#include <asm/segment.h> #define GET_USER(error,value,addr) error = get_user(value,addr) #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 #define PUT_USER(error,value,addr) error = put_user(value,addr) @@ -160,11 +159,6 @@ struct tty_struct *tty; /* ptr to TTY structure */ struct tty_struct *backup_tty; /* TTY to use if tty gets closed */ - /* Queues for select() functionality */ - wait_queue_head_t read_wait; - wait_queue_head_t write_wait; - wait_queue_head_t poll_wait; - int tbusy; /* reentrancy flag for tx wakeup code */ int woke_up; N_HDLC_BUF *tbuf; /* currently transmitting tx buffer */ @@ -235,9 +229,8 @@ printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__); /* Ensure that the n_hdlcd process is not hanging on select()/poll() */ - wake_up_interruptible (&n_hdlc->read_wait); - wake_up_interruptible (&n_hdlc->poll_wait); - wake_up_interruptible (&n_hdlc->write_wait); + wake_up_interruptible (&tty->read_wait); + wake_up_interruptible (&tty->write_wait); if (tty != NULL && tty->disc_data == n_hdlc) tty->disc_data = NULL; /* Break the tty->n_hdlc link */ @@ -328,7 +321,7 @@ if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_open() called (major=%u,minor=%u)\n", __FILE__,__LINE__, - MAJOR(tty->device), MINOR(tty->device)); + major(tty->device), minor(tty->device)); /* There should not be an existing table for this slot. */ if (n_hdlc) { @@ -432,8 +425,7 @@ n_hdlc->tbuf = NULL; /* wait up sleeping writers */ - wake_up_interruptible(&n_hdlc->write_wait); - wake_up_interruptible(&n_hdlc->poll_wait); + wake_up_interruptible(&tty->write_wait); /* get next pending transmit buffer */ tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); @@ -575,8 +567,7 @@ n_hdlc_buf_put(&n_hdlc->rx_buf_list,buf); /* wake up any blocked reads and perform async signalling */ - wake_up_interruptible (&n_hdlc->read_wait); - wake_up_interruptible (&n_hdlc->poll_wait); + wake_up_interruptible (&tty->read_wait); if (n_hdlc->tty->fasync != NULL) kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN); @@ -621,6 +612,9 @@ } for (;;) { + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + return -EIO; + n_hdlc = tty2n_hdlc (tty); if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) @@ -634,7 +628,7 @@ if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on (&n_hdlc->read_wait); + interruptible_sleep_on (&tty->read_wait); if (signal_pending(current)) return -EINTR; } @@ -703,7 +697,7 @@ count = maxframe; } - add_wait_queue(&n_hdlc->write_wait, &wait); + add_wait_queue(&tty->write_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); /* Allocate transmit buffer */ @@ -726,7 +720,7 @@ } set_current_state(TASK_RUNNING); - remove_wait_queue(&n_hdlc->write_wait, &wait); + remove_wait_queue(&tty->write_wait, &wait); if (!error) { /* Retrieve the user's buffer */ @@ -836,12 +830,14 @@ if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) { /* queue current process into any wait queue that */ /* may awaken in the future (read and write) */ - poll_wait(filp, &n_hdlc->poll_wait, wait); + + poll_wait(filp, &tty->read_wait, wait); + poll_wait(filp, &tty->write_wait, wait); /* set bits for operations that wont block */ if(n_hdlc->rx_buf_list.head) mask |= POLLIN | POLLRDNORM; /* readable */ - if(tty->flags & (1 << TTY_OTHER_CLOSED)) + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) mask |= POLLHUP; if(tty_hung_up_p(filp)) mask |= POLLHUP; @@ -895,11 +891,7 @@ /* Initialize the control block */ n_hdlc->magic = HDLC_MAGIC; - n_hdlc->flags = 0; - init_waitqueue_head(&n_hdlc->read_wait); - init_waitqueue_head(&n_hdlc->poll_wait); - init_waitqueue_head(&n_hdlc->write_wait); return n_hdlc; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/n_tty.c linux-2.5/drivers/char/n_tty.c --- linux-2.5.1/drivers/char/n_tty.c Fri Apr 6 17:42:55 2001 +++ linux-2.5/drivers/char/n_tty.c Tue Jan 1 23:42:41 2002 @@ -45,8 +45,8 @@ #include <asm/system.h> #include <asm/bitops.h> -#define CONSOLE_DEV MKDEV(TTY_MAJOR,0) -#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1) +#define IS_CONSOLE_DEV(dev) (kdev_val(dev) == __mkdev(TTY_MAJOR,0)) +#define IS_SYSCONS_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1)) #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -955,8 +955,8 @@ /* NOTE: not yet done after every sleep pending a thorough check of the logic of this change. -- jlc */ /* don't stop on /dev/console */ - if (file->f_dentry->d_inode->i_rdev != CONSOLE_DEV && - file->f_dentry->d_inode->i_rdev != SYSCONS_DEV && + if (!IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) && + !IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev) && current->tty == tty) { if (tty->pgrp <= 0) printk("read_chan: tty->pgrp <= 0!\n"); @@ -1135,8 +1135,8 @@ /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ if (L_TOSTOP(tty) && - file->f_dentry->d_inode->i_rdev != CONSOLE_DEV && - file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) { + !IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) && + !IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev)) { retval = tty_check_change(tty); if (retval) return retval; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/pc110pad.c linux-2.5/drivers/char/pc110pad.c --- linux-2.5.1/drivers/char/pc110pad.c Thu Nov 29 05:46:03 2001 +++ linux-2.5/drivers/char/pc110pad.c Thu Dec 27 15:14:59 2001 @@ -590,7 +590,7 @@ spin_lock_irqsave(&pc110_lock, flags); if (!--active_count) outb(0x30, current_params.io+2); /* switch off digitiser */ - spin_unlock_irqrestore(&active_lock, flags); + spin_unlock_irqrestore(&pc110_lock, flags); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/pc_keyb.c linux-2.5/drivers/char/pc_keyb.c --- linux-2.5.1/drivers/char/pc_keyb.c Sat Dec 8 00:21:05 2001 +++ linux-2.5/drivers/char/pc_keyb.c Sun Dec 30 19:12:33 2001 @@ -1231,3 +1231,26 @@ } #endif /* CONFIG_PSMOUSE */ + + +/* Tell the user who may be running in X and not see the console that we have + panic'ed. This is to distingush panics from "real" lockups. + Could in theory send the panic message as morse, but that is left as an + exercise for the reader. */ +void panic_blink(void) +{ + static unsigned long last_jiffie; + static char led; + /* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is + different. */ + if (jiffies - last_jiffie > HZ/2) { + led ^= 0x01 | 0x04; + while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); + kbd_write_output(KBD_CMD_SET_LEDS); + mdelay(1); + while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); + mdelay(1); + kbd_write_output(led); + last_jiffie = jiffies; + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/pcmcia/serial_cs.c linux-2.5/drivers/char/pcmcia/serial_cs.c --- linux-2.5.1/drivers/char/pcmcia/serial_cs.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/char/pcmcia/serial_cs.c Thu Dec 13 16:32:35 2001 @@ -2,7 +2,7 @@ A driver for PCMCIA serial devices - serial_cs.c 1.123 2000/08/24 18:46:38 + serial_cs.c 1.128 2001/10/18 12:18:35 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ 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 + 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 @@ -44,6 +44,7 @@ #include <linux/major.h> #include <asm/io.h> #include <asm/system.h> +#include <asm/byteorder.h> #include <pcmcia/version.h> #include <pcmcia/cs_types.h> @@ -53,30 +54,32 @@ #include <pcmcia/ds.h> #include <pcmcia/cisreg.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 = -"serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); +MODULE_DESCRIPTION("PCMCIA serial card driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); /* Enable the speaker? */ -static int do_sound = 1; +INT_MODULE_PARM(do_sound, 1); -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(do_sound, "i"); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -93,6 +96,8 @@ { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 }, { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 }, { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 }, { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 }, { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 }, { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 } @@ -357,7 +362,6 @@ found_port: if (i != CS_SUCCESS) { - printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); cs_error(link->handle, RequestIO, i); return -1; } @@ -437,7 +441,6 @@ i = CardServices(RequestIRQ, link->handle, &link->irq); if (i != CS_SUCCESS) { - printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } @@ -663,5 +666,3 @@ module_init(init_serial_cs); module_exit(exit_serial_cs); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/pcwd.c linux-2.5/drivers/char/pcwd.c --- linux-2.5.1/drivers/char/pcwd.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/pcwd.c Sun Jan 13 22:15:01 2002 @@ -40,6 +40,8 @@ * fairly useless proc entry. * 990610 removed said useless proc code for the merge <alan> * 000403 Removed last traces of proc code. <davej> + * 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com> + * Added timeout module option to override default */ #include <linux/module.h> @@ -76,7 +78,7 @@ */ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; -#define WD_VER "1.10 (06/05/99)" +#define WD_VER "1.12 (12/14/2001)" /* * It should be noted that PCWD_REVISION_B was removed because A and B @@ -88,7 +90,22 @@ #define PCWD_REVISION_A 1 #define PCWD_REVISION_C 2 -#define WD_TIMEOUT 3 /* 1 1/2 seconds for a timeout */ +#define WD_TIMEOUT 4 /* 2 seconds for a timeout */ +static int timeout_val = WD_TIMEOUT; +static int timeout = 2; + +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=2)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * These are the defines for the PC Watchdog card, revision A. @@ -127,7 +144,7 @@ if (prev_card_dat == 0xFF) return 0; - while(count < WD_TIMEOUT) { + while(count < timeout_val) { /* Read the raw card data from the port, and strip off the first 4 bits */ @@ -400,7 +417,7 @@ static int pcwd_open(struct inode *ino, struct file *filep) { - switch (MINOR(ino->i_rdev)) + switch (minor(ino->i_rdev)) { case WATCHDOG_MINOR: if ( !atomic_dec_and_test(&open_allowed) ) @@ -433,7 +450,7 @@ /* Can't seek (pread) on this device */ if (ppos != &file->f_pos) return -ESPIPE; - switch(MINOR(file->f_dentry->d_inode->i_rdev)) + switch(minor(file->f_dentry->d_inode->i_rdev)) { case TEMP_MINOR: /* @@ -453,18 +470,18 @@ static int pcwd_close(struct inode *ino, struct file *filep) { - if (MINOR(ino->i_rdev)==WATCHDOG_MINOR) + if (minor(ino->i_rdev)==WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - /* Disable the board */ - if (revision == PCWD_REVISION_C) { - spin_lock(&io_lock); - outb_p(0xA5, current_readport + 3); - outb_p(0xA5, current_readport + 3); - spin_unlock(&io_lock); + if (!nowayout) { + /* Disable the board */ + if (revision == PCWD_REVISION_C) { + spin_lock(&io_lock); + outb_p(0xA5, current_readport + 3); + outb_p(0xA5, current_readport + 3); + spin_unlock(&io_lock); + } + atomic_inc( &open_allowed ); } - atomic_inc( &open_allowed ); -#endif } return 0; } @@ -564,10 +581,16 @@ "temperature", &pcwd_fops }; + +static void __init pcwd_validate_timeout(void) +{ + timeout_val = timeout * 2; +} static int __init pcwatchdog_init(void) { int i, found = 0; + pcwd_validate_timeout(); spin_lock_init(&io_lock); revision = PCWD_REVISION_A; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/pcxx.c linux-2.5/drivers/char/pcxx.c --- linux-2.5.1/drivers/char/pcxx.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/char/pcxx.c Sun Jan 6 01:38:26 2002 @@ -406,7 +406,7 @@ int boardnum; int retval; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if(line < 0 || line >= nbdevs) { printk("line out of range in pcxe_open\n"); @@ -2080,7 +2080,7 @@ if(bc->orun) { bc->orun = 0; - printk("overrun! DigiBoard device minor=%d\n",MINOR(tty->device)); + printk("overrun! DigiBoard device minor=%d\n",minor(tty->device)); } rxwinon(ch); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ppdev.c linux-2.5/drivers/char/ppdev.c --- linux-2.5.1/drivers/char/ppdev.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/ppdev.c Thu Jan 10 22:41:07 2002 @@ -103,7 +103,7 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count, loff_t * ppos) { - unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev); + unsigned int minor = minor (file->f_dentry->d_inode->i_rdev); struct pp_struct *pp = file->private_data; char * kbuffer; ssize_t bytes_read = 0; @@ -183,7 +183,7 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count, loff_t * ppos) { - unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev); + unsigned int minor = minor (file->f_dentry->d_inode->i_rdev); struct pp_struct *pp = file->private_data; char * kbuffer; ssize_t bytes_written = 0; @@ -315,7 +315,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct pp_struct *pp = file->private_data; struct parport * port; @@ -324,6 +324,7 @@ case PPCLAIM: { struct ieee1284_info *info; + int ret; if (pp->flags & PP_CLAIMED) { printk (KERN_DEBUG CHRDEV @@ -339,7 +340,10 @@ } } - parport_claim_or_block (pp->pdev); + ret = parport_claim_or_block (pp->pdev); + if (ret < 0) + return ret; + pp->flags |= PP_CLAIMED; /* For interrupt-reporting to work, we need to be @@ -433,8 +437,12 @@ { unsigned int modes; - modes = pp->pdev->port->modes; - if (copy_to_user ((unsigned int *)arg, &modes, sizeof (port->modes))) { + port = parport_find_number (minor); + if (!port) + return -ENODEV; + + modes = port->modes; + if (copy_to_user ((unsigned int *)arg, &modes, sizeof (modes))) { return -EFAULT; } return 0; @@ -613,7 +621,7 @@ static int pp_open (struct inode * inode, struct file * file) { - unsigned int minor = MINOR (inode->i_rdev); + unsigned int minor = minor (inode->i_rdev); struct pp_struct *pp; if (minor >= PARPORT_MAX) @@ -642,7 +650,7 @@ static int pp_release (struct inode * inode, struct file * file) { - unsigned int minor = MINOR (inode->i_rdev); + unsigned int minor = minor (inode->i_rdev); struct pp_struct *pp = file->private_data; int compat_negot; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/pty.c linux-2.5/drivers/char/pty.c --- linux-2.5.1/drivers/char/pty.c Fri Sep 21 17:55:22 2001 +++ linux-2.5/drivers/char/pty.c Tue Jan 1 23:42:41 2002 @@ -88,14 +88,14 @@ set_bit(TTY_OTHER_CLOSED, &tty->flags); #ifdef CONFIG_UNIX98_PTYS { - unsigned int major = MAJOR(tty->device) - UNIX98_PTY_MASTER_MAJOR; + unsigned int major = major(tty->device) - UNIX98_PTY_MASTER_MAJOR; if ( major < UNIX98_NR_MAJORS ) { - devpts_pty_kill( MINOR(tty->device) + devpts_pty_kill( minor(tty->device) - tty->driver.minor_start + tty->driver.name_base ); } } #endif - tty_unregister_devfs (&tty->link->driver, MINOR (tty->device)); + tty_unregister_devfs (&tty->link->driver, minor(tty->device)); tty_vhangup(tty->link); } } @@ -239,7 +239,7 @@ #ifdef CONFIG_UNIX98_PTYS static int pty_get_device_number(struct tty_struct *tty, unsigned int *value) { - unsigned int result = MINOR(tty->device) + unsigned int result = minor(tty->device) - tty->driver.minor_start + tty->driver.name_base; return put_user(result, value); } @@ -314,7 +314,7 @@ retval = -ENODEV; if (!tty || !tty->link) goto out; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PTYS)) goto out; pty = (struct pty_struct *)(tty->driver.driver_state) + line; @@ -334,10 +334,9 @@ /* Register a slave for the master */ if (tty->driver.major == PTY_MASTER_MAJOR) tty_register_devfs(&tty->link->driver, - DEVFS_FL_CURRENT_OWNER | - DEVFS_FL_NO_PERSISTENCE | DEVFS_FL_WAIT, + DEVFS_FL_CURRENT_OWNER | DEVFS_FL_WAIT, tty->link->driver.minor_start + - MINOR(tty->device)-tty->driver.minor_start); + minor(tty->device)-tty->driver.minor_start); retval = 0; out: return retval; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/raw.c linux-2.5/drivers/char/raw.c --- linux-2.5.1/drivers/char/raw.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/char/raw.c Tue Jan 1 23:42:41 2002 @@ -74,7 +74,7 @@ int sector_size; int sector_bits; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); /* * Is it the control device? @@ -117,21 +117,8 @@ if (raw_devices[minor].inuse++) goto out; - /* - * Don't interfere with mounted devices: we cannot safely set - * the blocksize on a device which is already mounted. - */ - - sector_size = 512; - if (is_mounted(rdev)) { - if (blksize_size[MAJOR(rdev)]) - sector_size = blksize_size[MAJOR(rdev)][MINOR(rdev)]; - } else - sector_size = get_hardsect_size(rdev); - - set_blocksize(rdev, sector_size); + sector_size = get_hardsect_size(rdev); raw_devices[minor].sector_size = sector_size; - for (sector_bits = 0; !(sector_size & 1); ) sector_size>>=1, sector_bits++; raw_devices[minor].sector_bits = sector_bits; @@ -147,7 +134,7 @@ int minor; struct block_device *bdev; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); down(&raw_devices[minor].mutex); bdev = raw_devices[minor].binding; raw_devices[minor].inuse--; @@ -205,8 +192,8 @@ * major/minor numbers make sense. */ - if ((rq.block_major == NODEV && - rq.block_minor != NODEV) || + if ((rq.block_major == 0 && + rq.block_minor != 0) || rq.block_major > MAX_BLKDEV || rq.block_minor > MINORMASK) { err = -EINVAL; @@ -222,7 +209,7 @@ if (raw_devices[minor].binding) bdput(raw_devices[minor].binding); raw_devices[minor].binding = - bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor))); + bdget(kdev_t_to_nr(mk_kdev(rq.block_major, rq.block_minor))); up(&raw_devices[minor].mutex); } else { struct block_device *bdev; @@ -231,8 +218,8 @@ bdev = raw_devices[minor].binding; if (bdev) { dev = to_kdev_t(bdev->bd_dev); - rq.block_major = MAJOR(dev); - rq.block_minor = MINOR(dev); + rq.block_major = major(dev); + rq.block_minor = minor(dev); } else { rq.block_major = rq.block_minor = 0; } @@ -284,7 +271,7 @@ * First, a few checks on device size limits */ - minor = MINOR(filp->f_dentry->d_inode->i_rdev); + minor = minor(filp->f_dentry->d_inode->i_rdev); new_iobuf = 0; iobuf = filp->f_iobuf; @@ -304,12 +291,12 @@ sector_bits = raw_devices[minor].sector_bits; sector_mask = sector_size- 1; - if (blk_size[MAJOR(dev)]) - limit = (((loff_t) blk_size[MAJOR(dev)][MINOR(dev)]) << BLOCK_SIZE_BITS) >> sector_bits; + if (blk_size[major(dev)]) + limit = (((loff_t) blk_size[major(dev)][minor(dev)]) << BLOCK_SIZE_BITS) >> sector_bits; else limit = INT_MAX; dprintk ("rw_raw_dev: dev %d:%d (+%d)\n", - MAJOR(dev), MINOR(dev), limit); + major(dev), minor(dev), limit); err = -EINVAL; if ((*offp & sector_mask) || (size & sector_mask)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/rio/linux_compat.h linux-2.5/drivers/char/rio/linux_compat.h --- linux-2.5.1/drivers/char/rio/linux_compat.h Wed Jul 4 21:41:33 2001 +++ linux-2.5/drivers/char/rio/linux_compat.h Mon Jan 7 20:00:23 2002 @@ -60,9 +60,6 @@ #define getpid() (current->pid) -#define major(dev) MAJOR(dev) -#define minor(dev) MINOR(dev) - #define QSIZE SERIAL_XMIT_SIZE #define pseterr(errno) return (- errno) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/rio/rio.h linux-2.5/drivers/char/rio/rio.h --- linux-2.5.1/drivers/char/rio/rio.h Wed Aug 15 08:22:15 2001 +++ linux-2.5/drivers/char/rio/rio.h Sun Jan 6 01:38:26 2002 @@ -205,10 +205,10 @@ #define RIO_MODEMOFFSET 0x200 /* doesn't mean anything */ #define RIO_MODEM_MASK 0x1FF #define RIO_MODEM_BIT 0x200 -#define RIO_UNMODEM(DEV) (minor(DEV) & RIO_MODEM_MASK) -#define RIO_ISMODEM(DEV) (minor(DEV) & RIO_MODEM_BIT) -#define RIO_PORT(DEV,FIRST_MAJ) ( (major(DEV) - FIRST_MAJ) * PORTS_PER_HOST) \ - + minor(DEV) +#define RIO_UNMODEM(DEV) (MINOR(DEV) & RIO_MODEM_MASK) +#define RIO_ISMODEM(DEV) (MINOR(DEV) & RIO_MODEM_BIT) +#define RIO_PORT(DEV,FIRST_MAJ) ( (MAJOR(DEV) - FIRST_MAJ) * PORTS_PER_HOST) \ + + MINOR(DEV) #define splrio spltty diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/rio/rio_linux.c linux-2.5/drivers/char/rio/rio_linux.c --- linux-2.5.1/drivers/char/rio/rio_linux.c Thu Oct 25 20:53:47 2001 +++ linux-2.5/drivers/char/rio/rio_linux.c Sun Jan 6 01:38:26 2002 @@ -375,16 +375,16 @@ int rio_minor (kdev_t device) { - return MINOR (device) + - 256 * ((MAJOR (device) == RIO_NORMAL_MAJOR1) || - (MAJOR (device) == RIO_CALLOUT_MAJOR1)); + return minor (device) + + 256 * ((major (device) == RIO_NORMAL_MAJOR1) || + (major (device) == RIO_CALLOUT_MAJOR1)); } int rio_ismodem (kdev_t device) { - return (MAJOR (device) == RIO_NORMAL_MAJOR0) || - (MAJOR (device) == RIO_NORMAL_MAJOR1); + return (major (device) == RIO_NORMAL_MAJOR0) || + (major (device) == RIO_NORMAL_MAJOR1); } @@ -424,7 +424,7 @@ tty = ((struct Port *)ptr)->gs.tty; - modem = (MAJOR(tty->device) == RIO_NORMAL_MAJOR0) || (MAJOR(tty->device) == RIO_NORMAL_MAJOR1); + modem = (major(tty->device) == RIO_NORMAL_MAJOR0) || (major(tty->device) == RIO_NORMAL_MAJOR1); rv = RIOParam( (struct Port *) ptr, CONFIG, modem, 1); @@ -742,7 +742,7 @@ case TIOCGSERIAL: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0) - gs_getserial(&PortP->gs, (struct serial_struct *) arg); + rc = gs_getserial(&PortP->gs, (struct serial_struct *) arg); break; case TCSBRK: if ( PortP->State & RIO_DELETED ) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/rio/rio_linux.h linux-2.5/drivers/char/rio/rio_linux.h --- linux-2.5.1/drivers/char/rio/rio_linux.h Wed Jul 4 21:41:33 2001 +++ linux-2.5/drivers/char/rio/rio_linux.h Mon Jan 7 20:00:23 2002 @@ -178,10 +178,9 @@ #ifdef DEBUG #define rio_dprintk(f, str...) do { if (rio_debug & f) printk (str);} while (0) -#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ "\n") -#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit " __FUNCTION__ "\n") -#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter " __FUNCTION__ \ - "(port %d)\n", port->line) +#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __FUNCTION__) +#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __FUNCTION__) +#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__FUNCTION__, port->line) #else #define rio_dprintk(f, str...) /* nothing */ #define func_enter() diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/rio/rioctrl.c linux-2.5/drivers/char/rio/rioctrl.c --- linux-2.5.1/drivers/char/rio/rioctrl.c Sat Apr 14 03:26:07 2001 +++ linux-2.5/drivers/char/rio/rioctrl.c Sun Jan 6 01:38:26 2002 @@ -1737,15 +1737,15 @@ switch ( (uint)arg & RIO_DEV_MASK ) { case RIO_DEV_DIRECT: - arg = (caddr_t)drv_makedev(major(dev), port); + arg = (caddr_t)drv_makedev(MAJOR(dev), port); rio_dprintk (RIO_DEBUG_CTRL, "Makedev direct 0x%x is 0x%x\n",port, (int)arg); return (int)arg; case RIO_DEV_MODEM: - arg = (caddr_t)drv_makedev(major(dev), (port|RIO_MODEM_BIT) ); + arg = (caddr_t)drv_makedev(MAJOR(dev), (port|RIO_MODEM_BIT) ); rio_dprintk (RIO_DEBUG_CTRL, "Makedev modem 0x%x is 0x%x\n",port, (int)arg); return (int)arg; case RIO_DEV_XPRINT: - arg = (caddr_t)drv_makedev(major(dev), port); + arg = (caddr_t)drv_makedev(MAJOR(dev), port); rio_dprintk (RIO_DEBUG_CTRL, "Makedev printer 0x%x is 0x%x\n",port, (int)arg); return (int)arg; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/riscom8.c linux-2.5/drivers/char/riscom8.c --- linux-2.5.1/drivers/char/riscom8.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/char/riscom8.c Sun Jan 6 01:38:26 2002 @@ -1089,12 +1089,12 @@ struct riscom_board * bp; unsigned long flags; - board = RC_BOARD(MINOR(tty->device)); + board = RC_BOARD(minor(tty->device)); if (board > RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT)) return -ENODEV; bp = &rc_board[board]; - port = rc_port + board * RC_NPORT + RC_PORT(MINOR(tty->device)); + port = rc_port + board * RC_NPORT + RC_PORT(minor(tty->device)); if (rc_paranoia_check(port, tty->device, "rc_open")) return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/rocket.c linux-2.5/drivers/char/rocket.c --- linux-2.5.1/drivers/char/rocket.c Fri Sep 21 17:55:22 2001 +++ linux-2.5/drivers/char/rocket.c Mon Jan 7 20:13:11 2002 @@ -227,7 +227,7 @@ if (!info) return 1; if (info->magic != RPORT_MAGIC) { - printk(badmagic, MAJOR(device), MINOR(device), routine); + printk(badmagic, major(device), minor(device), routine); return 1; } #endif @@ -896,7 +896,7 @@ CHANNEL_t *cp; unsigned long page; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= MAX_RP_PORTS)) return -ENODEV; if (!tmp_buf) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/rtc.c linux-2.5/drivers/char/rtc.c --- linux-2.5.1/drivers/char/rtc.c Tue Nov 13 17:16:05 2001 +++ linux-2.5/drivers/char/rtc.c Sun Dec 30 19:12:33 2001 @@ -785,6 +785,9 @@ printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch); #endif #if RTC_IRQ + if (rtc_has_irq == 0) + goto no_irq2; + init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; spin_lock_irq(&rtc_lock); @@ -792,6 +795,7 @@ CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); spin_unlock_irq(&rtc_lock); rtc_freq = 1024; +no_irq2: #endif printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/sbc60xxwdt.c linux-2.5/drivers/char/sbc60xxwdt.c --- linux-2.5.1/drivers/char/sbc60xxwdt.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/sbc60xxwdt.c Sun Jan 13 22:15:01 2002 @@ -109,6 +109,15 @@ static int wdt_is_open; static int wdt_expect_close; +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * Whack the dog */ @@ -196,12 +205,15 @@ static int fop_open(struct inode * inode, struct file * file) { - switch(MINOR(inode->i_rdev)) + switch(minor(inode->i_rdev)) { case WATCHDOG_MINOR: /* Just in case we're already talking to someone... */ if(wdt_is_open) return -EBUSY; + if (nowayout) { + MOD_INC_USE_COUNT; + } /* Good, fire up the show */ wdt_is_open = 1; wdt_startup(); @@ -214,9 +226,9 @@ static int fop_close(struct inode * inode, struct file * file) { - if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) + if(minor(inode->i_rdev) == WATCHDOG_MINOR) { - if(wdt_expect_close) + if(wdt_expect_close && !nowayout) wdt_turnoff(); else { del_timer(&timer); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/ser_a2232.c linux-2.5/drivers/char/ser_a2232.c --- linux-2.5.1/drivers/char/ser_a2232.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/char/ser_a2232.c Sun Jan 6 01:38:27 2002 @@ -460,7 +460,7 @@ int retval; struct a2232_port *port; - line = MINOR(tty->device); + line = minor(tty->device); port = &a2232_ports[line]; tty->driver_data = port; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/serial.c linux-2.5/drivers/char/serial.c --- linux-2.5.1/drivers/char/serial.c Sun Nov 25 17:43:42 2001 +++ linux-2.5/drivers/char/serial.c Mon Jan 14 22:39:45 2002 @@ -122,11 +122,6 @@ #define ENABLE_SERIAL_ACPI #endif -#ifdef __ISAPNP__ -#ifndef ENABLE_SERIAL_PNP -#define ENABLE_SERIAL_PNP -#endif -#endif /* Set of debugging defines */ @@ -198,6 +193,7 @@ #include <linux/ioport.h> #include <linux/mm.h> #include <linux/slab.h> +#include <linux/spinlock.h> #if (LINUX_VERSION_CODE >= 131343) #include <linux/init.h> #endif @@ -211,9 +207,14 @@ #ifdef ENABLE_SERIAL_PCI #include <linux/pci.h> #endif -#ifdef ENABLE_SERIAL_PNP + #include <linux/isapnp.h> +#ifdef __ISAPNP__ +#ifndef ENABLE_SERIAL_PNP +#define ENABLE_SERIAL_PNP +#endif #endif + #ifdef CONFIG_MAGIC_SYSRQ #include <linux/sysrq.h> #endif @@ -231,8 +232,8 @@ #include <asm/irq.h> #include <asm/bitops.h> -#ifdef CONFIG_MAC_SERIAL -#define SERIAL_DEV_OFFSET 2 +#if defined(CONFIG_MAC_SERIAL) +#define SERIAL_DEV_OFFSET ((_machine == _MACH_prep || _machine == _MACH_chrp) ? 0 : 2) #else #define SERIAL_DEV_OFFSET 0 #endif @@ -1210,7 +1211,7 @@ if (!page) return -ENOMEM; - save_flags(flags); cli(); + spin_lock_irqsave( &info->irq_spinlock, flags); if (info->flags & ASYNC_INITIALIZED) { free_page(page); @@ -1448,11 +1449,11 @@ change_speed(info, 0); info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return 0; errout: - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return retval; } @@ -1476,7 +1477,7 @@ state->irq); #endif - save_flags(flags); cli(); /* Disable interrupts */ + spin_lock_irqsave( &info->irq_spinlock, flags); /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq @@ -1484,41 +1485,6 @@ */ wake_up_interruptible(&info->delta_msr_wait); - /* - * First unlink the serial port from the IRQ chain... - */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[state->irq] = info->next_port; - figure_IRQ_timeout(state->irq); - - /* - * Free the IRQ, if necessary - */ - if (state->irq && (!IRQ_ports[state->irq] || - !IRQ_ports[state->irq]->next_port)) { - if (IRQ_ports[state->irq]) { - free_irq(state->irq, &IRQ_ports[state->irq]); - retval = request_irq(state->irq, rs_interrupt_single, - SA_SHIRQ, "serial", - &IRQ_ports[state->irq]); - - if (retval) - printk("serial shutdown: request_irq: error %d" - " Couldn't reacquire IRQ.\n", retval); - } else - free_irq(state->irq, &IRQ_ports[state->irq]); - } - - if (info->xmit.buf) { - unsigned long pg = (unsigned long) info->xmit.buf; - info->xmit.buf = 0; - free_page(pg); - } - info->IER = 0; serial_outp(info, UART_IER, 0x00); /* disable all intrs */ #ifdef CONFIG_SERIAL_MANY_PORTS @@ -1575,7 +1541,43 @@ serial_outp(info, UART_IER, UART_IERX_SLEEP); } info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, &IRQ_ports[state->irq]); + retval = request_irq(state->irq, rs_interrupt_single, + SA_SHIRQ, "serial", + &IRQ_ports[state->irq]); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, &IRQ_ports[state->irq]); + } + + if (info->xmit.buf) { + unsigned long pg = (unsigned long) info->xmit.buf; + info->xmit.buf = 0; + free_page(pg); + } + + spin_unlock_irqrestore( &info->irq_spinlock, flags); } #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ @@ -3095,36 +3097,53 @@ sstate = rs_table + line; sstate->count++; - if (sstate->info) { - *ret_info = sstate->info; - return 0; - } + info = sstate->info; + + /* + * If the async_struct is already allocated, do the fastpath. + */ + if (info) + goto out; + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); if (!info) { sstate->count--; return -ENOMEM; } + memset(info, 0, sizeof(struct async_struct)); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->delta_msr_wait); info->magic = SERIAL_MAGIC; info->port = sstate->port; + info->hub6 = sstate->hub6; info->flags = sstate->flags; - info->io_type = sstate->io_type; - info->iomem_base = sstate->iomem_base; - info->iomem_reg_shift = sstate->iomem_reg_shift; info->xmit_fifo_size = sstate->xmit_fifo_size; + info->state = sstate; + spin_lock_init(&info->irq_spinlock); info->line = line; + info->iomem_base = sstate->iomem_base; + info->iomem_reg_shift = sstate->iomem_reg_shift; + info->io_type = sstate->io_type; info->tqueue.routine = do_softint; info->tqueue.data = info; - info->state = sstate; + if (sstate->info) { kfree(info); - *ret_info = sstate->info; - return 0; + info = sstate->info; + } else { + sstate->info = info; } - *ret_info = sstate->info = info; + +out: + /* + * If this is the first open, copy over some timeouts. + */ + if (sstate->count == 1) { + info->closing_wait = sstate->closing_wait; + } + *ret_info = info; return 0; } @@ -3133,6 +3152,10 @@ * 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. + * + * Note that on failure, we don't decrement the module use count - the tty + * later will call rs_close, which will decrement it for us as long as + * tty->driver_data is set non-NULL. --rmk */ static int rs_open(struct tty_struct *tty, struct file * filp) { @@ -3141,7 +3164,7 @@ unsigned long page; MOD_INC_USE_COUNT; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) { MOD_DEC_USE_COUNT; return -ENODEV; @@ -3153,10 +3176,8 @@ } tty->driver_data = info; info->tty = tty; - if (serial_paranoia_check(info, tty->device, "rs_open")) { - MOD_DEC_USE_COUNT; + if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV; - } #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, @@ -3171,10 +3192,8 @@ */ if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); - if (!page) { - MOD_DEC_USE_COUNT; + if (!page) return -ENOMEM; - } if (tmp_buf) free_page(page); else @@ -3188,7 +3207,6 @@ (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); - MOD_DEC_USE_COUNT; #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); @@ -3201,10 +3219,8 @@ * Start up serial port */ retval = startup(info); - if (retval) { - MOD_DEC_USE_COUNT; + if (retval) return retval; - } retval = block_til_ready(tty, filp, info); if (retval) { @@ -3212,7 +3228,6 @@ printk("rs_open returning after block_til_ready with %d\n", retval); #endif - MOD_DEC_USE_COUNT; return retval; } @@ -3647,6 +3662,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; save_flags(flags); cli(); @@ -4896,7 +4912,7 @@ static struct pci_driver serial_pci_driver = { name: "serial", probe: serial_init_one, - remove: serial_remove_one, + remove: __devexit_p(serial_remove_one), id_table: serial_pci_tbl, }; @@ -5397,6 +5413,7 @@ #endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; + serial_driver.name_base = SERIAL_DEV_OFFSET; serial_driver.num = NR_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; @@ -5408,7 +5425,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -5622,6 +5641,7 @@ info->io_type = req->io_type; info->iomem_base = req->iomem_base; info->iomem_reg_shift = req->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; } autoconfig(state); if (state->type == PORT_UNKNOWN) { @@ -5825,38 +5845,9 @@ serial_out(info, UART_IER, ier); } -/* - * Receive character from the serial port - */ -static int serial_console_wait_key(struct console *co) -{ - static struct async_struct *info; - int ier, c; - - info = &async_sercons; - - /* - * First save the IER then disable the interrupts so - * that the real driver for the port does not get the - * character. - */ - ier = serial_in(info, UART_IER); - serial_out(info, UART_IER, 0x00); - - while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0); - c = serial_in(info, UART_RX); - - /* - * Restore the interrupts - */ - serial_out(info, UART_IER, ier); - - return c; -} - static kdev_t serial_console_device(struct console *c) { - return MKDEV(TTY_MAJOR, 64 + c->index); + return mk_kdev(TTY_MAJOR, 64 + c->index); } /* @@ -5958,6 +5949,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; quot = state->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); #if defined(__powerpc__) || defined(__alpha__) @@ -5994,7 +5986,6 @@ name: "ttyS", write: serial_console_write, device: serial_console_device, - wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/serial167.c linux-2.5/drivers/char/serial167.c --- linux-2.5.1/drivers/char/serial167.c Mon Sep 17 04:23:07 2001 +++ linux-2.5/drivers/char/serial167.c Sun Jan 6 01:38:27 2002 @@ -65,7 +65,6 @@ #include <asm/system.h> #include <asm/io.h> -#include <asm/segment.h> #include <asm/bitops.h> #include <asm/mvme16xhw.h> #include <asm/bootinfo.h> @@ -103,6 +102,7 @@ DECLARE_TASK_QUEUE(tq_cyclades); struct tty_driver cy_serial_driver, cy_callout_driver; +static struct console sercons; extern int serial_console; static struct cyclades_port *serial_console_info = NULL; static unsigned int serial_console_cflag = 0; @@ -249,18 +249,18 @@ "Warning: cyclades_port out of range for (%d, %d) in %s\n"; if (!info) { - printk(badinfo, MAJOR(device), MINOR(device), routine); + printk(badinfo, major(device), minor(device), routine); return 1; } if( (long)info < (long)(&cy_port[0]) || (long)(&cy_port[NR_PORTS]) < (long)info ){ - printk(badrange, MAJOR(device), MINOR(device), routine); + printk(badrange, major(device), minor(device), routine); return 1; } if (info->magic != CYCLADES_MAGIC) { - printk(badmagic, MAJOR(device), MINOR(device), routine); + printk(badmagic, major(device), minor(device), routine); return 1; } #endif @@ -2133,7 +2133,7 @@ int retval, line; /* CP('O'); */ - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if ((line < 0) || (NR_PORTS <= line)){ return -ENODEV; } @@ -2409,6 +2409,7 @@ cy_serial_driver.table = serial_table; cy_serial_driver.termios = serial_termios; cy_serial_driver.termios_locked = serial_termios_locked; + cy_serial_driver.console = &sercons; cy_serial_driver.open = cy_open; cy_serial_driver.close = cy_close; cy_serial_driver.write = cy_write; @@ -2806,61 +2807,9 @@ restore_flags(flags); } -/* This is a hack; if there are multiple chars waiting in the chip we - * discard all but the last one, and return that. The cd2401 is not really - * designed to be driven in polled mode. - */ - -int serial167_console_wait_key(struct console *co) -{ - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - unsigned long flags; - volatile u_char sink; - u_char ier; - int port; - int keypress = 0; - - save_flags(flags); cli(); - - /* Ensure receiver is enabled! */ - - port = 0; - base_addr[CyCAR] = (u_char)port; - while (base_addr[CyCCR]) - ; - base_addr[CyCCR] = CyENB_RCVR; - ier = base_addr[CyIER]; - base_addr[CyIER] = CyRxData; - - while (!keypress) { - if (pcc2chip[PccSCCRICR] & 0x20) - { - /* We have an Rx int. Acknowledge it */ - sink = pcc2chip[PccRPIACKR]; - if ((base_addr[CyLICR] >> 2) == port) { - int cnt = base_addr[CyRFOC]; - while (cnt-- > 0) - { - keypress = base_addr[CyRDR]; - } - base_addr[CyREOIR] = 0; - } - else - base_addr[CyREOIR] = CyNOTRANS; - } - } - - base_addr[CyIER] = ier; - - restore_flags(flags); - - return keypress; -} - - static kdev_t serial167_console_device(struct console *c) { - return MKDEV(TTY_MAJOR, 64 + c->index); + return mk_kdev(TTY_MAJOR, 64 + c->index); } @@ -2874,7 +2823,6 @@ name: "ttyS", write: serial167_console_write, device: serial167_console_device, - wait_key: serial167_console_wait_key, setup: serial167_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/serial_21285.c linux-2.5/drivers/char/serial_21285.c --- linux-2.5.1/drivers/char/serial_21285.c Thu Sep 13 22:21:32 2001 +++ linux-2.5/drivers/char/serial_21285.c Sun Jan 6 01:38:27 2002 @@ -45,6 +45,7 @@ static struct termios *rs285_termios[1]; static struct termios *rs285_termios_locked[1]; +static struct console rs285_cons; static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char; static struct tty_struct *rs285_tty; @@ -264,7 +265,7 @@ int line; MOD_INC_USE_COUNT; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if (line) { MOD_DEC_USE_COUNT; return -ENODEV; @@ -312,7 +313,9 @@ rs285_driver.table = rs285_table; rs285_driver.termios = rs285_termios; rs285_driver.termios_locked = rs285_termios_locked; - +#ifdef CONFIG_SERIAL_21285_CONSOLE + rs285_driver.console = &rs285_cons; +#endif rs285_driver.open = rs285_open; rs285_driver.close = rs285_close; rs285_driver.write = rs285_write; @@ -389,20 +392,9 @@ enable_irq(IRQ_CONTX); } -static int rs285_console_wait_key(struct console *co) -{ - int c; - - disable_irq(IRQ_CONRX); - while (*CSR_UARTFLG & 0x10); - c = *CSR_UARTDR; - enable_irq(IRQ_CONRX); - return c; -} - static kdev_t rs285_console_device(struct console *c) { - return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); + return mk_kdev(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); } static int __init rs285_console_setup(struct console *co, char *options) @@ -493,7 +485,6 @@ name: SERIAL_21285_NAME, write: rs285_console_write, device: rs285_console_device, - wait_key: rs285_console_wait_key, setup: rs285_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/serial_amba.c linux-2.5/drivers/char/serial_amba.c --- linux-2.5.1/drivers/char/serial_amba.c Mon Sep 17 04:23:14 2001 +++ linux-2.5/drivers/char/serial_amba.c Sun Jan 6 01:38:27 2002 @@ -953,7 +953,7 @@ #if DEBUG printk("ambauart_flush_buffer(%d) called\n", - MINOR(tty->device) - tty->driver.minor_start); + minor(tty->device) - tty->driver.minor_start); #endif save_flags(flags); cli(); info->xmit.head = info->xmit.tail = 0; @@ -1515,7 +1515,7 @@ expire = jiffies + timeout; #if DEBUG printk("ambauart_wait_until_sent(%d), jiff=%lu, expire=%lu...\n", - MINOR(tty->device) - tty->driver.minor_start, jiffies, + minor(tty->device) - tty->driver.minor_start, jiffies, expire); #endif while (UART_GET_FR(info->port) & AMBA_UARTFR_BUSY) { @@ -1690,7 +1690,7 @@ static int ambauart_open(struct tty_struct *tty, struct file *filp) { struct amba_info *info; - int retval, line = MINOR(tty->device) - tty->driver.minor_start; + int retval, line = minor(tty->device) - tty->driver.minor_start; #if DEBUG printk("ambauart_open(%d) called\n", line); @@ -1789,7 +1789,9 @@ ambanormal_driver.table = ambauart_table; ambanormal_driver.termios = ambauart_termios; ambanormal_driver.termios_locked = ambauart_termios_locked; - +#ifdef CONFIG_SERIAL_AMBA_CONSOLE + ambanormal_driver.console = &ambauart_cons; +#endif ambanormal_driver.open = ambauart_open; ambanormal_driver.close = ambauart_close; ambanormal_driver.write = ambauart_write; @@ -1921,25 +1923,9 @@ UART_PUT_CR(port, old_cr); } -/* - * Receive character from the serial port - */ -static int ambauart_console_wait_key(struct console *co) -{ - struct amba_port *port = &amba_ports[co->index]; - unsigned int status; - int c; - - do { - status = UART_GET_FR(port); - } while (!UART_RX_DATA(status)); - c = UART_GET_CHAR(port); - return c; -} - static kdev_t ambauart_console_device(struct console *c) { - return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + c->index); + return mk_kdev(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + c->index); } static int __init ambauart_console_setup(struct console *co, char *options) @@ -2015,7 +2001,6 @@ read: ambauart_console_read, #endif device: ambauart_console_device, - wait_key: ambauart_console_wait_key, setup: ambauart_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/serial_tx3912.c linux-2.5/drivers/char/serial_tx3912.c --- linux-2.5.1/drivers/char/serial_tx3912.c Fri Nov 9 22:01:21 2001 +++ linux-2.5/drivers/char/serial_tx3912.c Sun Jan 6 01:38:27 2002 @@ -548,7 +548,7 @@ return -EIO; } - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; rs_dprintk (TX3912_UART_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p)\n", (int) current->pid, line, tty, current->tty); @@ -673,7 +673,7 @@ case TIOCGSERIAL: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0) - gs_getserial(&port->gs, (struct serial_struct *) arg); + rc = gs_getserial(&port->gs, (struct serial_struct *) arg); break; case TIOCSSERIAL: if ((rc = verify_area(VERIFY_READ, (void *) arg, @@ -854,7 +854,9 @@ rs_driver.table = rs_table; rs_driver.termios = rs_termios; rs_driver.termios_locked = rs_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + rs_driver.console = &sercons; +#endif rs_driver.open = rs_open; rs_driver.close = gs_close; rs_driver.write = gs_write; @@ -993,21 +995,6 @@ IntEnable2 = int2; } -static int serial_console_wait_key(struct console *co) -{ - unsigned int int2, res; - - int2 = IntEnable2; - IntEnable2 = 0; - - while (!(UartA_Ctrl1 & UART_RX_HOLD_FULL)); - res = UartA_Data; - udelay(10); - - IntEnable2 = int2; - return res; -} - static void serial_console_write(struct console *co, const char *s, unsigned count) { @@ -1022,7 +1009,7 @@ static kdev_t serial_console_device(struct console *c) { - return MKDEV(TTY_MAJOR, 64 + c->index); + return mk_kdev(TTY_MAJOR, 64 + c->index); } static __init int serial_console_setup(struct console *co, char *options) @@ -1065,7 +1052,6 @@ name: "ttyS", write: serial_console_write, device: serial_console_device, - wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: -1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/sh-sci.c linux-2.5/drivers/char/sh-sci.c --- linux-2.5.1/drivers/char/sh-sci.c Mon Oct 15 20:36:48 2001 +++ linux-2.5/drivers/char/sh-sci.c Sun Jan 6 01:38:27 2002 @@ -813,7 +813,7 @@ struct sci_port *port; int retval, line; - line = MINOR(tty->device) - SCI_MINOR_START; + line = minor(tty->device) - SCI_MINOR_START; if ((line < 0) || (line >= SCI_NPORTS)) return -ENODEV; @@ -919,7 +919,7 @@ case TIOCGSERIAL: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0) - gs_getserial(&port->gs, (struct serial_struct *) arg); + rc = gs_getserial(&port->gs, (struct serial_struct *) arg); break; case TIOCSSERIAL: if ((rc = verify_area(VERIFY_READ, (void *) arg, @@ -1040,7 +1040,9 @@ sci_driver.table = sci_table; sci_driver.termios = sci_termios; sci_driver.termios_locked = sci_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + sci_driver.console = &sercons; +#endif sci_driver.open = sci_open; sci_driver.close = gs_close; sci_driver.write = gs_write; @@ -1181,18 +1183,9 @@ put_string(sercons_port, s, count); } -/* - * Receive character from the serial port - */ -static int serial_console_wait_key(struct console *co) -{ - /* Not implemented yet */ - return 0; -} - static kdev_t serial_console_device(struct console *c) { - return MKDEV(SCI_MAJOR, SCI_MINOR_START + c->index); + return mk_kdev(SCI_MAJOR, SCI_MINOR_START + c->index); } /* @@ -1273,7 +1266,6 @@ name: "ttySC", write: serial_console_write, device: serial_console_device, - wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/shwdt.c linux-2.5/drivers/char/shwdt.c --- linux-2.5.1/drivers/char/shwdt.c Tue Dec 11 18:10:18 2001 +++ linux-2.5/drivers/char/shwdt.c Sun Jan 13 22:15:01 2002 @@ -9,6 +9,9 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * + * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT */ #include <linux/config.h> #include <linux/module.h> @@ -60,6 +63,15 @@ static int sh_is_open = 0; static struct watchdog_info sh_wdt_info; +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /** * sh_wdt_write_cnt - Write to Counter * @@ -131,11 +143,14 @@ */ static int sh_wdt_open(struct inode *inode, struct file *file) { - switch (MINOR(inode->i_rdev)) { + switch (minor(inode->i_rdev)) { case WATCHDOG_MINOR: if (sh_is_open) { return -EBUSY; } + if (nowayout) { + MOD_INC_USE_COUNT; + } sh_is_open = 1; sh_wdt_start(); @@ -160,10 +175,10 @@ { lock_kernel(); - if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - sh_wdt_stop(); -#endif + if (minor(inode->i_rdev) == WATCHDOG_MINOR) { + if (!nowayout) { + sh_wdt_stop(); + } sh_is_open = 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/softdog.c linux-2.5/drivers/char/softdog.c --- linux-2.5.1/drivers/char/softdog.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/softdog.c Sun Jan 13 22:15:01 2002 @@ -1,5 +1,5 @@ /* - * SoftDog 0.05: A Software Watchdog Device + * SoftDog 0.06: A Software Watchdog Device * * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. * http://www.redhat.com @@ -26,6 +26,10 @@ * * 19980911 Alan Cox * Made SMP safe for 2.3.x + * + * 20011214 Matt Domsch <Matt_Domsch@dell.com> + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Didn't add timeout option, as soft_margin option already exists. */ #include <linux/module.h> @@ -46,6 +50,15 @@ static int soft_margin = TIMER_MARGIN; /* in seconds */ MODULE_PARM(soft_margin,"i"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); MODULE_LICENSE("GPL"); /* @@ -83,9 +96,9 @@ { if(timer_alive) return -EBUSY; -#ifdef CONFIG_WATCHDOG_NOWAYOUT - MOD_INC_USE_COUNT; -#endif + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate timer */ @@ -98,11 +111,11 @@ { /* * Shut off the timer. - * Lock it in if it's a module and we defined ...NOWAYOUT + * Lock it in if it's a module and we set nowayout */ -#ifndef CONFIG_WATCHDOG_NOWAYOUT - del_timer(&watchdog_ticktock); -#endif + if(!nowayout) { + del_timer(&watchdog_ticktock); + } timer_alive=0; return 0; } @@ -159,7 +172,7 @@ fops: &softdog_fops, }; -static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.05, timer margin: %d sec\n"; +static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.06, soft_margin: %d sec, nowayout: %d\n"; static int __init watchdog_init(void) { @@ -170,7 +183,7 @@ if (ret) return ret; - printk(banner, soft_margin); + printk(banner, soft_margin, nowayout); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/sonypi.c linux-2.5/drivers/char/sonypi.c --- linux-2.5.1/drivers/char/sonypi.c Thu Nov 29 15:53:34 2001 +++ linux-2.5/drivers/char/sonypi.c Tue Jan 8 01:17:10 2002 @@ -109,25 +109,29 @@ return result; } -static void sonypi_ecrset(u16 addr, u16 value) { +static void sonypi_ecrset(u8 addr, u8 value) { - wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3); - outw_p(0x81, SONYPI_CST_IOPORT); - wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2); - outw_p(addr, SONYPI_DATA_IOPORT); - wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2); - outw_p(value, SONYPI_DATA_IOPORT); - wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2); -} - -static u16 sonypi_ecrget(u16 addr) { - - wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3); - outw_p(0x80, SONYPI_CST_IOPORT); - wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2); - outw_p(addr, SONYPI_DATA_IOPORT); - wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2); - return inw_p(SONYPI_DATA_IOPORT); + wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3); + outb_p(0x81, SONYPI_CST_IOPORT); + wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2); + outb_p(addr, SONYPI_DATA_IOPORT); + wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2); + outb_p(value, SONYPI_DATA_IOPORT); + wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2); +} + +static u8 sonypi_ecrget(u8 addr) { + + wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3); + outb_p(0x80, SONYPI_CST_IOPORT); + wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2); + outb_p(addr, SONYPI_DATA_IOPORT); + wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2); + return inb_p(SONYPI_DATA_IOPORT); +} + +static u16 sonypi_ecrget16(u8 addr) { + return sonypi_ecrget(addr) | (sonypi_ecrget(addr + 1) << 8); } /* Initializes the device - this comes from the AML code in the ACPI bios */ @@ -510,24 +514,60 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { int ret = 0; - u8 val; + u8 val8; + u16 val16; down(&sonypi_device.lock); switch (cmd) { - case SONYPI_IOCGBRT: - val = sonypi_ecrget(0x96) & 0xff; - if (copy_to_user((u8 *)arg, &val, sizeof(val))) { - ret = -EFAULT; - goto out; - } - break; - case SONYPI_IOCSBRT: - if (copy_from_user(&val, (u8 *)arg, sizeof(val))) { - ret = -EFAULT; - goto out; - } - sonypi_ecrset(0x96, val); - break; + case SONYPI_IOCGBRT: + val8 = sonypi_ecrget(0x96); + if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCSBRT: + if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) { + ret = -EFAULT; + goto out; + } + sonypi_ecrset(0x96, val8); + break; + case SONYPI_IOCGBAT1CAP: + val16 = sonypi_ecrget16(0xb2); + if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCGBAT1REM: + val16 = sonypi_ecrget16(0xa2); + if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCGBAT2CAP: + val16 = sonypi_ecrget16(0xba); + if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCGBAT2REM: + val16 = sonypi_ecrget16(0xaa); + if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCGBATFLAGS: + val8 = sonypi_ecrget(0x81) & 0x07; + if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) { + ret = -EFAULT; + goto out; + } + break; default: ret = -EINVAL; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/sonypi.h linux-2.5/drivers/char/sonypi.h --- linux-2.5.1/drivers/char/sonypi.h Thu Nov 29 15:53:34 2001 +++ linux-2.5/drivers/char/sonypi.h Tue Jan 8 01:17:10 2002 @@ -35,7 +35,7 @@ #ifdef __KERNEL__ #define SONYPI_DRIVER_MAJORVERSION 1 -#define SONYPI_DRIVER_MINORVERSION 8 +#define SONYPI_DRIVER_MINORVERSION 9 #include <linux/types.h> #include <linux/pci.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/specialix.c linux-2.5/drivers/char/specialix.c --- linux-2.5.1/drivers/char/specialix.c Fri Nov 9 22:01:21 2001 +++ linux-2.5/drivers/char/specialix.c Sun Jan 6 01:38:27 2002 @@ -1455,17 +1455,17 @@ struct specialix_board * bp; unsigned long flags; - board = SX_BOARD(MINOR(tty->device)); + board = SX_BOARD(minor(tty->device)); if (board > SX_NBOARD || !(sx_board[board].flags & SX_BOARD_PRESENT)) return -ENODEV; bp = &sx_board[board]; - port = sx_port + board * SX_NPORT + SX_PORT(MINOR(tty->device)); + port = sx_port + board * SX_NPORT + SX_PORT(minor(tty->device)); #ifdef DEBUG_SPECIALIX printk (KERN_DEBUG "Board = %d, bp = %p, port = %p, portno = %d.\n", - board, bp, port, SX_PORT(MINOR(tty->device))); + board, bp, port, SX_PORT(minor(tty->device))); #endif if (sx_paranoia_check(port, tty->device, "sx_open")) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/stallion.c linux-2.5/drivers/char/stallion.c --- linux-2.5.1/drivers/char/stallion.c Fri Sep 21 17:55:23 2001 +++ linux-2.5/drivers/char/stallion.c Sun Jan 6 01:38:27 2002 @@ -1018,7 +1018,7 @@ (int) filp, tty->device); #endif - minordev = MINOR(tty->device); + minordev = minor(tty->device); brdnr = MINOR2BRD(minordev); if (brdnr >= stl_nrbrds) return(-ENODEV); @@ -3133,7 +3133,7 @@ (int) fp, cmd, (int) arg); #endif - brdnr = MINOR(ip->i_rdev); + brdnr = minor(ip->i_rdev); if (brdnr >= STL_MAXBRDS) return(-ENODEV); rc = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/sx.c linux-2.5/drivers/char/sx.c --- linux-2.5.1/drivers/char/sx.c Fri Nov 9 22:01:21 2001 +++ linux-2.5/drivers/char/sx.c Sun Jan 6 01:38:27 2002 @@ -1160,7 +1160,8 @@ /* DCD went UP */ if( (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) && - (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED)) { + (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) && + !(port->gs.tty->termios->c_cflag & CLOCAL) ) { /* Are we blocking in open?*/ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n"); wake_up_interruptible(&port->gs.open_wait); @@ -1170,7 +1171,8 @@ } else { /* DCD went down! */ if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && - (port->gs.flags & ASYNC_CALLOUT_NOHUP))) { + (port->gs.flags & ASYNC_CALLOUT_NOHUP)) && + !(port->gs.tty->termios->c_cflag & CLOCAL) ) { sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n"); tty_hangup (port->gs.tty); } else { @@ -1420,7 +1422,7 @@ return -EIO; } - line = MINOR(tty->device); + line = minor(tty->device); sx_dprintk (SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, np=%d)\n", current->pid, line, tty, current->tty, sx_nports); @@ -1815,7 +1817,7 @@ case TIOCGSERIAL: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0) - gs_getserial(&port->gs, (struct serial_struct *) arg); + rc = gs_getserial(&port->gs, (struct serial_struct *) arg); break; case TIOCSSERIAL: if ((rc = verify_area(VERIFY_READ, (void *) arg, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/synclink.c linux-2.5/drivers/char/synclink.c --- linux-2.5.1/drivers/char/synclink.c Fri Sep 14 21:39:59 2001 +++ linux-2.5/drivers/char/synclink.c Sun Jan 6 01:38:27 2002 @@ -114,7 +114,6 @@ #endif #endif -#include <asm/segment.h> #define GET_USER(error,value,addr) error = get_user(value,addr) #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 #define PUT_USER(error,value,addr) error = put_user(value,addr) @@ -926,7 +925,7 @@ static int __init synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); -static void __exit synclink_remove_one (struct pci_dev *dev); +static void __devexit synclink_remove_one (struct pci_dev *dev); static struct pci_device_id synclink_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, }, @@ -940,7 +939,7 @@ name: "synclink", id_table: synclink_pci_tbl, probe: synclink_init_one, - remove: synclink_remove_one, + remove: __devexit_p(synclink_remove_one), }; static struct tty_driver serial_driver, callout_driver; @@ -3601,7 +3600,7 @@ unsigned long flags; /* verify range of specified line number */ - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= mgsl_device_count)) { printk("%s(%d):mgsl_open with illegal line #%d.\n", __FILE__,__LINE__,line); @@ -8219,7 +8218,7 @@ return 0; } -static void __exit synclink_remove_one (struct pci_dev *dev) +static void __devexit synclink_remove_one (struct pci_dev *dev) { } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/sysrq.c linux-2.5/drivers/char/sysrq.c --- linux-2.5.1/drivers/char/sysrq.c Mon Dec 10 21:52:53 2001 +++ linux-2.5/drivers/char/sysrq.c Wed Jan 2 17:17:02 2002 @@ -103,11 +103,9 @@ /* 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) { +static int is_local_disk(kdev_t dev) +{ + switch (major(dev)) { case IDE0_MAJOR: case IDE1_MAJOR: case IDE2_MAJOR: @@ -206,7 +204,7 @@ for (sb = sb_entry(super_blocks.next); sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) - if (!is_local_disk(sb->s_dev) && MAJOR(sb->s_dev)) + if (!is_local_disk(sb->s_dev) && major(sb->s_dev)) go_sync(sb, remount_flag); unlock_kernel(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/tpqic02.c linux-2.5/drivers/char/tpqic02.c --- linux-2.5.1/drivers/char/tpqic02.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/tpqic02.c Sun Jan 6 01:38:27 2002 @@ -1830,7 +1830,7 @@ /* can't print a ``long long'' (for filp->f_pos), so chop it */ printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx" - ", pos=%lx, flags=%x\n", MINOR(dev), buf, + ", pos=%lx, flags=%x\n", minor(dev), buf, (long) count, (unsigned long) filp->f_pos, flags); if (count % TAPE_BLKSIZE) { /* Only allow mod 512 bytes at a time. */ @@ -2027,7 +2027,7 @@ /* can't print a ``long long'' (for filp->f_pos), so chop it */ printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p" ", count=%lx, pos=%lx, flags=%x\n", - MINOR(dev), buf, + minor(dev), buf, (long) count, (unsigned long) filp->f_pos, flags); } @@ -2203,7 +2203,7 @@ kdevname(dev), flags); } - if (MINOR(dev) == 255) { /* special case for resetting */ + if (minor(dev) == 255) { /* special case for resetting */ if (capable(CAP_SYS_ADMIN)) { return (tape_reset(1) == TE_OK) ? -EAGAIN : -ENXIO; } else { @@ -2383,7 +2383,7 @@ } if (s != 0) { status_dead = YES; /* force reset */ - current_tape_dev = 0; /* earlier 0xff80 */ + current_tape_dev = NODEV;/* earlier 0xff80 */ return -EIO; } @@ -2522,7 +2522,7 @@ unsigned int iocmd, unsigned long ioarg) { int error; - int dev_maj = MAJOR(inode->i_rdev); + int dev_maj = major(inode->i_rdev); int c; struct mtop operation; unsigned char blk_addr[6]; @@ -2828,7 +2828,7 @@ return -ENODEV; } - current_tape_dev = MKDEV(QIC02_TAPE_MAJOR, 0); + current_tape_dev = mk_kdev(QIC02_TAPE_MAJOR, 0); #ifndef CONFIG_QIC02_DYNCONF printk(TPQIC02_NAME ": IRQ %d, DMA %d, IO 0x%x, IFC %s, %s, %s\n", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/tty_io.c linux-2.5/drivers/char/tty_io.c --- linux-2.5.1/drivers/char/tty_io.c Fri Nov 30 04:48:58 2001 +++ linux-2.5/drivers/char/tty_io.c Mon Jan 14 22:39:45 2002 @@ -102,10 +102,10 @@ #include <linux/kmod.h> -#define CONSOLE_DEV MKDEV(TTY_MAJOR,0) -#define TTY_DEV MKDEV(TTYAUX_MAJOR,0) -#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1) -#define PTMX_DEV MKDEV(TTYAUX_MAJOR,2) +#define IS_CONSOLE_DEV(dev) (kdev_val(dev) == __mkdev(TTY_MAJOR,0)) +#define IS_TTY_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,0)) +#define IS_SYSCONS_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1)) +#define IS_PTMX_DEV(dev) (kdev_val(dev) == __mkdev(TTYAUX_MAJOR,2)) #undef TTY_DEBUG_HANGUP @@ -185,7 +185,7 @@ static char * _tty_make_name(struct tty_struct *tty, const char *name, char *buf) { - int idx = (tty)?MINOR(tty->device) - tty->driver.minor_start:0; + int idx = (tty)? minor(tty->device) - tty->driver.minor_start:0; if (!tty) /* Hmm. NULL pointer. That's fun. */ strcpy(buf, "NULL tty"); @@ -196,7 +196,7 @@ return buf; } -#define TTY_NUMBER(tty) (MINOR((tty)->device) - (tty)->driver.minor_start + \ +#define TTY_NUMBER(tty) (minor((tty)->device) - (tty)->driver.minor_start + \ (tty)->driver.name_base) char *tty_name(struct tty_struct *tty, char *buf) @@ -331,8 +331,8 @@ int major, minor; struct tty_driver *p; - minor = MINOR(device); - major = MAJOR(device); + minor = minor(device); + major = major(device); for (p = tty_drivers; p; p = p->next) { if (p->major != major) @@ -442,8 +442,8 @@ file_list_lock(); for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) { struct file * filp = list_entry(l, struct file, f_list); - if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV || - filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV) { + if (IS_CONSOLE_DEV(filp->f_dentry->d_inode->i_rdev) || + IS_SYSCONS_DEV(filp->f_dentry->d_inode->i_rdev)) { cons_filp = filp; continue; } @@ -597,12 +597,6 @@ read_unlock(&tasklist_lock); } -void wait_for_keypress(void) -{ - struct console *c = console_drivers; - if (c) c->wait_key(c); -} - void stop_tty(struct tty_struct *tty) { if (tty->stopped) @@ -658,7 +652,7 @@ moved it to there. This should only be done for the N_TTY line discipline, anyway. Same goes for write_chan(). -- jlc. */ #if 0 - if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */ + if (!IS_CONSOLE_DEV(inode->i_rdev) && /* don't stop on /dev/console */ (tty->pgrp > 0) && (current->tty == tty) && (tty->pgrp != current->pgrp)) @@ -693,8 +687,13 @@ { ssize_t ret = 0, written = 0; - if (down_interruptible(&tty->atomic_write)) { - return -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&tty->atomic_write)) + return -EAGAIN; + } + else { + if (down_interruptible(&tty->atomic_write)) + return -ERESTARTSYS; } if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) { lock_kernel(); @@ -747,8 +746,8 @@ * well as /dev/tty0. */ inode = file->f_dentry->d_inode; - is_console = (inode->i_rdev == SYSCONS_DEV || - inode->i_rdev == CONSOLE_DEV); + is_console = IS_SYSCONS_DEV(inode->i_rdev) || + IS_CONSOLE_DEV(inode->i_rdev); if (is_console && redirect) tty = redirect; @@ -809,7 +808,7 @@ if (!driver) return -ENODEV; - idx = MINOR(device) - driver->minor_start; + idx = minor(device) - driver->minor_start; /* * Check whether we need to acquire the tty semaphore to avoid @@ -863,7 +862,7 @@ if (!o_tty) goto free_mem_out; initialize_tty_struct(o_tty); - o_tty->device = (kdev_t) MKDEV(driver->other->major, + o_tty->device = mk_kdev(driver->other->major, driver->other->minor_start + idx); o_tty->driver = *driver->other; @@ -1055,7 +1054,7 @@ tty_fasync(-1, filp, 0); - idx = MINOR(tty->device) - tty->driver.minor_start; + idx = minor(tty->device) - tty->driver.minor_start; pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_MASTER); o_tty = tty->link; @@ -1291,7 +1290,7 @@ retry_open: noctty = filp->f_flags & O_NOCTTY; device = inode->i_rdev; - if (device == TTY_DEV) { + if (IS_TTY_DEV(device)) { if (!current->tty) return -ENXIO; device = current->tty->device; @@ -1299,13 +1298,13 @@ /* noctty = 1; */ } #ifdef CONFIG_VT - if (device == CONSOLE_DEV) { + if (IS_CONSOLE_DEV(device)) { extern int fg_console; - device = MKDEV(TTY_MAJOR, fg_console + 1); + device = mk_kdev(TTY_MAJOR, fg_console + 1); noctty = 1; } #endif - if (device == SYSCONS_DEV) { + if (IS_SYSCONS_DEV(device)) { struct console *c = console_drivers; while(c && !c->device) c = c->next; @@ -1316,7 +1315,7 @@ noctty = 1; } - if (device == PTMX_DEV) { + if (IS_PTMX_DEV(device)) { #ifdef CONFIG_UNIX98_PTYS /* find a free pty. */ @@ -1330,7 +1329,7 @@ for (minor = driver->minor_start ; minor < driver->minor_start + driver->num ; minor++) { - device = MKDEV(driver->major, minor); + device = mk_kdev(driver->major, minor); if (!init_dev(device, &tty)) goto ptmx_found; /* ok! */ } } @@ -1338,8 +1337,8 @@ ptmx_found: set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ minor -= driver->minor_start; - devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start)); - tty_register_devfs(&pts_driver[major], DEVFS_FL_NO_PERSISTENCE, + devpts_pty_new(driver->other->name_base + minor, mk_kdev(driver->other->major, minor + driver->other->minor_start)); + tty_register_devfs(&pts_driver[major], DEVFS_FL_DEFAULT, pts_driver[major].minor_start + minor); noctty = 1; goto init_dev_done; @@ -1511,8 +1510,8 @@ static int tioccons(struct inode *inode, struct tty_struct *tty, struct tty_struct *real_tty) { - if (inode->i_rdev == SYSCONS_DEV || - inode->i_rdev == CONSOLE_DEV) { + if (IS_SYSCONS_DEV(inode->i_rdev) || + IS_CONSOLE_DEV(inode->i_rdev)) { if (!suser()) return -EPERM; redirect = NULL; @@ -2008,19 +2007,15 @@ { #ifdef CONFIG_DEVFS_FS umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR; - kdev_t device = MKDEV (driver->major, minor); + kdev_t device = mk_kdev(driver->major, minor); int idx = minor - driver->minor_start; char buf[32]; - switch (device) { - case TTY_DEV: - case PTMX_DEV: + if (IS_TTY_DEV(device) || IS_PTMX_DEV(device)) + mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + else { + if (driver->major == PTY_MASTER_MAJOR) mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - break; - default: - if (driver->major == PTY_MASTER_MAJOR) - mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - break; } if ( (minor < driver->minor_start) || (minor >= driver->minor_start + driver->num) ) { @@ -2188,6 +2183,11 @@ #ifdef CONFIG_SERIAL_CONSOLE #if (defined(CONFIG_8xx) || defined(CONFIG_8260)) console_8xx_init(); +#elif defined(CONFIG_MAC_SERIAL) && defined(CONFIG_SERIAL) + if (_machine == _MACH_Pmac) + mac_scc_console_init(); + else + serial_console_init(); #elif defined(CONFIG_MAC_SERIAL) mac_scc_console_init(); #elif defined(CONFIG_PARISC) @@ -2242,9 +2242,8 @@ static struct tty_driver dev_ptmx_driver; #endif #ifdef CONFIG_VT -extern void con_init_devfs (void); -extern void console_map_init(void); static struct tty_driver dev_console_driver; +extern int vty_init(void); #endif /* @@ -2284,19 +2283,12 @@ if (tty_register_driver(&dev_syscons_driver)) panic("Couldn't register /dev/console driver\n"); - /* console calls tty_register_driver() before kmalloc() works. - * Thus, we can't devfs_register() then. Do so now, instead. - */ -#ifdef CONFIG_VT - con_init_devfs(); -#endif - #ifdef CONFIG_UNIX98_PTYS dev_ptmx_driver = dev_tty_driver; dev_ptmx_driver.driver_name = "/dev/ptmx"; dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5; - dev_ptmx_driver.major= MAJOR(PTMX_DEV); - dev_ptmx_driver.minor_start = MINOR(PTMX_DEV); + dev_ptmx_driver.major= TTYAUX_MAJOR; + dev_ptmx_driver.minor_start = 2; dev_ptmx_driver.type = TTY_DRIVER_TYPE_SYSTEM; dev_ptmx_driver.subtype = SYSTEM_TYPE_SYSPTMX; @@ -2314,10 +2306,7 @@ if (tty_register_driver(&dev_console_driver)) panic("Couldn't register /dev/tty0 driver\n"); - - vcs_init(); - kbd_init(); - console_map_init(); + vty_init(); #endif #ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/vc_screen.c linux-2.5/drivers/char/vc_screen.c --- linux-2.5.1/drivers/char/vc_screen.c Mon Sep 17 04:22:40 2001 +++ linux-2.5/drivers/char/vc_screen.c Sun Jan 13 20:03:25 2002 @@ -49,7 +49,8 @@ vcs_size(struct inode *inode) { int size; - int currcons = MINOR(inode->i_rdev) & 127; + int minor = minor(inode->i_rdev); + int currcons = minor & 127; if (currcons == 0) currcons = fg_console; else @@ -59,7 +60,7 @@ size = video_num_lines * video_num_columns; - if (MINOR(inode->i_rdev) & 128) + if (minor & 128) size = 2*size + HEADER_SIZE; return size; } @@ -97,7 +98,7 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; - unsigned int currcons = MINOR(inode->i_rdev); + unsigned int currcons = minor(inode->i_rdev); long pos = *ppos; long viewed, attr, read; int col, maxcol; @@ -266,7 +267,7 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; - unsigned int currcons = MINOR(inode->i_rdev); + unsigned int currcons = minor(inode->i_rdev); long pos = *ppos; long viewed, attr, size, written; char *con_buf0; @@ -449,7 +450,7 @@ static int vcs_open(struct inode *inode, struct file *filp) { - unsigned int currcons = (MINOR(inode->i_rdev) & 127); + unsigned int currcons = minor(inode->i_rdev) & 127; if(currcons && !vc_cons_allocated(currcons-1)) return -ENXIO; return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/vme_scc.c linux-2.5/drivers/char/vme_scc.c --- linux-2.5.1/drivers/char/vme_scc.c Mon Sep 17 04:22:50 2001 +++ linux-2.5/drivers/char/vme_scc.c Sun Jan 6 01:38:27 2002 @@ -92,10 +92,10 @@ static void scc_break_ctl(struct tty_struct *tty, int break_state); static struct tty_driver scc_driver, scc_callout_driver; - static struct tty_struct *scc_table[2] = { NULL, }; static struct termios * scc_termios[2]; static struct termios * scc_termios_locked[2]; +static struct console sercons; struct scc_port scc_ports[2]; int scc_refcount; @@ -145,7 +145,9 @@ scc_driver.table = scc_table; scc_driver.termios = scc_termios; scc_driver.termios_locked = scc_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + scc_driver.console = &sercons; +#endif scc_driver.open = scc_open; scc_driver.close = gs_close; scc_driver.write = gs_write; @@ -833,7 +835,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp) { - int line = MINOR(tty->device) - SCC_MINOR_BASE; + int line = minor(tty->device) - SCC_MINOR_BASE; int retval; struct scc_port *port = &scc_ports[line]; int i, channel = port->channel; @@ -1065,44 +1067,9 @@ restore_flags(flags); } - -static int scc_console_wait_key(struct console *co) -{ - unsigned long flags; - volatile char *p = NULL; - int c; - -#ifdef CONFIG_MVME147_SCC - if (MACH_IS_MVME147) - p = (volatile char *)M147_SCC_A_ADDR; -#endif -#ifdef CONFIG_MVME162_SCC - if (MACH_IS_MVME16x) - p = (volatile char *)MVME_SCC_A_ADDR; -#endif -#ifdef CONFIG_BVME6000_SCC - if (MACH_IS_BVME6000) - p = (volatile char *)BVME_SCC_A_ADDR; -#endif - - save_flags(flags); - cli(); - - /* wait for rx buf filled */ - while ((*p & 0x01) == 0) - ; - - *p = 8; - scc_delay(); - c = *p; - restore_flags(flags); - return c; -} - - static kdev_t scc_console_device(struct console *c) { - return MKDEV(TTY_MAJOR, SCC_MINOR_BASE + c->index); + return mk_kdev(TTY_MAJOR, SCC_MINOR_BASE + c->index); } @@ -1116,7 +1083,6 @@ name: "ttyS", write: scc_console_write, device: scc_console_device, - wait_key: scc_console_wait_key, setup: scc_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/w83877f_wdt.c linux-2.5/drivers/char/w83877f_wdt.c --- linux-2.5.1/drivers/char/w83877f_wdt.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/w83877f_wdt.c Sun Jan 6 01:38:27 2002 @@ -196,7 +196,7 @@ static int fop_open(struct inode * inode, struct file * file) { - switch(MINOR(inode->i_rdev)) + switch(minor(inode->i_rdev)) { case WATCHDOG_MINOR: /* Just in case we're already talking to someone... */ @@ -214,7 +214,7 @@ static int fop_close(struct inode * inode, struct file * file) { - if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) + if(minor(inode->i_rdev) == WATCHDOG_MINOR) { if(wdt_expect_close) wdt_turnoff(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/wdt.c linux-2.5/drivers/char/wdt.c --- linux-2.5.1/drivers/char/wdt.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/wdt.c Sun Jan 13 22:15:01 2002 @@ -15,7 +15,7 @@ * * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> * - * Release 0.08. + * Release 0.09. * * Fixes * Dave Gregorich : Modularisation and minor bugs @@ -27,6 +27,7 @@ * Tim Hockin : Added insmod parameters, comment cleanup * Parameterized timeout * Tigran Aivazian : Restructured wdt_init() to handle failures + * Matt Domsch : added nowayout and timeout module options */ #include <linux/config.h> @@ -62,6 +63,26 @@ #define WD_TIMO (100*60) /* 1 minute */ +static int timeout_val = WD_TIMO; /* value passed to card */ +static int timeout = 60; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +static void __init +wdt_validate_timeout(void) +{ + timeout_val = timeout * 100; +} + #ifndef MODULE /** @@ -216,7 +237,7 @@ /* Write a watchdog value */ inb_p(WDT_DC); wdt_ctr_mode(1,2); - wdt_ctr_load(1,WD_TIMO); /* Timeout */ + wdt_ctr_load(1,timeout_val); /* Timeout */ outb_p(0, WDT_DC); } @@ -265,7 +286,7 @@ if (ptr != &file->f_pos) return -ESPIPE; - switch(MINOR(file->f_dentry->d_inode->i_rdev)) + switch(minor(file->f_dentry->d_inode->i_rdev)) { case TEMP_MINOR: c*=11; @@ -334,11 +355,14 @@ static int wdt_open(struct inode *inode, struct file *file) { - switch(MINOR(inode->i_rdev)) + switch(minor(inode->i_rdev)) { case WATCHDOG_MINOR: if(test_and_set_bit(0, &wdt_is_open)) return -EBUSY; + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate */ @@ -348,7 +372,7 @@ wdt_ctr_mode(1,2); wdt_ctr_mode(2,0); wdt_ctr_load(0, 8948); /* count at 100Hz */ - wdt_ctr_load(1,WD_TIMO); /* Timeout 120 seconds */ + wdt_ctr_load(1,timeout_val); /* Timeout */ wdt_ctr_load(2,65535); outb_p(0, WDT_DC); /* Enable */ return 0; @@ -373,12 +397,12 @@ static int wdt_release(struct inode *inode, struct file *file) { - if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) + if(minor(inode->i_rdev)==WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - inb_p(WDT_DC); /* Disable counters */ - wdt_ctr_load(2,0); /* 0 length reset pulses now */ -#endif + if (!nowayout) { + inb_p(WDT_DC); /* Disable counters */ + wdt_ctr_load(2,0); /* 0 length reset pulses now */ + } clear_bit(0, &wdt_is_open); } return 0; @@ -484,6 +508,7 @@ { int ret; + wdt_validate_timeout(); ret = misc_register(&wdt_miscdev); if (ret) { printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/wdt977.c linux-2.5/drivers/char/wdt977.c --- linux-2.5.1/drivers/char/wdt977.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/wdt977.c Sun Jan 13 22:15:01 2002 @@ -1,5 +1,5 @@ /* - * Wdt977 0.01: A Watchdog Device for Netwinder W83977AF chip + * Wdt977 0.02: A Watchdog Device for Netwinder W83977AF chip * * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>) * @@ -11,8 +11,13 @@ * 2 of the License, or (at your option) any later version. * * ----------------------- + * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * 19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface + * 06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts + * from minutes to seconds. */ - + #include <linux/module.h> #include <linux/config.h> #include <linux/types.h> @@ -21,56 +26,123 @@ #include <linux/miscdevice.h> #include <linux/init.h> #include <linux/smp_lock.h> +#include <linux/watchdog.h> #include <asm/io.h> #include <asm/system.h> #include <asm/mach-types.h> +#include <asm/uaccess.h> #define WATCHDOG_MINOR 130 -static int timeout = 3; +#define DEFAULT_TIMEOUT 1 /* default timeout = 1 minute */ + +static int timeout = DEFAULT_TIMEOUT*60; /* TO in seconds from user */ +static int timeoutM = DEFAULT_TIMEOUT; /* timeout in minutes */ static int timer_alive; static int testmode; +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=60"); +MODULE_PARM(testmode, "i"); +MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + + +/* This is kicking the watchdog by simply re-writing the timeout to reg. 0xF2 */ +int kick_wdog(void) +{ + /* + * Refresh the timer. + */ + + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and kicks watchdog reg F2 */ + /* F2 has the timeout in minutes */ + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeoutM,0x371); + + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + return 0; +} + + /* * Allow only one person to hold it open */ - + static int wdt977_open(struct inode *inode, struct file *file) { + if(timer_alive) return -EBUSY; -#ifdef CONFIG_WATCHDOG_NOWAYOUT - MOD_INC_USE_COUNT; -#endif + + /* convert seconds to minutes, rounding up */ + timeoutM = timeout + 59; + timeoutM /= 60; + + if (nowayout) + { + MOD_INC_USE_COUNT; + + /* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */ + if (!timeoutM) timeoutM = DEFAULT_TIMEOUT; + } timer_alive++; - //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. - if (timeout>255) - timeout = 255; - - printk(KERN_INFO "Watchdog: active, current timeout %d min.\n",timeout); - - // unlock the SuperIO chip - outb(0x87,0x370); - outb(0x87,0x370); - - //select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 - //F2 has the timeout in minutes - //F3 could be set to the POWER LED blink (with GP17 set to PowerLed) - // at timeout, and to reset timer on kbd/mouse activity (not now) - //F4 is used to just clear the TIMEOUT'ed state (bit 0) - + if (machine_is_netwinder()) + { + /* we have a hw bug somewhere, so each 977 minute is actually only 30sec + * this limits the max timeout to half of device max of 255 minutes... + */ + timeoutM += timeoutM; + } + + /* max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. */ + if (timeoutM > 255) timeoutM = 255; + + /* convert seconds to minutes */ + printk(KERN_INFO "Wdt977 Watchdog activated: timeout = %d sec, nowayout = %i, testmode = %i.\n", + machine_is_netwinder() ? (timeoutM>>1)*60 : timeoutM*60, + nowayout, testmode); + + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 + * F2 has the timeout in minutes + * F3 could be set to the POWER LED blink (with GP17 set to PowerLed) + * at timeout, and to reset timer on kbd/mouse activity (not impl.) + * F4 is used to just clear the TIMEOUT'ed state (bit 0) + */ outb(0x07,0x370); outb(0x08,0x371); outb(0xF2,0x370); - outb(timeout,0x371); + outb(timeoutM,0x371); outb(0xF3,0x370); - outb(0x00,0x371); //another setting is 0E for kbd/mouse/LED + outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */ outb(0xF4,0x370); outb(0x00,0x371); - - //at last select device Aux1 (dev=7) and set GP16 as a watchdog output + + /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ + /* in test mode watch the bit 1 on F4 to indicate "triggered" */ if (!testmode) { outb(0x07,0x370); @@ -78,9 +150,9 @@ outb(0xE6,0x370); outb(0x08,0x371); } - - // lock the SuperIO chip - outb(0xAA,0x370); + + /* lock the SuperIO chip */ + outb(0xAA,0x370); return 0; } @@ -89,84 +161,163 @@ { /* * Shut off the timer. - * Lock it in if it's a module and we defined ...NOWAYOUT + * Lock it in if it's a module and we set nowayout */ -#ifndef CONFIG_WATCHDOG_NOWAYOUT + if (!nowayout) + { + lock_kernel(); - // unlock the SuperIO chip - outb(0x87,0x370); - outb(0x87,0x370); - - //select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 - //F3 is reset to its default state - //F4 can clear the TIMEOUT'ed state (bit 0) - back to default - //We can not use GP17 as a PowerLed, as we use its usage as a RedLed - - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(0xFF,0x371); - outb(0xF3,0x370); - outb(0x00,0x371); - outb(0xF4,0x370); - outb(0x00,0x371); - outb(0xF2,0x370); - outb(0x00,0x371); - - //at last select device Aux1 (dev=7) and set GP16 as a watchdog output - outb(0x07,0x370); - outb(0x07,0x371); - outb(0xE6,0x370); - outb(0x08,0x371); - - // lock the SuperIO chip - outb(0xAA,0x370); + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 + * F3 is reset to its default state + * F4 can clear the TIMEOUT'ed state (bit 0) - back to default + * We can not use GP17 as a PowerLed, as we use its usage as a RedLed + */ + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(0xFF,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); + outb(0xF4,0x370); + outb(0x00,0x371); + outb(0xF2,0x370); + outb(0x00,0x371); - timer_alive=0; + /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); - printk(KERN_INFO "Watchdog: shutdown.\n"); -#endif + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + timer_alive=0; + unlock_kernel(); + + printk(KERN_INFO "Wdt977 Watchdog: shutdown\n"); + } return 0; } -static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos) + +/* + * wdt977_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t wdt977_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; - //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. - if (timeout>255) - timeout = 255; + if(count) + { + kick_wdog(); + return 1; + } + return 0; +} - /* - * Refresh the timer. - */ - - //we have a hw bug somewhere, so each 977 minute is actually only 30sec - //as such limit the max timeout to half of max of 255 minutes... -// if (timeout>126) -// timeout = 126; - - // unlock the SuperIO chip - outb(0x87,0x370); - outb(0x87,0x370); - - //select device Aux2 (device=8) and kicks watchdog reg F2 - //F2 has the timeout in minutes - - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(timeout,0x371); - - // lock the SuperIO chip - outb(0xAA,0x370); - - return 1; +/* + * wdt977_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. + */ + +static int wdt977_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ +static struct watchdog_info ident = { + identity : "Winbond 83977" +}; + +int temp; + + switch(cmd) + { + default: + return -ENOTTY; + + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *) arg); + + case WDIOC_GETSTATUS: + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and read watchdog reg F4 */ + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF4,0x370); + temp = inb(0x371); + + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + /* return info if "expired" in test mode */ + return put_user(temp & 1, (int *) arg); + + case WDIOC_KEEPALIVE: + kick_wdog(); + return 0; + + case WDIOC_SETTIMEOUT: + if (copy_from_user(&temp, (int *) arg, sizeof(int))) + return -EFAULT; + + /* convert seconds to minutes, rounding up */ + temp += 59; + temp /= 60; + + /* we have a hw bug somewhere, so each 977 minute is actually only 30sec + * this limits the max timeout to half of device max of 255 minutes... + */ + if (machine_is_netwinder()) + { + temp += temp; + } + + /* Sanity check */ + if (temp < 0 || temp > 255) + return -EINVAL; + + if (!temp && nowayout) + return -EINVAL; + + timeoutM = temp; + kick_wdog(); + return 0; + } } + static struct file_operations wdt977_fops= { owner: THIS_MODULE, write: wdt977_write, + ioctl: wdt977_ioctl, open: wdt977_open, release: wdt977_release, }; @@ -184,9 +335,9 @@ return -ENODEV; misc_register(&wdt977_miscdev); - printk(KERN_INFO "NetWinder Watchdog sleeping.\n"); + printk(KERN_INFO "Wdt977 Watchdog sleeping.\n"); return 0; -} +} static void __exit nwwatchdog_exit(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/char/wdt_pci.c linux-2.5/drivers/char/wdt_pci.c --- linux-2.5.1/drivers/char/wdt_pci.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/char/wdt_pci.c Sun Jan 13 22:15:01 2002 @@ -15,7 +15,7 @@ * * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> * - * Release 0.08. + * Release 0.09. * * Fixes * Dave Gregorich : Modularisation and minor bugs @@ -30,6 +30,7 @@ * Alan Cox : Split ISA and PCI cards into two drivers * Jeff Garzik : PCI cleanups * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures + * Matt Domsch : added nowayout and timeout module options */ #include <linux/config.h> @@ -83,6 +84,26 @@ #define WD_TIMO (100*60) /* 1 minute */ +static int timeout_val = WD_TIMO; /* value passed to card */ +static int timeout = 60; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +static void __init +wdtpci_validate_timeout(void) +{ + timeout_val = timeout * 100; +} + #ifndef MODULE /** @@ -232,7 +253,7 @@ /* Write a watchdog value */ inb_p(WDT_DC); wdtpci_ctr_mode(1,2); - wdtpci_ctr_load(1,WD_TIMO); /* Timeout */ + wdtpci_ctr_load(1,timeout_val); /* Timeout */ outb_p(0, WDT_DC); } @@ -281,7 +302,7 @@ if (ptr != &file->f_pos) return -ESPIPE; - switch(MINOR(file->f_dentry->d_inode->i_rdev)) + switch(minor(file->f_dentry->d_inode->i_rdev)) { case TEMP_MINOR: c*=11; @@ -350,16 +371,16 @@ static int wdtpci_open(struct inode *inode, struct file *file) { - switch(MINOR(inode->i_rdev)) + switch(minor(inode->i_rdev)) { case WATCHDOG_MINOR: if( test_and_set_bit(0,&wdt_is_open) ) { return -EBUSY; } -#ifdef CONFIG_WATCHDOG_NOWAYOUT - MOD_INC_USE_COUNT; -#endif + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate */ @@ -385,7 +406,7 @@ wdtpci_ctr_mode(1,2); wdtpci_ctr_mode(2,1); wdtpci_ctr_load(0,20833); /* count at 100Hz */ - wdtpci_ctr_load(1,WD_TIMO);/* Timeout 60 seconds */ + wdtpci_ctr_load(1,timeout_val); /* Timeout */ /* DO NOT LOAD CTR2 on PCI card! -- JPN */ outb_p(0, WDT_DC); /* Enable */ return 0; @@ -410,12 +431,12 @@ static int wdtpci_release(struct inode *inode, struct file *file) { - if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) + if(minor(inode->i_rdev)==WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - inb_p(WDT_DC); /* Disable counters */ - wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ -#endif + if (!nowayout) { + inb_p(WDT_DC); /* Disable counters */ + wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ + } clear_bit(0, &wdt_is_open ); } return 0; @@ -558,7 +579,7 @@ } -static void __exit wdtpci_remove_one (struct pci_dev *pdev) +static void __devexit wdtpci_remove_one (struct pci_dev *pdev) { /* here we assume only one device will ever have * been picked up and registered by probe function */ @@ -583,7 +604,7 @@ name: "wdt-pci", id_table: wdtpci_pci_tbl, probe: wdtpci_init_one, - remove: wdtpci_remove_one, + remove: __devexit_p(wdtpci_remove_one), }; @@ -617,6 +638,8 @@ if (rc < 1) return -ENODEV; + + wdtpci_validate_timeout(); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/fc4/fc.c linux-2.5/drivers/fc4/fc.c --- linux-2.5.1/drivers/fc4/fc.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/fc4/fc.c Sun Jan 6 19:17:50 2002 @@ -769,10 +769,10 @@ { unsigned long flags; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); if (FCP_CMND(SCpnt)->done) FCP_CMND(SCpnt)->done(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); } static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, int prepare) @@ -920,9 +920,9 @@ unsigned long flags; SCpnt->result = DID_ABORT; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); fcmd->done(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); printk("FC: soft abort\n"); return SUCCESS; } else { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/i2c/Config.in linux-2.5/drivers/i2c/Config.in --- linux-2.5.1/drivers/i2c/Config.in Thu Oct 11 15:05:47 2001 +++ linux-2.5/drivers/i2c/Config.in Thu Dec 27 16:32:31 2001 @@ -39,6 +39,10 @@ fi fi + if [ "$CONFIG_ALL_PPC" = "y" ] ; then + dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C + fi + # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/i2c/Makefile linux-2.5/drivers/i2c/Makefile --- linux-2.5.1/drivers/i2c/Makefile Thu Oct 11 15:05:47 2001 +++ linux-2.5/drivers/i2c/Makefile Thu Dec 27 16:32:31 2001 @@ -18,6 +18,7 @@ obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o obj-$(CONFIG_I2C_PROC) += i2c-proc.o +obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/i2c/i2c-dev.c linux-2.5/drivers/i2c/i2c-dev.c --- linux-2.5.1/drivers/i2c/i2c-dev.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/i2c/i2c-dev.c Wed Jan 2 01:31:40 2002 @@ -141,7 +141,7 @@ #ifdef DEBUG struct inode *inode = file->f_dentry->d_inode; printk("i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n", - MINOR(inode->i_rdev),(long) offset,origin); + minor(inode->i_rdev),(long) offset,origin); #endif /* DEBUG */ return -ESPIPE; } @@ -165,7 +165,7 @@ return -ENOMEM; #ifdef DEBUG - printk("i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev), + printk("i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev), count); #endif @@ -197,7 +197,7 @@ } #ifdef DEBUG - printk("i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev), + printk("i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev), count); #endif ret = i2c_master_send(client,tmp,count); @@ -218,7 +218,7 @@ #ifdef DEBUG printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", - MINOR(inode->i_rdev),cmd, arg); + minor(inode->i_rdev),cmd, arg); #endif /* DEBUG */ switch ( cmd ) { @@ -382,7 +382,7 @@ int i2cdev_open (struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct i2c_client *client; if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) { @@ -415,7 +415,7 @@ static int i2cdev_release (struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); kfree(file->private_data); file->private_data=NULL; #ifdef DEBUG diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/i2c/i2c-keywest.c linux-2.5/drivers/i2c/i2c-keywest.c --- linux-2.5.1/drivers/i2c/i2c-keywest.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/i2c/i2c-keywest.c Thu Jan 10 22:41:07 2002 @@ -0,0 +1,670 @@ +/* + i2c Support for Apple Keywest I2C Bus Controller + + Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org> + + Original work by + + Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.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. + + Changes: + + 2001/12/13 BenH New implementation + 2001/12/15 BenH Add support for "byte" and "quick" + transfers. Add i2c_xfer routine. + + ToDo: + + Figure out how to use combined mode on the chip + +*/ + +#include <linux/module.h> +#include <linux/config.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/timer.h> +#include <linux/spinlock.h> +#include <linux/completion.h> + +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> + +#include "i2c-keywest.h" + +#undef POLLED_MODE + +#define DBG(x...) do {\ + if (debug > 0) \ + printk(KERN_DEBUG "KW:" x); \ + } while(0) + + +MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); +MODULE_DESCRIPTION("I2C driver for Apple's Keywest"); +MODULE_LICENSE("GPL"); +MODULE_PARM(probe, "i"); +MODULE_PARM(debug, "i"); +EXPORT_NO_SYMBOLS; + +int probe = 0; +int debug = 0; + +static struct keywest_iface *ifaces = NULL; + +#ifdef POLLED_MODE +/* This isn't fast, but will go once I implement interrupt with + * proper timeout + */ +static u8 +wait_interrupt(struct keywest_iface* iface) +{ + int i; + u8 isr; + + for (i = 0; i < POLL_TIMEOUT; i++) { + isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK; + if (isr != 0) + return isr; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } + return isr; +} +#endif /* POLLED_MODE */ + + +static void +do_stop(struct keywest_iface* iface, int result) +{ + write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_STOP); + iface->state = state_stop; + iface->result = result; +} + +/* Main state machine for standard & standard sub mode */ +static void +handle_interrupt(struct keywest_iface *iface, u8 isr) +{ + int ack; + + DBG("handle_interrupt(), got: %x, status: %x, state: %d\n", + isr, read_reg(reg_status), iface->state); + if (isr == 0 && iface->state != state_stop) { + do_stop(iface, -1); + return; + } + if (isr & KW_I2C_IRQ_STOP && iface->state != state_stop) { + iface->result = -1; + iface->state = state_stop; + } + switch(iface->state) { + case state_addr: + if (!(isr & KW_I2C_IRQ_ADDR)) { + do_stop(iface, -1); + break; + } + ack = read_reg(reg_status); + DBG("ack on set address: %x\n", ack); + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + do_stop(iface, -1); + break; + } + /* Handle rw "quick" mode */ + if (iface->datalen == 0) + do_stop(iface, 0); + else if (iface->read_write == I2C_SMBUS_READ) { + iface->state = state_read; + if (iface->datalen > 1) + write_reg(reg_control, read_reg(reg_control) + | KW_I2C_CTL_AAK); + } else { + iface->state = state_write; + DBG("write byte: %x\n", *(iface->data)); + write_reg(reg_data, *(iface->data++)); + iface->datalen--; + } + + break; + case state_read: + if (!(isr & KW_I2C_IRQ_DATA)) { + do_stop(iface, -1); + break; + } + *(iface->data++) = read_reg(reg_data); + DBG("read byte: %x\n", *(iface->data-1)); + iface->datalen--; + if (iface->datalen == 0) + iface->state = state_stop; + else + write_reg(reg_control, 0); + break; + case state_write: + if (!(isr & KW_I2C_IRQ_DATA)) { + do_stop(iface, -1); + break; + } + /* Check ack status */ + ack = read_reg(reg_status); + DBG("ack on data write: %x\n", ack); + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + do_stop(iface, -1); + break; + } + if (iface->datalen) { + DBG("write byte: %x\n", *(iface->data)); + write_reg(reg_data, *(iface->data++)); + iface->datalen--; + } else + do_stop(iface, 0); + break; + + case state_stop: + if (!(isr & KW_I2C_IRQ_STOP) && (++iface->stopretry) < 10) + do_stop(iface, -1); + else { + iface->state = state_idle; + write_reg(reg_control, 0x00); + write_reg(reg_ier, 0x00); +#ifndef POLLED_MODE + complete(&iface->complete); +#endif /* POLLED_MODE */ + } + break; + } + + write_reg(reg_isr, isr); +} + +#ifndef POLLED_MODE + +/* Interrupt handler */ +static void +keywest_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct keywest_iface *iface = (struct keywest_iface *)dev_id; + + spin_lock(&iface->lock); + del_timer(&iface->timeout_timer); + handle_interrupt(iface, read_reg(reg_isr)); + if (iface->state != state_idle) { + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + } + spin_unlock(&iface->lock); +} + +static void +keywest_timeout(unsigned long data) +{ + struct keywest_iface *iface = (struct keywest_iface *)data; + + DBG("timeout !\n"); + spin_lock_irq(&iface->lock); + handle_interrupt(iface, read_reg(reg_isr)); + if (iface->state != state_idle) { + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + } + spin_unlock(&iface->lock); +} + +#endif /* POLLED_MODE */ + +/* + * SMBUS-type transfer entrypoint + */ +static s32 +keywest_smbus_xfer( struct i2c_adapter* adap, + u16 addr, + unsigned short flags, + char read_write, + u8 command, + int size, + union i2c_smbus_data* data) +{ + struct keywest_chan* chan = (struct keywest_chan*)adap->data; + struct keywest_iface* iface = chan->iface; + int len; + u8* buffer; + u16 cur_word; + int rc = 0; + + if (iface->state == state_dead) + return -1; + + /* Prepare datas & select mode */ + iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; + switch (size) { + case I2C_SMBUS_QUICK: + len = 0; + buffer = NULL; + iface->cur_mode |= KW_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE: + len = 1; + buffer = &data->byte; + iface->cur_mode |= KW_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE_DATA: + len = 1; + buffer = &data->byte; + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + break; + case I2C_SMBUS_WORD_DATA: + len = 2; + cur_word = cpu_to_le16(data->word); + buffer = (u8 *)&cur_word; + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + break; + case I2C_SMBUS_BLOCK_DATA: + len = data->block[0]; + buffer = &data->block[1]; + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + break; + default: + return -1; + } + + /* Original driver had this limitation */ + if (len > 32) + len = 32; + + down(&iface->sem); + + DBG("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n", + chan->chan_no, addr, len, read_write == I2C_SMBUS_READ); + + iface->data = buffer; + iface->datalen = len; + iface->state = state_addr; + iface->result = 0; + iface->stopretry = 0; + iface->read_write = read_write; + + /* Setup channel & clear pending irqs */ + write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); + write_reg(reg_isr, read_reg(reg_isr)); + write_reg(reg_status, 0); + + /* Set up address and r/w bit */ + write_reg(reg_addr, + (addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00)); + + /* Set up the sub address */ + if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB + || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) + write_reg(reg_subaddr, command); + + /* Arm timeout */ + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + + /* Start sending address & enable interrupt*/ + write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR); + write_reg(reg_ier, KW_I2C_IRQ_MASK); + +#ifdef POLLED_MODE + DBG("using polled mode...\n"); + /* State machine, to turn into an interrupt handler */ + while(iface->state != state_idle) { + u8 isr = wait_interrupt(iface); + handle_interrupt(iface, isr); + } +#else /* POLLED_MODE */ + DBG("using interrupt mode...\n"); + wait_for_completion(&iface->complete); +#endif /* POLLED_MODE */ + + rc = iface->result; + DBG("transfer done, result: %d\n", rc); + + if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ) + data->word = le16_to_cpu(cur_word); + + /* Release sem */ + up(&iface->sem); + + return rc; +} + +/* + * Generic i2c master transfer entrypoint + */ +static int +keywest_xfer( struct i2c_adapter *adap, + struct i2c_msg msgs[], + int num) +{ + struct keywest_chan* chan = (struct keywest_chan*)adap->data; + struct keywest_iface* iface = chan->iface; + struct i2c_msg *pmsg; + int i, completed; + int rc = 0; + + down(&iface->sem); + + /* Set adapter to standard mode */ + iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; + iface->cur_mode |= KW_I2C_MODE_STANDARD; + + completed = 0; + for (i = 0; rc >= 0 && i < num;) { + u8 addr; + + pmsg = &msgs[i++]; + addr = pmsg->addr; + if (pmsg->flags & I2C_M_TEN) { + printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n"); + rc = -EINVAL; + break; + } + DBG("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n", + chan->chan_no, + pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->len, addr, i, num); + + /* Setup channel & clear pending irqs */ + write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); + write_reg(reg_isr, read_reg(reg_isr)); + write_reg(reg_status, 0); + + iface->data = pmsg->buf; + iface->datalen = pmsg->len; + iface->state = state_addr; + iface->result = 0; + iface->stopretry = 0; + if (pmsg->flags & I2C_M_RD) + iface->read_write = I2C_SMBUS_READ; + else + iface->read_write = I2C_SMBUS_WRITE; + + /* Set up address and r/w bit */ + if (pmsg->flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + write_reg(reg_addr, + (addr << 1) | + ((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00)); + + /* Arm timeout */ + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + + /* Start sending address & enable interrupt*/ + write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR); + write_reg(reg_ier, KW_I2C_IRQ_MASK); + +#ifdef POLLED_MODE + DBG("using polled mode...\n"); + /* State machine, to turn into an interrupt handler */ + while(iface->state != state_idle) { + u8 isr = wait_interrupt(iface); + handle_interrupt(iface, isr); + } +#else /* POLLED_MODE */88 + DBG("using interrupt mode...\n"); + wait_for_completion(&iface->complete); +#endif /* POLLED_MODE */ + + rc = iface->result; + if (rc == 0) + completed++; + DBG("transfer done, result: %d\n", rc); + } + + /* Release sem */ + up(&iface->sem); + + return completed; +} + +static u32 +keywest_func(struct i2c_adapter * adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static void +keywest_inc(struct i2c_adapter *adapter) +{ + MOD_INC_USE_COUNT; +} + +static void +keywest_dec(struct i2c_adapter *adapter) +{ + MOD_DEC_USE_COUNT; +} + +/* For now, we only handle combined mode (smbus) */ +static struct i2c_algorithm keywest_algorithm = { + name: "Keywest i2c", + id: I2C_ALGO_SMBUS, + smbus_xfer: keywest_smbus_xfer, + master_xfer: keywest_xfer, + functionality: keywest_func, +}; + + +static int +create_iface(struct device_node* np) +{ + unsigned long steps, *psteps, *prate; + unsigned bsteps, tsize, i, nchan, addroffset; + struct keywest_iface* iface; + int rc; + + psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL); + steps = psteps ? (*psteps) : 0x10; + + /* Hrm... maybe we can be smarter here */ + for (bsteps = 0; (steps & 0x01) == 0; bsteps++) + steps >>= 1; + + if (!strcmp(np->parent->name, "uni-n")) { + nchan = 2; + addroffset = 3; + } else { + addroffset = 0; + nchan = 1; + } + + tsize = sizeof(struct keywest_iface) + + (sizeof(struct keywest_chan) + 4) * nchan; + iface = (struct keywest_iface *) kmalloc(tsize, GFP_KERNEL); + if (iface == NULL) { + printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n"); + return -ENOMEM; + } + memset(iface, 0, tsize); + init_MUTEX(&iface->sem); + spin_lock_init(&iface->lock); + init_completion(&iface->complete); + iface->bsteps = bsteps; + iface->chan_count = nchan; + iface->state = state_idle; + iface->irq = np->intrs[0].line; + iface->channels = (struct keywest_chan *) + (((unsigned long)(iface + 1) + 3UL) & ~3UL); + iface->base = (unsigned long)ioremap(np->addrs[0].address + addroffset, + np->addrs[0].size); + if (iface->base == 0) { + printk(KERN_ERR "i2c-keywest: can't map inteface !\n"); + kfree(iface); + return -ENOMEM; + } + + init_timer(&iface->timeout_timer); + iface->timeout_timer.function = keywest_timeout; + iface->timeout_timer.data = (unsigned long)iface; + + /* Select interface rate */ + iface->cur_mode = KW_I2C_MODE_100KHZ; + prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL); + if (prate) switch(*prate) { + case 100: + iface->cur_mode = KW_I2C_MODE_100KHZ; + break; + case 50: + iface->cur_mode = KW_I2C_MODE_50KHZ; + break; + case 25: + iface->cur_mode = KW_I2C_MODE_25KHZ; + break; + default: + printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n", + *prate); + } + + /* Select standard sub mode */ + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + + /* Write mode */ + write_reg(reg_mode, iface->cur_mode); + + /* Switch interrupts off & clear them*/ + write_reg(reg_ier, 0x00); + write_reg(reg_isr, KW_I2C_IRQ_MASK); + +#ifndef POLLED_MODE + /* Request chip interrupt */ + rc = request_irq(iface->irq, keywest_irq, 0, "keywest i2c", iface); + if (rc) { + printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq); + iounmap((void *)iface->base); + kfree(iface); + return -ENODEV; + } +#endif /* POLLED_MODE */ + + for (i=0; i<nchan; i++) { + struct keywest_chan* chan = &iface->channels[i]; + u8 addr; + + sprintf(chan->adapter.name, "%s %d", np->parent->name, i); + chan->iface = iface; + chan->chan_no = i; + chan->adapter.id = I2C_ALGO_SMBUS; + chan->adapter.algo = &keywest_algorithm; + chan->adapter.algo_data = NULL; + chan->adapter.inc_use = keywest_inc; + chan->adapter.dec_use = keywest_dec; + chan->adapter.client_register = NULL; + chan->adapter.client_unregister = NULL; + chan->adapter.data = chan; + + rc = i2c_add_adapter(&chan->adapter); + if (rc) { + printk("i2c-keywest.c: Adapter %s registration failed\n", + chan->adapter.name); + chan->adapter.data = NULL; + } + if (probe) { + printk("Probe: "); + for (addr = 0x00; addr <= 0x7f; addr++) { + if (i2c_smbus_xfer(&chan->adapter,addr, + 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) + printk("%02x ", addr); + } + printk("\n"); + } + } + + printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n", + np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps); + + iface->next = ifaces; + ifaces = iface; + return 0; +} + +static void +dispose_iface(struct keywest_iface *iface) +{ + int i, rc; + + ifaces = iface->next; + + /* Make sure we stop all activity */ + down(&iface->sem); +#ifndef POLLED_MODE + spin_lock_irq(&iface->lock); + while (iface->state != state_idle) { + spin_unlock_irq(&iface->lock); + schedule(); + spin_lock_irq(&iface->lock); + } +#endif /* POLLED_MODE */ + iface->state = state_dead; +#ifndef POLLED_MODE + spin_unlock_irq(&iface->lock); + free_irq(iface->irq, iface); +#endif /* POLLED_MODE */ + up(&iface->sem); + + /* Release all channels */ + for (i=0; i<iface->chan_count; i++) { + struct keywest_chan* chan = &iface->channels[i]; + if (!chan->adapter.data) + continue; + rc = i2c_del_adapter(&chan->adapter); + chan->adapter.data = NULL; + /* We aren't that prepared to deal with this... */ + if (rc) + printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n"); + } + iounmap((void *)iface->base); + kfree(iface); +} + +static int __init +i2c_keywest_init(void) +{ + struct device_node *np; + int rc = -ENODEV; + + np = find_compatible_devices("i2c", "keywest"); + while (np != 0) { + if (np->n_addrs >= 1 && np->n_intrs >= 1) + rc = create_iface(np); + np = np->next; + } + if (ifaces) + rc = 0; + return rc; +} + +static void __exit +i2c_keywest_cleanup(void) +{ + while(ifaces) + dispose_iface(ifaces); +} + +module_init(i2c_keywest_init); +module_exit(i2c_keywest_cleanup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/i2c/i2c-keywest.h linux-2.5/drivers/i2c/i2c-keywest.h --- linux-2.5.1/drivers/i2c/i2c-keywest.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/i2c/i2c-keywest.h Thu Dec 27 16:32:31 2001 @@ -0,0 +1,111 @@ +#ifndef __I2C_KEYWEST_H__ +#define __I2C_KEYWEST_H__ + +/* The Tumbler audio equalizer can be really slow sometimes */ +#define POLL_TIMEOUT (2*HZ) + +/* Register indices */ +typedef enum { + reg_mode = 0, + reg_control, + reg_status, + reg_isr, + reg_ier, + reg_addr, + reg_subaddr, + reg_data +} reg_t; + + +/* Mode register */ +#define KW_I2C_MODE_100KHZ 0x00 +#define KW_I2C_MODE_50KHZ 0x01 +#define KW_I2C_MODE_25KHZ 0x02 +#define KW_I2C_MODE_DUMB 0x00 +#define KW_I2C_MODE_STANDARD 0x04 +#define KW_I2C_MODE_STANDARDSUB 0x08 +#define KW_I2C_MODE_COMBINED 0x0C +#define KW_I2C_MODE_MODE_MASK 0x0C +#define KW_I2C_MODE_CHAN_MASK 0xF0 + +/* Control register */ +#define KW_I2C_CTL_AAK 0x01 +#define KW_I2C_CTL_XADDR 0x02 +#define KW_I2C_CTL_STOP 0x04 +#define KW_I2C_CTL_START 0x08 + +/* Status register */ +#define KW_I2C_STAT_BUSY 0x01 +#define KW_I2C_STAT_LAST_AAK 0x02 +#define KW_I2C_STAT_LAST_RW 0x04 +#define KW_I2C_STAT_SDA 0x08 +#define KW_I2C_STAT_SCL 0x10 + +/* IER & ISR registers */ +#define KW_I2C_IRQ_DATA 0x01 +#define KW_I2C_IRQ_ADDR 0x02 +#define KW_I2C_IRQ_STOP 0x04 +#define KW_I2C_IRQ_START 0x08 +#define KW_I2C_IRQ_MASK 0x0F + +/* Physical interface */ +struct keywest_iface +{ + unsigned long base; + unsigned bsteps; + int irq; + struct semaphore sem; + spinlock_t lock; + struct keywest_chan* channels; + unsigned chan_count; + u8 cur_mode; + char read_write; + u8* data; + unsigned datalen; + int state; + int result; + int stopretry; + struct timer_list timeout_timer; + struct completion complete; + struct keywest_iface* next; +}; + +enum { + state_idle, + state_addr, + state_read, + state_write, + state_stop, + state_dead +}; + +/* Channel on an interface */ +struct keywest_chan +{ + struct i2c_adapter adapter; + struct keywest_iface* iface; + unsigned chan_no; +}; + +/* Register access */ + +static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg) +{ + return in_8(((volatile u8 *)iface->base) + + (((unsigned)reg) << iface->bsteps)); +} + +static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val) +{ + out_8(((volatile u8 *)iface->base) + + (((unsigned)reg) << iface->bsteps), val); + (void)__read_reg(iface, reg); + udelay(10); +} + +#define write_reg(reg, val) __write_reg(iface, reg, val) +#define read_reg(reg) __read_reg(iface, reg) + + + +#endif /* __I2C_KEYWEST_H__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/i2c/i2c-proc.c linux-2.5/drivers/i2c/i2c-proc.c --- linux-2.5.1/drivers/i2c/i2c-proc.c Thu Oct 11 15:05:47 2001 +++ linux-2.5/drivers/i2c/i2c-proc.c Mon Jan 14 22:39:45 2002 @@ -119,6 +119,10 @@ sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr); } *name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL); + if (!*name) { + printk (KERN_WARNING "i2c_create_name: not enough memory\n"); + return -ENOMEM; + } strcpy(*name, name_buffer); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/amd74xx.c linux-2.5/drivers/ide/amd74xx.c --- linux-2.5.1/drivers/ide/amd74xx.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/ide/amd74xx.c Thu Dec 20 19:14:29 2001 @@ -459,6 +459,8 @@ hwif->tuneproc = &amd74xx_tune_drive; hwif->speedproc = &amd74xx_tune_chipset; + hwif->highmem = 1; + #ifndef CONFIG_BLK_DEV_IDEDMA hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/ataraid.c linux-2.5/drivers/ide/ataraid.c --- linux-2.5.1/drivers/ide/ataraid.c Thu Oct 25 20:58:35 2001 +++ linux-2.5/drivers/ide/ataraid.c Tue Jan 8 00:44:24 2002 @@ -70,7 +70,7 @@ static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int minor; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl)) return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg); @@ -80,7 +80,7 @@ static int ataraid_open(struct inode * inode, struct file * filp) { int minor; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open)) return (ataraid_ops[minor]->open)(inode,filp); @@ -91,7 +91,7 @@ static int ataraid_release(struct inode * inode, struct file * filp) { int minor; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release)) return (ataraid_ops[minor]->release)(inode,filp); @@ -102,7 +102,7 @@ { int minor; int retval; - minor = MINOR(bh->b_rdev)>>SHIFT; + minor = minor(bh->b_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) { @@ -121,11 +121,8 @@ void *ptr = NULL; while (!ptr) { ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO); - if (!ptr) { - __set_current_state(TASK_RUNNING); - current->policy |= SCHED_YIELD; - schedule(); - } + if (!ptr) + yield(); } return ptr; } @@ -137,11 +134,8 @@ void *ptr = NULL; while (!ptr) { ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO); - if (!ptr) { - __set_current_state(TASK_RUNNING); - current->policy |= SCHED_YIELD; - schedule(); - } + if (!ptr) + yield(); } return ptr; } @@ -235,7 +229,7 @@ void ataraid_register_disk(int device,long size) { - register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16, + register_disk(&ataraid_gendisk, mk_kdev(ATAMAJOR,16*device),16, &ataraid_fops,size); } @@ -269,7 +263,6 @@ ataraid_gendisk.major = ATAMAJOR; ataraid_gendisk.major_name = "ataraid"; ataraid_gendisk.minor_shift = 4; - ataraid_gendisk.max_p = 15; ataraid_gendisk.sizes = &ataraid_gendisk_sizes[0]; ataraid_gendisk.nr_real = 16; ataraid_gendisk.fops = &ataraid_fops; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/hd.c linux-2.5/drivers/ide/hd.c --- linux-2.5.1/drivers/ide/hd.c Sun Dec 16 23:37:16 2001 +++ linux-2.5/drivers/ide/hd.c Mon Jan 7 20:18:30 2002 @@ -558,7 +558,7 @@ reset_hd(); return; } - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; if (dev >= (NR_HD<<6) || (dev & 0x3f) || @@ -568,7 +568,7 @@ kdevname(CURRENT->rq_dev)); else printk("hd%c: bad access: block=%d, count=%d\n", - (MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect); + (minor(CURRENT->rq_dev)>>6)+'a', block, nsect); end_request(0); goto repeat; } @@ -626,7 +626,7 @@ struct hd_geometry *loc = (struct hd_geometry *) arg; int dev; - if ((!inode) || !(inode->i_rdev)) + if ((!inode) || kdev_none(inode->i_rdev)) return -EINVAL; dev = DEVICE_NR(inode->i_rdev); if (dev >= NR_HD) @@ -693,7 +693,6 @@ major: MAJOR_NR, major_name: "hd", minor_shift: 6, - max_p: 1 << 6, part: hd, sizes: hd_sizes, fops: &hd_fops, @@ -825,7 +824,7 @@ hd_gendisk.nr_real = NR_HD; for(drive=0; drive < NR_HD; drive++) - register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6, + register_disk(&hd_gendisk, mk_kdev(MAJOR_NR,drive<<6), 1<<6, &hd_fops, hd_info[drive].head * hd_info[drive].sect * hd_info[drive].cyl); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/hptraid.c linux-2.5/drivers/ide/hptraid.c --- linux-2.5.1/drivers/ide/hptraid.c Mon Oct 15 20:27:42 2001 +++ linux-2.5/drivers/ide/hptraid.c Mon Jan 7 20:47:14 2002 @@ -75,16 +75,16 @@ unsigned char val; unsigned long sectors; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; switch (cmd) { case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; - sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects; - if (MINOR(inode->i_rdev)&15) + sectors = ataraid_gendisk.part[minor(inode->i_rdev)].nr_sects; + if (minor(inode->i_rdev)&15) return put_user(sectors, (unsigned long *) arg); return put_user(raid[minor].sectors , (unsigned long *) arg); break; @@ -102,7 +102,7 @@ if (put_user(val, (byte *) &loc->sectors)) return -EFAULT; bios_cyl = raid[minor].sectors/63/255; if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -118,7 +118,7 @@ if (put_user(val, (byte *) &loc->sectors)) return -EFAULT; bios_cyl = raid[minor].sectors/63/255; if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -167,7 +167,7 @@ /* Partitions need adding of the start sector of the partition to the requested sector */ - rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; + rsect += ataraid_gendisk.part[minor(bh->b_rdev)].start_sect; /* Woops we need to split the request to avoid crossing a stride barrier */ if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) { @@ -226,32 +226,20 @@ #include "hptraid.h" -static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize) +static int __init read_disk_sb(struct block_device *bdev, + struct highpoint_raid_conf *buf) { - int ret = -EINVAL; - struct buffer_head *bh = NULL; - kdev_t dev = MKDEV(major,minor); - - if (blksize_size[major]==NULL) /* device doesn't exist */ - return -EINVAL; - - - /* Superblock is at 4096+412 bytes */ - set_blocksize (dev, 4096); - bh = bread (dev, 1, 4096); - - - if (bh) { - memcpy (buffer, bh->b_data, bufsize); - } else { - printk(KERN_ERR "hptraid: Error reading superblock.\n"); - goto abort; + /* Superblock is at 9*512 bytes */ + Sector sect; + unsigned char *p = read_dev_sector(bdev, 9, §); + + if (p) { + memcpy(buf, p, 512); + put_dev_sector(§); + return 0; } - ret = 0; -abort: - if (bh) - brelse (bh); - return ret; + printk(KERN_ERR "hptraid: Error reading superblock.\n"); + return -1; } static unsigned long maxsectors (int major,int minor) @@ -260,7 +248,7 @@ kdev_t dev; ide_drive_t *ideinfo; - dev = MKDEV(major,minor); + dev = mk_kdev(major,minor); ideinfo = get_info_ptr (dev); if (ideinfo==NULL) return 0; @@ -276,55 +264,58 @@ return lba; } +static struct highpoint_raid_conf __initdata prom; static void __init probedisk(int major, int minor,int device) { int i; - struct highpoint_raid_conf *prom; - static unsigned char block[4096]; - struct block_device *bdev; - - if (maxsectors(major,minor)==0) + struct block_device *bdev = bdget(mk_kdev(major,minor)); + struct gendisk *gd; + + if (!bdev) return; - - if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block))) - return; - - prom = (struct highpoint_raid_conf*)&block[512]; - - if (prom->magic!= 0x5a7816f0) - return; - if (prom->type) { + + if (blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) < 0) + return; + + if (maxsectors(major,minor)==0) + goto out; + + if (read_disk_sb(bdev, &prom)) + goto out; + + if (prom.magic!= 0x5a7816f0) + goto out; + if (prom.type) { printk(KERN_INFO "hptraid: only RAID0 is supported currently\n"); - return; + goto out; } - i = prom->disk_number; + i = prom.disk_number; if (i<0) - return; + goto out; if (i>8) - return; + goto out; - bdev = bdget(MKDEV(major,minor)); - if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) { - int j=0; - struct gendisk *gd; - raid[device].disk[i].bdev = bdev; - /* This is supposed to prevent others from stealing our underlying disks */ - /* now blank the /proc/partitions table for the wrong partition table, - so that scripts don't accidentally mount it and crash the kernel */ - /* XXX: the 0 is an utter hack --hch */ - gd=get_gendisk(MKDEV(major, 0)); - if (gd!=NULL) { - for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) - gd->part[j].nr_sects=0; - } - } - raid[device].disk[i].device = MKDEV(major,minor); + raid[device].disk[i].bdev = bdev; + /* This is supposed to prevent others from stealing our underlying disks */ + /* now blank the /proc/partitions table for the wrong partition table, + so that scripts don't accidentally mount it and crash the kernel */ + /* XXX: the 0 is an utter hack --hch */ + gd=get_gendisk(mk_kdev(major, 0)); + if (gd!=NULL) { + int j; + for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) + gd->part[j].nr_sects=0; + } + + raid[device].disk[i].device = mk_kdev(major,minor); raid[device].disk[i].sectors = maxsectors(major,minor); - raid[device].stride = (1<<prom->raid0_shift); - raid[device].disks = prom->raid_disks; - raid[device].sectors = prom->total_secs; - + raid[device].stride = (1<<prom.raid0_shift); + raid[device].disks = prom.raid_disks; + raid[device].sectors = prom.total_secs; + return; +out: + blkdev_put(bdev); } static void __init fill_cutoff(int device) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/icside.c linux-2.5/drivers/ide/icside.c --- linux-2.5.1/drivers/ide/icside.c Thu Oct 25 20:53:47 2001 +++ linux-2.5/drivers/ide/icside.c Thu Dec 27 22:10:28 2001 @@ -27,6 +27,7 @@ #include <asm/io.h> extern char *ide_xfer_verbose (byte xfer_rate); +extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); /* * Maximum number of interfaces per card @@ -225,29 +226,18 @@ static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq) { - struct buffer_head *bh; + request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue; struct scatterlist *sg = hwif->sg_table; - int nents = 0; + int nents = blk_rq_map_sg(q, rq, sg); - if (rq->cmd == READ) + if (rq->q && nents > rq->nr_phys_segments) + printk("icside: received %d segments, build %d\n", + rq->nr_phys_segments, nents); + + if (rq_data_dir(rq) == READ) hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; else hwif->sg_dma_direction = PCI_DMA_TODEVICE; - bh = rq->bh; - do { - unsigned char *virt_addr = bh->b_data; - unsigned int size = bh->b_size; - - while ((bh = bh->b_reqnext) != NULL) { - if ((virt_addr + size) != (unsigned char *)bh->b_data) - break; - size += bh->b_size; - } - memset(&sg[nents], 0, sizeof(*sg)); - sg[nents].address = virt_addr; - sg[nents].length = size; - nents++; - } while (bh != NULL); return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction); } @@ -267,39 +257,56 @@ pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction); } +/* + * Configure the IOMD to give the appropriate timings for the transfer + * mode being requested. We take the advice of the ATA standards, and + * calculate the cycle time based on the transfer mode, and the EIDE + * MW DMA specs that the drive provides in the IDENTIFY command. + * + * We have the following IOMD DMA modes to choose from: + * + * Type Active Recovery Cycle + * A 250 (250) 312 (550) 562 (800) + * B 187 250 437 + * C 125 (125) 125 (375) 250 (500) + * D 62 125 187 + * + * (figures in brackets are actual measured timings) + * + * However, we also need to take care of the read/write active and + * recovery timings: + * + * Read Write + * Mode Active -- Recovery -- Cycle IOMD type + * MW0 215 50 215 480 A + * MW1 80 50 50 150 C + * MW2 70 25 25 120 C + */ static int icside_config_if(ide_drive_t *drive, int xfer_mode) { int func = ide_dma_off; + int cycle_time = 0, use_dma_info = 0; switch (xfer_mode) { - case XFER_MW_DMA_2: - /* - * The cycle time is limited to 250ns by the r/w - * pulse width (90ns), however we should still - * have a maximum burst transfer rate of 8MB/s. - */ - drive->drive_data = 250; - break; - - case XFER_MW_DMA_1: - drive->drive_data = 250; - break; + case XFER_MW_DMA_2: cycle_time = 250; use_dma_info = 1; break; + case XFER_MW_DMA_1: cycle_time = 250; use_dma_info = 1; break; + case XFER_MW_DMA_0: cycle_time = 480; break; + } - case XFER_MW_DMA_0: - drive->drive_data = 480; - break; + /* + * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should + * take care to note the values in the ID... + */ + if (use_dma_info && drive->id->eide_dma_time > cycle_time) + cycle_time = drive->id->eide_dma_time; - default: - drive->drive_data = 0; - break; - } + drive->drive_data = cycle_time; if (!drive->init_speed) - drive->init_speed = (byte) xfer_mode; + drive->init_speed = xfer_mode; - if (drive->drive_data && - ide_config_drive_speed(drive, (byte) xfer_mode) == 0) + if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0) func = ide_dma_on; else drive->drive_data = 480; @@ -307,7 +314,7 @@ printk("%s: %s selected (peak %dMB/s)\n", drive->name, ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); - drive->current_speed = (byte) xfer_mode; + drive->current_speed = xfer_mode; return func; } @@ -414,7 +421,7 @@ * This is setup to be called as an extern for future support * to other special driver code. */ -static int check_drive_lists(ide_drive_t *drive, int good_bad) +static int icside_check_drive_lists(ide_drive_t *drive, int good_bad) { struct hd_driveid *id = drive->id; @@ -444,7 +451,7 @@ /* * Consult the list of known "bad" drives */ - if (check_drive_lists(drive, 0)) { + if (icside_check_drive_lists(drive, 0)) { func = ide_dma_off; goto out; } @@ -469,7 +476,7 @@ /* * Consult the list of known "good" drives */ - if (check_drive_lists(drive, 1)) { + if (icside_check_drive_lists(drive, 1)) { if (id->eide_dma_time > 150) goto out; xfer_mode = XFER_MW_DMA_1; @@ -502,6 +509,11 @@ case ide_dma_off_quietly: case ide_dma_on: + /* + * We don't need any bouncing. Yes, this looks the + * wrong way around, but it is correct. + */ + blk_queue_bounce_limit(&drive->queue, BLK_BOUNCE_ANY); drive->using_dma = (func == ide_dma_on); return 0; @@ -553,7 +565,8 @@ case ide_dma_bad_drive: case ide_dma_good_drive: - return check_drive_lists(drive, (func == ide_dma_good_drive)); + return icside_check_drive_lists(drive, (func == + ide_dma_good_drive)); case ide_dma_verbose: return icside_dma_verbose(drive); @@ -590,6 +603,15 @@ failed: printk(" -- ERROR, unable to allocate DMA table\n"); return 0; +} + +int ide_release_dma(ide_hwif_t *hwif) +{ + if (hwif->sg_table) { + kfree(hwif->sg_table); + hwif->sg_table = NULL; + } + return 1; } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/ide-cd.c linux-2.5/drivers/ide/ide-cd.c --- linux-2.5.1/drivers/ide/ide-cd.c Sun Dec 9 04:02:47 2001 +++ linux-2.5/drivers/ide/ide-cd.c Thu Jan 10 22:07:41 2002 @@ -594,7 +594,7 @@ cdrom_end_request (1, drive); *startstop = ide_error (drive, "request sense failure", stat); return 1; - } else if (rq->flags & REQ_PC) { + } else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) { /* All other functions, except for READ. */ struct completion *wait = NULL; pc = (struct packet_command *) rq->special; @@ -1398,11 +1398,8 @@ ide_init_drive_cmd (&req); req.flags = REQ_PC; req.special = (char *) pc; - if (ide_do_drive_cmd (drive, &req, ide_wait)) { - printk("%s: do_drive_cmd returned stat=%02x,err=%02x\n", - drive->name, req.buffer[0], req.buffer[1]); - /* FIXME: we should probably abort/retry or something */ - } + ide_do_drive_cmd (drive, &req, ide_wait); + /* FIXME: we should probably abort/retry or something */ if (pc->stat != 0) { /* The request failed. Retry if it was due to a unit attention status @@ -2015,7 +2012,7 @@ /* Now try to get the total cdrom capacity. */ minor = (drive->select.b.unit) << PARTN_BITS; - dev = MKDEV(HWIF(drive)->major, minor); + dev = mk_kdev(HWIF(drive)->major, minor); stat = cdrom_get_last_written(dev, &toc->capacity); if (stat) stat = cdrom_read_capacity(drive, &toc->capacity, sense); @@ -2481,7 +2478,7 @@ struct cdrom_device_info *devinfo = &info->devinfo; int minor = (drive->select.b.unit) << PARTN_BITS; - devinfo->dev = MKDEV (HWIF(drive)->major, minor); + devinfo->dev = mk_kdev(HWIF(drive)->major, minor); devinfo->ops = &ide_cdrom_dops; devinfo->mask = 0; *(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed; @@ -2588,6 +2585,13 @@ if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup) CDROM_CONFIG_FLAGS (drive)->close_tray = 0; + /* Some drives used by Apple don't advertise audio play + * but they do support reading TOC & audio datas + */ + if (strcmp (drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 || + strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0) + CDROM_CONFIG_FLAGS (drive)->audio_play = 1; + #if ! STANDARD_ATAPI if (cdi->sanyo_slot > 0) { CDROM_CONFIG_FLAGS (drive)->is_changer = 1; @@ -2671,10 +2675,12 @@ /* * default to read-only always and fix latter at the bottom */ - set_device_ro(MKDEV(HWIF(drive)->major, minor), 1); - set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE); + set_device_ro(mk_kdev(HWIF(drive)->major, minor), 1); + set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE); blk_queue_hardsect_size(&drive->queue, CD_FRAMESIZE); + blk_queue_prep_rq(&drive->queue, ll_10byte_cmd_build); + drive->special.all = 0; drive->ready_stat = 0; @@ -2792,7 +2798,7 @@ nslots = ide_cdrom_probe_capabilities (drive); if (CDROM_CONFIG_FLAGS(drive)->dvd_ram) - set_device_ro(MKDEV(HWIF(drive)->major, minor), 0); + set_device_ro(mk_kdev(HWIF(drive)->major, minor), 0); if (ide_cdrom_register (drive, nslots)) { printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name); @@ -2839,7 +2845,7 @@ static int ide_cdrom_check_media_change (ide_drive_t *drive) { - return cdrom_media_changed(MKDEV (HWIF (drive)->major, + return cdrom_media_changed(mk_kdev (HWIF (drive)->major, (drive->select.b.unit) << PARTN_BITS)); } @@ -2867,7 +2873,7 @@ * 1024 even for CDROM's */ blk_size[HWIF(drive)->major] = HWIF(drive)->gd->sizes; - set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE); + set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE); } static diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/ide-disk.c linux-2.5/drivers/ide/ide-disk.c --- linux-2.5.1/drivers/ide/ide-disk.c Thu Dec 6 22:02:57 2001 +++ linux-2.5/drivers/ide/ide-disk.c Thu Jan 3 23:04:39 2002 @@ -30,7 +30,7 @@ * Version 1.11 Highmem I/O support, Jens Axboe <axboe@suse.de> */ -#define IDEDISK_VERSION "1.10" +#define IDEDISK_VERSION "1.11" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -70,7 +70,7 @@ } } -static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) { ide_input_data(drive, buffer, wcount); if (drive->bswap) @@ -863,8 +863,10 @@ } /* We must remove proc entries defined in this module. Otherwise we oops while accessing these entries */ +#ifdef CONFIG_PROC_FS if (drive->proc) ide_remove_proc_entries(drive->proc, idedisk_proc); +#endif } ide_unregister_module(&idedisk_module); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/ide-floppy.c linux-2.5/drivers/ide/ide-floppy.c --- linux-2.5.1/drivers/ide/ide-floppy.c Fri Nov 30 16:33:50 2001 +++ linux-2.5/drivers/ide/ide-floppy.c Mon Jan 14 23:31:37 2002 @@ -336,23 +336,7 @@ #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 - -/* - * IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue. - */ -#define IDEFLOPPY_PC_RQ 90 - -#define IDEFLOPPY_LAST_RQ 90 - -/* - * A macro which can be used to check if a given request command - * originated in the driver or in the buffer cache layer. - */ -#define IDEFLOPPY_RQ_CMD(cmd) ((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ)) +#define IDEFLOPPY_RQ (REQ_SPECIAL) /* * Error codes which are returned in rq->errors to the higher part @@ -696,7 +680,7 @@ /* Why does this happen? */ if (!rq) return; - if (!IDEFLOPPY_RQ_CMD (rq->cmd)) { + if (!(rq->flags & IDEFLOPPY_RQ)) { ide_end_request (uptodate, hwgroup); return; } @@ -776,7 +760,7 @@ { ide_init_drive_cmd (rq); rq->buffer = (char *) pc; - rq->cmd = IDEFLOPPY_PC_RQ; + rq->flags = IDEFLOPPY_RQ; (void) ide_do_drive_cmd (drive, rq, ide_preempt); } @@ -1192,6 +1176,7 @@ { int block = sector / floppy->bs_factor; int blocks = rq->nr_sectors / floppy->bs_factor; + int cmd = rq_data_dir(rq); #if IDEFLOPPY_DEBUG_LOG printk ("create_rw1%d_cmd: block == %d, blocks == %d\n", @@ -1200,18 +1185,18 @@ idefloppy_init_pc (pc); if (test_bit (IDEFLOPPY_USE_READ12, &floppy->flags)) { - pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD; + pc->c[0] = cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD; put_unaligned (htonl (blocks), (unsigned int *) &pc->c[6]); } else { - pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD; + pc->c[0] = cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD; put_unaligned (htons (blocks), (unsigned short *) &pc->c[7]); } put_unaligned (htonl (block), (unsigned int *) &pc->c[2]); pc->callback = &idefloppy_rw_callback; pc->rq = rq; pc->b_data = rq->buffer; - pc->b_count = rq->cmd == READ ? 0 : rq->bio->bi_size; - if (rq->cmd == WRITE) + pc->b_count = cmd == READ ? 0 : rq->bio->bi_size; + if (rq->flags & REQ_RW) set_bit (PC_WRITING, &pc->flags); pc->buffer = NULL; pc->request_transfer = pc->buffer_size = blocks * floppy->block_size; @@ -1227,8 +1212,8 @@ idefloppy_pc_t *pc; #if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors); - printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); + printk (KERN_INFO "rq_status: %d, rq_dev: %u, flags: %lx, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors); + printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); #endif /* IDEFLOPPY_DEBUG_LOG */ if (rq->errors >= ERROR_MAX) { @@ -1240,24 +1225,20 @@ idefloppy_end_request (0, HWGROUP(drive)); return ide_stopped; } - switch (rq->cmd) { - case READ: - case WRITE: - if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) { - printk ("%s: unsupported r/w request size\n", drive->name); - idefloppy_end_request (0, HWGROUP(drive)); - return ide_stopped; - } - pc = idefloppy_next_pc_storage (drive); - idefloppy_create_rw_cmd (floppy, pc, rq, block); - break; - case IDEFLOPPY_PC_RQ: - pc = (idefloppy_pc_t *) rq->buffer; - break; - default: - printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd); - idefloppy_end_request (0,HWGROUP (drive)); + if (rq->flags & REQ_CMD) { + if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) { + printk ("%s: unsupported r/w request size\n", drive->name); + idefloppy_end_request (0, HWGROUP(drive)); return ide_stopped; + } + pc = idefloppy_next_pc_storage (drive); + idefloppy_create_rw_cmd (floppy, pc, rq, block); + } else if (rq->flags & IDEFLOPPY_RQ) { + pc = (idefloppy_pc_t *) rq->buffer; + } else { + blk_dump_rq_flags(rq, "ide-floppy: unsupported command in queue"); + idefloppy_end_request (0,HWGROUP (drive)); + return ide_stopped; } pc->rq = rq; return idefloppy_issue_pc (drive, pc); @@ -1273,7 +1254,7 @@ ide_init_drive_cmd (&rq); rq.buffer = (char *) pc; - rq.cmd = IDEFLOPPY_PC_RQ; + rq.flags = IDEFLOPPY_RQ; return ide_do_drive_cmd (drive, &rq, ide_wait); } @@ -2048,10 +2029,13 @@ printk ("%s: cleanup_module() called while still busy\n", drive->name); failed++; } + +#ifdef CONFIG_PROC_FS /* We must remove proc entries defined in this module. Otherwise we oops while accessing these entries */ if (drive->proc) ide_remove_proc_entries(drive->proc, idefloppy_proc); +#endif } ide_unregister_module(&idefloppy_module); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/ide-m8xx.c linux-2.5/drivers/ide/ide-m8xx.c --- linux-2.5.1/drivers/ide/ide-m8xx.c Mon Oct 8 18:40:13 2001 +++ linux-2.5/drivers/ide/ide-m8xx.c Thu Dec 27 16:32:31 2001 @@ -1,8 +1,14 @@ /* - * - * * linux/drivers/ide/ide-m8xx.c * + * Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de + * Modified for direct IDE interface + * by Thomas Lange, thomas@corelatus.com + * Modified for direct IDE interface on 8xx without using the PCMCIA + * controller + * by Steven.Scholz@imc-berlin.de + * Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups + * by Mathew Locke <mattl@mvista.com> */ #include <linux/config.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/ide-pmac.c linux-2.5/drivers/ide/ide-pmac.c --- linux-2.5.1/drivers/ide/ide-pmac.c Tue Oct 2 16:08:40 2001 +++ linux-2.5/drivers/ide/ide-pmac.c Thu Jan 10 22:41:07 2002 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-pmac.c Version ?.?? Mar. 18, 2000 + * linux/drivers/ide/ide-pmac.c * * Support for IDE interfaces on PowerMacs. * These IDE interfaces are memory-mapped and have a DBDMA channel @@ -24,26 +24,29 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/ide.h> - +#include <linux/notifier.h> +#include <linux/reboot.h> #include <asm/prom.h> #include <asm/io.h> #include <asm/dbdma.h> #include <asm/ide.h> #include <asm/mediabay.h> -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> +#include <asm/sections.h> +#include <asm/irq.h> #ifdef CONFIG_PMAC_PBOOK #include <linux/adb.h> #include <linux/pmu.h> -#include <asm/irq.h> #endif #include "ide_modes.h" extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); +extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq); -#undef IDE_PMAC_DEBUG +#define IDE_PMAC_DEBUG -#define IDE_SYSCLK_NS 30 -#define IDE_SYSCLK_ULTRA_PS 0x1d4c /* (15 * 1000 / 2)*/ +#define DMA_WAIT_TIMEOUT 500 struct pmac_ide_hwif { ide_ioreg_t regbase; @@ -52,12 +55,14 @@ int aapl_bus_id; struct device_node* node; u32 timings[2]; + struct resource* reg_resource; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC volatile struct dbdma_regs* dma_regs; struct dbdma_cmd* dma_table; + struct resource* dma_resource; #endif -} pmac_ide[MAX_HWIFS]; +} pmac_ide[MAX_HWIFS] __pmacdata; static int pmac_ide_count; @@ -65,33 +70,145 @@ controller_ohare, /* OHare based */ controller_heathrow, /* Heathrow/Paddington */ controller_kl_ata3, /* KeyLargo ATA-3 */ - controller_kl_ata4 /* KeyLargo ATA-4 */ + controller_kl_ata4, /* KeyLargo ATA-4 */ + controller_kl_ata4_80 /* KeyLargo ATA-4 with 80 conductor cable */ }; +/* + * Timing register definitions + */ + +/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */ +#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS) +#define SYSCLK_TICKS_66(t) (((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS) +#define IDE_SYSCLK_NS 30 /* 33Mhz cell */ +#define IDE_SYSCLK_66_NS 15 /* 66Mhz cell */ + +/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on + * 40 connector cable and to 4 on 80 connector one. + * Clock unit is 15ns (66Mhz) + * + * 3 Values can be programmed: + * - Write data setup, which appears to match the cycle time. They + * also call it DIOW setup. + * - Ready to pause time (from spec) + * - Address setup. That one is weird. I don't see where exactly + * it fits in UDMA cycles, I got it's name from an obscure piece + * of commented out code in Darwin. They leave it to 0, we do as + * well, despite a comment that would lead to think it has a + * min value of 45ns. + * Apple also add 60ns to the write data setup (or cycle time ?) on + * reads. I can't explain that, I tried it and it broke everything + * here. + */ +#define TR_66_UDMA_MASK 0xfff00000 +#define TR_66_UDMA_EN 0x00100000 /* Enable Ultra mode for DMA */ +#define TR_66_UDMA_ADDRSETUP_MASK 0xe0000000 /* Address setup */ +#define TR_66_UDMA_ADDRSETUP_SHIFT 29 +#define TR_66_UDMA_RDY2PAUS_MASK 0x1e000000 /* Ready 2 pause time */ +#define TR_66_UDMA_RDY2PAUS_SHIFT 25 +#define TR_66_UDMA_WRDATASETUP_MASK 0x01e00000 /* Write data setup time */ +#define TR_66_UDMA_WRDATASETUP_SHIFT 21 +#define TR_66_MDMA_MASK 0x000ffc00 +#define TR_66_MDMA_RECOVERY_MASK 0x000f8000 +#define TR_66_MDMA_RECOVERY_SHIFT 15 +#define TR_66_MDMA_ACCESS_MASK 0x00007c00 +#define TR_66_MDMA_ACCESS_SHIFT 10 +#define TR_66_PIO_MASK 0x000003ff +#define TR_66_PIO_RECOVERY_MASK 0x000003e0 +#define TR_66_PIO_RECOVERY_SHIFT 5 +#define TR_66_PIO_ACCESS_MASK 0x0000001f +#define TR_66_PIO_ACCESS_SHIFT 0 + +/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo + * Can do pio & mdma modes, clock unit is 30ns (33Mhz) + * + * The access time and recovery time can be programmed. Some older + * Darwin code base limit OHare to 150ns cycle time. I decided to do + * the same here fore safety against broken old hardware ;) + * The HalfTick bit, when set, adds half a clock (15ns) to the access + * time and removes one from recovery. It's not supported on KeyLargo + * implementation afaik. The E bit appears to be set for PIO mode 0 and + * is used to reach long timings used in this mode. + */ +#define TR_33_MDMA_MASK 0x003ff800 +#define TR_33_MDMA_RECOVERY_MASK 0x001f0000 +#define TR_33_MDMA_RECOVERY_SHIFT 16 +#define TR_33_MDMA_ACCESS_MASK 0x0000f800 +#define TR_33_MDMA_ACCESS_SHIFT 11 +#define TR_33_MDMA_HALFTICK 0x00200000 +#define TR_33_PIO_MASK 0x000007ff +#define TR_33_PIO_E 0x00000400 +#define TR_33_PIO_RECOVERY_MASK 0x000003e0 +#define TR_33_PIO_RECOVERY_SHIFT 5 +#define TR_33_PIO_ACCESS_MASK 0x0000001f +#define TR_33_PIO_ACCESS_SHIFT 0 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC -typedef struct { +/* Rounded Multiword DMA timings + * + * I gave up finding a generic formula for all controller + * types and instead, built tables based on timing values + * used by Apple in Darwin's implementation. + */ +struct mdma_timings_t { int accessTime; + int recoveryTime; int cycleTime; -} pmac_ide_timing; +}; + +struct mdma_timings_t mdma_timings_33[] __pmacdata = +{ + { 240, 240, 480 }, + { 180, 180, 360 }, + { 135, 135, 270 }, + { 120, 120, 240 }, + { 105, 105, 210 }, + { 90, 90, 180 }, + { 75, 75, 150 }, + { 75, 45, 120 }, + { 0, 0, 0 } +}; -/* Multiword DMA timings */ -static pmac_ide_timing mdma_timings[] = +struct mdma_timings_t mdma_timings_33k[] __pmacdata = { - { 215, 480 }, /* Mode 0 */ - { 80, 150 }, /* 1 */ - { 70, 120 } /* 2 */ + { 240, 240, 480 }, + { 180, 180, 360 }, + { 150, 150, 300 }, + { 120, 120, 240 }, + { 90, 120, 210 }, + { 90, 90, 180 }, + { 90, 60, 150 }, + { 90, 30, 120 }, + { 0, 0, 0 } }; -/* Ultra DMA timings (for use when I know how to calculate them */ -static pmac_ide_timing udma_timings[] = +struct mdma_timings_t mdma_timings_66[] __pmacdata = { - { 0, 114 }, /* Mode 0 */ - { 0, 75 }, /* 1 */ - { 0, 55 }, /* 2 */ - { 100, 45 }, /* 3 */ - { 100, 25 } /* 4 */ + { 240, 240, 480 }, + { 180, 180, 360 }, + { 135, 135, 270 }, + { 120, 120, 240 }, + { 105, 105, 210 }, + { 90, 90, 180 }, + { 90, 75, 165 }, + { 75, 45, 120 }, + { 0, 0, 0 } +}; + +/* Ultra DMA timings (rounded) */ +struct { + int addrSetup; /* ??? */ + int rdy2pause; + int wrDataSetup; +} udma_timings[] __pmacdata = +{ + { 0, 180, 120 }, /* Mode 0 */ + { 0, 150, 90 }, /* 1 */ + { 0, 120, 60 }, /* 2 */ + { 0, 90, 45 }, /* 3 */ + { 0, 90, 30 } /* 4 */ }; /* allow up to 256 DBDMA commands per xfer */ @@ -121,7 +238,14 @@ }; #endif /* CONFIG_PMAC_PBOOK */ -static int +static int pmac_ide_notify_reboot(struct notifier_block *, unsigned long, void *); +static struct notifier_block pmac_ide_reboot_notifier = { + pmac_ide_notify_reboot, + NULL, + 0 +}; + +static int __pmac pmac_ide_find(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -140,7 +264,8 @@ * N.B. this can't be an initfunc, because the media-bay task can * call ide_[un]register at any time. */ -void pmac_ide_init_hwif_ports(hw_regs_t *hw, +void __pmac +pmac_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { @@ -198,24 +323,31 @@ /* Setup timings for the selected drive (master/slave). I still need to verify if this * is enough, I beleive selectproc will be called whenever an IDE command is started, * but... */ -static void +static void __pmac pmac_ide_selectproc(ide_drive_t *drive) { int i = pmac_ide_find(drive); if (i < 0) return; - - if (drive->select.all & 0x10) + + if (drive->select.b.unit & 0x01) out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[1]); else out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[0]); + (void)in_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE)); } -/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */ -#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS) -#define SYSCLK_TICKS_UDMA(t) (((t) + IDE_SYSCLK_ULTRA_PS - 1) / IDE_SYSCLK_ULTRA_PS) -static __inline__ int +/* Note: We don't use the generic routine here because for some + * yet unexplained reasons, it cause some media-bay CD-ROMs to + * lockup the bus. Strangely, this new version of the code is + * almost identical to the generic one and works, I've not yet + * managed to figure out what bit is causing the lockup in the + * generic code, possibly a timing issue... + * + * --BenH + */ +static int __pmac wait_for_ready(ide_drive_t *drive) { /* Timeout bumped for some powerbooks */ @@ -241,51 +373,51 @@ return 0; } -/* Note: We don't use the generic routine here because some of Apple's - * controller seem to be very sensitive about how things are done. - * We should probably set the NIEN bit, but that's an example of thing - * that can cause the controller to hang under some circumstances when - * done on the media-bay CD-ROM during boot. We do get occasional - * spurrious interrupts because of that. - * --BenH - */ -static int +static int __pmac pmac_ide_do_setfeature(ide_drive_t *drive, byte command) { - unsigned long flags; int result = 1; - - save_flags(flags); - cli(); + unsigned long flags; + ide_hwif_t *hwif = HWIF(drive); + + disable_irq(hwif->irq); /* disable_irq_nosync ?? */ udelay(1); SELECT_DRIVE(HWIF(drive), drive); SELECT_MASK(HWIF(drive), drive, 0); udelay(1); + (void)GET_STAT(); /* Get rid of pending error state */ if(wait_for_ready(drive)) { printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); goto out; } - OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); + udelay(10); + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); OUT_BYTE(command, IDE_NSECTOR_REG); + OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); udelay(1); + __save_flags(flags); /* local CPU only */ + ide__sti(); /* local CPU only -- for jiffies */ result = wait_for_ready(drive); + __restore_flags(flags); /* local CPU only */ + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); if (result) printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); out: - restore_flags(flags); - + SELECT_MASK(HWIF(drive), drive, 0); + enable_irq(hwif->irq); return result; } /* Calculate PIO timings */ -static void +static void __pmac pmac_ide_tuneproc(ide_drive_t *drive, byte pio) { ide_pio_data_t d; int i; u32 *timings; - int accessTicks, recTicks; + unsigned accessTicks, recTicks; + unsigned accessTime, recTime; i = pmac_ide_find(drive); if (i < 0) @@ -293,27 +425,44 @@ pio = ide_get_best_pio_mode(drive, pio, 4, &d); accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time); - if (drive->select.all & 0x10) + if (drive->select.b.unit & 0x01) timings = &pmac_ide[i].timings[1]; else timings = &pmac_ide[i].timings[0]; - - if (pmac_ide[i].kind == controller_kl_ata4) { - /* The "ata-4" IDE controller of Core99 machines */ - accessTicks = SYSCLK_TICKS_UDMA(ide_pio_timings[pio].active_time * 1000); - recTicks = SYSCLK_TICKS_UDMA(d.cycle_time * 1000) - accessTicks; - *timings = ((*timings) & 0x1FFFFFC00) | accessTicks | (recTicks << 5); + recTime = d.cycle_time - ide_pio_timings[pio].active_time + - ide_pio_timings[pio].setup_time; + recTime = max(recTime, 150U); + accessTime = ide_pio_timings[pio].active_time; + accessTime = max(accessTime, 150U); + if (pmac_ide[i].kind == controller_kl_ata4 || + pmac_ide[i].kind == controller_kl_ata4_80) { + /* 66Mhz cell */ + accessTicks = SYSCLK_TICKS_66(accessTime); + accessTicks = min(accessTicks, 0x1fU); + recTicks = SYSCLK_TICKS_66(recTime); + recTicks = min(recTicks, 0x1fU); + *timings = ((*timings) & ~TR_66_PIO_MASK) | + (accessTicks << TR_66_PIO_ACCESS_SHIFT) | + (recTicks << TR_66_PIO_RECOVERY_SHIFT); } else { - /* The old "ata-3" IDE controller */ - accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time); - if (accessTicks < 4) - accessTicks = 4; - recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4; - if (recTicks < 1) - recTicks = 1; - - *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5); + /* 33Mhz cell */ + int ebit = 0; + accessTicks = SYSCLK_TICKS(accessTime); + accessTicks = min(accessTicks, 0x1fU); + accessTicks = max(accessTicks, 4U); + recTicks = SYSCLK_TICKS(recTime); + recTicks = min(recTicks, 0x1fU); + recTicks = max(recTicks, 5U) - 4; + if (recTicks > 9) { + recTicks--; /* guess, but it's only for PIO0, so... */ + ebit = 1; + } + *timings = ((*timings) & ~TR_33_PIO_MASK) | + (accessTicks << TR_33_PIO_ACCESS_SHIFT) | + (recTicks << TR_33_PIO_RECOVERY_SHIFT); + if (ebit) + *timings |= TR_33_PIO_E; } #ifdef IDE_PMAC_DEBUG @@ -326,70 +475,134 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC -static int -set_timings_udma(int intf, u32 *timings, byte speed) +static int __pmac +set_timings_udma(u32 *timings, byte speed) { - int cycleTime, accessTime; - int rdyToPauseTicks, cycleTicks; - - if (pmac_ide[intf].kind != controller_kl_ata4) - return 1; - - cycleTime = udma_timings[speed & 0xf].cycleTime; - accessTime = udma_timings[speed & 0xf].accessTime; - - rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); - cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000); + unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks; - *timings = ((*timings) & 0xe00fffff) | - ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20; + rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause); + wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup); + addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup); + + *timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) | + (wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | + (rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) | + (addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) | + TR_66_UDMA_EN; +#ifdef IDE_PMAC_DEBUG + printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n", + speed & 0xf, *timings); +#endif return 0; } -static int -set_timings_mdma(int intf, u32 *timings, byte speed) +static int __pmac +set_timings_mdma(int intf_type, u32 *timings, byte speed, int drive_cycle_time) { - int cycleTime, accessTime; - int accessTicks, recTicks; + int cycleTime, accessTime, recTime; + unsigned accessTicks, recTicks; + struct mdma_timings_t* tm; + int i; - /* Calculate accesstime and cycle time */ - cycleTime = mdma_timings[speed & 0xf].cycleTime; - accessTime = mdma_timings[speed & 0xf].accessTime; - if ((pmac_ide[intf].kind == controller_ohare) && (cycleTime < 150)) + /* Get default cycle time for mode */ + switch(speed & 0xf) { + case 0: cycleTime = 480; break; + case 1: cycleTime = 150; break; + case 2: cycleTime = 120; break; + default: + return -1; + } + /* Adjust for drive */ + if (drive_cycle_time && drive_cycle_time > cycleTime) + cycleTime = drive_cycle_time; + /* OHare limits according to some old Apple sources */ + if ((intf_type == controller_ohare) && (cycleTime < 150)) cycleTime = 150; + /* Get the proper timing array for this controller */ + switch(intf_type) { + case controller_kl_ata4: + case controller_kl_ata4_80: + tm = mdma_timings_66; + break; + case controller_kl_ata3: + tm = mdma_timings_33k; + break; + default: + tm = mdma_timings_33; + break; + } + /* Lookup matching access & recovery times */ + i = -1; + for (;;) { + if (tm[i+1].cycleTime < cycleTime) + break; + i++; + } + if (i < 0) + return -1; + cycleTime = tm[i].cycleTime; + accessTime = tm[i].accessTime; + recTime = tm[i].recoveryTime; - /* For ata-4 controller */ - if (pmac_ide[intf].kind == controller_kl_ata4) { - accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); - recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks; - *timings = ((*timings) & 0xffe003ff) | - (accessTicks | (recTicks << 5)) << 10; +#ifdef IDE_PMAC_DEBUG + printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n", + cycleTime, accessTime, recTime); +#endif + if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) { + /* 66Mhz cell */ + accessTicks = SYSCLK_TICKS_66(accessTime); + accessTicks = min(accessTicks, 0x1fU); + accessTicks = max(accessTicks, 0x1U); + recTicks = SYSCLK_TICKS_66(recTime); + recTicks = min(recTicks, 0x1fU); + recTicks = max(recTicks, 0x3U); + /* Clear out mdma bits and disable udma */ + *timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) | + (accessTicks << TR_66_MDMA_ACCESS_SHIFT) | + (recTicks << TR_66_MDMA_RECOVERY_SHIFT); + } else if (intf_type == controller_kl_ata3) { + /* 33Mhz cell on KeyLargo */ + accessTicks = SYSCLK_TICKS(accessTime); + accessTicks = max(accessTicks, 1U); + accessTicks = min(accessTicks, 0x1fU); + accessTime = accessTicks * IDE_SYSCLK_NS; + recTicks = SYSCLK_TICKS(recTime); + recTicks = max(recTicks, 1U); + recTicks = min(recTicks, 0x1fU); + *timings = ((*timings) & ~TR_33_MDMA_MASK) | + (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | + (recTicks << TR_33_MDMA_RECOVERY_SHIFT); } else { + /* 33Mhz cell on others */ int halfTick = 0; int origAccessTime = accessTime; - int origCycleTime = cycleTime; + int origRecTime = recTime; accessTicks = SYSCLK_TICKS(accessTime); - if (accessTicks < 1) - accessTicks = 1; + accessTicks = max(accessTicks, 1U); + accessTicks = min(accessTicks, 0x1fU); accessTime = accessTicks * IDE_SYSCLK_NS; - recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1; - if (recTicks < 1) - recTicks = 1; - cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS; - - /* KeyLargo ata-3 don't support the half-tick stuff */ - if ((pmac_ide[intf].kind != controller_kl_ata3) && - (accessTicks > 1) && - ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && - ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) { - halfTick = 1; - accessTicks--; - } - *timings = ((*timings) & 0x7FF) | - (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11; + recTicks = SYSCLK_TICKS(recTime); + recTicks = max(recTicks, 2U) - 1; + recTicks = min(recTicks, 0x1fU); + recTime = (recTicks + 1) * IDE_SYSCLK_NS; + if ((accessTicks > 1) && + ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && + ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) { + halfTick = 1; + accessTicks--; + } + *timings = ((*timings) & ~TR_33_MDMA_MASK) | + (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | + (recTicks << TR_33_MDMA_RECOVERY_SHIFT); + if (halfTick) + *timings |= TR_33_MDMA_HALFTICK; } +#ifdef IDE_PMAC_DEBUG + printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n", + speed & 0xf, *timings); +#endif return 0; } #endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */ @@ -397,11 +610,11 @@ /* You may notice we don't use this function on normal operation, * our, normal mdma function is supposed to be more precise */ -static int +static int __pmac pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) { int intf = pmac_ide_find(drive); - int unit = (drive->select.all & 0x10) ? 1:0; + int unit = (drive->select.b.unit & 0x01); int ret = 0; u32 *timings; @@ -414,19 +627,25 @@ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC case XFER_UDMA_4: case XFER_UDMA_3: + if (pmac_ide[intf].kind != controller_kl_ata4_80) + return 1; case XFER_UDMA_2: case XFER_UDMA_1: case XFER_UDMA_0: - ret = set_timings_udma(intf, timings, speed); + if (pmac_ide[intf].kind != controller_kl_ata4 && + pmac_ide[intf].kind != controller_kl_ata4_80) + return 1; + ret = set_timings_udma(timings, speed); break; case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: + ret = set_timings_mdma(pmac_ide[intf].kind, timings, speed, 0); + break; case XFER_SW_DMA_2: case XFER_SW_DMA_1: case XFER_SW_DMA_0: - ret = set_timings_mdma(intf, timings, speed); - break; + return 1; #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ case XFER_PIO_4: case XFER_PIO_3: @@ -451,13 +670,46 @@ return 0; } -ide_ioreg_t +static void __pmac +sanitize_timings(int i) +{ + unsigned value; + + switch(pmac_ide[i].kind) { + case controller_kl_ata4: + case controller_kl_ata4_80: + value = 0x0008438c; + break; + case controller_kl_ata3: + value = 0x00084526; + break; + case controller_heathrow: + case controller_ohare: + default: + value = 0x00074526; + break; + } + pmac_ide[i].timings[0] = pmac_ide[i].timings[1] = value; +} + +ide_ioreg_t __pmac pmac_ide_get_base(int index) { return pmac_ide[index].regbase; } -int +int __pmac +pmac_ide_check_base(ide_ioreg_t base) +{ + int ix; + + for (ix = 0; ix < MAX_HWIFS; ++ix) + if (base == pmac_ide[ix].regbase) + return ix; + return -1; +} + +int __pmac pmac_ide_get_irq(ide_ioreg_t base) { int ix; @@ -468,7 +720,7 @@ return 0; } -static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; +static int ide_majors[] __pmacdata = { 3, 22, 33, 34, 56, 57 }; kdev_t __init pmac_find_ide_boot(char *bootdevice, int n) @@ -532,6 +784,7 @@ for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) { struct device_node *tp; + struct pmac_ide_hwif* pmhw; int *bidp; int in_bay = 0; @@ -560,6 +813,22 @@ ++i; if (i >= MAX_HWIFS) break; + pmhw = &pmac_ide[i]; + + /* + * Some older OFs have bogus sizes, causing request_OF_resource + * to fail. We fix them up here + */ + if (np->addrs[0].size > 0x1000) + np->addrs[0].size = 0x1000; + if (np->n_addrs > 1 && np->addrs[1].size > 0x100) + np->addrs[1].size = 0x100; + + pmhw->reg_resource = request_OF_resource(np, 0, " (mac-io IDE IO)"); + if (!pmhw->reg_resource) { + printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name); + continue; + } base = (unsigned long) ioremap(np->addrs[0].address, 0x200) - _IO_BASE; @@ -574,21 +843,30 @@ } else { irq = np->intrs[0].line; } - pmac_ide[i].regbase = base; - pmac_ide[i].irq = irq; - pmac_ide[i].node = np; + pmhw->regbase = base; + pmhw->irq = irq; + pmhw->node = np; if (device_is_compatible(np, "keylargo-ata")) { if (strcmp(np->name, "ata-4") == 0) - pmac_ide[i].kind = controller_kl_ata4; + pmhw->kind = controller_kl_ata4; else - pmac_ide[i].kind = controller_kl_ata3; + pmhw->kind = controller_kl_ata3; } else if (device_is_compatible(np, "heathrow-ata")) - pmac_ide[i].kind = controller_heathrow; + pmhw->kind = controller_heathrow; else - pmac_ide[i].kind = controller_ohare; + pmhw->kind = controller_ohare; bidp = (int *)get_property(np, "AAPL,bus-id", NULL); - pmac_ide[i].aapl_bus_id = bidp ? *bidp : 0; + pmhw->aapl_bus_id = bidp ? *bidp : 0; + + if (pmhw->kind == controller_kl_ata4) { + char* cable = get_property(np, "cable-type", NULL); + if (cable && !strncmp(cable, "80-", 3)) + pmhw->kind = controller_kl_ata4_80; + } + + /* Make sure we have sane timings */ + sanitize_timings(i); if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) { @@ -596,39 +874,22 @@ media_bay_set_ide_infos(np->parent,base,irq,i); #endif /* CONFIG_PMAC_PBOOK */ in_bay = 1; - } else if (pmac_ide[i].kind == controller_ohare) { + if (!bidp) + pmhw->aapl_bus_id = 1; + } else if (pmhw->kind == controller_ohare) { /* The code below is having trouble on some ohare machines * (timing related ?). Until I can put my hand on one of these * units, I keep the old way */ - feature_set(np, FEATURE_IDE0_enable); + ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1); } else { /* This is necessary to enable IDE when net-booting */ printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n", - pmac_ide[i].aapl_bus_id); - switch(pmac_ide[i].aapl_bus_id) { - case 0: - feature_set(np, FEATURE_IDE0_reset); - mdelay(10); - feature_set(np, FEATURE_IDE0_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE0_reset); - break; - case 1: - feature_set(np, FEATURE_IDE1_reset); - mdelay(10); - feature_set(np, FEATURE_IDE1_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE1_reset); - break; - case 2: - /* This one exists only for KL, I don't know - about any enable bit */ - feature_set(np, FEATURE_IDE2_reset); - mdelay(10); - feature_clear(np, FEATURE_IDE2_reset); - break; - } + pmhw->aapl_bus_id); + ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 1); + ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmhw->aapl_bus_id, 1); + mdelay(10); + ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 0); big_delay = 1; } @@ -658,6 +919,7 @@ #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&idepmac_sleep_notifier); #endif /* CONFIG_PMAC_PBOOK */ + register_reboot_notifier(&pmac_ide_reboot_notifier); } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC @@ -665,6 +927,12 @@ static void __init pmac_ide_setup_dma(struct device_node *np, int ix) { + pmac_ide[ix].dma_resource = request_OF_resource(np, 1, " (mac-io IDE DMA)"); + if (!pmac_ide[ix].dma_resource) { + printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name); + return; + } + pmac_ide[ix].dma_regs = (volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200); @@ -692,7 +960,7 @@ * pmac_ide_build_dmatable builds the DBDMA command list * for a transfer and sets the DBDMA channel to point to it. */ -static int +static int __pmac pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr) { struct dbdma_cmd *table, *tstart; @@ -703,6 +971,13 @@ volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs; table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(pmac_ide[ix].dma_table); + +#ifdef IDE_PMAC_DEBUG + if (in_le32(&dma->status) & (RUN|ACTIVE)) + printk("ide-pmac: channel status not stopped ! (%x)\n", + in_le32(&dma->status)); +#endif + /* Make sure channel is stopped and all error conditions are clear */ out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); while (in_le32(&dma->status) & RUN) udelay(1); @@ -734,6 +1009,10 @@ * Note that one DBDMA command can transfer * at most 65535 bytes. */ +#ifdef IDE_PMAC_DEBUG + if (size & 0x01) + printk("ide-pmac: odd size transfer ! (%d)\n", size); +#endif while (size) { unsigned int tc = (size < 0xfe00)? size: 0xfe00; @@ -782,12 +1061,14 @@ } static __inline__ unsigned char -udma_bits_to_command(unsigned char bits) +udma_bits_to_command(unsigned char bits, int high_speed) { - if(bits & 0x10) - return XFER_UDMA_4; - if(bits & 0x08) - return XFER_UDMA_3; + if (high_speed) { + if(bits & 0x10) + return XFER_UDMA_4; + if(bits & 0x08) + return XFER_UDMA_3; + } if(bits & 0x04) return XFER_UDMA_2; if(bits & 0x02) @@ -798,14 +1079,13 @@ } /* Calculate MultiWord DMA timings */ -static int +static int __pmac pmac_ide_mdma_enable(ide_drive_t *drive, int idx) { byte bits = drive->id->dma_mword & 0x07; byte feature = dma_bits_to_command(bits); u32 *timings; - int cycleTime, accessTime; - int accessTicks, recTicks; + int drive_cycle_time; struct hd_driveid *id = drive->id; int ret; @@ -821,66 +1101,30 @@ drive->init_speed = feature; /* which drive is it ? */ - if (drive->select.all & 0x10) + if (drive->select.b.unit & 0x01) timings = &pmac_ide[idx].timings[1]; else timings = &pmac_ide[idx].timings[0]; - /* Calculate accesstime and cycle time */ - cycleTime = mdma_timings[feature & 0xf].cycleTime; - accessTime = mdma_timings[feature & 0xf].accessTime; + /* Check if drive provide explicit cycle time */ if ((id->field_valid & 2) && (id->eide_dma_time)) - cycleTime = id->eide_dma_time; - if ((pmac_ide[idx].kind == controller_ohare) && (cycleTime < 150)) - cycleTime = 150; + drive_cycle_time = id->eide_dma_time; + else + drive_cycle_time = 0; + + /* Calculate controller timings */ + set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time); - /* For ata-4 controller */ - if (pmac_ide[idx].kind == controller_kl_ata4) { - accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); - recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks; - *timings = ((*timings) & 0xffe003ff) | - (accessTicks | (recTicks << 5)) << 10; - } else { - int halfTick = 0; - int origAccessTime = accessTime; - int origCycleTime = cycleTime; - - accessTicks = SYSCLK_TICKS(accessTime); - if (accessTicks < 1) - accessTicks = 1; - accessTime = accessTicks * IDE_SYSCLK_NS; - recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1; - if (recTicks < 1) - recTicks = 1; - cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS; - - /* KeyLargo ata-3 don't support the half-tick stuff */ - if ((pmac_ide[idx].kind != controller_kl_ata3) && - (accessTicks > 1) && - ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && - ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) { - halfTick = 1; - accessTicks--; - } - *timings = ((*timings) & 0x7FF) | - (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11; - } -#ifdef IDE_PMAC_DEBUG - printk(KERN_INFO "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n", - feature & 0xf, *timings); -#endif drive->current_speed = feature; return 1; } /* Calculate Ultra DMA timings */ -static int -pmac_ide_udma_enable(ide_drive_t *drive, int idx) +static int __pmac +pmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed) { byte bits = drive->id->dma_ultra & 0x1f; - byte feature = udma_bits_to_command(bits); - int cycleTime, accessTime; - int rdyToPauseTicks, cycleTicks; + byte feature = udma_bits_to_command(bits, high_speed); u32 *timings; int ret; @@ -896,25 +1140,18 @@ drive->init_speed = feature; /* which drive is it ? */ - if (drive->select.all & 0x10) + if (drive->select.b.unit & 0x01) timings = &pmac_ide[idx].timings[1]; else timings = &pmac_ide[idx].timings[0]; - cycleTime = udma_timings[feature & 0xf].cycleTime; - accessTime = udma_timings[feature & 0xf].accessTime; - - rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); - cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000); - - *timings = ((*timings) & 0xe00fffff) | - ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20; + set_timings_udma(timings, feature); drive->current_speed = feature; return 1; } -static int +static int __pmac pmac_ide_check_dma(ide_drive_t *drive) { int ata4, udma, idx; @@ -935,21 +1172,20 @@ enable = 0; udma = 0; - ata4 = (pmac_ide[idx].kind == controller_kl_ata4); + ata4 = (pmac_ide[idx].kind == controller_kl_ata4 || + pmac_ide[idx].kind == controller_kl_ata4_80); if(enable) { if (ata4 && (drive->media == ide_disk) && - (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) { + (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) { /* UltraDMA modes. */ - drive->using_dma = pmac_ide_udma_enable(drive, idx); + drive->using_dma = pmac_ide_udma_enable(drive, idx, + pmac_ide[idx].kind == controller_kl_ata4_80); } if (!drive->using_dma && (id->dma_mword & 0x0007)) { /* Normal MultiWord DMA modes. */ drive->using_dma = pmac_ide_mdma_enable(drive, idx); } - /* Without this, strange things will happen on Keylargo-based - * machines - */ OUT_BYTE(0, IDE_CONTROL_REG); /* Apply settings to controller */ pmac_ide_selectproc(drive); @@ -957,10 +1193,13 @@ return 0; } -int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) +static int __pmac +pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - int ix, dstat, i; + int ix, dstat; volatile struct dbdma_regs *dma; + byte unit = (drive->select.b.unit & 0x01); + byte ata4; /* Can we stuff a pointer to our intf structure in config_data * or select_data in hwif ? @@ -969,7 +1208,9 @@ if (ix < 0) return 0; dma = pmac_ide[ix].dma_regs; - + ata4 = (pmac_ide[ix].kind == controller_kl_ata4 || + pmac_ide[ix].kind == controller_kl_ata4_80); + switch (func) { case ide_dma_off: printk(KERN_INFO "%s: DMA disabled\n", drive->name); @@ -984,6 +1225,13 @@ case ide_dma_write: if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write)) return 1; + /* Apple adds 60ns to wrDataSetup on reads */ + if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) { + out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), + pmac_ide[ix].timings[unit] + + ((func == ide_dma_read) ? 0x00800000UL : 0)); + (void)in_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE)); + } drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; @@ -992,35 +1240,56 @@ IDE_COMMAND_REG); case ide_dma_begin: out_le32(&dma->control, (RUN << 16) | RUN); + /* Make sure it gets to the controller right now */ + (void)in_le32(&dma->control); break; - case ide_dma_end: + case ide_dma_end: /* returns 1 on error, 0 otherwise */ drive->waiting_for_dma = 0; dstat = in_le32(&dma->status); out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16)); /* verify good dma status */ return (dstat & (RUN|DEAD|ACTIVE)) != RUN; - case ide_dma_test_irq: - if ((in_le32(&dma->status) & (RUN|ACTIVE)) == RUN) - return 1; - /* That's a bit ugly and dangerous, but works in our case - * to workaround a problem with the channel status staying - * active if the drive returns an error + case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ + /* We have to things to deal with here: + * + * - The dbdma won't stop if the command was started + * but completed with an error without transfering all + * datas. This happens when bad blocks are met during + * a multi-block transfer. + * + * - The dbdma fifo hasn't yet finished flushing to + * to system memory when the disk interrupt occurs. + * + * The trick here is to increment drive->waiting_for_dma, + * and return as if no interrupt occured. If the counter + * reach a certain timeout value, we then return 1. If + * we really got the interrupt, it will happen right away + * again. + * Apple's solution here may be more elegant. They issue + * a DMA channel interrupt (a separate irq line) via a DBDMA + * NOP command just before the STOP, and wait for both the + * disk and DBDMA interrupts to have completed. */ - if (IDE_CONTROL_REG) { - byte stat; - stat = GET_ALTSTAT(); - if (stat & ERR_STAT) - return 1; - } - /* In some edge cases, some datas may still be in the dbdma - * engine fifo, we wait a bit for dbdma to complete + + /* If ACTIVE is cleared, the STOP command have passed and + * transfer is complete. */ - while ((in_le32(&dma->status) & (RUN|ACTIVE)) != RUN) { - if (++i > 100) - return 0; - udelay(1); + if (!(in_le32(&dma->status) & ACTIVE)) + return 1; + if (!drive->waiting_for_dma) + printk(KERN_WARNING "ide%d, ide_dma_test_irq \ + called while not waiting\n", ix); + + /* If dbdma didn't execute the STOP command yet, the + * active bit is still set */ + drive->waiting_for_dma++; + if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) { + printk(KERN_WARNING "ide%d, timeout waiting \ + for dbdma command stop\n", ix); + return 1; } - return 1; + udelay(1); + return 0; /* Let's implement tose just in case someone wants them */ case ide_dma_bad_drive: @@ -1041,8 +1310,8 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ -#ifdef CONFIG_PMAC_PBOOK -static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base) +static void __pmac +idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base) { int j; @@ -1052,7 +1321,9 @@ switch (drive->media) { case ide_disk: /* Spin down the drive */ - outb(0xa0, base+0x60); + outb(drive->select.all, base+0x60); + (void)inb(base+0x60); + udelay(100); outb(0x0, base+0x30); outb(0x0, base+0x20); outb(0x0, base+0x40); @@ -1076,8 +1347,10 @@ } } -static void idepmac_wake_device(ide_drive_t *drive, int used_dma) - { +#ifdef CONFIG_PMAC_PBOOK +static void __pmac +idepmac_wake_device(ide_drive_t *drive, int used_dma) +{ /* We force the IDE subdriver to check for a media change * This must be done first or we may lost the condition * @@ -1101,12 +1374,15 @@ HWGROUP(drive)->busy = 1; pmac_ide_check_dma(drive); HWGROUP(drive)->busy = 0; + if (!list_empty(&drive->queue.queue_head)) + ide_do_request(HWGROUP(drive), 0); spin_unlock_irq(&io_request_lock); } #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ } -static void idepmac_sleep_interface(int i, unsigned base, int mediabay) +static void __pmac +idepmac_sleep_interface(int i, unsigned base, int mediabay) { struct device_node* np = pmac_ide[i].node; @@ -1118,73 +1394,85 @@ if (mediabay) return; - /* Disable and reset the bus */ - feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IDE0_enable); - switch(pmac_ide[i].aapl_bus_id) { - case 0: - feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IDE0_enable); - break; - case 1: - feature_set(np, FEATURE_IDE1_reset); - feature_clear(np, FEATURE_IDE1_enable); - break; - case 2: - feature_set(np, FEATURE_IDE2_reset); - break; - } + /* Disable the bus */ + ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 0); } -static void idepmac_wake_interface(int i, unsigned long base, int mediabay) +static void __pmac +idepmac_wake_interface(int i, unsigned long base, int mediabay) { struct device_node* np = pmac_ide[i].node; if (!mediabay) { /* Revive IDE disk and controller */ - switch(pmac_ide[i].aapl_bus_id) { - case 0: - feature_set(np, FEATURE_IDE0_reset); - feature_set(np, FEATURE_IOBUS_enable); - mdelay(10); - feature_set(np, FEATURE_IDE0_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE0_reset); - break; - case 1: - feature_set(np, FEATURE_IDE1_reset); - feature_set(np, FEATURE_IOBUS_enable); - mdelay(10); - feature_set(np, FEATURE_IDE1_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE1_reset); - break; - case 2: - /* This one exists only for KL, I don't know - about any enable bit */ - feature_set(np, FEATURE_IDE2_reset); - mdelay(10); - feature_clear(np, FEATURE_IDE2_reset); - break; - } + ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 1); + ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 1); + mdelay(10); + ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 0); + } +} + +static void +idepmac_sleep_drive(ide_drive_t *drive, int idx, unsigned long base) +{ + int unlock = 0; + + /* Wait for HW group to complete operations */ + if (ide_spin_wait_hwgroup(drive)) { + // What can we do here ? Wake drive we had already + // put to sleep and return an error ? + } else { + unlock = 1; + /* Lock HW group */ + HWGROUP(drive)->busy = 1; + /* Stop the device */ + idepmac_sleep_device(drive, idx, base); } + if (unlock) + spin_unlock_irq(&io_request_lock); +} + +static void +idepmac_wake_drive(ide_drive_t *drive, unsigned long base) +{ + unsigned long flags; + int j; /* Reset timings */ - pmac_ide_selectproc(&ide_hwifs[i].drives[0]); + pmac_ide_selectproc(drive); mdelay(10); + + /* Wait up to 20 seconds for the drive to be ready */ + for (j = 0; j < 200; j++) { + int status; + mdelay(100); + outb(drive->select.all, base + 0x60); + if (inb(base + 0x60) != drive->select.all) + continue; + status = inb(base + 0x70); + if (!(status & BUSY_STAT)) + break; + } + + /* We resume processing on the HW group */ + spin_lock_irqsave(&io_request_lock, flags); + HWGROUP(drive)->busy = 0; + if (!list_empty(&drive->queue.queue_head)) + ide_do_request(HWGROUP(drive), 0); + spin_unlock_irqrestore(&io_request_lock, flags); } /* Note: We support only master drives for now. This will have to be * improved if we want to handle sleep on the iMacDV where the CD-ROM * is a slave */ -static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) +static int __pmac +idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) { int i, ret; unsigned long base; - unsigned long flags; int big_delay; - + switch (when) { case PBOOK_SLEEP_REQUEST: break; @@ -1193,34 +1481,19 @@ case PBOOK_SLEEP_NOW: for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; - ide_drive_t *drive; - int unlock = 0; + int dn; if ((base = pmac_ide[i].regbase) == 0) - continue; + continue; hwif = &ide_hwifs[i]; - drive = &hwif->drives[0]; - - if (drive->present) { - /* Wait for HW group to complete operations */ - if (ide_spin_wait_hwgroup(drive)) { - // What can we do here ? Wake drive we had already - // put to sleep and return an error ? - } else { - unlock = 1; - /* Lock HW group */ - HWGROUP(drive)->busy = 1; - - /* Stop the device */ - idepmac_sleep_device(drive, i, base); - - } + for (dn=0; dn<MAX_DRIVES; dn++) { + if (!hwif->drives[dn].present) + continue; + idepmac_sleep_drive(&hwif->drives[dn], i, base); } /* Disable irq during sleep */ disable_irq(pmac_ide[i].irq); - if (unlock) - spin_unlock_irq(&io_request_lock); /* Check if this is a media bay with an IDE device or not * a media bay. @@ -1237,6 +1510,9 @@ if ((base = pmac_ide[i].regbase) == 0) continue; + /* Make sure we have sane timings */ + sanitize_timings(i); + /* Check if this is a media bay with an IDE device or not * a media bay */ @@ -1253,46 +1529,79 @@ for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; - ide_drive_t *drive; - int j, used_dma; + int used_dma, dn; + int irq_on = 0; if ((base = pmac_ide[i].regbase) == 0) continue; hwif = &ide_hwifs[i]; - drive = &hwif->drives[0]; - - /* Wait for the drive to come up and set it's DMA */ - if (drive->present) { - /* Wait up to 20 seconds */ - for (j = 0; j < 200; j++) { - int status; - mdelay(100); - status = inb(base + 0x70); - if (!(status & BUSY_STAT)) - break; + for (dn=0; dn<MAX_DRIVES; dn++) { + ide_drive_t *drive = &hwif->drives[dn]; + if (!drive->present) + continue; + /* We don't have re-configured DMA yet */ + used_dma = drive->using_dma; + drive->using_dma = 0; + idepmac_wake_drive(drive, base); + if (!irq_on) { + enable_irq(pmac_ide[i].irq); + irq_on = 1; } - } - - /* We don't have re-configured DMA yet */ - used_dma = drive->using_dma; - drive->using_dma = 0; - - /* We resume processing on the HW group */ - spin_lock_irqsave(&io_request_lock, flags); - enable_irq(pmac_ide[i].irq); - if (drive->present) - HWGROUP(drive)->busy = 0; - spin_unlock_irqrestore(&io_request_lock, flags); - - /* Wake the device - * We could handle the slave here - */ - if (drive->present) idepmac_wake_device(drive, used_dma); + } + if (!irq_on) + enable_irq(pmac_ide[i].irq); } break; } return PBOOK_SLEEP_OK; } #endif /* CONFIG_PMAC_PBOOK */ + +static int __pmac +pmac_ide_notify_reboot(struct notifier_block *this, unsigned long code, void *x) +{ + int i, gotone; + unsigned long base; + + if (code != SYS_HALT && code != SYS_POWER_OFF) + return 0; + + gotone = 0; + for (i = 0; i < pmac_ide_count; ++i) { + ide_hwif_t *hwif; + ide_drive_t *drive; + int unlock = 0; + int dn; + + if ((base = pmac_ide[i].regbase) == 0) + continue; + + hwif = &ide_hwifs[i]; + for (dn=0; dn<MAX_DRIVES; dn++) { + drive = &hwif->drives[dn]; + if (drive->present) { + gotone = 1; + /* Wait for HW group to complete operations */ + if (ide_spin_wait_hwgroup(drive)) { + // What can we do here ? Wake drive we had already + // put to sleep and return an error ? + } else { + unlock = 1; + /* Lock HW group */ + HWGROUP(drive)->busy = 1; + + /* Stop the device */ + idepmac_sleep_device(drive, i, base); + } + } + if (unlock) + spin_unlock_irq(&io_request_lock); + } + } + if (gotone) + mdelay(1000); + + return NOTIFY_DONE; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/ide-probe.c linux-2.5/drivers/ide/ide-probe.c --- linux-2.5.1/drivers/ide/ide-probe.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/ide/ide-probe.c Thu Jan 3 23:04:39 2002 @@ -595,17 +595,18 @@ { request_queue_t *q = &drive->queue; int max_sectors; +#ifdef CONFIG_BLK_DEV_PDC4030 + int is_pdc4030_chipset = (HWIF(drive)->chipset == ide_pdc4030); +#else + const int is_pdc4030_chipset = 0; +#endif q->queuedata = HWGROUP(drive); blk_init_queue(q, do_ide_request, &ide_lock); blk_queue_segment_boundary(q, 0xffff); /* IDE can do up to 128K per request, pdc4030 needs smaller limit */ -#ifdef CONFIG_BLK_DEV_PDC4030 - max_sectors = 127; -#else - max_sectors = 255; -#endif + max_sectors = (is_pdc4030_chipset ? 127 : 255); blk_queue_max_sectors(q, max_sectors); /* IDE DMA can do PRD_ENTRIES number of segments. */ @@ -796,9 +797,7 @@ gd->major = hwif->major; /* our major device number */ gd->major_name = IDE_MAJOR_NAME; /* treated special in genhd.c */ gd->minor_shift = PARTN_BITS; /* num bits for partitions */ - gd->max_p = 1<<PARTN_BITS; /* 1 + max partitions / drive */ gd->nr_real = units; /* current num real drives */ - gd->real_devices= hwif; /* ptr to internal data */ gd->next = NULL; /* linked list of major devs */ gd->fops = ide_fops; /* file operations */ gd->de_arr = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/ide-timing.h linux-2.5/drivers/ide/ide-timing.h --- linux-2.5.1/drivers/ide/ide-timing.h Sat Feb 3 19:27:43 2001 +++ linux-2.5/drivers/ide/ide-timing.h Mon Jan 14 14:38:05 2002 @@ -2,11 +2,9 @@ #define _IDE_TIMING_H /* - * $Id: ide-timing.h,v 1.5 2001/01/15 21:48:56 vojtech Exp $ + * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1999-2001 Vojtech Pavlik */ /* @@ -25,16 +23,14 @@ * 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@suse.cz>, or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include <linux/hdreg.h> -#ifndef XFER_PIO_5 #define XFER_PIO_5 0x0d #define XFER_UDMA_SLOW 0x4f -#endif struct ide_timing { short mode; @@ -49,13 +45,15 @@ }; /* - * PIO 0-5, MWDMA 0-2 and UDMA 0-5 timings (in nanoseconds). + * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds). * These were taken from ATA/ATAPI-6 standard, rev 0a, except - * for PIO 5, which is a nonstandard extension. + * for PIO 5, which is a nonstandard extension and UDMA6, which + * is currently supported only by Maxtor drives. */ static struct ide_timing ide_timing[] = { + { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, @@ -105,6 +103,7 @@ #define EZ(v,unit) ((v)?ENOUGH(v,unit):0) #define XFER_MODE 0xf0 +#define XFER_UDMA_133 0x48 #define XFER_UDMA_100 0x44 #define XFER_UDMA_66 0x42 #define XFER_UDMA 0x40 @@ -123,6 +122,9 @@ if ((map & XFER_UDMA) && (id->field_valid & 4)) { /* Want UDMA and UDMA bitmap valid */ + if ((map & XFER_UDMA_133) == XFER_UDMA_133) + if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best; + if ((map & XFER_UDMA_100) == XFER_UDMA_100) if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best; @@ -174,14 +176,14 @@ static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT) { - q->setup = EZ(t->setup, T); - q->act8b = EZ(t->act8b, T); - q->rec8b = EZ(t->rec8b, T); - q->cyc8b = EZ(t->cyc8b, T); - q->active = EZ(t->active, T); - q->recover = EZ(t->recover, T); - q->cycle = EZ(t->cycle, T); - q->udma = EZ(t->udma, UT); + q->setup = EZ(t->setup * 1000, T); + q->act8b = EZ(t->act8b * 1000, T); + q->rec8b = EZ(t->rec8b * 1000, T); + q->cyc8b = EZ(t->cyc8b * 1000, T); + q->active = EZ(t->active * 1000, T); + q->recover = EZ(t->recover * 1000, T); + q->cycle = EZ(t->cycle * 1000, T); + q->udma = EZ(t->udma * 1000, UT); } static void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, struct ide_timing *m, unsigned int what) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/ide.c linux-2.5/drivers/ide/ide.c --- linux-2.5.1/drivers/ide/ide.c Sun Dec 16 20:21:02 2001 +++ linux-2.5/drivers/ide/ide.c Sun Jan 13 17:38:30 2002 @@ -580,7 +580,7 @@ } if (!end_that_request_first(rq, uptodate, nr_secs)) { - add_blkdev_randomness(MAJOR(rq->rq_dev)); + add_blkdev_randomness(major(rq->rq_dev)); blkdev_dequeue_request(rq); hwgroup->rq = NULL; end_that_request_last(rq); @@ -653,7 +653,7 @@ continue; if (drive->media!=ide_disk && drive->media!=ide_floppy) continue; - register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS), + register_disk(gd,mk_kdev(hwif->major,unit<<PARTN_BITS), #ifdef CONFIG_BLK_DEV_ISAPNP (drive->forced_geom && drive->noprobe) ? 1 : #endif /* CONFIG_BLK_DEV_ISAPNP */ @@ -1223,7 +1223,7 @@ { ide_startstop_t startstop; unsigned long block; - unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS; + unsigned int minor = minor(rq->rq_dev), unit = minor >> PARTN_BITS; ide_hwif_t *hwif = HWIF(drive); BUG_ON(!(rq->flags & REQ_STARTED)); @@ -1241,12 +1241,6 @@ printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev)); goto kill_rq; } -#ifdef DEBUG - if (rq->bh && !buffer_locked(rq->bh)) { - printk("%s: block not locked\n", drive->name); - goto kill_rq; - } -#endif block = rq->sector; /* Strange disk manager remap */ @@ -1390,7 +1384,10 @@ * will start the next request from the queue. If no more work remains, * the driver will clear the hwgroup->flags IDE_BUSY flag and exit. */ -static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq) +/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back + * into life on wakeup from machine sleep. + */ +void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq) { ide_drive_t *drive; ide_hwif_t *hwif; @@ -1478,7 +1475,7 @@ */ request_queue_t *ide_get_queue (kdev_t dev) { - ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data; + ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[major(dev)].data; return &hwif->drives[DEVICE_NR(dev) & 1].queue; } @@ -1784,7 +1781,7 @@ */ ide_drive_t *get_info_ptr (kdev_t i_rdev) { - int major = MAJOR(i_rdev); + int major = major(i_rdev); unsigned int h; for (h = 0; h < MAX_HWIFS; ++h) { @@ -1851,7 +1848,7 @@ #endif rq->errors = 0; rq->rq_status = RQ_ACTIVE; - rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS); + rq->rq_dev = mk_kdev(major,(drive->select.b.unit)<<PARTN_BITS); if (action == ide_wait) rq->waiting = &wait; spin_lock_irqsave(&ide_lock, flags); @@ -1880,7 +1877,7 @@ { struct gendisk *g = HWIF(drive)->gd; int minor = (drive->select.b.unit << g->minor_shift); - kdev_t dev = MKDEV(g->major, minor); + kdev_t dev = mk_kdev(g->major, minor); grok_partitions(dev, current_capacity(drive)); } @@ -1939,7 +1936,7 @@ if (drive->revalidate) { drive->revalidate = 0; if (!initializing) - (void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS)); + (void) ide_revalidate_disk(mk_kdev(hwif->major, unit<<PARTN_BITS)); } } } @@ -2119,7 +2116,7 @@ minor = drive->select.b.unit << PARTN_BITS; for (p = 0; p < (1<<PARTN_BITS); ++p) { if (drive->part[p].nr_sects > 0) { - kdev_t devp = MKDEV(hwif->major, minor+p); + kdev_t devp = mk_kdev(hwif->major, minor+p); invalidate_device(devp, 0); } } @@ -2624,9 +2621,8 @@ kdev_t dev; ide_settings_t *setting; - if (!inode || !(dev = inode->i_rdev)) - return -EINVAL; - major = MAJOR(dev); minor = MINOR(dev); + dev = inode->i_rdev; + major = major(dev); minor = minor(dev); if ((drive = get_info_ptr(inode->i_rdev)) == NULL) return -ENODEV; @@ -2635,7 +2631,7 @@ err = ide_read_setting(drive, setting); return err >= 0 ? put_user(err, (long *) arg) : err; } else { - if ((MINOR(inode->i_rdev) & PARTN_MASK)) + if ((minor(inode->i_rdev) & PARTN_MASK)) return -EINVAL; return ide_write_setting(drive, setting, arg); } @@ -2651,7 +2647,7 @@ if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT; if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, + if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -2664,7 +2660,7 @@ if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT; if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, + if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -2676,7 +2672,7 @@ if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT; if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, + if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -2687,7 +2683,7 @@ case HDIO_OBSOLETE_IDENTITY: case HDIO_GET_IDENTITY: - if (MINOR(inode->i_rdev) & PARTN_MASK) + if (minor(inode->i_rdev) & PARTN_MASK) return -EINVAL; if (drive->id == NULL) return -ENOMSG; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/pdc4030.c linux-2.5/drivers/ide/pdc4030.c --- linux-2.5.1/drivers/ide/pdc4030.c Wed Jul 18 01:53:55 2001 +++ linux-2.5/drivers/ide/pdc4030.c Mon Jan 7 20:22:55 2002 @@ -66,8 +66,10 @@ * some technical information which has shed a glimmer of light on some of the * problems I was having, especially with writes. * - * There are still problems with the robustness and efficiency of this driver - * because I still don't understand what the card is doing with interrupts. + * There are still potential problems with the robustness and efficiency of + * this driver because I still don't understand what the card is doing with + * interrupts, however, it has been stable for a while with no reports of ill + * effects. */ #define DEBUG_READ @@ -308,7 +310,9 @@ byte stat; int total_remaining; unsigned int sectors_left, sectors_avail, nsect; + unsigned long flags; struct request *rq; + char *to; if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { return ide_error(drive, "promise_read_intr", stat); @@ -330,15 +334,15 @@ if (nsect > sectors_avail) nsect = sectors_avail; sectors_avail -= nsect; - ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); + to = ide_map_buffer(rq, &flags); + idedisk_input_data(drive, to, nsect * SECTOR_WORDS); #ifdef DEBUG_READ printk(KERN_DEBUG "%s: promise_read: sectors(%ld-%ld), " "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector, - rq->sector+nsect-1, (unsigned long) rq->buffer, - rq->nr_sectors-nsect); + rq->sector+nsect-1, (unsigned long) to, rq->nr_sectors-nsect); #endif + ide_unmap_buffer(to, &flags); rq->sector += nsect; - rq->buffer += nsect<<9; rq->errors = 0; rq->nr_sectors -= nsect; total_remaining = rq->nr_sectors; @@ -389,7 +393,6 @@ { ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = hwgroup->rq; - int i; if (GET_STAT() & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { @@ -406,10 +409,7 @@ #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name); #endif - for (i = rq->nr_sectors; i > 0; ) { - i -= rq->current_nr_sectors; - ide_end_request(1, hwgroup); - } + __ide_end_request(hwgroup, 1, rq->nr_sectors); return ide_stopped; } @@ -495,10 +495,19 @@ */ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq) { + ide_startstop_t startstop; unsigned long timeout; byte stat; - if (rq->cmd == READ) { +/* Check that it's a regular command. If not, bomb out early. */ + if (!(rq->flags & REQ_CMD)) { + blk_dump_rq_flags(rq, "pdc4030 bad flags"); + ide_end_request(0, HWGROUP(drive)); + return ide_stopped; + } + + switch (rq_data_dir(rq)) { + case READ: OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG); /* * The card's behaviour is odd at this point. If the data is @@ -531,9 +540,17 @@ printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n", drive->name); return ide_stopped; - } else if (rq->cmd == WRITE) { - ide_startstop_t startstop; + break; + + case WRITE: OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG); +/* + * Strategy on write is: + * look for the DRQ that should have been immediately asserted + * copy the request into the hwgroup's scratchpad + * call the promise_write function to deal with writing the data out + * NOTE: No interrupts are generated on writes. Write completion must be polled + */ if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing " "PROMISE_WRITE\n", drive->name); @@ -543,11 +560,11 @@ __cli(); /* local CPU only */ HWGROUP(drive)->wrq = *rq; /* scratchpad */ return promise_write(drive); + break; - } else { - printk("KERN_WARNING %s: bad command: %d\n", - drive->name, rq->cmd); + default: + printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n"); ide_end_request(0, HWGROUP(drive)); - return ide_stopped; + break; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/pdcraid.c linux-2.5/drivers/ide/pdcraid.c --- linux-2.5.1/drivers/ide/pdcraid.c Tue Nov 13 17:19:41 2001 +++ linux-2.5/drivers/ide/pdcraid.c Mon Jan 7 20:47:23 2002 @@ -102,17 +102,17 @@ unsigned int minor; unsigned long sectors; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; switch (cmd) { case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; - sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects; - if (MINOR(inode->i_rdev)&15) + sectors = ataraid_gendisk.part[minor(inode->i_rdev)].nr_sects; + if (minor(inode->i_rdev)&15) return put_user(sectors, (unsigned long *) arg); return put_user(raid[minor].sectors , (unsigned long *) arg); break; @@ -127,7 +127,7 @@ if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT; if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT; if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -139,7 +139,7 @@ if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT; if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT; if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -387,18 +387,14 @@ #include "pdcraid.h" -static unsigned long calc_pdcblock_offset (int major,int minor) +static unsigned long calc_pdcblock_offset(struct block_device *bdev) { unsigned long lba = 0; - kdev_t dev; - ide_drive_t *ideinfo; - - dev = MKDEV(major,minor); - ideinfo = get_info_ptr (dev); + ide_drive_t *ideinfo = get_info_ptr(to_kdev_t(bdev->bd_dev)); + if (ideinfo==NULL) return 0; - - + /* first sector of the last cluster */ if (ideinfo->head==0) return 0; @@ -412,42 +408,32 @@ } -static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize) +static int read_disk_sb(struct block_device *bdev, struct promise_raid_conf *p) { - int ret = -EINVAL; - struct buffer_head *bh = NULL; - kdev_t dev = MKDEV(major,minor); unsigned long sb_offset; + char *buffer; + int i; - if (blksize_size[major]==NULL) /* device doesn't exist */ - return -EINVAL; - - /* * Calculate the position of the superblock, * it's at first sector of the last cylinder */ - sb_offset = calc_pdcblock_offset(major,minor)/8; - /* The /8 transforms sectors into 4Kb blocks */ + sb_offset = calc_pdcblock_offset(bdev); if (sb_offset==0) return -1; - - set_blocksize (dev, 4096); - bh = bread (dev, sb_offset, 4096); - - if (bh) { - memcpy (buffer, bh->b_data, bufsize); - } else { - printk(KERN_ERR "pdcraid: Error reading superblock.\n"); - goto abort; + for (i = 0, buffer = (char*)p; i < 4; i++, buffer += 512) { + Sector sect; + char *q = read_dev_sector(bdev, sb_offset + i, §); + if (!p) { + printk(KERN_ERR "pdcraid: Error reading superblock.\n"); + return -1; + } + memcpy(buffer, q, 512); + put_dev_sector(§); } - ret = 0; -abort: - if (bh) - brelse (bh); - return ret; + return 0; } static unsigned int calc_sb_csum (unsigned int* ptr) @@ -464,12 +450,11 @@ static int cookie = 0; +static struct promise_raid_conf __initdata prom; static void __init probedisk(int devindex,int device, int raidlevel) { int i; int major, minor; - struct promise_raid_conf *prom; - static unsigned char block[4096]; struct block_device *bdev; if (devlist[devindex].device!=-1) /* already assigned to another array */ @@ -478,44 +463,48 @@ major = devlist[devindex].major; minor = devlist[devindex].minor; - if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block))) - return; - - prom = (struct promise_raid_conf*)&block[512]; - - /* the checksums must match */ - if (prom->checksum != calc_sb_csum((unsigned int*)prom)) - return; - if (prom->raid.type!=raidlevel) /* different raidlevel */ + bdev = bdget(mk_kdev(major,minor)); + if (!bdev) return; - if ((cookie!=0) && (cookie != prom->raid.magic_1)) /* different array */ + if (blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) != 0) return; + + if (read_disk_sb(bdev, &prom)) + goto out; + + /* the checksums must match */ + if (prom.checksum != calc_sb_csum((unsigned int*)&prom)) + goto out; + if (prom.raid.type!=raidlevel) /* different raidlevel */ + goto out; + + if ((cookie!=0) && (cookie != prom.raid.magic_1)) /* different array */ + goto out; - cookie = prom->raid.magic_1; + cookie = prom.raid.magic_1; /* This looks evil. But basically, we have to search for our adapternumber in the arraydefinition, both of which are in the superblock */ - for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) { - if ( (prom->raid.disk[i].channel== prom->raid.channel) && - (prom->raid.disk[i].device == prom->raid.device) ) { - - bdev = bdget(MKDEV(major,minor)); - if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) { - raid[device].disk[i].bdev = bdev; - } - raid[device].disk[i].device = MKDEV(major,minor); - raid[device].disk[i].sectors = prom->raid.disk_secs; - raid[device].stride = (1<<prom->raid.raid0_shift); - raid[device].disks = prom->raid.total_disks; - raid[device].sectors = prom->raid.total_secs; - raid[device].geom.heads = prom->raid.heads+1; - raid[device].geom.sectors = prom->raid.sectors; - raid[device].geom.cylinders = prom->raid.cylinders+1; + for (i=0;(i<prom.raid.total_disks)&&(i<8);i++) { + if ( (prom.raid.disk[i].channel== prom.raid.channel) && + (prom.raid.disk[i].device == prom.raid.device) ) { + + raid[device].disk[i].bdev = bdev; + raid[device].disk[i].device = mk_kdev(major,minor); + raid[device].disk[i].sectors = prom.raid.disk_secs; + raid[device].stride = (1<<prom.raid.raid0_shift); + raid[device].disks = prom.raid.total_disks; + raid[device].sectors = prom.raid.total_secs; + raid[device].geom.heads = prom.raid.heads+1; + raid[device].geom.sectors = prom.raid.sectors; + raid[device].geom.cylinders = prom.raid.cylinders+1; devlist[devindex].device=device; - } + return; + } } - +out: + blkdev_put(bdev, BDEV_RAW); } static void __init fill_cutoff(int device) @@ -562,7 +551,7 @@ for (i=0;i<8;i++) { if (raid[device].disk[i].device!=0) { printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n", - i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device)); + i,raid[device].disk[i].sectors/2048,major(raid[device].disk[i].device),minor(raid[device].disk[i].device)); count++; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ide/via82cxxx.c linux-2.5/drivers/ide/via82cxxx.c --- linux-2.5.1/drivers/ide/via82cxxx.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/ide/via82cxxx.c Thu Dec 27 22:10:28 2001 @@ -1,5 +1,5 @@ /* - * $Id: via82cxxx.c,v 3.29 2001/09/10 10:06:00 vojtech Exp $ + * $Id: via82cxxx.c,v 3.33 2001/12/23 22:46:12 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik * @@ -7,23 +7,21 @@ * Michel Aubry * Jeff Garzik * Andre Hedrick - * - * Sponsored by SuSE */ /* * VIA IDE driver for Linux. Supports * * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, - * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233 + * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a * * southbridges, which can be found in * * VIA Apollo Master, VP, VP2, VP2/97, VP3, VPX, VPX/97, MVP3, MVP4, P6, Pro, * ProII, ProPlus, Pro133, Pro133+, Pro133A, Pro133A Dual, Pro133T, Pro133Z, * PLE133, PLE133T, Pro266, Pro266T, ProP4X266, PM601, PM133, PN133, PL133T, - * PX266, PM266, KX133, KT133, KT133A, KLE133, KT266, KX266, KM133, KM133A, - * KL133, KN133, KM266 + * PX266, PM266, KX133, KT133, KT133A, KT133E, KLE133, KT266, KX266, KM133, + * KM133A, KL133, KN133, KM266 * PC-Chips VXPro, VXPro+, VXTwo, TXPro-III, TXPro-AGP, AGPPro, ViaGra, BXToo, * BXTel, BXpert * AMD 640, 640 AGP, 750 IronGate, 760, 760MP @@ -32,9 +30,9 @@ * * chipsets. Supports * - * PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-5 + * PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-6 * - * (this includes UDMA33, 66 and 100) modes. UDMA66 and higher modes are + * (this includes UDMA33, 66, 100 and 133) modes. UDMA66 and higher modes are * 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. @@ -56,8 +54,8 @@ * 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@suse.cz>, or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include <linux/config.h> @@ -87,10 +85,12 @@ #define VIA_UDMA_33 0x001 #define VIA_UDMA_66 0x002 #define VIA_UDMA_100 0x003 +#define VIA_UDMA_133 0x004 #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_NO_UNMASK 0x080 /* Doesn't work with IRQ unmasking on */ +#define VIA_BAD_ID 0x100 /* Has wrong vendor ID (0x1107) */ /* * VIA SouthBridge chips. @@ -104,10 +104,11 @@ unsigned short flags; } via_isa_bridges[] = { #ifdef FUTURE_BRIDGES - { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_100 }, - { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_100 }, - { "vt8233c", PCI_DEVICE_ID_VIA_8233C, 0x00, 0x2f, VIA_UDMA_100 }, + { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 }, + { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 }, #endif + { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 }, + { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 }, { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 }, { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 }, { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 }, @@ -121,6 +122,7 @@ { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO }, { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO }, { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK }, + { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID }, { NULL } }; @@ -128,7 +130,7 @@ static unsigned char via_enabled; static unsigned int via_80w; static unsigned int via_clock; -static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" }; +static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" }; /* * VIA /proc entry. @@ -151,7 +153,7 @@ 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], den[4], + int 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; @@ -161,7 +163,7 @@ via_print("----------VIA BusMastering IDE Configuration----------------"); - via_print("Driver Version: 3.29"); + via_print("Driver Version: 3.33"); via_print("South Bridge: VIA %s", via_config->name); pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t); @@ -170,7 +172,7 @@ 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); + via_print("PCI clock: %d.%dMHz", via_clock / 1000, via_clock / 100 % 10); pci_read_config_byte(dev, VIA_MISC_1, &t); via_print("Master Read Cycle IRDY: %dws", (t & 64) >> 6); @@ -218,40 +220,45 @@ 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]); + speed[i] = 2 * via_clock / (active[i] + recover[i]); + cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock; if (!uen[i] || !den[i]) continue; switch (via_config->flags & VIA_UDMA) { - - case VIA_UDMA_100: - speed[i] = 60 * via_clock / udma[i]; - cycle[i] = 333 / via_clock * udma[i]; + + case VIA_UDMA_33: + speed[i] = 2 * via_clock / udma[i]; + cycle[i] = 1000000 * udma[i] / via_clock; break; case VIA_UDMA_66: - speed[i] = 40 * via_clock / (udma[i] * umul[i]); - cycle[i] = 500 / via_clock * (udma[i] * umul[i]); + speed[i] = 4 * via_clock / (udma[i] * umul[i]); + cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock; break; - case VIA_UDMA_33: - speed[i] = 20 * via_clock / udma[i]; - cycle[i] = 1000 / via_clock * udma[i]; + case VIA_UDMA_100: + speed[i] = 6 * via_clock / udma[i]; + cycle[i] = 333333 * udma[i] / via_clock; + break; + + case VIA_UDMA_133: + speed[i] = 8 * via_clock / udma[i]; + cycle[i] = 250000 * udma[i] / via_clock; break; } } 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]); - via_print_drive("Cmd Recovery: ", "%8dns", (1000 / via_clock) * recover8b[i]); - via_print_drive("Data Active: ", "%8dns", (1000 / via_clock) * active[i]); - via_print_drive("Data Recovery: ", "%8dns", (1000 / via_clock) * recover[i]); + via_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / via_clock); + via_print_drive("Cmd Active: ", "%8dns", 1000000 * active8b[i] / via_clock); + via_print_drive("Cmd Recovery: ", "%8dns", 1000000 * recover8b[i] / via_clock); + via_print_drive("Data Active: ", "%8dns", 1000000 * active[i] / via_clock); + via_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / via_clock); via_print_drive("Cycle Time: ", "%8dns", cycle[i]); - via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 10, speed[i] % 10); + via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10); return p - buffer; /* hoping it is less than 4K... */ } @@ -280,6 +287,7 @@ case VIA_UDMA_33: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break; case VIA_UDMA_66: t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break; case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break; + case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break; default: return; } @@ -296,20 +304,21 @@ { ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); struct ide_timing t, p; - int T, UT; + unsigned int T, UT; if (speed != XFER_PIO_SLOW && speed != drive->current_speed) if (ide_config_drive_speed(drive, speed)) printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n", drive->dn >> 1, drive->dn & 1); - T = 1000 / via_clock; + T = 1000000000 / via_clock; switch (via_config->flags & VIA_UDMA) { case VIA_UDMA_33: UT = T; break; case VIA_UDMA_66: UT = T/2; break; case VIA_UDMA_100: UT = T/3; break; - default: UT = T; break; + case VIA_UDMA_133: UT = T/4; break; + default: UT = T; } ide_timing_compute(drive, speed, &t, T, UT); @@ -365,7 +374,8 @@ 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)); + (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) | + (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0)); via_set_drive(drive, speed); @@ -395,14 +405,16 @@ */ for (via_config = via_isa_bridges; via_config->id; via_config++) - if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, via_config->id, NULL))) { + if ((isa = pci_find_device(PCI_VENDOR_ID_VIA + + !!(via_config->flags & VIA_BAD_ID), via_config->id, NULL))) { + pci_read_config_byte(isa, PCI_REVISION_ID, &t); if (t >= via_config->rev_min && t <= via_config->rev_max) break; } if (!via_config->id) { - printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@suse.cz>\n"); + printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@ucw.cz>\n"); return -ENODEV; } @@ -412,22 +424,28 @@ switch (via_config->flags & VIA_UDMA) { - case VIA_UDMA_100: - - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 3))) - via_80w |= (1 << (1 - (i >> 4))); /* BIOS 80-wire bit or UDMA w/ < 50ns/cycle */ - break; - case VIA_UDMA_66: - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); /* Enable Clk66 */ pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008); for (i = 24; i >= 0; i -= 8) if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2)) via_80w |= (1 << (1 - (i >> 4))); /* 2x PCI clock and UDMA w/ < 3T/cycle */ break; + + case VIA_UDMA_100: + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 4))) + via_80w |= (1 << (1 - (i >> 4))); /* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */ + break; + + case VIA_UDMA_133: + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 8))) + via_80w |= (1 << (1 - (i >> 4))); /* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */ + break; + } if (via_config->flags & VIA_BAD_CLK66) { /* Disable Clk66 */ @@ -466,10 +484,17 @@ * Determine system bus clock. */ - via_clock = system_bus_clock(); - if (via_clock < 20 || via_clock > 50) { + via_clock = system_bus_clock() * 1000; + + switch (via_clock) { + case 33000: via_clock = 33333; break; + case 37000: via_clock = 37500; break; + case 41000: via_clock = 41666; break; + } + + if (via_clock < 20000 || via_clock > 50000) { printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock); - printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to force UDMA66/UDMA100.\n"); + printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to assume 80-wire cable.\n"); via_clock = 33; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ieee1394/hosts.c linux-2.5/drivers/ieee1394/hosts.c --- linux-2.5.1/drivers/ieee1394/hosts.c Tue Oct 2 04:24:24 2001 +++ linux-2.5/drivers/ieee1394/hosts.c Thu Dec 13 16:32:35 2001 @@ -170,10 +170,10 @@ list_for_each(hlh, &tmpl->hosts) { host = list_entry(hlh, struct hpsb_host, list); if (host->initialized) { + highlevel_remove_host(host); + host->initialized = 0; abort_requests(host); - - highlevel_remove_host(host); tmpl->release_host(host); while (test_bit(0, &host->timeout_tq.sync)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ieee1394/ieee1394_core.c linux-2.5/drivers/ieee1394/ieee1394_core.c --- linux-2.5.1/drivers/ieee1394/ieee1394_core.c Wed Oct 17 21:19:20 2001 +++ linux-2.5/drivers/ieee1394/ieee1394_core.c Thu Dec 13 16:32:35 2001 @@ -318,7 +318,7 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) { - host->node_id = 0xffc0 | phyid; + host->node_id = LOCAL_BUS | phyid; host->in_bus_reset = 0; host->is_root = isroot; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ieee1394/nodemgr.c linux-2.5/drivers/ieee1394/nodemgr.c --- linux-2.5.1/drivers/ieee1394/nodemgr.c Wed Oct 17 21:19:20 2001 +++ linux-2.5/drivers/ieee1394/nodemgr.c Thu Dec 13 16:32:35 2001 @@ -359,7 +359,7 @@ kfree(buf); kfree(envp); if (value != 0) - HPSB_DEBUG("NodeMgr: hotplug policy returned 0x%x", value); + HPSB_DEBUG("NodeMgr: hotplug policy returned %d", value); } #else @@ -369,9 +369,8 @@ { #ifdef CONFIG_IEEE1394_VERBOSEDEBUG HPSB_DEBUG("NodeMgr: nodemgr_call_policy(): hotplug not enabled"); -#else - return; #endif + return; } #endif /* CONFIG_HOTPLUG */ @@ -582,13 +581,13 @@ struct hpsb_host *host, nodeid_t nodeid) { struct list_head *lh; + struct unit_directory *ud; - if (ne->nodeid != nodeid) + if (ne->nodeid != nodeid) { HPSB_DEBUG("Node " NODE_BUS_FMT " changed to " NODE_BUS_FMT, NODE_BUS_ARGS(ne->nodeid), NODE_BUS_ARGS(nodeid)); - - ne->host = host; - ne->nodeid = nodeid; + ne->nodeid = nodeid; + } if (ne->busopt.generation != ((busoptions >> 4) & 0xf)) nodemgr_process_config_rom (ne, busoptions); @@ -597,8 +596,6 @@ atomic_set(&ne->generation, get_hpsb_generation(ne->host)); list_for_each (lh, &ne->unit_directories) { - struct unit_directory *ud; - ud = list_entry (lh, struct unit_directory, node_list); if (ud->driver != NULL && ud->driver->update != NULL) ud->driver->update(ud); @@ -679,57 +676,76 @@ return; } +/* Used to schedule each nodes config rom probe */ +struct node_probe_task { + nodeid_t nodeid; + struct hpsb_host *host; + atomic_t *count; + struct tq_struct task; +}; + /* This is where we probe the nodes for their information and provided * features. */ -static void nodemgr_node_probe(void *data) +static void nodemgr_node_probe_one(void *__npt) { - struct hpsb_host *host = (struct hpsb_host *)data; - struct selfid *sid = (struct selfid *)host->topology_map; - struct list_head *lh, *next; + struct node_probe_task *npt = (struct node_probe_task *)__npt; struct node_entry *ne; - int nodecount = host->node_count; - nodeid_t nodeid = LOCAL_BUS; quadlet_t buffer[5]; octlet_t guid; - unsigned long flags; /* We need to detect when the ConfigROM's generation has changed, * so we only update the node's info when it needs to be. */ - for (; nodecount; nodecount--, nodeid++, sid++) { - /* Skip extended, and non-active node's */ - while (sid->extended) - sid++; - if (!sid->link_active) - continue; - if (read_businfo_block (host, nodeid, buffer, sizeof(buffer) >> 2)) - continue; + if (read_businfo_block (npt->host, npt->nodeid, buffer, sizeof(buffer) >> 2)) + goto probe_complete; - if (buffer[1] != IEEE1394_BUSID_MAGIC) { - /* This isn't a 1394 device */ - HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device", - NODE_BUS_ARGS(nodeid)); - continue; - } + if (buffer[1] != IEEE1394_BUSID_MAGIC) { + /* This isn't a 1394 device */ + HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device", + NODE_BUS_ARGS(npt->nodeid)); + goto probe_complete; + } + + guid = ((u64)buffer[3] << 32) | buffer[4]; + ne = hpsb_guid_get_entry(guid); + + if (!ne) + nodemgr_create_node(guid, buffer[2], npt->host, npt->nodeid); + else + nodemgr_update_node(ne, buffer[2], npt->host, npt->nodeid); + +probe_complete: + atomic_dec(npt->count); + + kfree(npt); + + return; +} - guid = ((u64)buffer[3] << 32) | buffer[4]; - ne = hpsb_guid_get_entry(guid); +static void nodemgr_node_probe_cleanup(void *__npt) +{ + struct node_probe_task *npt = (struct node_probe_task *)__npt; + unsigned long flags; + struct list_head *lh, *next; + struct node_entry *ne; + + /* If things aren't done yet, reschedule ourselves. */ + if (atomic_read(npt->count)) { + schedule_task(&npt->task); + return; + } - if (!ne) - nodemgr_create_node(guid, buffer[2], host, nodeid); - else - nodemgr_update_node(ne, buffer[2], host, nodeid); - } + kfree(npt->count); /* Now check to see if we have any nodes that aren't referenced * any longer. */ - write_lock_irqsave(&node_lock, flags); + write_lock_irqsave(&node_lock, flags); for (lh = node_list.next; lh != &node_list; lh = next) { ne = list_entry(lh, struct node_entry, list); next = lh->next; /* Only checking this host */ - if (ne->host != host) + if (ne->host != npt->host) continue; /* If the generation didn't get updated, then either the @@ -741,9 +757,70 @@ } write_unlock_irqrestore(&node_lock, flags); + kfree(npt); + return; } +static void nodemgr_node_probe(void *__host) +{ + struct hpsb_host *host = (struct hpsb_host *)__host; + int nodecount = host->node_count; + struct selfid *sid = (struct selfid *)host->topology_map; + nodeid_t nodeid = LOCAL_BUS; + struct node_probe_task *npt; + atomic_t *count; + + count = kmalloc(sizeof (*count), GFP_KERNEL); + + if (count == NULL) { + HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe"); + return; + } + + atomic_set(count, 0); + + for (; nodecount; nodecount--, nodeid++, sid++) { + while (sid->extended) + sid++; + if (!sid->link_active || nodeid == host->node_id) + continue; + + npt = kmalloc(sizeof (*npt), GFP_KERNEL); + + if (npt == NULL) { + HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe"); + break; + } + + INIT_TQUEUE(&npt->task, nodemgr_node_probe_one, npt); + npt->host = host; + npt->nodeid = nodeid; + npt->count = count; + + atomic_inc(count); + + schedule_task(&npt->task); + } + + /* Now schedule a task to clean things up after the node probes + * are done. */ + npt = kmalloc (sizeof (*npt), GFP_KERNEL); + + if (npt == NULL) { + HPSB_ERR ("NodeMgr: out of memory in nodemgr_node_probe"); + return; + } + + INIT_TQUEUE(&npt->task, nodemgr_node_probe_cleanup, npt); + npt->host = host; + npt->nodeid = 0; + npt->count = count; + + schedule_task(&npt->task); + + return; +} struct node_entry *hpsb_guid_get_entry(u64 guid) { @@ -864,7 +941,7 @@ write_unlock_irqrestore(&node_lock, flags); spin_lock_irqsave (&host_info_lock, flags); - list_for_each(lh, &host_info_list) { + list_for_each_safe(lh, next, &host_info_list) { struct host_info *hi = list_entry(lh, struct host_info, list); if (hi->host == host) { list_del(&hi->list); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ieee1394/ohci1394.c linux-2.5/drivers/ieee1394/ohci1394.c --- linux-2.5.1/drivers/ieee1394/ohci1394.c Tue Oct 2 04:24:24 2001 +++ linux-2.5/drivers/ieee1394/ohci1394.c Sun Dec 30 21:17:30 2001 @@ -99,23 +99,18 @@ #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/vmalloc.h> #include <linux/init.h> #ifdef CONFIG_ALL_PPC -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #include <asm/prom.h> #include <asm/pci-bridge.h> #endif -/* Revert to old bus reset algorithm that works on my Pismo until - * the new one is fixed - */ -#undef BUSRESET_WORKAROUND - #include "ieee1394.h" #include "ieee1394_types.h" #include "hosts.h" @@ -175,7 +170,7 @@ MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); static char version[] __devinitdata = - "v0.51 08/08/01 Ben Collins <bcollins@debian.org>"; + "$Revision: 1.80 $ Ben Collins <bcollins@debian.org>"; /* Module Parameters */ MODULE_PARM(attempt_root,"i"); @@ -516,12 +511,9 @@ /* After enabling LPS, we need to wait for the connection * between phy and link to be established. This should be * signaled by the LPS bit becoming 1, but this happens - * immediately. Instead we wait for reads from LinkControl to - * give a valid result, i.e. not 0xffffffff. */ - while (reg_read(ohci, OHCI1394_LinkControlSet) == 0xffffffff) { - DBGMSG(ohci->id, "waiting for phy-link connection"); - mdelay(2); - } + * immediately. There seems to be no consistent way to wait + * for this, but 50ms seems to be enough. */ + mdelay(50); /* Set the bus number */ reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); @@ -1131,11 +1123,7 @@ * selfIDComplete interrupt. */ spin_lock_irqsave(&ohci->event_lock, flags); event = reg_read(ohci, OHCI1394_IntEventClear); -#ifdef BUSRESET_WORKAROUND - reg_write(ohci, OHCI1394_IntEventClear, event); -#else reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset); -#endif spin_unlock_irqrestore(&ohci->event_lock, flags); if (!event) return; @@ -1154,11 +1142,17 @@ * selfID phase, so we disable busReset interrupts, to * avoid burying the cpu in interrupt requests. */ spin_lock_irqsave(&ohci->event_lock, flags); -#ifdef BUSRESET_WORKAROUND - reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); -#else reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset); -#endif + if (ohci->dev->vendor == PCI_VENDOR_ID_APPLE && + ohci->dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { + udelay(10); + while(reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) { + reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); + spin_unlock_irqrestore(&ohci->event_lock, flags); + udelay(10); + spin_lock_irqsave(&ohci->event_lock, flags); + } + } spin_unlock_irqrestore(&ohci->event_lock, flags); if (!host->in_bus_reset) { DBGMSG(ohci->id, "irq_handler: Bus reset requested%s", @@ -1309,12 +1303,10 @@ /* Finally, we clear the busReset event and reenable * the busReset interrupt. */ -#ifndef BUSRESET_WORKAROUND spin_lock_irqsave(&ohci->event_lock, flags); reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); spin_unlock_irqrestore(&ohci->event_lock, flags); -#endif event &= ~OHCI1394_selfIDComplete; } @@ -1966,8 +1958,6 @@ cf_put_keyval(&cr, 0x03, 0x00005e); /* Vendor ID */ cf_put_refer(&cr, 0x81, 2); /* Textual description unit */ cf_put_keyval(&cr, 0x0c, 0x0083c0); /* Node capabilities */ - cf_put_refer(&cr, 0xd1, 3); /* IPv4 unit directory */ - cf_put_refer(&cr, 0xd1, 4); /* IPv6 unit directory */ /* NOTE: Add other unit referers here, and append at bottom */ cf_unit_end(&cr); @@ -1980,46 +1970,6 @@ cf_put_4bytes(&cr, '9', '4', 0x0, 0x0); cf_unit_end(&cr); - /* IPv4 unit directory, RFC 2734 */ - cf_unit_begin(&cr, 3); - cf_put_keyval(&cr, 0x12, 0x00005e); /* Unit spec ID */ - cf_put_refer(&cr, 0x81, 6); /* Textual description unit */ - cf_put_keyval(&cr, 0x13, 0x000001); /* Unit software version */ - cf_put_refer(&cr, 0x81, 7); /* Textual description unit */ - cf_unit_end(&cr); - - cf_unit_begin(&cr, 6); - cf_put_keyval(&cr, 0, 0); - cf_put_1quad(&cr, 0); - cf_put_4bytes(&cr, 'I', 'A', 'N', 'A'); - cf_unit_end(&cr); - - cf_unit_begin(&cr, 7); - cf_put_keyval(&cr, 0, 0); - cf_put_1quad(&cr, 0); - cf_put_4bytes(&cr, 'I', 'P', 'v', '4'); - cf_unit_end(&cr); - - /* IPv6 unit directory, draft-ietf-ipngwg-1394-01.txt */ - cf_unit_begin(&cr, 4); - cf_put_keyval(&cr, 0x12, 0x00005e); /* Unit spec ID */ - cf_put_refer(&cr, 0x81, 8); /* Textual description unit */ - cf_put_keyval(&cr, 0x13, 0x000002); /* (Proposed) Unit software version */ - cf_put_refer(&cr, 0x81, 9); /* Textual description unit */ - cf_unit_end(&cr); - - cf_unit_begin(&cr, 8); - cf_put_keyval(&cr, 0, 0); - cf_put_1quad(&cr, 0); - cf_put_4bytes(&cr, 'I', 'A', 'N', 'A'); - cf_unit_end(&cr); - - cf_unit_begin(&cr, 9); - cf_put_keyval(&cr, 0, 0); - cf_put_1quad(&cr, 0); - cf_put_4bytes(&cr, 'I', 'P', 'v', '6'); - cf_unit_end(&cr); - ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu; } @@ -2309,8 +2259,8 @@ of_node = pci_device_to_OF_node(ohci->dev); if (of_node) { - feature_set_firewire_power(of_node, 0); - feature_set_firewire_cable_power(of_node, 0); + pmac_call_feature(PMAC_FTR_1394_ENABLE, of_node, 0, 0); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, of_node, 0, 0); } } #endif /* CONFIG_ALL_PPC */ @@ -2423,7 +2373,7 @@ name: OHCI1394_DRIVER_NAME, id_table: ohci1394_pci_tbl, probe: ohci1394_add_one, - remove: ohci1394_remove_one, + remove: __devexit_p(ohci1394_remove_one), }; static void __exit ohci1394_cleanup (void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ieee1394/pcilynx.c linux-2.5/drivers/ieee1394/pcilynx.c --- linux-2.5.1/drivers/ieee1394/pcilynx.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/drivers/ieee1394/pcilynx.c Mon Jan 7 20:48:20 2002 @@ -794,7 +794,7 @@ static int mem_open(struct inode *inode, struct file *file) { - int cid = MINOR(inode->i_rdev); + int cid = minor(inode->i_rdev); enum { t_rom, t_aux, t_ram } type; struct memdata *md; @@ -1637,8 +1637,8 @@ static void __exit pcilynx_cleanup(void) { - pci_unregister_driver(&lynx_pcidriver); hpsb_unregister_lowlevel(&lynx_template); + pci_unregister_driver(&lynx_pcidriver); PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module"); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ieee1394/raw1394.c linux-2.5/drivers/ieee1394/raw1394.c --- linux-2.5.1/drivers/ieee1394/raw1394.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/ieee1394/raw1394.c Mon Jan 7 20:51:38 2002 @@ -915,7 +915,7 @@ { struct file_info *fi; - if (MINOR(inode->i_rdev)) { + if (minor(inode->i_rdev)) { return -ENXIO; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ieee1394/sbp2.c linux-2.5/drivers/ieee1394/sbp2.c --- linux-2.5.1/drivers/ieee1394/sbp2.c Wed Oct 17 21:19:20 2001 +++ linux-2.5/drivers/ieee1394/sbp2.c Mon Jan 14 13:39:58 2002 @@ -222,8 +222,25 @@ * when we register our driver. This change * automtically adds hotplug support to the driver. * Kristian Hogsberg <hogsberg@users.sf.net> + * + * 11/17/01 - Various bugfixes/cleanups: + * * Remember to logout of device in sbp2_disconnect. + * * If we fail to reconnect to a device after bus reset + * remember to release unit directory, so the ieee1394 + * knows we no longer manage it. + * * Unregister scsi hosts in sbp2_remove_host when a + * hpsb_host goes away. + * * Remove stupid hack in sbp2_remove_host. + * * Switched to "manual" module initialization + * (i.e. not scsi_module.c) and moved sbp2_cleanup + * moved sbp2scsi_release to sbp2_module_ext. The + * release function is called once pr. registered + * scsi host, but sbp2_cleanup should only be called + * upon module unload. Moved much initialization + * from sbp2scsi_detect to sbp2_module_init. + * Kristian Hogsberg <hogsberg@users.sf.net> */ - + /* @@ -244,6 +261,7 @@ #include <linux/proc_fs.h> #include <linux/blk.h> #include <linux/smp_lock.h> +#include <linux/init.h> #include <asm/current.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -395,7 +413,7 @@ * Globals */ -Scsi_Host_Template *global_scsi_tpnt = NULL; +static Scsi_Host_Template scsi_driver_template; static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 }; @@ -671,13 +689,13 @@ static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id, struct sbp2scsi_host_info *hi) { - struct list_head *lh; + struct list_head *lh, *next; struct sbp2_command_info *command; unsigned long flags; sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags); if (!list_empty(&scsi_id->sbp2_command_orb_completed)) { - list_for_each(lh, &scsi_id->sbp2_command_orb_completed) { + list_for_each_safe(lh, next, &scsi_id->sbp2_command_orb_completed) { command = list_entry(lh, struct sbp2_command_info, list); /* Release our generic DMA's */ @@ -868,7 +886,6 @@ hpsb_unregister_highlevel(sbp2_hl_handle); sbp2_hl_handle = NULL; } - return; } static int sbp2_probe(struct unit_directory *ud) @@ -889,8 +906,10 @@ SBP2_DEBUG("sbp2_disconnect"); hi = sbp2_find_host_info(ud->ne->host); - if (hi != NULL) - sbp2_remove_device(hi, scsi_id); + if (hi != NULL) { + sbp2_logout_device(hi, scsi_id); + sbp2_remove_device(hi, scsi_id); + } } static void sbp2_update(struct unit_directory *ud) @@ -909,12 +928,10 @@ */ if (sbp2_login_device(hi, scsi_id)) { - /* Login failed too... so, just mark him as - * unvalidated, so that he gets cleaned up - * later. - */ + /* Login failed too, just remove the device. */ SBP2_ERR("sbp2_reconnect_device failed!"); sbp2_remove_device(hi, scsi_id); + hpsb_release_unit_directory(ud); return; } } @@ -978,7 +995,10 @@ sbp2_spin_unlock(&sbp2_host_info_lock, flags); /* Register our host with the SCSI stack. */ - sbp2scsi_register_scsi_host(hi); + hi->scsi_host = scsi_register (&scsi_driver_template, sizeof(void *)); + if (hi->scsi_host) + hi->scsi_host->hostdata[0] = (unsigned long)hi; + scsi_driver_template.present++; return; } @@ -1003,13 +1023,12 @@ } /* - * This function is called when the host is removed + * This function is called when a host is removed. */ static void sbp2_remove_host(struct hpsb_host *host) { struct sbp2scsi_host_info *hi; unsigned long flags; - int i; SBP2_DEBUG("sbp2_remove_host"); @@ -1017,22 +1036,11 @@ hi = sbp2_find_host_info(host); if (hi != NULL) { - /* Here's an annoying hack: we get a disconnect - * callback for each device, so this loop shouldn't be - * necessary. However, the sbp2 driver receives the - * remove_host callback before the nodemgr, so when we - * get the disconnect callback, we've already freed - * the host. Thus, we free the devices here... - */ - for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) { - if (hi->scsi_id[i] != NULL) { - sbp2_logout_device(hi, hi->scsi_id[i]); - sbp2_remove_device(hi, hi->scsi_id[i]); - } - } sbp2util_remove_request_packet_pool(hi); sbp2_host_count--; list_del(&hi->list); + scsi_unregister(hi->scsi_host); + scsi_driver_template.present--; kfree(hi); } else @@ -1203,10 +1211,7 @@ */ if (sbp2_login_device(hi, scsi_id)) { - /* - * Login failed... so, just mark him as unvalidated, so - * that he gets cleaned up later. - */ + /* Login failed, just remove the device. */ SBP2_ERR("sbp2_login_device failed"); sbp2_remove_device(hi, scsi_id); return -EBUSY; @@ -1231,11 +1236,13 @@ } /* - * This function removes (cleans-up after) any unvalidated sbp2 devices + * This function removes an sbp2 device from the sbp2scsi_host_info struct. */ static void sbp2_remove_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) { + SBP2_DEBUG("sbp2_remove_device"); + /* Complete any pending commands with selection timeout */ sbp2scsi_complete_all_commands(hi, scsi_id, DID_NO_CONNECT); @@ -1276,8 +1283,7 @@ SBP2_DMA_FREE("single logout orb"); } - SBP2_DEBUG("Unvalidated SBP-2 device removed, SCSI ID = %d", - scsi_id->id); + SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id); hi->scsi_id[scsi_id->id] = NULL; kfree(scsi_id); } @@ -1381,7 +1387,7 @@ /* * Check status - */ + */ if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) || STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) || STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) { @@ -1687,9 +1693,9 @@ scsi_id->max_payload_size = min(sbp2_speedto_maxrec[scsi_id->speed_code], (u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1)); - SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [0x%02x/%u]", + SBP2_ERR("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]", NODE_BUS_ARGS(scsi_id->ne->nodeid), hpsb_speedto_str[scsi_id->speed_code], - scsi_id->max_payload_size, 1 << ((u32)scsi_id->max_payload_size + 2)); + 1 << ((u32)scsi_id->max_payload_size + 2)); return(0); } @@ -2860,127 +2866,111 @@ return(0); } -/* - * This routine is called at setup (init) and does nothing. Not used here. =) - */ -void sbp2scsi_setup( char *str, int *ints) -{ - SBP2_DEBUG("sbp2scsi_setup"); - return; -} - -/* - * This is our detection routine, and is where we init everything. - */ static int sbp2scsi_detect (Scsi_Host_Template *tpnt) { SBP2_DEBUG("sbp2scsi_detect"); - global_scsi_tpnt = tpnt; + /* + * Call sbp2_init to register with the ieee1394 stack. This + * results in a callback to sbp2_add_host for each ieee1394 + * host controller currently registered, and for each of those + * we register a scsi host with the scsi stack. + */ + sbp2_init(); + + /* We return the number of hosts registered. */ + return sbp2_host_count; +} + +MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>"); +MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver"); +MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME); +MODULE_LICENSE("GPL"); + +/* SCSI host template */ +static Scsi_Host_Template scsi_driver_template = { + name: "IEEE-1394 SBP-2 protocol driver", + detect: sbp2scsi_detect, + queuecommand: sbp2scsi_queuecommand, + abort: sbp2scsi_abort, + reset: sbp2scsi_reset, + bios_param: sbp2scsi_biosparam, + can_queue: SBP2SCSI_MAX_OUTSTANDING_CMDS, + this_id: -1, + sg_tablesize: SBP2_MAX_SG_ELEMENTS, + cmd_per_lun: SBP2SCSI_MAX_CMDS_PER_LUN, + use_clustering: SBP2_CLUSTERING, + emulated: 1, + + module: THIS_MODULE, + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,26) - global_scsi_tpnt->proc_name = SBP2_DEVICE_NAME; + proc_name: SBP2_DEVICE_NAME #endif +}; + +static int sbp2_module_init(void) +{ + SBP2_DEBUG("sbp2_module_init"); + /* * Module load option for force one command at a time */ if (serialize_io) { SBP2_ERR("Driver forced to serialize I/O (serialize_io = 1)"); - global_scsi_tpnt->can_queue = 1; - global_scsi_tpnt->cmd_per_lun = 1; + scsi_driver_template.can_queue = 1; + scsi_driver_template.cmd_per_lun = 1; } /* - * Module load option to limit max size of requests from the scsi drivers + * Module load option to limit max size of requests from the + * scsi drivers */ if (no_large_packets) { - SBP2_ERR("Driver forced to limit max transfer size (no_large_packets = 1)"); - global_scsi_tpnt->sg_tablesize = 0x1f; - global_scsi_tpnt->use_clustering = DISABLE_CLUSTERING; + SBP2_ERR("Driver forced to limit max transfer size " + "(no_large_packets = 1)"); + scsi_driver_template.sg_tablesize = 0x1f; + scsi_driver_template.use_clustering = DISABLE_CLUSTERING; } if (mode_sense_hack) { SBP2_ERR("Mode sense emulation enabled (mode_sense_hack = 1)"); } - sbp2_init(); - - if (!sbp2_host_count) { - SBP2_ERR("Please load the lower level IEEE-1394 driver (e.g. ohci1394) before sbp2..."); + /* + * Ideally we would register our scsi_driver_template with the + * scsi stack and after that register with the ieee1394 stack + * and process the add_host callbacks. However, the detect + * function in the scsi host template requires that we find at + * least one host, so we "nest" the registrations by calling + * sbp2_init from the detect function. + */ + if (scsi_register_module(MODULE_SCSI_HA, &scsi_driver_template) || + !scsi_driver_template.present) { + SBP2_ERR("Please load the lower level IEEE-1394 driver " + "(e.g. ohci1394) before sbp2..."); sbp2_cleanup(); + return -ENODEV; } - /* - * Since we are returning this count, it means that sbp2 must be - * loaded "after" the host adapter module... - */ - return(sbp2_host_count); + return 0; } -/* - * This function is called from sbp2_add_host, and is where we register - * our scsi host - */ -static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi) +static void __exit sbp2_module_exit(void) { - struct Scsi_Host *shpnt = NULL; - - SBP2_DEBUG("sbp2scsi_register_scsi_host"); - SBP2_DEBUG("sbp2scsi_host_info = %p", hi); + SBP2_DEBUG("sbp2_module_exit"); /* - * Let's register with the scsi stack + * On module unload we unregister with the ieee1394 stack + * which results in remove_host callbacks for all ieee1394 + * host controllers. In the callbacks we unregister the + * corresponding scsi hosts. */ - if (global_scsi_tpnt) { - - shpnt = scsi_register (global_scsi_tpnt, sizeof(void *)); - - /* - * If successful, save off a context (to be used when SCSI - * commands are received) - */ - if (shpnt) { - shpnt->hostdata[0] = (unsigned long)hi; - } - } - - return; -} - -/* Called when our module is released */ -static int sbp2scsi_release(struct Scsi_Host *host) -{ - SBP2_DEBUG("sbp2scsi_release"); sbp2_cleanup(); - return(0); -} -/* Called for contents of procfs */ -static const char *sbp2scsi_info (struct Scsi_Host *host) -{ - return "IEEE-1394 SBP-2 protocol driver"; + if (scsi_unregister_module(MODULE_SCSI_HA, &scsi_driver_template)) + SBP2_ERR("sbp2_module_exit: couldn't unregister scsi driver"); } -MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>"); -MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver"); -MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME); -MODULE_LICENSE("GPL"); - -/* SCSI host template */ -static Scsi_Host_Template driver_template = { - name: "IEEE1394 SBP-2", - detect: sbp2scsi_detect, - release: sbp2scsi_release, - info: sbp2scsi_info, - queuecommand: sbp2scsi_queuecommand, - abort: sbp2scsi_abort, - reset: sbp2scsi_reset, - bios_param: sbp2scsi_biosparam, - can_queue: SBP2SCSI_MAX_OUTSTANDING_CMDS, - this_id: -1, - sg_tablesize: SBP2_MAX_SG_ELEMENTS, - cmd_per_lun: SBP2SCSI_MAX_CMDS_PER_LUN, - use_clustering: SBP2_CLUSTERING, - emulated: 1 -}; - -#include "../scsi/scsi_module.c" +module_init(sbp2_module_init); +module_exit(sbp2_module_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ieee1394/sbp2.h linux-2.5/drivers/ieee1394/sbp2.h --- linux-2.5.1/drivers/ieee1394/sbp2.h Wed Oct 17 21:19:20 2001 +++ linux-2.5/drivers/ieee1394/sbp2.h Sat Dec 29 00:52:33 2001 @@ -403,6 +403,13 @@ spinlock_t sbp2_request_packet_lock; /* + * This is the scsi host we register with the scsi mid level. + * We keep a reference to it here, so we can unregister it + * when the hpsb_host is removed. + */ + struct Scsi_Host *scsi_host; + + /* * Lists keeping track of inuse/free sbp2_request_packets. These structures are * used for sending out sbp2 command and agent reset packets. We initially create * a pool of request packets so that we don't have to do any kmallocs while in critical @@ -498,7 +505,6 @@ /* * Scsi interface related prototypes */ -static const char *sbp2scsi_info (struct Scsi_Host *host); static int sbp2scsi_detect (Scsi_Host_Template *tpnt); void sbp2scsi_setup(char *str, int *ints); static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]); @@ -509,6 +515,5 @@ u32 status); static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status, Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); -static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi); #endif /* SBP2_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ieee1394/video1394.c linux-2.5/drivers/ieee1394/video1394.c --- linux-2.5.1/drivers/ieee1394/video1394.c Tue Oct 2 04:24:25 2001 +++ linux-2.5/drivers/ieee1394/video1394.c Mon Jan 7 20:49:52 2002 @@ -43,10 +43,11 @@ #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/vmalloc.h> +#include <linux/timex.h> +#include <linux/mm.h> #include "ieee1394.h" #include "ieee1394_types.h" @@ -95,6 +96,7 @@ struct dma_cmd **ir_prg; struct it_dma_prg **it_prg; unsigned int *buffer_status; + struct timeval *buffer_time; /* time when the buffer was received */ unsigned int *last_used_cmd; /* For ISO Transmit with variable sized packets only ! */ int ctrlClear; @@ -102,8 +104,8 @@ int cmdPtr; int ctxMatch; wait_queue_head_t waitq; - spinlock_t lock; - unsigned int syt_offset; + spinlock_t lock; + unsigned int syt_offset; int flags; }; @@ -304,6 +306,8 @@ if ((*d)->buffer_status) kfree((*d)->buffer_status); + if ((*d)->buffer_time) + kfree((*d)->buffer_time); if ((*d)->last_used_cmd) kfree((*d)->last_used_cmd); if ((*d)->next_buffer) @@ -437,6 +441,8 @@ d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int), GFP_KERNEL); + d->buffer_time = kmalloc(d->num_desc * sizeof(struct timeval), + GFP_KERNEL); d->last_used_cmd = kmalloc(d->num_desc * sizeof(unsigned int), GFP_KERNEL); d->next_buffer = kmalloc(d->num_desc * sizeof(int), @@ -447,6 +453,11 @@ free_dma_iso_ctx(&d); return NULL; } + if (d->buffer_time == NULL) { + PRINT(KERN_ERR, ohci->id, "Failed to allocate buffer_time"); + free_dma_iso_ctx(&d); + return NULL; + } if (d->last_used_cmd == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate last_used_cmd"); free_dma_iso_ctx(&d); @@ -458,6 +469,7 @@ return NULL; } memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int)); + memset(d->buffer_time, 0, d->num_desc * sizeof(struct timeval)); memset(d->last_used_cmd, 0, d->num_desc * sizeof(unsigned int)); memset(d->next_buffer, -1, d->num_desc * sizeof(int)); @@ -604,6 +616,7 @@ if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) { reset_ir_status(d, i); d->buffer_status[i] = VIDEO1394_BUFFER_READY; + get_fast_time(&d->buffer_time[i]); } } spin_unlock(&d->lock); @@ -851,7 +864,7 @@ struct video_card *p; list_for_each(lh, &video1394_cards) { p = list_entry(lh, struct video_card, list); - if (p->id == MINOR(inode->i_rdev)) { + if (p->id == minor(inode->i_rdev)) { video = p; ohci = video->ohci; break; @@ -861,7 +874,7 @@ spin_unlock_irqrestore(&video1394_cards_lock, flags); if (video == NULL) { - PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d", MINOR(inode->i_rdev)); + PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d", minor(inode->i_rdev)); return -EFAULT; } @@ -876,9 +889,23 @@ if(copy_from_user(&v, (void *)arg, sizeof(v))) return -EFAULT; + + /* if channel < 0, find lowest available one */ + if (v.channel < 0) { + mask = (u64)0x1; + for (i=0; i<ISO_CHANNELS; i++) { + if (!(ohci->ISO_channel_usage & mask)) { + v.channel = i; + PRINT(KERN_INFO, ohci->id, "Found free channel %d\n", i); + break; + } + mask = mask << 1; + } + } + if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) { PRINT(KERN_ERR, ohci->id, - "Iso channel %d out of bound", v.channel); + "Iso channel %d out of bounds", v.channel); return -EFAULT; } mask = (u64)0x1<<v.channel; @@ -1092,6 +1119,7 @@ } case VIDEO1394_LISTEN_WAIT_BUFFER: + case VIDEO1394_LISTEN_POLL_BUFFER: { struct video1394_wait v; struct dma_iso_ctx *d; @@ -1120,6 +1148,12 @@ d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; break; case VIDEO1394_BUFFER_QUEUED: + if (cmd == VIDEO1394_LISTEN_POLL_BUFFER) { + /* for polling, return error code EINTR */ + spin_unlock_irqrestore(&d->lock, flags); + return -EINTR; + } + #if 1 while(d->buffer_status[v.buffer]!= VIDEO1394_BUFFER_READY) { @@ -1147,6 +1181,10 @@ return -EFAULT; } + /* set time of buffer */ + v.filltime = d->buffer_time[v.buffer]; +// printk("Buffer %d time %d\n", v.buffer, (d->buffer_time[v.buffer]).tv_usec); + /* * Look ahead to see how many more buffers have been received */ @@ -1329,7 +1367,7 @@ struct video_card *p; list_for_each(lh, &video1394_cards) { p = list_entry(lh, struct video_card, list); - if (p->id == MINOR(file->f_dentry->d_inode->i_rdev)) { + if (p->id == minor(file->f_dentry->d_inode->i_rdev)) { video = p; break; } @@ -1339,7 +1377,7 @@ if (video == NULL) { PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d", - MINOR(file->f_dentry->d_inode->i_rdev)); + minor(file->f_dentry->d_inode->i_rdev)); return -EFAULT; } @@ -1358,7 +1396,7 @@ static int video1394_open(struct inode *inode, struct file *file) { - int i = MINOR(inode->i_rdev); + int i = minor(inode->i_rdev); unsigned long flags; struct video_card *video = NULL; struct list_head *lh; @@ -1398,7 +1436,7 @@ struct video_card *p; list_for_each(lh, &video1394_cards) { p = list_entry(lh, struct video_card, list); - if (p->id == MINOR(inode->i_rdev)) { + if (p->id == minor(inode->i_rdev)) { video = p; break; } @@ -1408,7 +1446,7 @@ if (video == NULL) { PRINT_G(KERN_ERR, __FUNCTION__": Unknown device for minor %d", - MINOR(inode->i_rdev)); + minor(inode->i_rdev)); return 1; } @@ -1596,7 +1634,8 @@ { struct ti_ohci *ohci; unsigned long flags; - struct list_head *lh; + struct list_head *lh, *next; + struct video_card *p; /* We only work with the OHCI-1394 driver */ if (strcmp(host->template->name, OHCI1394_DRIVER_NAME)) @@ -1605,14 +1644,11 @@ ohci = (struct ti_ohci *)host->hostdata; spin_lock_irqsave(&video1394_cards_lock, flags); - if (!list_empty(&video1394_cards)) { - struct video_card *p; - list_for_each(lh, &video1394_cards) { - p = list_entry(lh, struct video_card, list); - if (p ->ohci == ohci) { - remove_card(p); - break; - } + list_for_each_safe(lh, next, &video1394_cards) { + p = list_entry(lh, struct video_card, list); + if (p->ohci == ohci) { + remove_card(p); + break; } } spin_unlock_irqrestore(&video1394_cards_lock, flags); @@ -1652,7 +1688,7 @@ devfs_unregister(devfs_handle); devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME); - PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module\n"); + PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module"); } static int __init video1394_init_module (void) @@ -1678,6 +1714,7 @@ return -ENOMEM; } + PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module"); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/ieee1394/video1394.h linux-2.5/drivers/ieee1394/video1394.h --- linux-2.5.1/drivers/ieee1394/video1394.h Sun Aug 12 19:39:02 2001 +++ linux-2.5/drivers/ieee1394/video1394.h Thu Dec 13 16:32:35 2001 @@ -35,11 +35,12 @@ VIDEO1394_LISTEN_CHANNEL = 0, VIDEO1394_UNLISTEN_CHANNEL, VIDEO1394_LISTEN_QUEUE_BUFFER, - VIDEO1394_LISTEN_WAIT_BUFFER, + VIDEO1394_LISTEN_WAIT_BUFFER, // wait until buffer is ready VIDEO1394_TALK_CHANNEL, VIDEO1394_UNTALK_CHANNEL, VIDEO1394_TALK_QUEUE_BUFFER, - VIDEO1394_TALK_WAIT_BUFFER + VIDEO1394_TALK_WAIT_BUFFER, + VIDEO1394_LISTEN_POLL_BUFFER // return immediately with -EINTR if not ready }; #define VIDEO1394_SYNC_FRAMES 0x00000001 @@ -47,7 +48,7 @@ #define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004 struct video1394_mmap { - unsigned int channel; + int channel; /* -1 to find an open channel in LISTEN/TALK */ unsigned int sync_tag; unsigned int nb_buffers; unsigned int buf_size; @@ -69,6 +70,7 @@ struct video1394_wait { unsigned int channel; unsigned int buffer; + struct timeval filltime; /* time of buffer full */ }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/input/evdev.c linux-2.5/drivers/input/evdev.c --- linux-2.5.1/drivers/input/evdev.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/input/evdev.c Wed Jan 2 17:23:52 2002 @@ -119,7 +119,7 @@ static int evdev_open(struct inode * inode, struct file * file) { struct evdev_list *list; - int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE; + int i = minor(inode->i_rdev) - EVDEV_MINOR_BASE; if (i >= EVDEV_MINORS || !evdev_table[i]) return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/input/input.c linux-2.5/drivers/input/input.c --- linux-2.5.1/drivers/input/input.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/input/input.c Wed Jan 2 17:23:52 2002 @@ -368,7 +368,7 @@ static int input_open_file(struct inode *inode, struct file *file) { - struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5]; + struct input_handler *handler = input_table[minor(inode->i_rdev) >> 5]; struct file_operations *old_fops, *new_fops = NULL; int err; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/input/joydev.c linux-2.5/drivers/input/joydev.c --- linux-2.5.1/drivers/input/joydev.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/input/joydev.c Wed Jan 2 17:23:52 2002 @@ -31,7 +31,6 @@ #include <asm/io.h> #include <asm/system.h> -#include <asm/segment.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/joystick.h> @@ -190,7 +189,7 @@ static int joydev_open(struct inode *inode, struct file *file) { struct joydev_list *list; - int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE; + int i = minor(inode->i_rdev) - JOYDEV_MINOR_BASE; if (i >= JOYDEV_MINORS || !joydev_table[i]) return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/input/mousedev.c linux-2.5/drivers/input/mousedev.c --- linux-2.5.1/drivers/input/mousedev.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/input/mousedev.c Wed Jan 2 17:23:52 2002 @@ -214,7 +214,7 @@ static int mousedev_open(struct inode * inode, struct file * file) { struct mousedev_list *list; - int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE; + int i = minor(inode->i_rdev) - MOUSEDEV_MINOR_BASE; if (i >= MOUSEDEV_MINORS || !mousedev_table[i]) return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/Config.in linux-2.5/drivers/isdn/Config.in --- linux-2.5.1/drivers/isdn/Config.in Fri Nov 30 17:48:32 2001 +++ linux-2.5/drivers/isdn/Config.in Thu Jan 3 22:26:39 2002 @@ -42,6 +42,7 @@ fi bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6 bool ' HiSax Support for US NI1' CONFIG_HISAX_NI1 + int ' Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8 comment ' HiSax supported cards' bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0 bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3 @@ -81,7 +82,7 @@ dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL - dep_tristate 'Fritz!PCIv2 support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL + dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL fi endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/act2000/act2000.h linux-2.5/drivers/isdn/act2000/act2000.h --- linux-2.5.1/drivers/isdn/act2000/act2000.h Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/act2000/act2000.h Mon Jan 7 20:52:48 2002 @@ -68,7 +68,6 @@ #include <linux/errno.h> #include <linux/fs.h> #include <linux/major.h> -#include <asm/segment.h> #include <asm/io.h> #include <linux/kernel.h> #include <linux/signal.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/avmcard.h linux-2.5/drivers/isdn/avmb1/avmcard.h --- linux-2.5.1/drivers/isdn/avmb1/avmcard.h Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/avmb1/avmcard.h Thu Jan 3 23:04:39 2002 @@ -1,4 +1,4 @@ -/* $Id: avmcard.h,v 1.8.6.4 2001/09/23 22:24:33 kai Exp $ +/* $Id: avmcard.h,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ * * Copyright 1999 by Carsten Paeth <calle@calle.de> * @@ -39,13 +39,21 @@ avm_c2 }; +typedef struct avmcard_dmabuf { + long size; + __u8 *dmabuf; + dma_addr_t dmaaddr; +} avmcard_dmabuf; + typedef struct avmcard_dmainfo { - __u32 recvlen; - __u8 recvbuf[128+2048]; - struct sk_buff_head send_queue; - __u8 sendbuf[128+2048]; -} avmcard_dmainfo; + __u32 recvlen; + avmcard_dmabuf recvbuf; + + avmcard_dmabuf sendbuf; + struct sk_buff_head send_queue; + struct pci_dev *pcidev; +} avmcard_dmainfo; typedef struct avmcard { char name[32]; @@ -543,6 +551,11 @@ int b1ctl_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl); + +avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *, + long rsize, long ssize); +void avmcard_dma_free(avmcard_dmainfo *); + /* b1dma.c */ int b1pciv4_detect(avmcard *card); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/b1.c linux-2.5/drivers/isdn/avmb1/b1.c --- linux-2.5.1/drivers/isdn/avmb1/b1.c Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/avmb1/b1.c Thu Jan 3 23:04:39 2002 @@ -1,4 +1,4 @@ -/* $Id: b1.c,v 1.20.6.7 2001/09/23 22:24:33 kai Exp $ +/* $Id: b1.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ * * Common module for AVM B1 cards. * @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/pci.h> #include <linux/skbuff.h> #include <linux/delay.h> #include <linux/mm.h> @@ -27,7 +28,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.20.6.7 $"; +static char *revision = "$Revision: 1.1.4.1.2.1 $"; /* ------------------------------------------------------------- */ @@ -638,6 +639,65 @@ } /* ------------------------------------------------------------- */ + +#ifdef CONFIG_PCI + +avmcard_dmainfo * +avmcard_dma_alloc(char *name, struct pci_dev *pdev, long rsize, long ssize) +{ + avmcard_dmainfo *p; + void *buf; + + p = kmalloc(sizeof(avmcard_dmainfo), GFP_KERNEL); + if (!p) { + printk(KERN_WARNING "%s: no memory.\n", name); + goto err; + } + memset(p, 0, sizeof(avmcard_dmainfo)); + + p->recvbuf.size = rsize; + buf = pci_alloc_consistent(pdev, rsize, &p->recvbuf.dmaaddr); + if (!buf) { + printk(KERN_WARNING "%s: allocation of receive dma buffer failed.\n", name); + goto err_kfree; + } + p->recvbuf.dmabuf = buf; + + p->sendbuf.size = ssize; + buf = pci_alloc_consistent(pdev, ssize, &p->sendbuf.dmaaddr); + if (!buf) { + printk(KERN_WARNING "%s: allocation of send dma buffer failed.\n", name); + goto err_free_consistent; + } + + p->sendbuf.dmabuf = buf; + skb_queue_head_init(&p->send_queue); + + return p; + + err_free_consistent: + pci_free_consistent(p->pcidev, p->recvbuf.size, + p->recvbuf.dmabuf, p->recvbuf.dmaaddr); + err_kfree: + kfree(p); + err: + return 0; +} + +void avmcard_dma_free(avmcard_dmainfo *p) +{ + pci_free_consistent(p->pcidev, p->recvbuf.size, + p->recvbuf.dmabuf, p->recvbuf.dmaaddr); + pci_free_consistent(p->pcidev, p->sendbuf.size, + p->sendbuf.dmabuf, p->sendbuf.dmaaddr); + skb_queue_purge(&p->send_queue); + kfree(p); +} + +EXPORT_SYMBOL(avmcard_dma_alloc); +EXPORT_SYMBOL(avmcard_dma_free); + +#endif EXPORT_SYMBOL(b1_irq_table); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/b1dma.c linux-2.5/drivers/isdn/avmb1/b1dma.c --- linux-2.5.1/drivers/isdn/avmb1/b1dma.c Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/avmb1/b1dma.c Thu Jan 3 23:04:39 2002 @@ -1,4 +1,4 @@ -/* $Id: b1dma.c,v 1.11.6.8 2001/09/23 22:24:33 kai Exp $ +/* $Id: b1dma.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ * * Common module for AVM B1 cards that support dma with AMCC * @@ -32,7 +32,7 @@ #error FIXME: driver requires 32-bit platform #endif -static char *revision = "$Revision: 1.11.6.8 $"; +static char *revision = "$Revision: 1.1.4.1.2.1 $"; /* ------------------------------------------------------------- */ @@ -388,7 +388,7 @@ cmd = CAPIMSG_COMMAND(skb->data); subcmd = CAPIMSG_SUBCOMMAND(skb->data); - p = dma->sendbuf; + p = dma->sendbuf.dmabuf; if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { __u16 dlen = CAPIMSG_DATALEN(skb->data); @@ -399,7 +399,7 @@ _put_byte(&p, SEND_MESSAGE); _put_slice(&p, skb->data, len); } - txlen = (__u8 *)p - (__u8 *)dma->sendbuf; + txlen = (__u8 *)p - (__u8 *)dma->sendbuf.dmabuf; #ifdef CONFIG_B1DMA_DEBUG printk(KERN_DEBUG "tx(%d): put msg len=%d\n", inint, txlen); @@ -414,11 +414,11 @@ printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n", inint, skb->data[2], txlen); #endif - memcpy(dma->sendbuf, skb->data+2, skb->len-2); + memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2); } txlen = (txlen + 3) & ~3; - b1dmaoutmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf)); + b1dmaoutmeml(card->mbase+AMCC_TXPTR, dma->sendbuf.dmaaddr); b1dmaoutmeml(card->mbase+AMCC_TXLEN, txlen); card->csr |= EN_TX_TC_INT; @@ -461,7 +461,7 @@ avmcard_dmainfo *dma = card->dma; struct capi_ctr *ctrl = cinfo->capi_ctrl; struct sk_buff *skb; - void *p = dma->recvbuf+4; + void *p = dma->recvbuf.dmabuf+4; __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; __u8 b1cmd = _get_byte(&p); @@ -597,18 +597,19 @@ b1dmaoutmeml(card->mbase+AMCC_INTCSR, newcsr); if ((status & RX_TC_INT) != 0) { - __u8 *recvbuf = card->dma->recvbuf; + struct avmcard_dmainfo *dma = card->dma; __u32 rxlen; if (card->dma->recvlen == 0) { - card->dma->recvlen = *((__u32 *)recvbuf); - rxlen = (card->dma->recvlen + 3) & ~3; + dma->recvlen = *((__u32 *)dma->recvbuf.dmabuf); + rxlen = (dma->recvlen + 3) & ~3; b1dmaoutmeml(card->mbase+AMCC_RXPTR, - virt_to_phys(recvbuf+4)); + dma->recvbuf.dmaaddr+4); b1dmaoutmeml(card->mbase+AMCC_RXLEN, rxlen); } else { b1dma_handle_rx(card); - card->dma->recvlen = 0; - b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf)); + dma->recvlen = 0; + b1dmaoutmeml(card->mbase+AMCC_RXPTR, + dma->recvbuf.dmaaddr); b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4); } } @@ -744,7 +745,7 @@ t1outp(card->port, 0x10, 0xF0); card->dma->recvlen = 0; - b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf)); + b1dmaoutmeml(card->mbase+AMCC_RXPTR, card->dma->recvbuf.dmaaddr); b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4); card->csr |= EN_RX_TC_INT; b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); @@ -855,7 +856,7 @@ __u8 flag; int len = 0; char *s; - __u32 txaddr, txlen, rxaddr, rxlen, csr; + __u32 txoff, txlen, rxoff, rxlen, csr; len += sprintf(page+len, "%-16s %s\n", "name", card->name); len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); @@ -911,13 +912,11 @@ save_flags(flags); cli(); - txaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x2c)); - txaddr -= (__u32)card->dma->sendbuf; - txlen = b1dmainmeml(card->mbase+0x30); - - rxaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x24)); - rxaddr -= (__u32)card->dma->recvbuf; - rxlen = b1dmainmeml(card->mbase+0x28); + txoff = (dma_addr_t)b1dmainmeml(card->mbase+0x2c)-card->dma->sendbuf.dmaaddr; + txlen = b1dmainmeml(card->mbase+0x30); + + rxoff = (dma_addr_t)b1dmainmeml(card->mbase+0x24)-card->dma->recvbuf.dmaaddr; + rxlen = b1dmainmeml(card->mbase+0x28); csr = b1dmainmeml(card->mbase+AMCC_INTCSR); @@ -928,11 +927,11 @@ len += sprintf(page+len, "%-16s 0x%lx\n", "csr", (unsigned long)csr); len += sprintf(page+len, "%-16s %lu\n", - "txoff", (unsigned long)txaddr); + "txoff", (unsigned long)txoff); len += sprintf(page+len, "%-16s %lu\n", "txlen", (unsigned long)txlen); len += sprintf(page+len, "%-16s %lu\n", - "rxoff", (unsigned long)rxaddr); + "rxoff", (unsigned long)rxoff); len += sprintf(page+len, "%-16s %lu\n", "rxlen", (unsigned long)rxlen); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/b1pci.c linux-2.5/drivers/isdn/avmb1/b1pci.c --- linux-2.5.1/drivers/isdn/avmb1/b1pci.c Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/avmb1/b1pci.c Tue Jan 8 00:44:24 2002 @@ -1,4 +1,4 @@ -/* $Id: b1pci.c,v 1.29.6.5 2001/09/23 22:24:33 kai Exp $ +/* $Id: b1pci.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ * * Module for AVM B1 PCI-card. * @@ -26,11 +26,11 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.29.6.5 $"; +static char *revision = "$Revision: 1.1.4.1.2.1 $"; /* ------------------------------------------------------------- */ -static struct pci_device_id b1pci_pci_tbl[] __initdata = { +static struct pci_device_id b1pci_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID }, { } /* Terminating entry */ }; @@ -108,7 +108,9 @@ /* ------------------------------------------------------------- */ -static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) +static int b1pci_add_card(struct capi_driver *driver, + struct capicardparams *p, + struct pci_dev *dev) { avmcard *card; avmctrl_info *cinfo; @@ -237,7 +239,7 @@ release_region(card->port, AVMB1_PORTLEN); ctrl->driverdata = 0; kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; @@ -262,7 +264,9 @@ /* ------------------------------------------------------------- */ -static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p) +static int b1pciv4_add_card(struct capi_driver *driver, + struct capicardparams *p, + struct pci_dev *dev) { avmcard *card; avmctrl_info *cinfo; @@ -278,18 +282,17 @@ return -ENOMEM; } memset(card, 0, sizeof(avmcard)); - card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC); + card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128); if (!card->dma) { - printk(KERN_WARNING "%s: no memory.\n", driver->name); + printk(KERN_WARNING "%s: dma alloc.\n", driver->name); kfree(card); MOD_DEC_USE_COUNT; return -ENOMEM; } - memset(card->dma, 0, sizeof(avmcard_dmainfo)); cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC); if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -ENOMEM; @@ -308,7 +311,7 @@ "%s: ports 0x%03x-0x%03x in use.\n", driver->name, card->port, card->port + AVMB1_PORTLEN); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EBUSY; @@ -319,7 +322,7 @@ printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", driver->name, card->membase); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EIO; @@ -332,7 +335,7 @@ driver->name, card->port, retval); iounmap(card->mbase); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EIO; @@ -349,7 +352,7 @@ iounmap(card->mbase); release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EBUSY; @@ -362,15 +365,13 @@ free_irq(card->irq, card); release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EBUSY; } card->cardnr = cinfo->capi_ctrl->cnr; - skb_queue_head_init(&card->dma->send_queue); - printk(KERN_INFO "%s: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n", driver->name, card->port, card->irq, @@ -403,7 +404,8 @@ static int ncards = 0; -static int add_card(struct pci_dev *dev) +static int __devinit b1pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { struct capi_driver *driver = &b1pci_driver; struct capicardparams param; @@ -429,9 +431,9 @@ "%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n", driver->name, param.port, param.irq, param.membase); #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 - retval = b1pciv4_add_card(driver, ¶m); + retval = b1pciv4_add_card(driver, ¶m, dev); #else - retval = b1pci_add_card(driver, ¶m); + retval = b1pci_add_card(driver, ¶m, dev); #endif if (retval != 0) { printk(KERN_ERR @@ -445,7 +447,7 @@ printk(KERN_INFO "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", driver->name, param.port, param.irq); - retval = b1pci_add_card(driver, ¶m); + retval = b1pci_add_card(driver, ¶m, dev); if (retval != 0) { printk(KERN_ERR "%s: no AVM-B1 at i/o %#x, irq %d detected\n", @@ -455,13 +457,18 @@ return retval; } +static struct pci_driver b1pci_pci_driver = { + name: "b1pci", + id_table: b1pci_pci_tbl, + probe: b1pci_probe, +}; + static int __init b1pci_init(void) { struct capi_driver *driver = &b1pci_driver; #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 struct capi_driver *driverv4 = &b1pciv4_driver; #endif - struct pci_dev *dev = NULL; char *p; MOD_INC_USE_COUNT; @@ -504,10 +511,7 @@ } #endif - while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev))) { - if (add_card(dev) == 0) - ncards++; - } + ncards = pci_register_driver(&b1pci_pci_driver); if (ncards) { printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n", driver->name, ncards); @@ -515,6 +519,7 @@ return 0; } printk(KERN_ERR "%s: NO B1-PCI card detected\n", driver->name); + pci_unregister_driver(&b1pci_pci_driver); detach_capi_driver(driver); #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 detach_capi_driver(driverv4); @@ -525,9 +530,10 @@ static void __exit b1pci_exit(void) { - detach_capi_driver(&b1pci_driver); + pci_unregister_driver(&b1pci_pci_driver); + detach_capi_driver(&b1pci_driver); #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 - detach_capi_driver(&b1pciv4_driver); + detach_capi_driver(&b1pciv4_driver); #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/c4.c linux-2.5/drivers/isdn/avmb1/c4.c --- linux-2.5.1/drivers/isdn/avmb1/c4.c Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/avmb1/c4.c Tue Jan 8 00:44:24 2002 @@ -1,4 +1,4 @@ -/* $Id: c4.c,v 1.20.6.11 2001/09/23 22:24:33 kai Exp $ +/* $Id: c4.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ * * Module for AVM C4 & C2 card. * @@ -29,7 +29,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.20.6.11 $"; +static char *revision = "$Revision: 1.1.4.1.2.1 $"; #undef CONFIG_C4_DEBUG #undef CONFIG_C4_POLLDEBUG @@ -38,9 +38,9 @@ static int suppress_pollack; -static struct pci_device_id c4_pci_tbl[] __initdata = { - { PCI_VENDOR_ID_DEC,PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4 }, - { PCI_VENDOR_ID_DEC,PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2 }, +static struct pci_device_id c4_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, 4 }, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2, 2 }, { } /* Terminating entry */ }; @@ -439,7 +439,7 @@ cmd = CAPIMSG_COMMAND(skb->data); subcmd = CAPIMSG_SUBCOMMAND(skb->data); - p = dma->sendbuf; + p = dma->sendbuf.dmabuf; if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { __u16 dlen = CAPIMSG_DATALEN(skb->data); @@ -450,7 +450,7 @@ _put_byte(&p, SEND_MESSAGE); _put_slice(&p, skb->data, len); } - txlen = (__u8 *)p - (__u8 *)dma->sendbuf; + txlen = (__u8 *)p - (__u8 *)dma->sendbuf.dmabuf; #ifdef CONFIG_C4_DEBUG printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen); #endif @@ -464,11 +464,11 @@ printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n", card->name, skb->data[2], txlen); #endif - memcpy(dma->sendbuf, skb->data+2, skb->len-2); + memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2); } txlen = (txlen + 3) & ~3; - c4outmeml(card->mbase+MBOX_DOWN_ADDR, virt_to_phys(dma->sendbuf)); + c4outmeml(card->mbase+MBOX_DOWN_ADDR, dma->sendbuf.dmaaddr); c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen); card->csr |= DBELL_DOWN_ARM; @@ -510,7 +510,7 @@ struct capi_ctr *ctrl; avmctrl_info *cinfo; struct sk_buff *skb; - void *p = dma->recvbuf; + void *p = dma->recvbuf.dmabuf; __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; __u8 b1cmd = _get_byte(&p); __u32 cidx; @@ -702,7 +702,7 @@ c4outmeml(card->mbase+MBOX_UP_LEN, 0); c4_handle_rx(card); card->dma->recvlen = 0; - c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf)); + c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size); c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); } @@ -885,8 +885,8 @@ c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08); card->dma->recvlen = 0; - c4outmeml(card->mbase+MBOX_UP_ADDR, virt_to_phys(card->dma->recvbuf)); - c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf)); + c4outmeml(card->mbase+MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr); + c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size); c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); restore_flags(flags); @@ -944,7 +944,7 @@ release_region(card->port, AVMB1_PORTLEN); ctrl->driverdata = 0; kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; @@ -1123,6 +1123,7 @@ static int c4_add_card(struct capi_driver *driver, struct capicardparams *p, + struct pci_dev *dev, int nr) { avmctrl_info *cinfo; @@ -1140,18 +1141,17 @@ return -ENOMEM; } memset(card, 0, sizeof(avmcard)); - card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC); + card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128); if (!card->dma) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); MOD_DEC_USE_COUNT; return -ENOMEM; } - memset(card->dma, 0, sizeof(avmcard_dmainfo)); cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC); if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -ENOMEM; @@ -1173,7 +1173,7 @@ "%s: ports 0x%03x-0x%03x in use.\n", driver->name, card->port, card->port + AVMB1_PORTLEN); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EBUSY; @@ -1184,7 +1184,7 @@ printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", driver->name, card->membase); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EIO; @@ -1195,7 +1195,7 @@ driver->name, card->port, retval); iounmap(card->mbase); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EIO; @@ -1211,7 +1211,7 @@ iounmap(card->mbase); release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EBUSY; @@ -1231,7 +1231,7 @@ iounmap(card->mbase); free_irq(card->irq, card); release_region(card->port, AVMB1_PORTLEN); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card->ctrlinfo); kfree(card); MOD_DEC_USE_COUNT; @@ -1241,8 +1241,6 @@ card->cardnr = cinfo->capi_ctrl->cnr; } - skb_queue_head_init(&card->dma->send_queue); - printk(KERN_INFO "%s: AVM C%d at i/o %#x, irq %d, mem %#lx\n", driver->name, nr, card->port, card->irq, card->membase); @@ -1286,8 +1284,6 @@ add_card: 0, /* no add_card function */ }; -static int ncards = 0; - static int c4_attach_driver (struct capi_driver * driver) { char *p; @@ -1310,46 +1306,49 @@ return 0; } -static int __init search_cards(struct capi_driver * driver, - int pci_id, int nr) +static int __devinit c4_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - struct pci_dev * dev = NULL; - int retval = 0; + int nr = ent->driver_data; + struct capi_driver *driver = (nr == 2) ? &c2_driver : &c4_driver; + int retval = 0; + struct capicardparams param; + + if (pci_enable_device(dev) < 0) { + printk(KERN_ERR "%s: failed to enable AVM-C%d\n", + driver->name, nr); + return -ENODEV; + } + pci_set_master(dev); - while ((dev = pci_find_subsys( - PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, - PCI_VENDOR_ID_AVM, pci_id, dev))) { - struct capicardparams param; - - if (pci_enable_device(dev) < 0) { - printk(KERN_ERR "%s: failed to enable AVM-C%d\n", - driver->name, nr); - continue; - } - pci_set_master(dev); - - param.port = pci_resource_start(dev, 1); - param.irq = dev->irq; - param.membase = pci_resource_start(dev, 0); - - printk(KERN_INFO - "%s: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n", - driver->name, nr, param.port, param.irq, param.membase); - retval = c4_add_card(driver, ¶m, nr); - if (retval != 0) { - printk(KERN_ERR - "%s: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n", - driver->name, nr, param.port, param.irq, param.membase); - continue; - } - ncards++; + param.port = pci_resource_start(dev, 1); + param.irq = dev->irq; + param.membase = pci_resource_start(dev, 0); + + printk(KERN_INFO + "%s: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n", + driver->name, nr, param.port, param.irq, param.membase); + + retval = c4_add_card(driver, ¶m, dev, nr); + if (retval != 0) { + printk(KERN_ERR + "%s: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n", + driver->name, nr, param.port, param.irq, param.membase); + return -ENODEV; } - return retval; + return 0; } +static struct pci_driver c4_pci_driver = { + name: "c4", + id_table: c4_pci_tbl, + probe: c4_probe, +}; + static int __init c4_init(void) { int retval; + int ncards; MOD_INC_USE_COUNT; @@ -1365,21 +1364,7 @@ return retval; } - retval = search_cards(&c4_driver, PCI_DEVICE_ID_AVM_C4, 4); - if (retval && ncards == 0) { - detach_capi_driver(&c2_driver); - detach_capi_driver(&c4_driver); - MOD_DEC_USE_COUNT; - return retval; - } - retval = search_cards(&c2_driver, PCI_DEVICE_ID_AVM_C2, 2); - if (retval && ncards == 0) { - detach_capi_driver(&c2_driver); - detach_capi_driver(&c4_driver); - MOD_DEC_USE_COUNT; - return retval; - } - + ncards = pci_register_driver(&c4_pci_driver); if (ncards) { printk(KERN_INFO "%s: %d C4/C2 card(s) detected\n", c4_driver.name, ncards); @@ -1387,6 +1372,7 @@ return 0; } printk(KERN_ERR "%s: NO C4/C2 card detected\n", c4_driver.name); + pci_unregister_driver(&c4_pci_driver); detach_capi_driver(&c4_driver); detach_capi_driver(&c2_driver); MOD_DEC_USE_COUNT; @@ -1395,8 +1381,9 @@ static void __exit c4_exit(void) { - detach_capi_driver(&c2_driver); - detach_capi_driver(&c4_driver); + pci_unregister_driver(&c4_pci_driver); + detach_capi_driver(&c2_driver); + detach_capi_driver(&c4_driver); } module_init(c4_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/capi.c linux-2.5/drivers/isdn/avmb1/capi.c --- linux-2.5.1/drivers/isdn/avmb1/capi.c Thu Dec 6 22:01:17 2001 +++ linux-2.5/drivers/isdn/avmb1/capi.c Tue Jan 8 00:44:24 2002 @@ -1,4 +1,4 @@ -/* $Id: capi.c,v 1.44.6.15 2001/09/28 08:05:29 kai Exp $ +/* $Id: capi.c,v 1.1.4.1.2.2 2001/12/21 15:00:17 kai Exp $ * * CAPI 2.0 Interface for Linux * @@ -29,7 +29,6 @@ #include <linux/netdevice.h> #include <linux/ppp_defs.h> #include <linux/if_ppp.h> -#undef CAPI_PPP_ON_RAW_DEVICE #endif /* CONFIG_PPP */ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #include <linux/skbuff.h> @@ -45,7 +44,7 @@ #include "capifs.h" #endif -static char *revision = "$Revision: 1.44.6.15 $"; +static char *revision = "$Revision: 1.1.4.1.2.2 $"; MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface"); MODULE_AUTHOR("Carsten Paeth"); @@ -59,13 +58,11 @@ int capi_major = 68; /* allocated */ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -int capi_rawmajor = 190; int capi_ttymajor = 191; #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ MODULE_PARM(capi_major, "i"); #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -MODULE_PARM(capi_rawmajor, "i"); MODULE_PARM(capi_ttymajor, "i"); #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ @@ -83,7 +80,7 @@ struct capiminor; struct capiminor { - struct capiminor *next; + struct list_head list; struct capincci *nccip; unsigned int minor; @@ -92,7 +89,6 @@ u16 datahandle; u16 msgid; - struct file *file; struct tty_struct *tty; int ttyinstop; int ttyoutstop; @@ -104,15 +100,10 @@ struct sk_buff_head outqueue; int outbytes; - /* for raw device */ - struct sk_buff_head recvqueue; - wait_queue_head_t recvwait; - wait_queue_head_t sendwait; - /* transmit path */ struct datahandle_queue { struct datahandle_queue *next; - u16 datahandle; + u16 datahandle; } *ackqueue; int nack; @@ -129,11 +120,9 @@ }; struct capidev { - struct capidev *next; - struct file *file; + struct list_head list; u16 applid; u16 errcode; - unsigned int minor; unsigned userflags; struct sk_buff_head recvqueue; @@ -150,17 +139,21 @@ /* -------- global variables ---------------------------------------- */ -static struct capi_interface *capifuncs = 0; -static struct capidev *capidev_openlist = 0; +static struct capi_interface *capifuncs; + +static rwlock_t capidev_list_lock = RW_LOCK_UNLOCKED; +static LIST_HEAD(capidev_list); + #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -static struct capiminor *minors = 0; +static rwlock_t capiminor_list_lock = RW_LOCK_UNLOCKED; +static LIST_HEAD(capiminor_list); #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ -static kmem_cache_t *capidev_cachep = 0; -static kmem_cache_t *capincci_cachep = 0; +static kmem_cache_t *capidev_cachep; +static kmem_cache_t *capincci_cachep; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -static kmem_cache_t *capiminor_cachep = 0; -static kmem_cache_t *capidh_cachep = 0; +static kmem_cache_t *capiminor_cachep; +static kmem_cache_t *capidh_cachep; #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -218,14 +211,16 @@ static struct capiminor *capiminor_alloc(u16 applid, u32 ncci) { - struct capiminor *mp, **pp; - unsigned int minor = 0; - - MOD_INC_USE_COUNT; - mp = (struct capiminor *)kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC); - if (!mp) { - MOD_DEC_USE_COUNT; - printk(KERN_ERR "capi: can't alloc capiminor\n"); + struct capiminor *mp, *p; + struct list_head *l; + unsigned int minor = 0; + unsigned long flags; + + MOD_INC_USE_COUNT; + mp = kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC); + if (!mp) { + MOD_DEC_USE_COUNT; + printk(KERN_ERR "capi: can't alloc capiminor\n"); return 0; } #ifdef _DEBUG_REFCOUNT @@ -240,54 +235,59 @@ skb_queue_head_init(&mp->inqueue); skb_queue_head_init(&mp->outqueue); - skb_queue_head_init(&mp->recvqueue); - init_waitqueue_head(&mp->recvwait); - init_waitqueue_head(&mp->sendwait); - - for (pp = &minors; *pp; pp = &(*pp)->next) { - if ((*pp)->minor < minor) - continue; - if ((*pp)->minor > minor) + write_lock_irqsave(&capiminor_list_lock, flags); + list_for_each(l, &capiminor_list) { + p = list_entry(l, struct capiminor, list); + if (p->minor > minor) { + mp->minor = minor; + list_add_tail(&mp->list, &p->list); break; + } minor++; } - mp->minor = minor; - mp->next = *pp; - *pp = mp; + write_unlock_irqrestore(&capiminor_list_lock, flags); + if (l == &capiminor_list) { + kfree(mp); + return NULL; + } return mp; } static void capiminor_free(struct capiminor *mp) { - struct capiminor **pp; + unsigned long flags; - pp = &minors; - while (*pp) { - if (*pp == mp) { - *pp = (*pp)->next; - if (mp->ttyskb) kfree_skb(mp->ttyskb); - mp->ttyskb = 0; - skb_queue_purge(&mp->recvqueue); - skb_queue_purge(&mp->inqueue); - skb_queue_purge(&mp->outqueue); - capiminor_del_all_ack(mp); - kmem_cache_free(capiminor_cachep, mp); - MOD_DEC_USE_COUNT; + write_lock_irqsave(&capiminor_list_lock, flags); + list_del(&mp->list); + write_unlock_irqrestore(&capiminor_list_lock, flags); + + if (mp->ttyskb) kfree_skb(mp->ttyskb); + mp->ttyskb = 0; + skb_queue_purge(&mp->inqueue); + skb_queue_purge(&mp->outqueue); + capiminor_del_all_ack(mp); + kmem_cache_free(capiminor_cachep, mp); + MOD_DEC_USE_COUNT; #ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(THIS_MODULE)); + printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(THIS_MODULE)); #endif - return; - } else { - pp = &(*pp)->next; - } - } } -static struct capiminor *capiminor_find(unsigned int minor) +struct capiminor *capiminor_find(unsigned int minor) { - struct capiminor *p; - for (p = minors; p && p->minor != minor; p = p->next) - ; + struct list_head *l; + struct capiminor *p = NULL; + + read_lock(&capiminor_list_lock); + list_for_each(l, &capiminor_list) { + p = list_entry(l, struct capiminor, list); + if (p->minor == minor) + break; + } + read_unlock(&capiminor_list_lock); + if (l == &capiminor_list) + return NULL; + return p; } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ @@ -318,9 +318,7 @@ printk(KERN_DEBUG "set mp->nccip\n"); #endif #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) - kdev = MKDEV(capi_rawmajor, mp->minor); - capifs_new_ncci('r', mp->minor, kdev); - kdev = MKDEV(capi_ttymajor, mp->minor); + kdev = mk_kdev(capi_ttymajor, mp->minor); capifs_new_ncci(0, mp->minor, kdev); #endif } @@ -355,13 +353,6 @@ printk(KERN_DEBUG "reset mp->nccip\n"); #endif tty_hangup(mp->tty); - } else if (mp->file) { - mp->nccip = 0; -#ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "reset mp->nccip\n"); -#endif - wake_up_interruptible(&mp->recvwait); - wake_up_interruptible(&mp->sendwait); } else { capiminor_free(mp); } @@ -388,51 +379,57 @@ /* -------- struct capidev ------------------------------------------ */ -static struct capidev *capidev_alloc(struct file *file) +static struct capidev *capidev_alloc(void) { struct capidev *cdev; - struct capidev **pp; + unsigned long flags; - cdev = (struct capidev *)kmem_cache_alloc(capidev_cachep, GFP_KERNEL); + cdev = kmem_cache_alloc(capidev_cachep, GFP_KERNEL); if (!cdev) return 0; memset(cdev, 0, sizeof(struct capidev)); - cdev->file = file; - cdev->minor = MINOR(file->f_dentry->d_inode->i_rdev); skb_queue_head_init(&cdev->recvqueue); init_waitqueue_head(&cdev->recvwait); - pp=&capidev_openlist; - while (*pp) pp = &(*pp)->next; - *pp = cdev; + write_lock_irqsave(&capidev_list_lock, flags); + list_add_tail(&cdev->list, &capidev_list); + write_unlock_irqrestore(&capidev_list_lock, flags); return cdev; } static void capidev_free(struct capidev *cdev) { - struct capidev **pp; + unsigned long flags; if (cdev->applid) (*capifuncs->capi_release) (cdev->applid); cdev->applid = 0; skb_queue_purge(&cdev->recvqueue); - - pp=&capidev_openlist; - while (*pp && *pp != cdev) pp = &(*pp)->next; - if (*pp) - *pp = cdev->next; + write_lock_irqsave(&capidev_list_lock, flags); + list_del(&cdev->list); + write_unlock_irqrestore(&capidev_list_lock, flags); kmem_cache_free(capidev_cachep, cdev); } static struct capidev *capidev_find(u16 applid) { - struct capidev *p; - for (p=capidev_openlist; p; p = p->next) { + // FIXME this doesn't guarantee that the device won't go away shortly + struct list_head *l; + struct capidev *p = NULL; + + read_lock(&capidev_list_lock); + list_for_each(l, &capidev_list) { + p = list_entry(l, struct capidev, list); if (p->applid == applid) break; } + read_unlock(&capidev_list_lock); + + if (l == &capidev_list) + return NULL; + return p; } @@ -504,33 +501,6 @@ kfree_skb(skb); return 0; - } else if (mp->file) { - if (skb_queue_len(&mp->recvqueue) > CAPINC_MAX_RECVQUEUE) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: no room in raw queue\n"); -#endif - return -1; - } - if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { - printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); - return -1; - } - datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); - errcode = (*capifuncs->capi_put_message)(mp->applid, nskb); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", - errcode); - kfree_skb(nskb); - return -1; - } - (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => raw\n", - datahandle, skb->len); -#endif - skb_queue_tail(&mp->recvqueue, skb); - wake_up_interruptible(&mp->recvwait); - return 0; } #ifdef _DEBUG_DATAFLOW printk(KERN_DEBUG "capi: currently no receiver\n"); @@ -612,8 +582,6 @@ mp->outbytes -= len; kfree_skb(skb); } - if (count) - wake_up_interruptible(&mp->sendwait); return count; } @@ -686,8 +654,6 @@ if (mp->tty) { if (mp->tty->ldisc.write_wakeup) mp->tty->ldisc.write_wakeup(mp->tty); - } else { - wake_up_interruptible(&mp->sendwait); } (void)handle_minor_send(mp); @@ -1004,8 +970,6 @@ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if ((mp = nccip->minorp) != 0) { count += atomic_read(&mp->ttyopencount); - if (mp->file) - count++; } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ return count; @@ -1040,13 +1004,9 @@ if (file->private_data) return -EEXIST; - if ((file->private_data = capidev_alloc(file)) == 0) + if ((file->private_data = capidev_alloc()) == 0) return -ENOMEM; - MOD_INC_USE_COUNT; -#ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(THIS_MODULE)); -#endif return 0; } @@ -1059,10 +1019,6 @@ capidev_free(cdev); file->private_data = NULL; - MOD_DEC_USE_COUNT; -#ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE)); -#endif return 0; } @@ -1079,209 +1035,17 @@ }; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -/* -------- file_operations for capincci ---------------------------- */ - -static int -capinc_raw_open(struct inode *inode, struct file *file) -{ - struct capiminor *mp; - - if (file->private_data) - return -EEXIST; - if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0) - return -ENXIO; - if (mp->nccip == 0) - return -ENXIO; - if (mp->file) - return -EBUSY; - -#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; - handle_minor_recv(mp); - return 0; -} - -static ssize_t -capinc_raw_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - struct capiminor *mp = (struct capiminor *)file->private_data; - struct sk_buff *skb; - int retval; - size_t copied = 0; - - if (ppos != &file->f_pos) - return -ESPIPE; - - if (!mp || !mp->nccip) - return -EINVAL; - - if ((skb = skb_dequeue(&mp->recvqueue)) == 0) { - - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - for (;;) { - interruptible_sleep_on(&mp->recvwait); - if (mp->nccip == 0) - return 0; - if ((skb = skb_dequeue(&mp->recvqueue)) != 0) - break; - if (signal_pending(current)) - break; - } - if (skb == 0) - return -ERESTARTNOHAND; - } - do { - if (count < skb->len) { - retval = copy_to_user(buf, skb->data, count); - if (retval) { - skb_queue_head(&mp->recvqueue, skb); - return retval; - } - skb_pull(skb, count); - skb_queue_head(&mp->recvqueue, skb); - copied += count; - return copied; - } else { - retval = copy_to_user(buf, skb->data, skb->len); - if (retval) { - skb_queue_head(&mp->recvqueue, skb); - return copied; - } - copied += skb->len; - count -= skb->len; - buf += skb->len; - kfree_skb(skb); - } - } while ((skb = skb_dequeue(&mp->recvqueue)) != 0); - - return copied; -} - -static ssize_t -capinc_raw_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - struct capiminor *mp = (struct capiminor *)file->private_data; - struct sk_buff *skb; - int retval; - - if (ppos != &file->f_pos) - return -ESPIPE; - - if (!mp || !mp->nccip) - 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))) { - kfree_skb(skb); - return -EFAULT; - } - - while (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - interruptible_sleep_on(&mp->sendwait); - if (mp->nccip == 0) { - kfree_skb(skb); - return -EIO; - } - if (signal_pending(current)) - return -ERESTARTNOHAND; - } - skb_queue_tail(&mp->outqueue, skb); - mp->outbytes += skb->len; - (void)handle_minor_send(mp); - return count; -} - -static unsigned int -capinc_raw_poll(struct file *file, poll_table * wait) -{ - struct capiminor *mp = (struct capiminor *)file->private_data; - unsigned int mask = 0; - - if (!mp || !mp->nccip) - return POLLERR|POLLHUP; - - poll_wait(file, &(mp->recvwait), wait); - if (!skb_queue_empty(&mp->recvqueue)) - mask |= POLLIN | POLLRDNORM; - poll_wait(file, &(mp->sendwait), wait); - if (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) - mask = POLLOUT | POLLWRNORM; - return mask; -} - -static int -capinc_raw_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct capiminor *mp = (struct capiminor *)file->private_data; - if (!mp || !mp->nccip) - return -EINVAL; - - switch (cmd) { - } - return -EINVAL; -} - -static int -capinc_raw_release(struct inode *inode, struct file *file) -{ - struct capiminor *mp = (struct capiminor *)file->private_data; - - if (mp) { - mp->file = 0; - if (mp->nccip == 0) { - capiminor_free(mp); - file->private_data = NULL; - } - } - -#ifdef _DEBUG_REFCOUNT - printk(KERN_DEBUG "capinc_raw_release %d\n", GET_USE_COUNT(THIS_MODULE)); -#endif - return 0; -} - -static struct file_operations capinc_raw_fops = -{ - owner: THIS_MODULE, - llseek: no_llseek, - read: capinc_raw_read, - write: capinc_raw_write, - poll: capinc_raw_poll, - ioctl: capinc_raw_ioctl, - open: capinc_raw_open, - release: capinc_raw_release, -}; - /* -------- tty_operations for capincci ----------------------------- */ static int capinc_tty_open(struct tty_struct * tty, struct file * file) { struct capiminor *mp; - if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0) + if ((mp = capiminor_find(minor(file->f_dentry->d_inode->i_rdev))) == 0) return -ENXIO; if (mp->nccip == 0) return -ENXIO; - if (mp->file) - return -EBUSY; - skb_queue_head_init(&mp->recvqueue); - init_waitqueue_head(&mp->recvwait); - init_waitqueue_head(&mp->sendwait); tty->driver_data = (void *)mp; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_tty_open %d\n", GET_USE_COUNT(THIS_MODULE)); @@ -1454,7 +1218,7 @@ return room; } -static int capinc_tty_chars_in_buffer(struct tty_struct *tty) +int capinc_tty_chars_in_buffer(struct tty_struct *tty) { struct capiminor *mp = (struct capiminor *)tty->driver_data; if (!mp || !mp->nccip) { @@ -1662,11 +1426,13 @@ int count, int *eof, void *data) { struct capidev *cdev; + struct list_head *l; int len = 0; - for (cdev=capidev_openlist; cdev; cdev = cdev->next) { - len += sprintf(page+len, "%d %d %lu %lu %lu %lu\n", - cdev->minor, + read_lock(&capidev_list_lock); + list_for_each(l, &capidev_list) { + cdev = list_entry(l, struct capidev, list); + len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n", cdev->applid, cdev->nrecvctlpkt, cdev->nrecvdatapkt, @@ -1680,11 +1446,13 @@ goto endloop; } } + endloop: + read_unlock(&capidev_list_lock); if (len < count) *eof = 1; - if (len>count) len = count; - if (len<0) len = 0; + if (len > count) len = count; + if (len < 0) len = 0; return len; } @@ -1697,18 +1465,16 @@ { struct capidev *cdev; struct capincci *np; + struct list_head *l; int len = 0; - for (cdev=capidev_openlist; cdev; cdev = cdev->next) { + read_lock(&capidev_list_lock); + list_for_each(l, &capidev_list) { + cdev = list_entry(l, struct capidev, list); for (np=cdev->nccis; np; np = np->next) { - len += sprintf(page+len, "%d 0x%x%s\n", - cdev->applid, - np->ncci, -#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE - ""); -#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ - np->minorp && np->minorp->file ? " open" : ""); -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ + len += sprintf(page+len, "%d 0x%x\n", + cdev->applid, + np->ncci); if (len <= off) { off -= len; len = 0; @@ -1719,6 +1485,7 @@ } } endloop: + read_unlock(&capidev_list_lock); *start = page+off; if (len < count) *eof = 1; @@ -1889,19 +1656,6 @@ return -EIO; } -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - if (devfs_register_chrdev(capi_rawmajor, "capi/r%d", &capinc_raw_fops)) { - devfs_unregister_chrdev(capi_major, "capi20"); - printk(KERN_ERR "capi20: unable to get major %d\n", capi_rawmajor); - MOD_DEC_USE_COUNT; - return -EIO; - } - devfs_register_series (NULL, "capi/r%u", CAPINC_NR_PORTS, - DEVFS_FL_DEFAULT, - capi_rawmajor, 0, - S_IFCHR | S_IRUSR | S_IWUSR, - &capinc_raw_fops, NULL); -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ devfs_register (NULL, "isdn/capi20", DEVFS_FL_DEFAULT, capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, &capi_fops, NULL); @@ -1911,9 +1665,6 @@ MOD_DEC_USE_COUNT; devfs_unregister_chrdev(capi_major, "capi20"); -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); -#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ devfs_unregister(devfs_find_handle(NULL, "capi20", capi_major, 0, DEVFS_SPECIAL_CHR, 0)); @@ -1924,7 +1675,6 @@ if (capinc_tty_init() < 0) { (void) detach_capi_interface(&cuser); devfs_unregister_chrdev(capi_major, "capi20"); - devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); MOD_DEC_USE_COUNT; return -ENOMEM; } @@ -1932,13 +1682,6 @@ if (alloc_init() < 0) { #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - unsigned int j; - devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); - for (j = 0; j < CAPINC_NR_PORTS; j++) { - char devname[32]; - sprintf(devname, "capi/r%u", j); - devfs_unregister(devfs_find_handle(NULL, devname, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0)); - } capinc_tty_exit(); #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ (void) detach_capi_interface(&cuser); @@ -1970,9 +1713,6 @@ static void __exit capi_exit(void) { -#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - unsigned int j; -#endif alloc_exit(); (void)proc_exit(); @@ -1981,12 +1721,6 @@ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE capinc_tty_exit(); - devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); - for (j = 0; j < CAPINC_NR_PORTS; j++) { - char devname[32]; - sprintf(devname, "capi/r%u", j); - devfs_unregister(devfs_find_handle(NULL, devname, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0)); - } #endif (void) detach_capi_interface(&cuser); printk(KERN_NOTICE "capi: Rev %s: unloaded\n", rev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/capidrv.c linux-2.5/drivers/isdn/avmb1/capidrv.c --- linux-2.5.1/drivers/isdn/avmb1/capidrv.c Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/avmb1/capidrv.c Sat Jan 5 00:08:34 2002 @@ -29,7 +29,6 @@ #include <linux/kernelcapi.h> #include <linux/ctype.h> #include <linux/init.h> -#include <asm/segment.h> #include "capiutil.h" #include "capicmd.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/capifs.c linux-2.5/drivers/isdn/avmb1/capifs.c --- linux-2.5.1/drivers/isdn/avmb1/capifs.c Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/avmb1/capifs.c Sat Jan 5 00:08:35 2002 @@ -430,7 +430,7 @@ inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid; inode->i_nlink = 1; inode->i_ino = ino + 2; - init_special_inode(inode, sbi->mode|S_IFCHR, np->kdev); + init_special_inode(inode, sbi->mode|S_IFCHR, kdev_t_to_nr(np->kdev)); } } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/capiutil.c linux-2.5/drivers/isdn/avmb1/capiutil.c --- linux-2.5.1/drivers/isdn/avmb1/capiutil.c Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/avmb1/capiutil.c Sat Jan 5 00:08:36 2002 @@ -17,7 +17,6 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/init.h> -#include <asm/segment.h> #include <linux/config.h> #include "capiutil.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/kcapi.c linux-2.5/drivers/isdn/avmb1/kcapi.c --- linux-2.5.1/drivers/isdn/avmb1/kcapi.c Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/avmb1/kcapi.c Thu Jan 3 22:26:39 2002 @@ -17,7 +17,6 @@ #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/ioport.h> -#include <asm/segment.h> #include <linux/proc_fs.h> #include <linux/skbuff.h> #include <linux/tqueue.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/avmb1/t1pci.c linux-2.5/drivers/isdn/avmb1/t1pci.c --- linux-2.5.1/drivers/isdn/avmb1/t1pci.c Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/avmb1/t1pci.c Tue Jan 8 00:44:24 2002 @@ -1,4 +1,4 @@ -/* $Id: t1pci.c,v 1.13.6.6 2001/09/23 22:24:34 kai Exp $ +/* $Id: t1pci.c,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ * * Module for AVM T1 PCI-card. * @@ -26,14 +26,14 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.13.6.6 $"; +static char *revision = "$Revision: 1.1.4.1.2.1 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG /* ------------------------------------------------------------- */ -static struct pci_device_id t1pci_pci_tbl[] __initdata = { +static struct pci_device_id t1pci_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID }, { } /* Terminating entry */ }; @@ -62,7 +62,7 @@ release_region(card->port, AVMB1_PORTLEN); ctrl->driverdata = 0; kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; @@ -70,7 +70,9 @@ /* ------------------------------------------------------------- */ -static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) +static int t1pci_add_card(struct capi_driver *driver, + struct capicardparams *p, + struct pci_dev *dev) { avmcard *card; avmctrl_info *cinfo; @@ -86,18 +88,17 @@ return -ENOMEM; } memset(card, 0, sizeof(avmcard)); - card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC); + card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128); if (!card->dma) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); MOD_DEC_USE_COUNT; return -ENOMEM; } - memset(card->dma, 0, sizeof(avmcard_dmainfo)); cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC); if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -ENOMEM; @@ -116,7 +117,7 @@ "%s: ports 0x%03x-0x%03x in use.\n", driver->name, card->port, card->port + AVMB1_PORTLEN); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EBUSY; @@ -127,7 +128,7 @@ printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", driver->name, card->membase); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EIO; @@ -144,7 +145,7 @@ driver->name, card->port, retval); iounmap(card->mbase); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EIO; @@ -160,7 +161,7 @@ iounmap(card->mbase); release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EBUSY; @@ -173,15 +174,13 @@ free_irq(card->irq, card); release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); - kfree(card->dma); + avmcard_dma_free(card->dma); kfree(card); MOD_DEC_USE_COUNT; return -EBUSY; } card->cardnr = cinfo->capi_ctrl->cnr; - skb_queue_head_init(&card->dma->send_queue); - printk(KERN_INFO "%s: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n", driver->name, card->port, card->irq, card->membase); @@ -226,27 +225,63 @@ add_card: 0, /* no add_card function */ }; -static int ncards = 0; +/* ------------------------------------------------------------- */ + +static int __devinit t1pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + struct capi_driver *driver = &t1pci_driver; + struct capicardparams param; + int retval; + + if (pci_enable_device(dev) < 0) { + printk(KERN_ERR "%s: failed to enable AVM-T1-PCI\n", + driver->name); + return -ENODEV; + } + pci_set_master(dev); + + param.port = pci_resource_start(dev, 1); + param.irq = dev->irq; + param.membase = pci_resource_start(dev, 0); + + 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); + + retval = t1pci_add_card(driver, ¶m, dev); + if (retval != 0) { + 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); + return -ENODEV; + } + return 0; +} + +static struct pci_driver t1pci_pci_driver = { + name: "t1pci", + id_table: t1pci_pci_tbl, + probe: t1pci_probe, +}; static int __init t1pci_init(void) { struct capi_driver *driver = &t1pci_driver; - struct pci_dev *dev = NULL; char *p; - int retval; + int ncards; MOD_INC_USE_COUNT; if ((p = strchr(revision, ':')) != 0 && p[1]) { - strncpy(driver->revision, p + 2, sizeof(driver->revision)); - driver->revision[sizeof(driver->revision)-1] = 0; + strncpy(driver->revision, p + 2, sizeof(driver->revision) - 1); if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision) *(p-1) = 0; } printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); - di = attach_capi_driver(driver); + di = attach_capi_driver(&t1pci_driver); if (!di) { printk(KERN_ERR "%s: failed to attach capi_driver\n", driver->name); @@ -254,32 +289,7 @@ 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); - - 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); - retval = t1pci_add_card(driver, ¶m); - if (retval != 0) { - 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); - continue; - } - ncards++; - } + ncards = pci_register_driver(&t1pci_pci_driver); if (ncards) { printk(KERN_INFO "%s: %d T1-PCI card(s) detected\n", driver->name, ncards); @@ -287,6 +297,7 @@ return 0; } printk(KERN_ERR "%s: NO T1-PCI card detected\n", driver->name); + pci_unregister_driver(&t1pci_pci_driver); detach_capi_driver(&t1pci_driver); MOD_DEC_USE_COUNT; return -ENODEV; @@ -294,7 +305,8 @@ static void __exit t1pci_exit(void) { - detach_capi_driver(&t1pci_driver); + pci_unregister_driver(&t1pci_pci_driver); + detach_capi_driver(&t1pci_driver); } module_init(t1pci_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/eicon/eicon.h linux-2.5/drivers/isdn/eicon/eicon.h --- linux-2.5.1/drivers/isdn/eicon/eicon.h Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/eicon/eicon.h Mon Jan 7 20:53:26 2002 @@ -123,7 +123,6 @@ #include <linux/errno.h> #include <linux/fs.h> #include <linux/major.h> -#include <asm/segment.h> #include <asm/io.h> #include <linux/kernel.h> #include <linux/signal.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/eicon/lincfg.c linux-2.5/drivers/isdn/eicon/lincfg.c --- linux-2.5.1/drivers/isdn/eicon/lincfg.c Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/eicon/lincfg.c Sun Dec 30 21:17:30 2001 @@ -11,7 +11,6 @@ #include <linux/fs.h> #undef N_DATA /* Because we have our own definition */ -#include <asm/segment.h> #include <asm/io.h> #include "sys.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/hisax/Makefile linux-2.5/drivers/isdn/hisax/Makefile --- linux-2.5.1/drivers/isdn/hisax/Makefile Fri Nov 30 17:48:32 2001 +++ linux-2.5/drivers/isdn/hisax/Makefile Tue Dec 18 14:56:45 2001 @@ -4,6 +4,10 @@ O_TARGET := vmlinux-obj.o +# Define maximum number of cards + +EXTRA_CFLAGS += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS) + # Objects that export symbols. export-objs := config.o fsm.o hisax_isac.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/hisax/config.c linux-2.5/drivers/isdn/hisax/config.c --- linux-2.5.1/drivers/isdn/hisax/config.c Fri Nov 30 17:48:32 2001 +++ linux-2.5/drivers/isdn/hisax/config.c Thu Jan 3 23:04:39 2002 @@ -1,4 +1,4 @@ -/* $Id: config.c,v 2.57.6.20 2001/09/23 22:24:47 kai Exp $ +/* $Id: config.c,v 1.1.4.2.2.1 2001/12/09 20:18:40 kai Exp $ * * Author Karsten Keil * Copyright by Karsten Keil <keil@isdn4linux.de> @@ -336,27 +336,19 @@ NULL, \ } -#define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL} - -struct IsdnCard cards[] = { +struct IsdnCard cards[HISAX_MAX_CARDS] = { FIRST_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, }; -static char HiSaxID[64] __devinitdata = { 0, }; +#define HISAX_IDSIZE (HISAX_MAX_CARDS*8) +static char HiSaxID[HISAX_IDSIZE] __devinitdata = { 0, }; char *HiSax_id __devinitdata = HiSaxID; #ifdef MODULE /* Variables for insmod */ -static int type[8] __devinitdata = { 0, }; -static int protocol[8] __devinitdata = { 0, }; -static int io[8] __devinitdata = { 0, }; +static int type[HISAX_MAX_CARDS] __devinitdata = { 0, }; +static int protocol[HISAX_MAX_CARDS] __devinitdata = { 0, }; +static int io[HISAX_MAX_CARDS] __devinitdata = { 0, }; #undef IO0_IO1 #ifdef CONFIG_HISAX_16_3 #define IO0_IO1 @@ -366,25 +358,27 @@ #define IO0_IO1 #endif #ifdef IO0_IO1 -static int io0[8] __devinitdata = { 0, }; -static int io1[8] __devinitdata = { 0, }; +static int io0[HISAX_MAX_CARDS] __devinitdata = { 0, }; +static int io1[HISAX_MAX_CARDS] __devinitdata = { 0, }; #endif -static int irq[8] __devinitdata = { 0, }; -static int mem[8] __devinitdata = { 0, }; +static int irq[HISAX_MAX_CARDS] __devinitdata = { 0, }; +static int mem[HISAX_MAX_CARDS] __devinitdata = { 0, }; static char *id __devinitdata = HiSaxID; +#define PARM_PARA "1-" __MODULE_STRING(HISAX_MAX_CARDS) "i" + MODULE_DESCRIPTION("ISDN4Linux: Driver for passive ISDN cards"); MODULE_AUTHOR("Karsten Keil"); MODULE_LICENSE("GPL"); -MODULE_PARM(type, "1-8i"); -MODULE_PARM(protocol, "1-8i"); -MODULE_PARM(io, "1-8i"); -MODULE_PARM(irq, "1-8i"); -MODULE_PARM(mem, "1-8i"); +MODULE_PARM(type, PARM_PARA); +MODULE_PARM(protocol, PARM_PARA); +MODULE_PARM(io, PARM_PARA); +MODULE_PARM(irq, PARM_PARA); +MODULE_PARM(mem, PARM_PARA); MODULE_PARM(id, "s"); #ifdef IO0_IO1 -MODULE_PARM(io0, "1-8i"); -MODULE_PARM(io1, "1-8i"); +MODULE_PARM(io0, PARM_PARA); +MODULE_PARM(io1, PARM_PARA); #endif #endif /* MODULE */ @@ -448,6 +442,7 @@ i = 0; j = 1; while (argc && (i < HISAX_MAX_CARDS)) { + cards[i].protocol = DEFAULT_PROTO; if (argc) { cards[i].typ = ints[j]; j++; @@ -475,13 +470,15 @@ } i++; } - if (str && *str) { - strcpy(HiSaxID, str); - HiSax_id = HiSaxID; - } else { + if (str && *str) { + if (strlen(str) < HISAX_IDSIZE) + strcpy(HiSaxID, str); + else + printk(KERN_WARNING "HiSax: ID too long!"); + } else strcpy(HiSaxID, "HiSax"); - HiSax_id = HiSaxID; - } + + HiSax_id = HiSaxID; return 1; } @@ -1396,6 +1393,8 @@ if (protocol[i]) { cards[j].protocol = protocol[i]; nzproto++; + } else { + cards[j].protocol = DEFAULT_PROTO; } switch (type[i]) { case ISDN_CTYPE_16_0: @@ -1473,15 +1472,22 @@ } else { /* QUADRO is a 4 BRI card */ cards[j++].para[0] = 1; - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j++].para[0] = 2; - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j++].para[0] = 3; - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j].para[0] = 4; + /* we need to check if further cards can be added */ + if (j < HISAX_MAX_CARDS) { + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 2; + } + if (j < HISAX_MAX_CARDS) { + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 3; + } + if (j < HISAX_MAX_CARDS) { + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j].para[0] = 4; + } } break; } @@ -1554,6 +1560,8 @@ cards[i].typ = type[i]; if (protocol[i]) { cards[i].protocol = protocol[i]; + } else { + cards[i].protocol = DEFAULT_PROTO; } } cards[0].para[0] = pcm_irq; @@ -1594,6 +1602,8 @@ cards[i].typ = type[i]; if (protocol[i]) { cards[i].protocol = protocol[i]; + } else { + cards[i].protocol = DEFAULT_PROTO; } } cards[0].para[0] = pcm_irq; @@ -1634,6 +1644,8 @@ cards[i].typ = type[i]; if (protocol[i]) { cards[i].protocol = protocol[i]; + } else { + cards[i].protocol = DEFAULT_PROTO; } } cards[0].para[0] = pcm_irq; @@ -1674,6 +1686,8 @@ cards[i].typ = type[i]; if (protocol[i]) { cards[i].protocol = protocol[i]; + } else { + cards[i].protocol = DEFAULT_PROTO; } } cards[0].para[0] = pcm_irq; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/hisax/hisax.h linux-2.5/drivers/isdn/hisax/hisax.h --- linux-2.5.1/drivers/isdn/hisax/hisax.h Sun Sep 30 19:26:05 2001 +++ linux-2.5/drivers/isdn/hisax/hisax.h Mon Jan 7 20:53:37 2002 @@ -1,4 +1,4 @@ -/* $Id: hisax.h,v 2.52.6.9 2001/09/23 22:24:48 kai Exp $ +/* $Id: hisax.h,v 1.1.4.1.2.1 2001/12/09 20:18:40 kai Exp $ * * Basic declarations, defines and prototypes * @@ -10,7 +10,6 @@ #include <linux/errno.h> #include <linux/fs.h> #include <linux/major.h> -#include <asm/segment.h> #include <asm/io.h> #include <linux/delay.h> #include <linux/kernel.h> @@ -949,8 +948,6 @@ #define MON1_RX 2 #define MON0_TX 4 #define MON1_TX 8 - -#define HISAX_MAX_CARDS 8 #define ISDN_CTYPE_16_0 1 #define ISDN_CTYPE_8_0 2 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/hisax/st5481.h linux-2.5/drivers/isdn/hisax/st5481.h --- linux-2.5.1/drivers/isdn/hisax/st5481.h Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/isdn/hisax/st5481.h Tue Jan 8 00:44:24 2002 @@ -309,7 +309,7 @@ typedef void (*ctrl_complete_t)(void *); typedef struct ctrl_msg { - devrequest dr; + struct usb_ctrlrequest dr; ctrl_complete_t complete; void *context; } ctrl_msg; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/hisax/st5481_init.c linux-2.5/drivers/isdn/hisax/st5481_init.c --- linux-2.5.1/drivers/isdn/hisax/st5481_init.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/isdn/hisax/st5481_init.c Thu Dec 13 16:32:35 2001 @@ -178,7 +178,7 @@ static struct usb_driver st5481_usb_driver = { name: "st5481_usb", probe: probe_st5481, - disconnect: disconnect_st5481, + disconnect: __devexit_p(disconnect_st5481), id_table: st5481_ids, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/hisax/st5481_usb.c linux-2.5/drivers/isdn/hisax/st5481_usb.c --- linux-2.5.1/drivers/isdn/hisax/st5481_usb.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/isdn/hisax/st5481_usb.c Tue Jan 8 00:44:24 2002 @@ -41,9 +41,9 @@ (unsigned char *)&ctrl->msg_fifo.data[r_index]; DBG(1,"request=0x%02x,value=0x%04x,index=%x", - ((struct ctrl_msg *)urb->setup_packet)->dr.request, - ((struct ctrl_msg *)urb->setup_packet)->dr.value, - ((struct ctrl_msg *)urb->setup_packet)->dr.index); + ((struct ctrl_msg *)urb->setup_packet)->dr.bRequest, + ((struct ctrl_msg *)urb->setup_packet)->dr.wValue, + ((struct ctrl_msg *)urb->setup_packet)->dr.wIndex); // Prepare the URB urb->dev = adapter->usb_dev; @@ -69,11 +69,11 @@ } ctrl_msg = &ctrl->msg_fifo.data[w_index]; - ctrl_msg->dr.requesttype = requesttype; - ctrl_msg->dr.request = request; - ctrl_msg->dr.value = cpu_to_le16p(&value); - ctrl_msg->dr.index = cpu_to_le16p(&index); - ctrl_msg->dr.length = 0; + ctrl_msg->dr.bRequestType = requesttype; + ctrl_msg->dr.bRequest = request; + ctrl_msg->dr.wValue = cpu_to_le16p(&value); + ctrl_msg->dr.wIndex = cpu_to_le16p(&index); + ctrl_msg->dr.wLength = 0; ctrl_msg->complete = complete; ctrl_msg->context = context; @@ -140,17 +140,17 @@ ctrl_msg = (struct ctrl_msg *)urb->setup_packet; - if (ctrl_msg->dr.request == USB_REQ_CLEAR_FEATURE) { + if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { /* Special case handling for pipe reset */ - le16_to_cpus(&ctrl_msg->dr.index); + le16_to_cpus(&ctrl_msg->dr.wIndex); usb_endpoint_running(adapter->usb_dev, - ctrl_msg->dr.index & ~USB_DIR_IN, - (ctrl_msg->dr.index & USB_DIR_IN) == 0); + ctrl_msg->dr.wIndex & ~USB_DIR_IN, + (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0); /* toggle is reset on clear */ usb_settoggle(adapter->usb_dev, - ctrl_msg->dr.index & ~USB_DIR_IN, - (ctrl_msg->dr.index & USB_DIR_IN) == 0, + ctrl_msg->dr.wIndex & ~USB_DIR_IN, + (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0, 0); @@ -560,7 +560,7 @@ */ int st5481_isoc_flatten(struct urb *urb) { - piso_packet_descriptor_t pipd,pend; + iso_packet_descriptor_t *pipd,*pend; unsigned char *src,*dst; unsigned int len; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/icn/icn.h linux-2.5/drivers/isdn/icn/icn.h --- linux-2.5.1/drivers/isdn/icn/icn.h Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/isdn/icn/icn.h Mon Jan 7 20:58:23 2002 @@ -39,7 +39,6 @@ #include <linux/errno.h> #include <linux/fs.h> #include <linux/major.h> -#include <asm/segment.h> #include <asm/io.h> #include <linux/kernel.h> #include <linux/signal.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/isdn_bsdcomp.c linux-2.5/drivers/isdn/isdn_bsdcomp.c --- linux-2.5.1/drivers/isdn/isdn_bsdcomp.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/isdn/isdn_bsdcomp.c Sun Dec 30 21:17:30 2001 @@ -71,7 +71,6 @@ #include <asm/system.h> #include <asm/bitops.h> -#include <asm/segment.h> #include <asm/byteorder.h> #include <asm/types.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/isdn_common.c linux-2.5/drivers/isdn/isdn_common.c --- linux-2.5.1/drivers/isdn/isdn_common.c Fri Nov 9 21:41:41 2001 +++ linux-2.5/drivers/isdn/isdn_common.c Sat Jan 5 00:37:50 2002 @@ -963,7 +963,7 @@ static ssize_t isdn_read(struct file *file, char *buf, size_t count, loff_t * off) { - uint minor = MINOR(file->f_dentry->d_inode->i_rdev); + uint minor = minor(file->f_dentry->d_inode->i_rdev); int len = 0; ulong flags; int drvidx; @@ -1077,7 +1077,7 @@ static ssize_t isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) { - uint minor = MINOR(file->f_dentry->d_inode->i_rdev); + uint minor = minor(file->f_dentry->d_inode->i_rdev); int drvidx; int chidx; int retval; @@ -1143,7 +1143,7 @@ isdn_poll(struct file *file, poll_table * wait) { unsigned int mask = 0; - unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + unsigned int minor = minor(file->f_dentry->d_inode->i_rdev); int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); lock_kernel(); @@ -1184,7 +1184,7 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) { - uint minor = MINOR(inode->i_rdev); + uint minor = minor(inode->i_rdev); isdn_ctrl c; int drvidx; int chidx; @@ -1635,7 +1635,7 @@ static int isdn_open(struct inode *ino, struct file *filep) { - uint minor = MINOR(ino->i_rdev); + uint minor = minor(ino->i_rdev); int drvidx; int chidx; int retval = -ENODEV; @@ -1696,7 +1696,7 @@ static int isdn_close(struct inode *ino, struct file *filep) { - uint minor = MINOR(ino->i_rdev); + uint minor = minor(ino->i_rdev); lock_kernel(); if (minor == ISDN_MINOR_STATUS) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/isdn_ppp.c linux-2.5/drivers/isdn/isdn_ppp.c --- linux-2.5.1/drivers/isdn/isdn_ppp.c Fri Nov 9 21:41:41 2001 +++ linux-2.5/drivers/isdn/isdn_ppp.c Thu Jan 3 22:26:40 2002 @@ -586,7 +586,7 @@ if (is->debug & 0x2) printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", - MINOR(file->f_dentry->d_inode->i_rdev)); + minor(file->f_dentry->d_inode->i_rdev)); /* just registers wait_queue hook. This doesn't really wait. */ poll_wait(file, &is->wq, wait); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/isdn_tty.c linux-2.5/drivers/isdn/isdn_tty.c --- linux-2.5.1/drivers/isdn/isdn_tty.c Fri Nov 9 21:41:41 2001 +++ linux-2.5/drivers/isdn/isdn_tty.c Thu Jan 3 22:26:40 2002 @@ -1019,12 +1019,12 @@ #ifdef MODEM_PARANOIA_CHECK if (!info) { printk(KERN_WARNING "isdn_tty: null info_struct for (%d, %d) in %s\n", - MAJOR(device), MINOR(device), routine); + major(device), minor(device), routine); return 1; } if (info->magic != ISDN_ASYNC_MAGIC) { printk(KERN_WARNING "isdn_tty: bad magic for modem struct (%d, %d) in %s\n", - MAJOR(device), MINOR(device), routine); + major(device), minor(device), routine); return 1; } #endif @@ -1740,7 +1740,7 @@ int retval, line; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if (line < 0 || line > ISDN_MAX_CHANNELS) return -ENODEV; info = &dev->mdm.info[line]; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/isdnloop/isdnloop.h linux-2.5/drivers/isdn/isdnloop/isdnloop.h --- linux-2.5.1/drivers/isdn/isdnloop/isdnloop.h Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/isdn/isdnloop/isdnloop.h Mon Jan 7 20:58:26 2002 @@ -37,7 +37,6 @@ #include <linux/errno.h> #include <linux/fs.h> #include <linux/major.h> -#include <asm/segment.h> #include <asm/io.h> #include <linux/kernel.h> #include <linux/signal.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/sc/command.c linux-2.5/drivers/isdn/sc/command.c --- linux-2.5.1/drivers/isdn/sc/command.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/isdn/sc/command.c Sun Jan 6 01:38:27 2002 @@ -95,7 +95,7 @@ if(adapter[i]->driverId == driver) return i; } - return -NODEV; + return -ENODEV; } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/sc/includes.h linux-2.5/drivers/isdn/sc/includes.h --- linux-2.5.1/drivers/isdn/sc/includes.h Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/isdn/sc/includes.h Mon Jan 7 20:58:38 2002 @@ -6,7 +6,6 @@ #include <linux/version.h> #include <linux/errno.h> -#include <asm/segment.h> #include <asm/io.h> #include <linux/delay.h> #include <linux/kernel.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/isdn/tpam/tpam_main.c linux-2.5/drivers/isdn/tpam/tpam_main.c --- linux-2.5.1/drivers/isdn/tpam/tpam_main.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/isdn/tpam/tpam_main.c Sat Jan 5 00:51:29 2002 @@ -254,7 +254,7 @@ name: "tpam", id_table: tpam_pci_tbl, probe: tpam_probe, - remove: tpam_remove, + remove: __devexit_p(tpam_remove), }; static int __init tpam_init(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/Makefile linux-2.5/drivers/macintosh/Makefile --- linux-2.5.1/drivers/macintosh/Makefile Thu Aug 30 03:49:36 2001 +++ linux-2.5/drivers/macintosh/Makefile Thu Dec 27 16:32:31 2001 @@ -32,9 +32,11 @@ obj-$(CONFIG_MAC_HID) += mac_hid.o obj-$(CONFIG_INPUT_ADBHID) += adbhid.o obj-$(CONFIG_PPC_RTC) += rtc.o +obj-$(CONFIG_ANSLCD) += ans-lcd.o obj-$(CONFIG_ADB_PMU) += via-pmu.o obj-$(CONFIG_ADB_CUDA) += via-cuda.o +obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o obj-$(CONFIG_ADB) += adb.o obj-$(CONFIG_ADB_KEYBOARD) += mac_keyb.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/adb.c linux-2.5/drivers/macintosh/adb.c --- linux-2.5.1/drivers/macintosh/adb.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/macintosh/adb.c Thu Dec 27 16:32:31 2001 @@ -34,6 +34,7 @@ #include <linux/wait.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/completion.h> #include <asm/uaccess.h> #ifdef CONFIG_PPC #include <asm/prom.h> @@ -78,7 +79,7 @@ static int adb_inited = 0; static pid_t adb_probe_task_pid; static int adb_probe_task_flag; -static wait_queue_head_t adb_probe_task_wq; +static struct completion adb_probe_task_comp; static int sleepy_trackpad; int __adb_probe_sync; @@ -318,7 +319,7 @@ if (machine_is_compatible("AAPL,PowerBook1998") || machine_is_compatible("PowerBook1,1")) sleepy_trackpad = 1; - init_waitqueue_head(&adb_probe_task_wq); + init_completion(&adb_probe_task_comp); adbdev_init(); adb_reset_bus(); } @@ -435,7 +436,7 @@ static void adb_probe_wakeup(struct adb_request *req) { - wake_up(&adb_probe_task_wq); + complete(&adb_probe_task_comp); } static struct adb_request adb_sreq; @@ -484,20 +485,11 @@ if ((flags & ADBREQ_SYNC) && (current->pid && adb_probe_task_pid && adb_probe_task_pid == current->pid)) { - DECLARE_WAITQUEUE(wait, current); req->done = adb_probe_wakeup; - add_wait_queue(&adb_probe_task_wq, &wait); rc = adb_controller->send_request(req, 0); if (rc || req->complete) goto bail; - for (;;) { - set_current_state(TASK_UNINTERRUPTIBLE); - if (req->complete) - break; - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&adb_probe_task_wq, &wait); + wait_for_completion(&adb_probe_task_comp); rc = 0; goto bail; } @@ -705,17 +697,16 @@ return ret; req = NULL; + spin_lock_irqsave(&state->lock, flags); add_wait_queue(&state->wait_queue, &wait); current->state = TASK_INTERRUPTIBLE; for (;;) { - spin_lock_irqsave(&state->lock, flags); req = state->completed; if (req != NULL) state->completed = req->next; else if (atomic_read(&state->n_pending) == 0) ret = -EIO; - spin_unlock_irqrestore(&state->lock, flags); if (req != NULL || ret != 0) break; @@ -727,12 +718,15 @@ ret = -ERESTARTSYS; break; } + spin_unlock_irqrestore(&state->lock, flags); schedule(); + spin_lock_irqsave(&state->lock, flags); } current->state = TASK_RUNNING; remove_wait_queue(&state->wait_queue, &wait); - + spin_unlock_irqrestore(&state->lock, flags); + if (ret) return ret; @@ -755,6 +749,8 @@ if (count < 2 || count > sizeof(req->data)) return -EINVAL; + if (adb_controller == NULL) + return -ENXIO; ret = verify_area(VERIFY_READ, buf, count); if (ret) return ret; @@ -774,7 +770,10 @@ goto out; atomic_inc(&state->n_pending); - if (adb_controller == NULL) return -ENXIO; + + /* If a probe is in progress, wait for it to complete */ + while (adb_probe_task_pid != 0 || test_bit(0, &adb_probe_task_flag)) + schedule(); /* Special case for ADB_BUSRESET request, all others are sent to the controller */ @@ -782,6 +781,8 @@ &&(req->data[1] == ADB_BUSRESET)) { ret = do_adb_reset_bus(); atomic_dec(&state->n_pending); + if (ret == 0) + ret = count; goto out; } else { req->reply_expected = ((req->data[1] & 0xc) == 0xc); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/adbhid.c linux-2.5/drivers/macintosh/adbhid.c --- linux-2.5.1/drivers/macintosh/adbhid.c Tue Sep 18 21:23:14 2001 +++ linux-2.5/drivers/macintosh/adbhid.c Thu Dec 27 16:32:31 2001 @@ -273,26 +273,39 @@ break; case 0x1f: /* Powerbook button device */ { + int down = (data[1] == (data[1] & 0xf)); #ifdef CONFIG_PMAC_BACKLIGHT int backlight = get_backlight_level(); - +#endif /* * XXX: Where is the contrast control for the passive? * -- Cort */ - switch (data[1]) { + switch (data[1] & 0x0f) { case 0x8: /* mute */ + input_report_key(&adbhid[id]->input, KEY_MUTE, + data[1] == (data[1] & 0xf)); break; - case 0x7: /* contrast decrease */ + case 0x7: /* volume decrease */ + input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, + data[1] == (data[1] & 0xf)); break; - case 0x6: /* contrast increase */ + case 0x6: /* volume increase */ + input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, + data[1] == (data[1] & 0xf)); + break; + + case 0xb: /* eject */ + input_report_key(&adbhid[id]->input, KEY_EJECTCD, + data[1] == (data[1] & 0xf)); break; +#ifdef CONFIG_PMAC_BACKLIGHT case 0xa: /* brightness decrease */ - if (backlight < 0) + if (!down || backlight < 0) break; if (backlight > BACKLIGHT_OFF) set_backlight_level(backlight-1); @@ -301,15 +314,15 @@ break; case 0x9: /* brightness increase */ - if (backlight < 0) + if (!down || backlight < 0) break; if (backlight < BACKLIGHT_MAX) set_backlight_level(backlight+1); else set_backlight_level(BACKLIGHT_MAX); break; - } #endif /* CONFIG_PMAC_BACKLIGHT */ + } } break; } @@ -504,6 +517,11 @@ case 0x1f: /* Powerbook button device */ sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x", id, default_id, original_handler_id); + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + set_bit(KEY_MUTE, adbhid[id]->input.keybit); + set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit); + set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit); + set_bit(KEY_EJECTCD, adbhid[id]->input.keybit); break; } if (adbhid[id]->name[0]) @@ -542,16 +560,38 @@ } +static u16 +adbhid_input_reregister(int id, int default_id, int org_handler_id, + int cur_handler_id, int mk) +{ + if (adbhid[id]) { + if (adbhid[id]->input.idproduct != + ((id << 12)|(default_id << 8)|org_handler_id)) { + adbhid_input_unregister(id); + adbhid_input_register(id, default_id, org_handler_id, + cur_handler_id, mk); + } + } else + adbhid_input_register(id, default_id, org_handler_id, + cur_handler_id, mk); + return 1<<id; +} + +static void +adbhid_input_devcleanup(u16 exist) +{ + int i; + for(i=1; i<16; i++) + if (adbhid[i] && !(exist&(1<<i))) + adbhid_input_unregister(i); +} + static void adbhid_probe(void) { struct adb_request req; int i, default_id, org_handler_id, cur_handler_id; - - for (i = 1; i < 16; i++) { - if (adbhid[i]) - adbhid_input_unregister(i); - } + u16 reg = 0; adb_register(ADB_MOUSE, 0, &mouse_ids, adbhid_mouse_input); adb_register(ADB_KEYBOARD, 0, &keyboard_ids, adbhid_keyboard_input); @@ -580,14 +620,14 @@ printk("ADB keyboard at %d, handler 1\n", id); adb_get_infos(id, &default_id, &cur_handler_id); - adbhid_input_register(id, default_id, org_handler_id, cur_handler_id, 0); + reg |= adbhid_input_reregister(id, default_id, org_handler_id, cur_handler_id, 0); } for (i = 0; i < buttons_ids.nids; i++) { int id = buttons_ids.id[i]; adb_get_infos(id, &default_id, &org_handler_id); - adbhid_input_register(id, default_id, org_handler_id, org_handler_id, 0); + reg |= adbhid_input_reregister(id, default_id, org_handler_id, org_handler_id, 0); } /* Try to switch all mice to handler 4, or 2 for three-button @@ -676,9 +716,10 @@ printk("\n"); adb_get_infos(id, &default_id, &cur_handler_id); - adbhid_input_register(id, default_id, org_handler_id, + reg |= adbhid_input_reregister(id, default_id, org_handler_id, cur_handler_id, mouse_kind); } + adbhid_input_devcleanup(reg); } static void diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/ans-lcd.c linux-2.5/drivers/macintosh/ans-lcd.c --- linux-2.5.1/drivers/macintosh/ans-lcd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/macintosh/ans-lcd.c Thu Dec 27 16:32:31 2001 @@ -0,0 +1,171 @@ +/* + * /dev/lcd driver for Apple Network Servers. + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/fcntl.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <asm/uaccess.h> +#include <asm/sections.h> +#include <asm/prom.h> +#include <asm/ans-lcd.h> +#include <asm/io.h> + +#define ANSLCD_ADDR 0xf301c000 +#define ANSLCD_CTRL_IX 0x00 +#define ANSLCD_DATA_IX 0x10 + +static unsigned long anslcd_short_delay = 80; +static unsigned long anslcd_long_delay = 3280; +static volatile unsigned char* anslcd_ptr; + +#undef DEBUG + +static void __pmac +anslcd_write_byte_ctrl ( unsigned char c ) +{ +#ifdef DEBUG + printk(KERN_DEBUG "LCD: CTRL byte: %02x\n",c); +#endif + out_8(anslcd_ptr + ANSLCD_CTRL_IX, c); + switch(c) { + case 1: + case 2: + case 3: + udelay(anslcd_long_delay); break; + default: udelay(anslcd_short_delay); + } +} + +static void __pmac +anslcd_write_byte_data ( unsigned char c ) +{ + out_8(anslcd_ptr + ANSLCD_DATA_IX, c); + udelay(anslcd_short_delay); +} + +static ssize_t __pmac +anslcd_write( struct file * file, const char * buf, + size_t count, loff_t *ppos ) +{ + const char * p = buf; + int i; + +#ifdef DEBUG + printk(KERN_DEBUG "LCD: write\n"); +#endif + + if ( verify_area(VERIFY_READ, buf, count) ) + return -EFAULT; + for ( i = *ppos; count > 0; ++i, ++p, --count ) + { + char c; + __get_user(c, p); + anslcd_write_byte_data( c ); + } + *ppos = i; + return p - buf; +} + +static int __pmac +anslcd_ioctl( struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg ) +{ + char ch, *temp; + +#ifdef DEBUG + printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg); +#endif + + switch ( cmd ) + { + case ANSLCD_CLEAR: + anslcd_write_byte_ctrl ( 0x38 ); + anslcd_write_byte_ctrl ( 0x0f ); + anslcd_write_byte_ctrl ( 0x06 ); + anslcd_write_byte_ctrl ( 0x01 ); + anslcd_write_byte_ctrl ( 0x02 ); + return 0; + case ANSLCD_SENDCTRL: + temp = (char *) arg; + __get_user(ch, temp); + for (; ch; temp++) { /* FIXME: This is ugly, but should work, as a \0 byte is not a valid command code */ + anslcd_write_byte_ctrl ( ch ); + __get_user(ch, temp); + } + return 0; + case ANSLCD_SETSHORTDELAY: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + anslcd_short_delay=arg; + return 0; + case ANSLCD_SETLONGDELAY: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + anslcd_long_delay=arg; + return 0; + default: + return -EINVAL; + } +} + +static int __pmac +anslcd_open( struct inode * inode, struct file * file ) +{ + return 0; +} + +struct file_operations anslcd_fops = { + write: anslcd_write, + ioctl: anslcd_ioctl, + open: anslcd_open, +}; + +static struct miscdevice anslcd_dev = { + ANSLCD_MINOR, + "anslcd", + &anslcd_fops +}; + +const char anslcd_logo[] = "********************" /* Line #1 */ + "* LINUX! *" /* Line #3 */ + "* Welcome to *" /* Line #2 */ + "********************"; /* Line #4 */ + +int __init +anslcd_init(void) +{ + int a; + struct device_node* node; + + node = find_devices("lcd"); + if (!node || !node->parent) + return -ENODEV; + if (strcmp(node->parent->name, "gc")) + return -ENODEV; + + anslcd_ptr = (volatile unsigned char*)ioremap(ANSLCD_ADDR, 0x20); + + misc_register(&anslcd_dev); + +#ifdef DEBUG + printk(KERN_DEBUG "LCD: init\n"); +#endif + + anslcd_write_byte_ctrl ( 0x38 ); + anslcd_write_byte_ctrl ( 0x0c ); + anslcd_write_byte_ctrl ( 0x06 ); + anslcd_write_byte_ctrl ( 0x01 ); + anslcd_write_byte_ctrl ( 0x02 ); + for(a=0;a<80;a++) { + anslcd_write_byte_data(anslcd_logo[a]); + } + return 0; +} + +__initcall(anslcd_init); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/apm_emu.c linux-2.5/drivers/macintosh/apm_emu.c --- linux-2.5.1/drivers/macintosh/apm_emu.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/macintosh/apm_emu.c Thu Dec 27 16:32:31 2001 @@ -0,0 +1,545 @@ +/* APM emulation layer for PowerMac + * + * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * Lots of code inherited from apm.c, see appropriate notice in + * arch/i386/kernel/apm.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, 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. + * + * + */ + +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/poll.h> +#include <linux/types.h> +#include <linux/stddef.h> +#include <linux/timer.h> +#include <linux/fcntl.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/proc_fs.h> +#include <linux/miscdevice.h> +#include <linux/apm_bios.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/pm.h> +#include <linux/kernel.h> +#include <linux/smp_lock.h> + +#include <linux/adb.h> +#include <linux/pmu.h> + +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/machdep.h> + +#undef DEBUG + +#ifdef DEBUG +#define DBG(args...) printk(KERN_DEBUG args) +//#define DBG(args...) xmon_printf(args) +#else +#define DBG(args...) do { } while (0) +#endif + +/* + * The apm_bios device is one of the misc char devices. + * This is its minor number. + */ +#define APM_MINOR_DEV 134 + +/* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 20 + +#define FAKE_APM_BIOS_VERSION 0x0101 + +#define APM_USER_NOTIFY_TIMEOUT (5*HZ) + +/* + * The per-file APM data + */ +struct apm_user { + int magic; + struct apm_user * next; + int suser: 1; + int suspend_waiting: 1; + int suspends_pending; + int suspends_read; + int event_head; + int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The magic number in apm_user + */ +#define APM_BIOS_MAGIC 0x4101 + +/* + * Local variables + */ +static int suspends_pending; + +static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); +static struct apm_user * user_list; + +static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier apm_sleep_notifier = { + apm_notify_sleep, + SLEEP_LEVEL_USERLAND, +}; + +static char driver_version[] = "0.5"; /* no spaces */ + +#ifdef DEBUG +static char * apm_event_name[] = { + "system standby", + "system suspend", + "normal resume", + "critical resume", + "low battery", + "power status change", + "update time", + "critical suspend", + "user standby", + "user suspend", + "system standby resume", + "capabilities change" +}; +#define NR_APM_EVENT_NAME \ + (sizeof(apm_event_name) / sizeof(apm_event_name[0])) + +#endif + +static int queue_empty(struct apm_user *as) +{ + return as->event_head == as->event_tail; +} + +static apm_event_t get_queued_event(struct apm_user *as) +{ + as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + return as->events[as->event_tail]; +} + +static void queue_event(apm_event_t event, struct apm_user *sender) +{ + struct apm_user * as; + + DBG("apm_emu: queue_event(%s)\n", apm_event_name[event-1]); + if (user_list == NULL) + return; + for (as = user_list; as != NULL; as = as->next) { + if (as == sender) + continue; + as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; + if (as->event_head == as->event_tail) { + static int notified; + + if (notified++ == 0) + printk(KERN_ERR "apm_emu: an event queue overflowed\n"); + as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + } + as->events[as->event_head] = event; + if (!as->suser) + continue; + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + as->suspends_pending++; + suspends_pending++; + break; + case APM_NORMAL_RESUME: + as->suspend_waiting = 0; + break; + } + } + wake_up_interruptible(&apm_waitqueue); +} + +static int check_apm_user(struct apm_user *as, const char *func) +{ + if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { + printk(KERN_ERR "apm_emu: %s passed bad filp\n", func); + return 1; + } + return 0; +} + +static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos) +{ + struct apm_user * as; + int i; + apm_event_t event; + DECLARE_WAITQUEUE(wait, current); + + as = fp->private_data; + if (check_apm_user(as, "read")) + return -EIO; + if (count < sizeof(apm_event_t)) + return -EINVAL; + if (queue_empty(as)) { + if (fp->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&apm_waitqueue, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty(as) && !signal_pending(current)) { + schedule(); + goto repeat; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_waitqueue, &wait); + } + i = count; + while ((i >= sizeof(event)) && !queue_empty(as)) { + event = get_queued_event(as); + DBG("apm_emu: do_read, returning: %s\n", apm_event_name[event-1]); + if (copy_to_user(buf, &event, sizeof(event))) { + if (i < count) + break; + return -EFAULT; + } + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + as->suspends_read++; + break; + } + buf += sizeof(event); + i -= sizeof(event); + } + if (i < count) + return count - i; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +static unsigned int do_poll(struct file *fp, poll_table * wait) +{ + struct apm_user * as; + + as = fp->private_data; + if (check_apm_user(as, "poll")) + return 0; + poll_wait(fp, &apm_waitqueue, wait); + if (!queue_empty(as)) + return POLLIN | POLLRDNORM; + return 0; +} + +static int do_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +{ + struct apm_user * as; + DECLARE_WAITQUEUE(wait, current); + + as = filp->private_data; + if (check_apm_user(as, "ioctl")) + return -EIO; + if (!as->suser) + return -EPERM; + switch (cmd) { + case APM_IOC_SUSPEND: + /* If a suspend message was sent to userland, we + * consider this as a confirmation message + */ + if (as->suspends_read > 0) { + as->suspends_read--; + as->suspends_pending--; + suspends_pending--; + } else { + // Route to PMU suspend ? + break; + } + as->suspend_waiting = 1; + add_wait_queue(&apm_waitqueue, &wait); + DBG("apm_emu: ioctl waking up sleep waiter !\n"); + wake_up(&apm_suspend_waitqueue); + mb(); + while(as->suspend_waiting && !signal_pending(current)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_waitqueue, &wait); + break; + default: + return -EINVAL; + } + return 0; +} + +static int do_release(struct inode * inode, struct file * filp) +{ + struct apm_user * as; + + as = filp->private_data; + if (check_apm_user(as, "release")) + return 0; + filp->private_data = NULL; + lock_kernel(); + if (as->suspends_pending > 0) { + suspends_pending -= as->suspends_pending; + if (suspends_pending <= 0) + wake_up(&apm_suspend_waitqueue); + } + if (user_list == as) + user_list = as->next; + else { + struct apm_user * as1; + + for (as1 = user_list; + (as1 != NULL) && (as1->next != as); + as1 = as1->next) + ; + if (as1 == NULL) + printk(KERN_ERR "apm: filp not in user list\n"); + else + as1->next = as->next; + } + unlock_kernel(); + kfree(as); + return 0; +} + +static int do_open(struct inode * inode, struct file * filp) +{ + struct apm_user * as; + + as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); + if (as == NULL) { + printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", + sizeof(*as)); + return -ENOMEM; + } + as->magic = APM_BIOS_MAGIC; + as->event_tail = as->event_head = 0; + as->suspends_pending = 0; + as->suspends_read = 0; + /* + * XXX - this is a tiny bit broken, when we consider BSD + * process accounting. If the device is opened by root, we + * instantly flag that we used superuser privs. Who knows, + * we might close the device immediately without doing a + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); + as->next = user_list; + user_list = as; + filp->private_data = as; + + DBG("apm_emu: opened by %s, suser: %d\n", current->comm, (int)as->suser); + + return 0; +} + +/* Wait for all clients to ack the suspend request. APM API + * doesn't provide a way to NAK, but this could be added + * here. + */ +static int wait_all_suspend(void) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&apm_suspend_waitqueue, &wait); + DBG("apm_emu: wait_all_suspend(), suspends_pending: %d\n", suspends_pending); + while(suspends_pending > 0) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_suspend_waitqueue, &wait); + + DBG("apm_emu: wait_all_suspend() - complete !\n"); + + return 1; +} + +static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when) +{ + switch(when) { + case PBOOK_SLEEP_REQUEST: + queue_event(APM_SYS_SUSPEND, NULL); + if (!wait_all_suspend()) + return PBOOK_SLEEP_REFUSE; + break; + case PBOOK_SLEEP_REJECT: + case PBOOK_WAKE: + queue_event(APM_NORMAL_RESUME, NULL); + break; + } + return PBOOK_SLEEP_OK; +} + +#define APM_CRITICAL 10 +#define APM_LOW 30 + +static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length) +{ + /* Arguments, with symbols from linux/apm_bios.h. Information is + from the Get Power Status (0x0a) call unless otherwise noted. + + 0) Linux driver version (this will change if format changes) + 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. + 2) APM flags from APM Installation Check (0x00): + bit 0: APM_16_BIT_SUPPORT + bit 1: APM_32_BIT_SUPPORT + bit 2: APM_IDLE_SLOWS_CLOCK + bit 3: APM_BIOS_DISABLED + bit 4: APM_BIOS_DISENGAGED + 3) AC line status + 0x00: Off-line + 0x01: On-line + 0x02: On backup power (BIOS >= 1.1 only) + 0xff: Unknown + 4) Battery status + 0x00: High + 0x01: Low + 0x02: Critical + 0x03: Charging + 0x04: Selected battery not present (BIOS >= 1.2 only) + 0xff: Unknown + 5) Battery flag + bit 0: High + bit 1: Low + bit 2: Critical + bit 3: Charging + bit 7: No system battery + 0xff: Unknown + 6) Remaining battery life (percentage of charge): + 0-100: valid + -1: Unknown + 7) Remaining battery life (time units): + Number of remaining minutes or seconds + -1: Unknown + 8) min = minutes; sec = seconds */ + + unsigned short ac_line_status = 0xff; + unsigned short battery_status = 0xff; + unsigned short battery_flag = 0xff; + int percentage = -1; + int time_units = -1; + int real_count = 0; + int i; + char * p = buf; + + ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0); + for (i=0; i<pmu_battery_count; i++) { + if (percentage < 0) + percentage = 0; + if (time_units < 0) + time_units = 0; + if (pmu_batteries[i].flags & PMU_BATT_PRESENT) { + percentage += (pmu_batteries[i].charge * 100) / + pmu_batteries[i].max_charge; + /* hrm... should we provide the remaining charge + * time when AC is plugged ? If yes, just remove + * that test --BenH + */ + if (!ac_line_status) + time_units += pmu_batteries[i].time_remaining / 60; + real_count++; + if (pmu_batteries[i].flags & PMU_BATT_CHARGING) + battery_flag |= 0x08; + } + } + if (real_count) { + percentage /= real_count; + if (percentage <= APM_CRITICAL) { + battery_status = 0x02; + battery_flag = 0x04; + } else if (percentage <= APM_LOW) { + battery_status = 0x01; + battery_flag = 0x02; + } else { + battery_status = 0x00; + battery_flag = 0x01; + } + if (battery_flag & 0x08) + battery_status = 0x03; + } + p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + driver_version, + (FAKE_APM_BIOS_VERSION >> 8) & 0xff, + FAKE_APM_BIOS_VERSION & 0xff, + 0, + ac_line_status, + battery_status, + battery_flag, + percentage, + time_units, + "min"); + + return p - buf; +} + +static struct file_operations apm_bios_fops = { + owner: THIS_MODULE, + read: do_read, + poll: do_poll, + ioctl: do_ioctl, + open: do_open, + release: do_release, +}; + +static struct miscdevice apm_device = { + APM_MINOR_DEV, + "apm_bios", + &apm_bios_fops +}; + +static int __init apm_emu_init(void) +{ + struct proc_dir_entry *apm_proc; + + if (sys_ctrler != SYS_CTRLER_PMU) { + printk(KERN_INFO "apm_emu: Requires a machine with a PMU.\n"); + return -ENODEV; + } + + apm_proc = create_proc_info_entry("apm", 0, NULL, apm_emu_get_info); + if (apm_proc) + SET_MODULE_OWNER(apm_proc); + + misc_register(&apm_device); + + pmu_register_sleep_notifier(&apm_sleep_notifier); + + printk(KERN_INFO "apm_emu: APM Emulation %s initialized.\n", driver_version); + + return 0; +} + +static void __exit apm_emu_exit(void) +{ + pmu_unregister_sleep_notifier(&apm_sleep_notifier); + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); + + printk(KERN_INFO "apm_emu: APM Emulation removed.\n"); +} + +module_init(apm_emu_init); +module_exit(apm_emu_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt"); +MODULE_DESCRIPTION("APM emulation layer for PowerMac"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/mac_hid.c linux-2.5/drivers/macintosh/mac_hid.c --- linux-2.5.1/drivers/macintosh/mac_hid.c Wed Jun 27 20:37:35 2001 +++ linux-2.5/drivers/macintosh/mac_hid.c Thu Dec 27 16:32:31 2001 @@ -200,15 +200,15 @@ 0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */ 0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0, /* 0x08-0x0f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ - 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18-0x1f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, KEY_VOLUMEUP, 0,/* 0x18-0x1f */ + 0, 0, 0, 0, 0, KEY_VOLUMEDOWN, KEY_MUTE, 0, /* 0x20-0x27 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ 0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ, /* 0x30-0x37 */ - KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */ + KEY_RIGHTALT, 0, 0, KEY_EJECTCD, 0, 0, 0, 0, /* 0x38-0x3f */ 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40-0x47 */ KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */ KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */ - 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, KEY_POWER, 0, /* 0x58-0x5f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ 0, 0, 0, 0, 0, 0, 0, KEY_MACRO, /* 0x68-0x6f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/mac_keyb.c linux-2.5/drivers/macintosh/mac_keyb.c --- linux-2.5.1/drivers/macintosh/mac_keyb.c Tue Sep 18 21:23:14 2001 +++ linux-2.5/drivers/macintosh/mac_keyb.c Thu Dec 27 15:56:12 2001 @@ -256,7 +256,6 @@ #endif extern struct kbd_struct kbd_table[]; -extern wait_queue_head_t keypress_wait; extern void handle_scancode(unsigned char, int); @@ -423,7 +422,6 @@ struct tty_struct *tty; tty = console_driver.table? console_driver.table[fg_console]: NULL; - wake_up(&keypress_wait); if (tty) { tty_insert_flip_char(tty, ch, 0); con_schedule_flip(tty); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/macserial.c linux-2.5/drivers/macintosh/macserial.c --- linux-2.5.1/drivers/macintosh/macserial.c Mon Oct 15 20:43:24 2001 +++ linux-2.5/drivers/macintosh/macserial.c Sun Dec 30 21:17:30 2001 @@ -38,9 +38,9 @@ #include <asm/irq.h> #include <asm/prom.h> #include <asm/system.h> -#include <asm/segment.h> #include <asm/bitops.h> -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #include <linux/adb.h> #include <linux/pmu.h> #ifdef CONFIG_KGDB @@ -1179,7 +1179,7 @@ } memset(info->curregs, 0, sizeof(info->curregs)); - memset(info->curregs, 0, sizeof(info->pendregs)); + memset(info->pendregs, 0, sizeof(info->pendregs)); info->flags &= ~ZILOG_INITIALIZED; } @@ -1194,69 +1194,34 @@ { int delay = 0; - if (feature_test(info->dev_node, FEATURE_Serial_enable) < 0) - return 0; /* don't have serial power control */ - - /* The timings looks strange but that's the ones MacOS seems - to use for the internal modem. I think we can use a lot faster - ones, at least whe not using the modem, this should be tested. - */ if (state) { PWRDBG("ttyS%02d: powering up hardware\n", info->line); - if (feature_test(info->dev_node, FEATURE_Serial_enable) == 0) { - feature_set(info->dev_node, FEATURE_Serial_enable); - mdelay(10); - feature_set(info->dev_node, FEATURE_Serial_reset); - mdelay(15); - feature_clear(info->dev_node, FEATURE_Serial_reset); - mdelay(10); - } - if (info->zs_chan_a == info->zs_channel) - feature_set(info->dev_node, FEATURE_Serial_IO_A); - else - feature_set(info->dev_node, FEATURE_Serial_IO_B); - delay = 10; - if (info->is_cobalt_modem) { - feature_set_modem_power(info->dev_node, 1); + pmac_call_feature( + PMAC_FTR_SCC_ENABLE, + info->dev_node, info->port_type, 1); + if (info->is_internal_modem) { + pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, + info->dev_node, 0, 1); delay = 2500; /* wait for 2.5s before using */ - } -#ifdef CONFIG_PMAC_PBOOK - if (info->is_irda) - pmu_enable_irled(1); -#endif /* CONFIG_PMAC_PBOOK */ + } else if (info->is_irda) + mdelay(50); /* Do better here once the problems + * with blocking have been ironed out + */ } else { /* TODO: Make that depend on a timer, don't power down * immediately */ PWRDBG("ttyS%02d: shutting down hardware\n", info->line); - if (info->is_cobalt_modem) { + if (info->is_internal_modem) { PWRDBG("ttyS%02d: shutting down modem\n", info->line); - feature_set_modem_power(info->dev_node, 0); - } -#ifdef CONFIG_PMAC_PBOOK - if (info->is_irda) - pmu_enable_irled(0); -#endif /* CONFIG_PMAC_PBOOK */ - - if (info->zs_chan_a == info->zs_channel && !info->is_irda) { - PWRDBG("ttyS%02d: shutting down SCC channel A\n", info->line); - feature_clear(info->dev_node, FEATURE_Serial_IO_A); - } else if (!info->is_irda) { - PWRDBG("ttyS%02d: shutting down SCC channel B\n", info->line); - feature_clear(info->dev_node, FEATURE_Serial_IO_B); - } - /* XXX for now, shut down SCC core only on powerbooks */ - if (is_powerbook - && !(feature_test(info->dev_node, FEATURE_Serial_IO_A) || - feature_test(info->dev_node, FEATURE_Serial_IO_B))) { - PWRDBG("ttyS%02d: shutting down SCC core\n", info->line); - feature_set(info->dev_node, FEATURE_Serial_reset); - mdelay(15); - feature_clear(info->dev_node, FEATURE_Serial_reset); - mdelay(25); - feature_clear(info->dev_node, FEATURE_Serial_enable); - mdelay(5); - } + pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, + info->dev_node, 0, 0); + } + pmac_call_feature( + PMAC_FTR_SCC_ENABLE, + info->dev_node, info->port_type, 0); } return delay; } @@ -2381,7 +2346,7 @@ * Initialize one channel, both the mac_serial and mac_zschannel * structs. We use the dev_node field of the mac_serial struct. */ -static void +static int chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan, struct mac_zschannel *zs_chan_a) { @@ -2411,12 +2376,15 @@ /* setup misc varariables */ zss->kgdb_channel = 0; - zss->is_cobalt_modem = device_is_compatible(ch, "cobalt"); - /* XXX tested only with wallstreet PowerBook, - should do no harm anyway */ + /* For now, we assume you either have a slot-names property + * with "Modem" in it, or your channel is compatible with + * "cobalt". Might need additional fixups + */ + zss->is_internal_modem = device_is_compatible(ch, "cobalt"); conn = get_property(ch, "AAPL,connector", &len); zss->is_irda = conn && (strcmp(conn, "infrared") == 0); + zss->port_type = PMAC_SCC_ASYNC; /* 1999 Powerbook G3 has slot-names property instead */ slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len); if (slots && slots->count > 0) { @@ -2425,8 +2393,29 @@ else if (strcmp(slots->name, "Modem") == 0) zss->is_internal_modem = 1; } + if (zss->is_irda) + zss->port_type = PMAC_SCC_IRDA; + if (zss->is_internal_modem) { + struct device_node* i2c_modem = find_devices("i2c-modem"); + if (i2c_modem) { + char* mid = get_property(i2c_modem, "modem-id", NULL); + if (mid) switch(*mid) { + case 0x04 : + case 0x05 : + case 0x07 : + case 0x08 : + case 0x0b : + case 0x0c : + zss->port_type = PMAC_SCC_I2S1; + } + printk(KERN_INFO "macserial: i2c-modem detected, id: %d\n", + mid ? (*mid) : 0); + } else { + printk(KERN_INFO "macserial: serial modem detected\n"); + } + } - if (zss->has_dma) { + while (zss->has_dma) { zss->dma_priv = NULL; /* it seems that the last two addresses are the DMA controllers */ @@ -2437,11 +2426,13 @@ zss->tx_dma_irq = ch->intrs[1].line; zss->rx_dma_irq = ch->intrs[2].line; spin_lock_init(&zss->rx_dma_lock); + break; } init_timer(&zss->powerup_timer); zss->powerup_timer.function = powerup_done; zss->powerup_timer.data = (unsigned long) zss; + return 0; } /* Ask the PROM how many Z8530s we have and initialize their zs_channels */ @@ -2496,13 +2487,15 @@ continue; /* set up A side */ - chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan); + if (chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan)) + continue; ++zs_chan; /* set up B side, if it exists */ if (nchan > 1) - chan_init(&zs_soft[chip + 1 - chan_a_index], - zs_chan, zs_chan - 1); + if (chan_init(&zs_soft[chip + 1 - chan_a_index], + zs_chan, zs_chan - 1)) + continue; ++zs_chan; } *pp = 0; @@ -2528,13 +2521,35 @@ if (zs_chain == 0) probe_sccs(); - /* XXX assume it's a powerbook if we have a via-pmu */ + /* XXX assume it's a powerbook if we have a via-pmu + * + * This is OK for core99 machines as well. + */ is_powerbook = find_devices("via-pmu") != 0; - /* Register the interrupt handler for each one */ + /* Register the interrupt handler for each one + * We also request the OF resources here as probe_sccs() + * might be called too early for that + */ save_flags(flags); cli(); for (i = 0; i < zs_channels_found; ++i) { + struct device_node* ch = zs_soft[i].dev_node; + if (!request_OF_resource(ch, 0, NULL)) { + printk(KERN_ERR "macserial: can't request IO resource !\n"); + return -ENODEV; + } if (zs_soft[i].has_dma) { + if (!request_OF_resource(ch, ch->n_addrs - 2, " (tx dma)")) { + printk(KERN_ERR "macserial: can't request TX DMA resource !\n"); + zs_soft[i].has_dma = 0; + goto no_dma; + } + if (!request_OF_resource(ch, ch->n_addrs - 1, " (rx dma)")) { + release_OF_resource(ch, ch->n_addrs - 2); + printk(KERN_ERR "macserial: can't request RX DMA resource !\n"); + zs_soft[i].has_dma = 0; + goto no_dma; + } if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0, "SCC-txdma", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", @@ -2546,6 +2561,7 @@ zs_soft[i].rx_dma_irq); disable_irq(zs_soft[i].rx_dma_irq); } +no_dma: if (request_irq(zs_soft[i].irq, rs_interrupt, 0, "SCC", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", @@ -2580,7 +2596,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -2676,9 +2694,7 @@ connector = get_property(info->dev_node, "AAPL,connector", &lenp); if (connector) printk(", port = %s", connector); - if (info->is_cobalt_modem) - printk(" (cobalt modem)"); - else if (info->is_internal_modem) + if (info->is_internal_modem) printk(" (internal modem)"); if (info->is_irda) printk(" (IrDA)"); @@ -2712,6 +2728,12 @@ free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]); free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]); } + release_OF_resource(zs_soft[i].dev_node, 0); + if (zs_soft[i].has_dma) { + struct device_node* ch = zs_soft[i].dev_node; + release_OF_resource(ch, ch->n_addrs - 2); + release_OF_resource(ch, ch->n_addrs - 1); + } } restore_flags(flags); tty_unregister_driver(&callout_driver); @@ -2792,30 +2814,6 @@ /* Don't disable the transmitter. */ } -/* - * Receive character from the serial port - */ -static int serial_console_wait_key(struct console *co) -{ - struct mac_serial *info = zs_soft + co->index; - int val; - - /* Turn of interrupts and enable the transmitter. */ - write_zsreg(info->zs_channel, R1, info->curregs[1] & ~INT_ALL_Rx); - write_zsreg(info->zs_channel, R3, info->curregs[3] | RxENABLE); - - /* Wait for something in the receive buffer. */ - while((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) - eieio(); - val = read_zsdata(info->zs_channel); - - /* Restore the values in the registers. */ - write_zsreg(info->zs_channel, R1, info->curregs[1]); - write_zsreg(info->zs_channel, R3, info->curregs[3]); - - return val; -} - static kdev_t serial_console_device(struct console *c) { return MKDEV(TTY_MAJOR, 64 + c->index); @@ -3006,7 +3004,6 @@ name: "ttyS", write: serial_console_write, device: serial_console_device, - wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/macserial.h linux-2.5/drivers/macintosh/macserial.h --- linux-2.5.1/drivers/macintosh/macserial.h Wed Jun 27 20:37:35 2001 +++ linux-2.5/drivers/macintosh/macserial.h Thu Dec 27 16:32:31 2001 @@ -111,8 +111,8 @@ char kgdb_channel; /* Kgdb is running on this channel */ char is_cons; /* Is this our console. */ char is_internal_modem; /* is connected to an internal modem */ - char is_cobalt_modem; /* is a gatwick-based cobalt modem */ char is_irda; /* is connected to an IrDA codec */ + int port_type; /* Port type for pmac_feature */ unsigned char tx_active; /* character is being xmitted */ unsigned char tx_stopped; /* output is suspended */ unsigned char power_wait; /* waiting for power-up delay to expire */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/mediabay.c linux-2.5/drivers/macintosh/mediabay.c --- linux-2.5.1/drivers/macintosh/mediabay.c Sat Sep 8 19:38:42 2001 +++ linux-2.5/drivers/macintosh/mediabay.c Thu Dec 27 16:32:31 2001 @@ -25,9 +25,13 @@ #include <asm/prom.h> #include <asm/pgtable.h> #include <asm/io.h> -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #include <asm/mediabay.h> #include <asm/sections.h> +#include <asm/ohare.h> +#include <asm/heathrow.h> +#include <asm/keylargo.h> #include <linux/adb.h> #include <linux/pmu.h> @@ -40,7 +44,7 @@ #endif #undef MB_USE_INTERRUPTS -#undef MB_DEBUG +#define MB_DEBUG #define MB_IGNORE_SIGNALS #ifdef MB_DEBUG @@ -49,24 +53,46 @@ #define MBDBG(fmt, arg...) do { } while (0) #endif -struct media_bay_hw { - unsigned char b0; - unsigned char contents; - unsigned char b2; - unsigned char b3; +/* Type of media bay */ +enum { + mb_ohare, + mb_heathrow, + mb_keylargo +}; + +#define MB_FCR32(bay, r) ((bay)->base + ((r) >> 2)) +#define MB_FCR8(bay, r) (((volatile u8*)((bay)->base)) + (r)) + +#define MB_IN32(bay,r) (in_le32(MB_FCR32(bay,r))) +#define MB_OUT32(bay,r,v) (out_le32(MB_FCR32(bay,r), (v))) +#define MB_BIS(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) | (v))) +#define MB_BIC(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) & ~(v))) +#define MB_IN8(bay,r) (in_8(MB_FCR8(bay,r))) +#define MB_OUT8(bay,r,v) (out_8(MB_FCR8(bay,r), (v))) + +struct media_bay_info; + +struct mb_ops { + char* name; + u8 (*content)(struct media_bay_info* bay); + void (*power)(struct media_bay_info* bay, int on_off); + int (*setup_bus)(struct media_bay_info* bay, u8 device_id); + void (*un_reset)(struct media_bay_info* bay); + void (*un_reset_ide)(struct media_bay_info* bay); }; struct media_bay_info { - volatile struct media_bay_hw* addr; - volatile u8* extint_gpio; + volatile u32* base; int content_id; int state; int last_value; int value_count; int timer; struct device_node* dev_node; - int pismo; /* New PowerBook3,1 */ - int gpio_cache; + int mb_type; + struct mb_ops* ops; + int index; + int cached_gpio; #ifdef CONFIG_BLK_DEV_IDE unsigned long cd_base; int cd_index; @@ -77,33 +103,12 @@ #define MAX_BAYS 2 -static volatile struct media_bay_info media_bays[MAX_BAYS]; +static struct media_bay_info media_bays[MAX_BAYS]; int media_bay_count = 0; -inline int mb_content(volatile struct media_bay_info *bay) -{ - if (bay->pismo) { - unsigned char new_gpio = in_8(bay->extint_gpio + 0xe) & 2; - if (new_gpio) { - bay->gpio_cache = new_gpio; - return MB_NO; - } else if (bay->gpio_cache != new_gpio) { - /* make sure content bits are set */ - feature_set(bay->dev_node, FEATURE_Mediabay_content); - udelay(5); - bay->gpio_cache = new_gpio; - } - return (in_le32((unsigned*)bay->addr) >> 4) & 0xf; - } else { - int cont = (in_8(&bay->addr->contents) >> 4) & 7; - return (cont == 7) ? MB_NO : cont; - } -} - #ifdef CONFIG_BLK_DEV_IDE /* check the busy bit in the media-bay ide interface (assumes the media-bay contains an ide device) */ -//#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0xc0) == 0x40) #define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0) #endif @@ -116,7 +121,7 @@ * Consider the media-bay ID value stable if it is the same for * this number of milliseconds */ -#define MB_STABLE_DELAY 40 +#define MB_STABLE_DELAY 100 /* Wait after powering up the media bay this delay in ms * timeout bumped for some powerbooks @@ -166,175 +171,259 @@ mb_powering_down /* Powering down (avoid too fast down/up) */ }; -static void poll_media_bay(int which); -static void set_media_bay(int which, int id); -static void set_mb_power(int which, int onoff); -static void media_bay_step(int i); -static int media_bay_task(void *); +#define MB_POWER_SOUND 0x08 +#define MB_POWER_FLOPPY 0x04 +#define MB_POWER_ATA 0x02 +#define MB_POWER_PCI 0x01 +#define MB_POWER_OFF 0x00 -#ifdef MB_USE_INTERRUPTS -static void media_bay_intr(int irq, void *devid, struct pt_regs *regs); -#endif +/* + * Functions for polling content of media bay + */ + +static u8 __pmac +ohare_mb_content(struct media_bay_info *bay) +{ + return (MB_IN32(bay, OHARE_MBCR) >> 12) & 7; +} + +static u8 __pmac +heathrow_mb_content(struct media_bay_info *bay) +{ + return (MB_IN32(bay, HEATHROW_MBCR) >> 12) & 7; +} + +static u8 __pmac +keylargo_mb_content(struct media_bay_info *bay) +{ + int new_gpio; + + new_gpio = MB_IN8(bay, KL_GPIO_MEDIABAY_IRQ) & KEYLARGO_GPIO_INPUT_DATA; + if (new_gpio) { + bay->cached_gpio = new_gpio; + return MB_NO; + } else if (bay->cached_gpio != new_gpio) { + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); + (void)MB_IN32(bay, KEYLARGO_MBCR); + udelay(5); + MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); + (void)MB_IN32(bay, KEYLARGO_MBCR); + udelay(5); + bay->cached_gpio = new_gpio; + } + return (MB_IN32(bay, KEYLARGO_MBCR) >> 4) & 7; +} /* - * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL - * register is always set when there is something in the media bay. - * This causes problems for the interrupt code if we attach an interrupt - * handler to the media-bay interrupt, because it tends to go into - * an infinite loop calling the media bay interrupt handler. - * Therefore we do it all by polling the media bay once each tick. + * Functions for powering up/down the bay, puts the bay device + * into reset state as well */ -void __pmac -media_bay_init(void) +static void __pmac +ohare_mb_power(struct media_bay_info* bay, int on_off) { - struct device_node *np; - int n,i; - - for (i=0; i<MAX_BAYS; i++) { - memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info)); - media_bays[i].content_id = -1; -#ifdef CONFIG_BLK_DEV_IDE - media_bays[i].cd_index = -1; -#endif + if (on_off) { + /* Power up device, assert it's reset line */ + MB_BIC(bay, OHARE_FCR, OH_BAY_RESET_N); + MB_BIC(bay, OHARE_FCR, OH_BAY_POWER_N); + } else { + /* Disable all devices */ + MB_BIC(bay, OHARE_FCR, OH_BAY_DEV_MASK); + MB_BIC(bay, OHARE_FCR, OH_FLOPPY_ENABLE); + /* Cut power from bay, release reset line */ + MB_BIS(bay, OHARE_FCR, OH_BAY_POWER_N); + MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); + MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); } - - np = find_devices("media-bay"); - n = 0; - while(np && (n<MAX_BAYS)) { - if (np->n_addrs == 0) - continue; - media_bays[n].addr = (volatile struct media_bay_hw *) - ioremap(np->addrs[0].address, sizeof(struct media_bay_hw)); + MB_BIC(bay, OHARE_MBCR, 0x00000F00); +} - media_bays[n].pismo = device_is_compatible(np, "keylargo-media-bay"); - if (media_bays[n].pismo) { - if (!np->parent || strcmp(np->parent->name, "mac-io")) { - printk(KERN_ERR "Pismo media-bay has no mac-io parent !\n"); - continue; - } - media_bays[n].extint_gpio = ioremap(np->parent->addrs[0].address - + 0x58, 0x10); - } +static void __pmac +heathrow_mb_power(struct media_bay_info* bay, int on_off) +{ + if (on_off) { + /* Power up device, assert it's reset line */ + MB_BIC(bay, HEATHROW_FCR, HRW_BAY_RESET_N); + MB_BIC(bay, HEATHROW_FCR, HRW_BAY_POWER_N); + } else { + /* Disable all devices */ + MB_BIC(bay, HEATHROW_FCR, HRW_BAY_DEV_MASK); + MB_BIC(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); + /* Cut power from bay, release reset line */ + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_POWER_N); + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); + MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); + } + MB_BIC(bay, HEATHROW_MBCR, 0x00000F00); +} -#ifdef MB_USE_INTERRUPTS - if (np->n_intrs == 0) { - printk(KERN_ERR "media bay %d has no irq\n",n); - continue; - } +static void __pmac +keylargo_mb_power(struct media_bay_info* bay, int on_off) +{ + if (on_off) { + /* Power up device, assert it's reset line */ + MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); + MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); + } else { + /* Disable all devices */ + MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); + MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); + /* Cut power from bay, release reset line */ + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); + MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); + } + MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); +} - if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) { - printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", - np->intrs[0].line, n); - continue; - } -#endif - media_bay_count++; - - media_bays[n].dev_node = np; +/* + * Functions for configuring the media bay for a given type of device, + * enable the related busses + */ - /* Force an immediate detect */ - set_mb_power(n,0); - mdelay(MB_POWER_DELAY); - if(!media_bays[n].pismo) - out_8(&media_bays[n].addr->contents, 0x70); - mdelay(MB_STABLE_DELAY); - media_bays[n].content_id = MB_NO; - media_bays[n].last_value = mb_content(&media_bays[n]); - media_bays[n].value_count = MS_TO_HZ(MB_STABLE_DELAY); - media_bays[n].state = mb_empty; - do { - mdelay(1000/HZ); - media_bay_step(n); - } while((media_bays[n].state != mb_empty) && - (media_bays[n].state != mb_up)); +static int __pmac +ohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id) +{ + switch(device_id) { + case MB_FD: + case MB_FD1: + MB_BIS(bay, OHARE_FCR, OH_BAY_FLOPPY_ENABLE); + MB_BIS(bay, OHARE_FCR, OH_FLOPPY_ENABLE); + return 0; + case MB_CD: + MB_BIC(bay, OHARE_FCR, OH_IDE1_RESET_N); + MB_BIS(bay, OHARE_FCR, OH_BAY_IDE_ENABLE); + return 0; + case MB_PCI: + MB_BIS(bay, OHARE_FCR, OH_BAY_PCI_ENABLE); + return 0; + } + return -ENODEV; +} - n++; - np=np->next; +static int __pmac +heathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id) +{ + switch(device_id) { + case MB_FD: + case MB_FD1: + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_FLOPPY_ENABLE); + MB_BIS(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); + return 0; + case MB_CD: + MB_BIC(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_IDE_ENABLE); + return 0; + case MB_PCI: + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_PCI_ENABLE); + return 0; } + return -ENODEV; +} - if (media_bay_count) - { - printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count); +static int __pmac +keylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id) +{ + switch(device_id) { + case MB_CD: + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); + MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); + MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); + return 0; + case MB_PCI: + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_PCI_ENABLE); + return 0; + case MB_SOUND: + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_SOUND_ENABLE); + return 0; + } + return -ENODEV; +} -#ifdef CONFIG_PMAC_PBOOK - pmu_register_sleep_notifier(&mb_sleep_notifier); -#endif /* CONFIG_PMAC_PBOOK */ +/* + * Functions for tweaking resets + */ - kernel_thread(media_bay_task, NULL, - CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - } +static void __pmac +ohare_mb_un_reset(struct media_bay_info* bay) +{ + MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); } -#ifdef MB_USE_INTERRUPTS static void __pmac -media_bay_intr(int irq, void *devid, struct pt_regs *regs) +heathrow_mb_un_reset(struct media_bay_info* bay) { + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); +} + +static void __pmac +keylargo_mb_un_reset(struct media_bay_info* bay) +{ + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); +} + +static void __pmac +ohare_mb_un_reset_ide(struct media_bay_info* bay) +{ + MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); +} + +static void __pmac +heathrow_mb_un_reset_ide(struct media_bay_info* bay) +{ + MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); } -#endif static void __pmac -set_mb_power(int which, int onoff) +keylargo_mb_un_reset_ide(struct media_bay_info* bay) { - volatile struct media_bay_info* mb = &media_bays[which]; + MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); +} +static inline void __pmac +set_mb_power(struct media_bay_info* bay, int onoff) +{ + /* Power up up and assert the bay reset line */ if (onoff) { - feature_set(mb->dev_node, FEATURE_Mediabay_power); - udelay(10); - feature_set(mb->dev_node, FEATURE_Mediabay_reset); - udelay(10); - mb->state = mb_powering_up; - MBDBG("mediabay%d: powering up\n", which); - } else { - feature_clear(mb->dev_node, FEATURE_Mediabay_floppy_enable); - if (mb->pismo) - feature_clear(mb->dev_node, FEATURE_IDE0_enable); - else - feature_clear(mb->dev_node, FEATURE_IDE1_enable); - feature_clear(mb->dev_node, FEATURE_Mediabay_IDE_switch); - feature_clear(mb->dev_node, FEATURE_Mediabay_PCI_enable); - feature_clear(mb->dev_node, FEATURE_SWIM3_enable); - feature_clear(mb->dev_node, FEATURE_Mediabay_power); - mb->state = mb_powering_down; - MBDBG("mediabay%d: powering down\n", which); + bay->ops->power(bay, 1); + bay->state = mb_powering_up; + MBDBG("mediabay%d: powering up\n", bay->index); + } else { + /* Make sure everything is powered down & disabled */ + bay->ops->power(bay, 0); + bay->state = mb_powering_down; + MBDBG("mediabay%d: powering down\n", bay->index); } - mb->timer = MS_TO_HZ(MB_POWER_DELAY); + bay->timer = MS_TO_HZ(MB_POWER_DELAY); } static void __pmac -set_media_bay(int which, int id) +poll_media_bay(struct media_bay_info* bay) { - volatile struct media_bay_info* bay; + int id = bay->ops->content(bay); - bay = &media_bays[which]; - - switch (id) { - case MB_CD: - if (bay->pismo) { - feature_set(bay->dev_node, FEATURE_Mediabay_IDE_switch); - udelay(10); - feature_set(bay->dev_node, FEATURE_IDE0_enable); - udelay(10); - feature_set(bay->dev_node, FEATURE_IDE0_reset); - } else { - feature_set(bay->dev_node, FEATURE_IDE1_enable); - udelay(10); - feature_set(bay->dev_node, FEATURE_IDE1_reset); + if (id == bay->last_value) { + if (id != bay->content_id + && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) { + /* If the device type changes without going thru "MB_NO", we force + a pass by "MB_NO" to make sure things are properly reset */ + if ((id != MB_NO) && (bay->content_id != MB_NO)) { + id = MB_NO; + MBDBG("mediabay%d: forcing MB_NO\n", bay->index); } - printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which); - break; - case MB_FD: - case MB_FD1: - feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable); - feature_set(bay->dev_node, FEATURE_SWIM3_enable); - printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which); - break; - case MB_NO: - break; - default: - printk(KERN_INFO "media bay %d contains an unknown device (%d)\n", - which, id); - break; + MBDBG("mediabay%d: switching to %d\n", bay->index, id); + set_mb_power(bay, id != MB_NO); + bay->content_id = id; + if (id == MB_NO) { +#ifdef CONFIG_BLK_DEV_IDE + bay->cd_retry = 0; +#endif + printk(KERN_INFO "media bay %d is empty\n", bay->index); + } + } + } else { + bay->last_value = id; + bay->value_count = 0; } } @@ -412,11 +501,11 @@ static void __pmac media_bay_step(int i) { - volatile struct media_bay_info* bay = &media_bays[i]; + struct media_bay_info* bay = &media_bays[i]; /* We don't poll when powering down */ if (bay->state != mb_powering_down) - poll_media_bay(i); + poll_media_bay(bay); /* If timer expired or polling IDE busy, run state machine */ if ((bay->state != mb_ide_waiting) && (bay->timer != 0) && ((--bay->timer) != 0)) @@ -424,13 +513,17 @@ switch(bay->state) { case mb_powering_up: - set_media_bay(i, bay->last_value); + if (bay->ops->setup_bus(bay, bay->last_value) < 0) { + MBDBG("mediabay%d: device not supported (kind:%d)\n", i, bay->content_id); + set_mb_power(bay, 0); + break; + } bay->timer = MS_TO_HZ(MB_RESET_DELAY); bay->state = mb_enabling_bay; MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id); break; case mb_enabling_bay: - feature_clear(bay->dev_node, FEATURE_Mediabay_reset); + bay->ops->un_reset(bay); bay->timer = MS_TO_HZ(MB_SETUP_DELAY); bay->state = mb_resetting; MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id); @@ -444,16 +537,13 @@ } #ifdef CONFIG_BLK_DEV_IDE MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id); - if (bay->pismo) - feature_clear(bay->dev_node, FEATURE_IDE0_reset); - else - feature_clear(bay->dev_node, FEATURE_IDE1_reset); + bay->ops->un_reset_ide(bay); bay->timer = MS_TO_HZ(MB_IDE_WAIT); bay->state = mb_ide_resetting; #else printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i); - set_mb_power(i, 0); -#endif // #ifdef CONFIG_BLK_DEV_IDE + set_mb_power(bay, 0); +#endif /* CONFIG_BLK_DEV_IDE */ break; #ifdef CONFIG_BLK_DEV_IDE @@ -481,7 +571,7 @@ /* We eventually do a retry */ bay->cd_retry++; printk("IDE register error\n"); - set_mb_power(i, 0); + set_mb_power(bay, 0); } else { printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index); MBDBG("mediabay %d IDE ready\n", i); @@ -491,10 +581,10 @@ if (bay->timer == 0) { printk("\nIDE Timeout in bay %d !\n", i); MBDBG("mediabay%d: nIDE Timeout !\n", i); - set_mb_power(i, 0); + set_mb_power(bay, 0); } break; -#endif // #ifdef CONFIG_BLK_DEV_IDE +#endif /* CONFIG_BLK_DEV_IDE */ case mb_powering_down: bay->state = mb_empty; @@ -514,7 +604,7 @@ bay->content_id = MB_NO; } } -#endif +#endif /* CONFIG_BLK_DEV_IDE */ MBDBG("mediabay%d: end of power down\n", i); break; } @@ -526,7 +616,7 @@ * with the IDE driver. It needs to be a thread because * ide_register can't be called from interrupt context. */ -int __pmac +static int __pmac media_bay_task(void *x) { int i; @@ -547,37 +637,12 @@ } } -void __pmac -poll_media_bay(int which) +#ifdef MB_USE_INTERRUPTS +static void __pmac +media_bay_intr(int irq, void *devid, struct pt_regs *regs) { - volatile struct media_bay_info* bay = &media_bays[which]; - int id = mb_content(bay); - - if (id == bay->last_value) { - if (id != bay->content_id - && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) { - /* If the device type changes without going thru "MB_NO", we force - a pass by "MB_NO" to make sure things are properly reset */ - if ((id != MB_NO) && (bay->content_id != MB_NO)) { - id = MB_NO; - MBDBG("mediabay%d: forcing MB_NO\n", which); - } - MBDBG("mediabay%d: switching to %d\n", which, id); - set_mb_power(which, id != MB_NO); - bay->content_id = id; - if (id == MB_NO) { -#ifdef CONFIG_BLK_DEV_IDE - bay->cd_retry = 0; -#endif - printk(KERN_INFO "media bay %d is empty\n", which); - } - } - } else { - bay->last_value = id; - bay->value_count = 0; - } } - +#endif #ifdef CONFIG_PMAC_PBOOK /* @@ -586,7 +651,7 @@ int __pmac mb_notify_sleep(struct pmu_sleep_notifier *self, int when) { - volatile struct media_bay_info* bay; + struct media_bay_info* bay; int i; switch (when) { @@ -597,7 +662,7 @@ case PBOOK_SLEEP_NOW: for (i=0; i<media_bay_count; i++) { bay = &media_bays[i]; - set_mb_power(i, 0); + set_mb_power(bay, 0); mdelay(10); } break; @@ -609,14 +674,11 @@ they seem to help the 3400 get it right. */ /* Force MB power to 0 */ - set_mb_power(i, 0); + set_mb_power(bay, 0); mdelay(MB_POWER_DELAY); - if (!bay->pismo) - out_8(&bay->addr->contents, 0x70); - mdelay(MB_STABLE_DELAY); - if (mb_content(bay) != bay->content_id) + if (bay->ops->content(bay) != bay->content_id) continue; - set_mb_power(i, 1); + set_mb_power(bay, 1); bay->last_value = bay->content_id; bay->value_count = MS_TO_HZ(MB_STABLE_DELAY); bay->timer = MS_TO_HZ(MB_POWER_DELAY); @@ -634,4 +696,135 @@ return PBOOK_SLEEP_OK; } #endif /* CONFIG_PMAC_PBOOK */ + + +/* Definitions of "ops" structures. + */ +static struct mb_ops ohare_mb_ops __pmacdata = { + name: "Ohare", + content: ohare_mb_content, + power: ohare_mb_power, + setup_bus: ohare_mb_setup_bus, + un_reset: ohare_mb_un_reset, + un_reset_ide: ohare_mb_un_reset_ide, +}; + +static struct mb_ops heathrow_mb_ops __pmacdata = { + name: "Heathrow", + content: heathrow_mb_content, + power: heathrow_mb_power, + setup_bus: heathrow_mb_setup_bus, + un_reset: heathrow_mb_un_reset, + un_reset_ide: heathrow_mb_un_reset_ide, +}; + +static struct mb_ops keylargo_mb_ops __pmacdata = { + name: "KeyLargo", + content: keylargo_mb_content, + power: keylargo_mb_power, + setup_bus: keylargo_mb_setup_bus, + un_reset: keylargo_mb_un_reset, + un_reset_ide: keylargo_mb_un_reset_ide, +}; + +/* + * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL + * register is always set when there is something in the media bay. + * This causes problems for the interrupt code if we attach an interrupt + * handler to the media-bay interrupt, because it tends to go into + * an infinite loop calling the media bay interrupt handler. + * Therefore we do it all by polling the media bay once each tick. + */ + +void __pmac +media_bay_init(void) +{ + struct device_node *np; + int n,i; + + for (i=0; i<MAX_BAYS; i++) { + memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info)); + media_bays[i].content_id = -1; +#ifdef CONFIG_BLK_DEV_IDE + media_bays[i].cd_index = -1; +#endif + } + + np = find_devices("media-bay"); + n = 0; + while(np && (n<MAX_BAYS)) { + struct media_bay_info* bay = &media_bays[n]; + if (!np->parent || np->n_addrs == 0 || !request_OF_resource(np, 0, NULL)) { + np = np->next; + printk(KERN_ERR "media-bay: Can't request IO resource !\n"); + continue; + } + bay->mb_type = mb_ohare; + + if (device_is_compatible(np, "keylargo-media-bay")) { + bay->mb_type = mb_keylargo; + bay->ops = &keylargo_mb_ops; + } else if (device_is_compatible(np, "heathrow-media-bay")) { + bay->mb_type = mb_heathrow; + bay->ops = &heathrow_mb_ops; + } else if (device_is_compatible(np, "ohare-media-bay")) { + bay->mb_type = mb_ohare; + bay->ops = &ohare_mb_ops; + } else { + printk(KERN_ERR "mediabay: Unknown bay type !\n"); + np = np->next; + continue; + } + bay->base = (volatile u32*)ioremap(np->parent->addrs[0].address, 0x1000); + + /* Enable probe logic on keylargo */ + if (bay->mb_type == mb_keylargo) + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); +#ifdef MB_USE_INTERRUPTS + if (np->n_intrs == 0) { + printk(KERN_ERR "media bay %d has no irq\n",n); + np = np->next; + continue; + } + + if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) { + printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", + np->intrs[0].line, n); + np = np->next; + continue; + } +#endif + media_bay_count++; + + printk(KERN_INFO "mediabay%d: Registered %s media-bay\n", n, bay->ops->name); + bay->dev_node = np; + bay->index = n; + + /* Force an immediate detect */ + set_mb_power(bay, 0); + mdelay(MB_POWER_DELAY); + bay->content_id = MB_NO; + bay->last_value = bay->ops->content(bay); + bay->value_count = MS_TO_HZ(MB_STABLE_DELAY); + bay->state = mb_empty; + do { + mdelay(1000/HZ); + media_bay_step(n); + } while((bay->state != mb_empty) && + (bay->state != mb_up)); + + n++; + np=np->next; + } + + if (media_bay_count) + { +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&mb_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ + + kernel_thread(media_bay_task, NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/rtc.c linux-2.5/drivers/macintosh/rtc.c --- linux-2.5.1/drivers/macintosh/rtc.c Mon Oct 15 20:43:24 2001 +++ linux-2.5/drivers/macintosh/rtc.c Thu Dec 27 16:32:31 2001 @@ -34,14 +34,13 @@ void get_rtc_time(struct rtc_time *t) { unsigned long nowtime; - + nowtime = (ppc_md.get_rtc_time)(); to_tm(nowtime, t); t->tm_year -= 1900; - t->tm_mon -= 1; - t->tm_wday -= 1; + t->tm_mon -= 1; /* Make sure userland has a 0-based month */ } /* Set the current date and time in the real time clock. */ @@ -49,7 +48,8 @@ { unsigned long nowtime; - nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); (ppc_md.set_rtc_time)(nowtime); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/via-cuda.c linux-2.5/drivers/macintosh/via-cuda.c --- linux-2.5.1/drivers/macintosh/via-cuda.c Tue May 1 23:05:00 2001 +++ linux-2.5/drivers/macintosh/via-cuda.c Thu Dec 27 16:32:31 2001 @@ -191,6 +191,8 @@ if (via == NULL) return -ENODEV; + request_OF_resource(vias, 0, NULL); + if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) { printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ); return -EAGAIN; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/macintosh/via-pmu.c linux-2.5/drivers/macintosh/via-pmu.c --- linux-2.5.1/drivers/macintosh/via-pmu.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/macintosh/via-pmu.c Thu Jan 10 22:41:07 2002 @@ -9,9 +9,9 @@ * and the RTC (real time clock) chip. * * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. + * Copyright (C) 2001 Benjamin Herrenschmidt * - * todo: - Check this driver for smp safety (new Core99 motherboards). - * - Cleanup synchro between VIA interrupt and GPIO-based PMU + * todo: - Cleanup synchro between VIA interrupt and GPIO-based PMU * interrupt. * * @@ -45,10 +45,12 @@ #include <asm/sections.h> #include <asm/irq.h> #include <asm/hardirq.h> -#include <asm/feature.h> +#include <asm/pmac_feature.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> +#include <asm/sections.h> #include <asm/cputable.h> +#include <asm/time.h> #ifdef CONFIG_PMAC_BACKLIGHT #include <asm/backlight.h> #endif @@ -56,9 +58,13 @@ /* Some compile options */ #undef SUSPEND_USES_PMU #define DEBUG_SLEEP +#undef HACKED_PCI_SAVE /* Misc minor number allocated for /dev/pmu */ -#define PMU_MINOR 154 +#define PMU_MINOR 154 + +/* How many iterations between battery polls */ +#define BATTERY_POLLING_COUNT 2 static volatile unsigned char *via; @@ -108,7 +114,7 @@ static struct adb_request *current_req; static struct adb_request *last_req; static struct adb_request *req_awaiting_reply; -static unsigned char interrupt_data[32]; +static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */ static unsigned char *reply_ptr; static int data_index; static int data_len; @@ -126,9 +132,26 @@ static int pmu_version; static int drop_interrupts; #ifdef CONFIG_PMAC_PBOOK +static int option_lid_wakeup = 1; static int sleep_in_progress; +static int can_sleep; +#endif /* CONFIG_PMAC_PBOOK */ + +static struct proc_dir_entry *proc_pmu_root; +static struct proc_dir_entry *proc_pmu_info; +static struct proc_dir_entry *proc_pmu_options; + +#ifdef CONFIG_PMAC_PBOOK +int pmu_battery_count; +int pmu_cur_battery; +unsigned int pmu_power_flags; +struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; +static int query_batt_timer = BATTERY_POLLING_COUNT; +static struct adb_request batt_req; +static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES]; #endif /* CONFIG_PMAC_PBOOK */ +int __fake_sleep; int asleep; struct notifier_block *sleep_notifier_list; @@ -153,15 +176,22 @@ static void pmu_done(struct adb_request *req); static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs); -static void set_volume(int level); static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); +static int proc_get_info(char *page, char **start, off_t off, + int count, int *eof, void *data); #ifdef CONFIG_PMAC_BACKLIGHT static int pmu_set_backlight_level(int level, void* data); static int pmu_set_backlight_enable(int on, int level, void* data); #endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef CONFIG_PMAC_PBOOK static void pmu_pass_intr(unsigned char *data, int len); -#endif +static int proc_get_batt(char *page, char **start, off_t off, + int count, int *eof, void *data); +#endif /* CONFIG_PMAC_PBOOK */ +static int proc_read_options(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int proc_write_options(struct file *file, const char *buffer, + unsigned long count, void *data); #ifdef CONFIG_ADB struct adb_driver via_pmu_driver = { @@ -309,6 +339,10 @@ } else pmu_kind = PMU_UNKNOWN; +#ifdef CONFIG_PMAC_PBOOK + if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) + can_sleep = 1; +#endif /* CONFIG_PMAC_PBOOK */ via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ @@ -362,9 +396,14 @@ if (vias == NULL) return -ENODEV; + request_OF_resource(vias, 0, NULL); + bright_req_1.complete = 1; bright_req_2.complete = 1; bright_req_3.complete = 1; +#ifdef CONFIG_PMAC_PBOOK + batt_req.complete = 1; +#endif if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) { @@ -388,6 +427,46 @@ register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); #endif /* CONFIG_PMAC_BACKLIGHT */ +#ifdef CONFIG_PMAC_PBOOK + if (machine_is_compatible("AAPL,3400/2400") || + machine_is_compatible("AAPL,3500")) + pmu_battery_count = 1; + else if (machine_is_compatible("AAPL,PowerBook1998") || + machine_is_compatible("PowerBook1,1")) + pmu_battery_count = 2; + else { + struct device_node* prim = find_devices("power-mgt"); + u32 *prim_info = NULL; + if (prim) + prim_info = (u32 *)get_property(prim, "prim-info", NULL); + if (prim_info) { + /* Other stuffs here yet unknown */ + pmu_battery_count = (prim_info[6] >> 16) & 0xff; + } + } +#endif /* CONFIG_PMAC_PBOOK */ + /* Create /proc/pmu */ + proc_pmu_root = proc_mkdir("pmu", 0); + if (proc_pmu_root) { + int i; + proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root, + proc_get_info, NULL); +#ifdef CONFIG_PMAC_PBOOK + for (i=0; i<pmu_battery_count; i++) { + char title[16]; + sprintf(title, "battery_%d", i); + proc_pmu_batt[i] = create_proc_read_entry(title, 0, proc_pmu_root, + proc_get_batt, (void *)i); + } +#endif /* CONFIG_PMAC_PBOOK */ + proc_pmu_options = create_proc_entry("options", 0600, proc_pmu_root); + if (proc_pmu_options) { + proc_pmu_options->nlink = 1; + proc_pmu_options->read_proc = proc_read_options; + proc_pmu_options->write_proc = proc_write_options; + } + } + /* Make sure PMU settle down before continuing. This is _very_ important * since the IDE probe may shut interrupts down for quite a bit of time. If * a PMU communication is pending while this happens, the PMU may timeout @@ -448,8 +527,8 @@ pmu_request(&req, NULL, 1, PMU_GET_VERSION); while (!req.complete) pmu_poll(); - if (req.reply_len > 1) - pmu_version = req.reply[1]; + if (req.reply_len > 0) + pmu_version = req.reply[0]; return 1; } @@ -460,6 +539,263 @@ return pmu_kind; } +#ifdef CONFIG_PMAC_PBOOK + +/* + * WARNING ! This code probably needs some debugging... -- BenH. + */ +static void __pmac +done_battery_state_ohare(struct adb_request* req) +{ + unsigned int bat_flags = 0; + int current = 0; + unsigned int capa, max, voltage, time; + int lrange[] = { 0, 275, 850, 1680, 2325, + 2765, 3160, 3500, 3830, 4115, + 4360, 4585, 4795, 4990, 5170, + 5340, 5510, 5710, 5930, 6150, + 6370, 6500 + }; + + if (req->reply[0] & 0x01) + pmu_power_flags |= PMU_PWR_AC_PRESENT; + else + pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + + if (req->reply[0] & 0x04) { + int vb, i, j, charge, pcharge; + bat_flags |= PMU_BATT_PRESENT; + vb = (req->reply[1] << 8) | req->reply[2]; + voltage = ((vb * 2650) + 726650)/100; + current = *((signed char *)&req->reply[5]); + if ((req->reply[0] & 0x01) == 0 && (current > 200)) + vb += (current - 200) * 15; + else if (req->reply[0] & 0x02) + vb = (vb - 10) * 100; + i = (33000 - vb) / 10; + j = i - (i % 100); + if (j <= 0) + charge = 0; + else if (j >= 21) + charge = 650000; + else + charge = (lrange[j + 1] - lrange[j]) * (i - j) + (lrange[j] * 100); + charge = (1000 - charge / 650) / 10; + if (req->reply[0] & 0x40) { + pcharge = (req->reply[6] << 8) + req->reply[7]; + if (pcharge > 6500) + pcharge = 6500; + pcharge *= 100; + pcharge = (1000 - pcharge / 650) / 10; + if (pcharge < charge) + charge = pcharge; + } + capa = charge; + max = 100; + time = (charge * 274) / current; + current = -current; + + } else + capa = max = current = voltage = time = 0; + + if ((req->reply[0] & 0x02) && (current > 0)) + bat_flags |= PMU_BATT_CHARGING; + if (req->reply[0] & 0x04) /* CHECK THIS ONE */ + bat_flags |= PMU_BATT_PRESENT; + + pmu_batteries[pmu_cur_battery].flags = bat_flags; + pmu_batteries[pmu_cur_battery].charge = capa; + pmu_batteries[pmu_cur_battery].max_charge = max; + pmu_batteries[pmu_cur_battery].current = current; + pmu_batteries[pmu_cur_battery].voltage = voltage; + pmu_batteries[pmu_cur_battery].time_remaining = time; +} + +static void __pmac +done_battery_state_smart(struct adb_request* req) +{ + /* format: + * [0] : format of this structure (known: 3,4,5) + * [1] : flags + * + * format 3 & 4: + * + * [2] : charge + * [3] : max charge + * [4] : current + * [5] : voltage + * + * format 5: + * + * [2][3] : charge + * [4][5] : max charge + * [6][7] : current + * [8][9] : voltage + */ + + unsigned int bat_flags = 0; + int current; + unsigned int capa, max, voltage; + + if (req->reply[1] & 0x01) + pmu_power_flags |= PMU_PWR_AC_PRESENT; + else + pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + + + if (req->reply[1] & 0x04) { + bat_flags |= PMU_BATT_PRESENT; + switch(req->reply[0]) { + case 3: + case 4: capa = req->reply[2]; + max = req->reply[3]; + current = *((signed char *)&req->reply[4]); + voltage = req->reply[5]; + break; + case 5: capa = (req->reply[2] << 8) | req->reply[3]; + max = (req->reply[4] << 8) | req->reply[5]; + current = *((signed short *)&req->reply[6]); + voltage = (req->reply[8] << 8) | req->reply[9]; + break; + default: + printk(KERN_WARNING "pmu.c : unrecognized battery info, len: %d, %02x %02x %02x %02x\n", + req->reply_len, req->reply[0], req->reply[1], req->reply[2], req->reply[3]); + break; + } + } else + capa = max = current = voltage = 0; + + if ((req->reply[1] & 0x01) && (current > 0)) + bat_flags |= PMU_BATT_CHARGING; + + pmu_batteries[pmu_cur_battery].flags = bat_flags; + pmu_batteries[pmu_cur_battery].charge = capa; + pmu_batteries[pmu_cur_battery].max_charge = max; + pmu_batteries[pmu_cur_battery].current = current; + pmu_batteries[pmu_cur_battery].voltage = voltage; + if (current) { + if ((req->reply[1] & 0x01) && (current > 0)) + pmu_batteries[pmu_cur_battery].time_remaining + = ((max-capa) * 3600) / current; + else + pmu_batteries[pmu_cur_battery].time_remaining + = (capa * 3600) / (-current); + } else + pmu_batteries[pmu_cur_battery].time_remaining = 0; + + pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count; +} + +static void __pmac +query_battery_state(void) +{ + if (!batt_req.complete) + return; + if (pmu_kind == PMU_OHARE_BASED) + pmu_request(&batt_req, done_battery_state_ohare, + 1, PMU_BATTERY_STATE); + else + pmu_request(&batt_req, done_battery_state_smart, + 2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1); +} + +#endif /* CONFIG_PMAC_PBOOK */ + +static int +proc_get_info(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char* p = page; + + p += sprintf(p, "PMU driver version : %d\n", PMU_DRIVER_VERSION); + p += sprintf(p, "PMU firmware version : %02x\n", pmu_version); +#ifdef CONFIG_PMAC_PBOOK + p += sprintf(p, "AC Power : %d\n", + ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0)); + p += sprintf(p, "Battery count : %d\n", pmu_battery_count); +#endif /* CONFIG_PMAC_PBOOK */ + + return p - page; +} + +#ifdef CONFIG_PMAC_PBOOK +static int +proc_get_batt(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int batnum = (int)data; + char *p = page; + + p += sprintf(p, "\n"); + p += sprintf(p, "flags : %08x\n", + pmu_batteries[batnum].flags); + p += sprintf(p, "charge : %d\n", + pmu_batteries[batnum].charge); + p += sprintf(p, "max_charge : %d\n", + pmu_batteries[batnum].max_charge); + p += sprintf(p, "current : %d\n", + pmu_batteries[batnum].current); + p += sprintf(p, "voltage : %d\n", + pmu_batteries[batnum].voltage); + p += sprintf(p, "time rem. : %d\n", + pmu_batteries[batnum].time_remaining); + + return p - page; +} +#endif /* CONFIG_PMAC_PBOOK */ + +static int +proc_read_options(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + +#ifdef CONFIG_PMAC_PBOOK + if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) + p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup); +#endif /* CONFIG_PMAC_PBOOK */ + + return p - page; +} + +static int +proc_write_options(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char tmp[33]; + char *label, *val; + unsigned long fcount = count; + + if (!count) + return -EINVAL; + if (count > 32) + count = 32; + if (copy_from_user(tmp, buffer, count)) + return -EFAULT; + tmp[count] = 0; + + label = tmp; + while(*label == ' ') + label++; + val = label; + while(*val && (*val != '=')) { + if (*val == ' ') + *val = 0; + val++; + } + if ((*val) == 0) + return -EINVAL; + *(val++) = 0; + while(*val == ' ') + val++; +#ifdef CONFIG_PMAC_PBOOK + if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) + if (!strcmp(label, "lid_wakeup")) + option_lid_wakeup = ((*val) == '1'); +#endif /* CONFIG_PMAC_PBOOK */ + return fcount; +} + #ifdef CONFIG_ADB /* Send an ADB command */ static int __openfirmware @@ -622,11 +958,7 @@ for (i = 0; i < nbytes; ++i) req->data[i] = va_arg(list, int); va_end(list); - if (pmu_data_len[req->data[0]][1] != 0) { - req->reply[0] = ADB_RET_OK; - req->reply_len = 1; - } else - req->reply_len = 0; + req->reply_len = 0; req->reply_expected = 0; return pmu_queue_request(req); } @@ -835,10 +1167,14 @@ spin_lock_irqsave(&pmu_lock, flags); ++disable_poll; - while ((intr = in_8(&via[IFR])) != 0) { + for (;;) { + intr = in_8(&via[IFR]) & (SR_INT | CB1_INT); + if (intr == 0) + break; if (++nloop > 1000) { printk(KERN_DEBUG "PMU: stuck in intr loop, " - "intr=%x pmu_state=%d\n", intr, pmu_state); + "intr=%x, ier=%x pmu_state=%d\n", + intr, in_8(&via[IER]), pmu_state); break; } out_8(&via[IFR], intr); @@ -847,15 +1183,6 @@ else if (intr & CB1_INT) adb_int_pending = 1; } - /* This is not necessary except if synchronous ADB requests are done - * with interrupts off, which should not happen. Since I'm not sure - * this "wiring" will remain, I'm commenting it out for now. Please do - * not remove. -- BenH. - */ -#if 0 - if (gpio_reg && !pmu_suspended && (in_8(gpio_reg + 0x9) & 0x02) == 0) - adb_int_pending = 1; -#endif if (pmu_state == idle) { if (adb_int_pending) { @@ -866,9 +1193,8 @@ wait_for_ack(); send_byte(PMU_INT_ACK); adb_int_pending = 0; - } else if (current_req) { + } else if (current_req) pmu_start(); - } } --disable_poll; @@ -878,8 +1204,10 @@ static void __openfirmware gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) { - adb_int_pending = 1; - via_pmu_interrupt(0, 0, 0); + if ((in_8(gpio_reg + 0x9) & 0x02) == 0) { + adb_int_pending = 1; + via_pmu_interrupt(0, 0, 0); + } } static void __openfirmware @@ -1040,16 +1368,25 @@ adb_input(data+1, len-1, regs, 1); #endif /* CONFIG_ADB */ } - } else if (data[0] == 0x08 && len == 3) { - /* sound/brightness buttons pressed */ + } else { + /* Sound/brightness button pressed */ + if ((data[0] & PMU_INT_SNDBRT) && len == 3) { #ifdef CONFIG_PMAC_BACKLIGHT - set_backlight_level(data[1] >> 4); + set_backlight_level(data[1] >> 4); #endif - set_volume(data[2]); - } else { + } #ifdef CONFIG_PMAC_PBOOK - pmu_pass_intr(data, len); -#endif + /* Environement or tick interrupt, query batteries */ + if (pmu_battery_count && (data[0] & PMU_INT_TICK)) { + if ((--query_batt_timer) == 0) { + query_battery_state(); + query_batt_timer = BATTERY_POLLING_COUNT; + } + } else if (pmu_battery_count && (data[0] & PMU_INT_ENVIRONMENT)) + query_battery_state(); + if (data[0]) + pmu_pass_intr(data, len); +#endif /* CONFIG_PMAC_PBOOK */ } } @@ -1116,11 +1453,6 @@ pmu_poll(); } -static void __openfirmware -set_volume(int level) -{ -} - void __openfirmware pmu_restart(void) { @@ -1266,10 +1598,14 @@ * PCI devices which may get powered off when we sleep. */ static struct pci_save { +#ifndef HACKED_PCI_SAVE u16 command; u16 cache_lat; u16 intr; u32 rom_address; +#else + u32 config[16]; +#endif } *pbook_pci_saves; static int n_pbook_pci_saves; @@ -1293,14 +1629,24 @@ return; pci_for_each_dev(pd) { +#ifndef HACKED_PCI_SAVE pci_read_config_word(pd, PCI_COMMAND, &ps->command); pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address); +#else + int i; + for (i=1;i<16;i++) + pci_read_config_dword(pd, i<<4, &ps->config[i]); +#endif ++ps; } } +/* For this to work, we must take care of a few things: If gmac was enabled + * during boot, it will be in the pci dev list. If it's disabled at this point + * (and it will probably be), then you can't access it's config space. + */ static void __openfirmware pbook_pci_restore(void) { @@ -1310,7 +1656,13 @@ int j; pci_for_each_dev(pd) { +#ifdef HACKED_PCI_SAVE + int i; ps++; + for (i=2;i<16;i++) + pci_write_config_dword(pd, i<<4, ps->config[i]); + pci_write_config_dword(pd, 4, ps->config[1]); +#else if (ps->command == 0) continue; pci_read_config_word(pd, PCI_COMMAND, &cmd); @@ -1330,8 +1682,8 @@ ps->intr); pci_write_config_word(pd, PCI_COMMAND, ps->command); break; - /* other header types not restored at present */ } +#endif } } @@ -1370,7 +1722,7 @@ } mdelay(50); } -#endif /* DEBUG_SLEEP */ +#endif /* * Put the powerbook to sleep. @@ -1403,6 +1755,15 @@ out_8(&via[IER], IER_SET | SR_INT | CB1_INT); } +static inline void wakeup_decrementer(void) +{ + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + * so use get_tbl, not native + */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); +} + #define GRACKLE_PM (1<<7) #define GRACKLE_DOZE (1<<5) #define GRACKLE_NAP (1<<4) @@ -1436,6 +1797,10 @@ * vmalloc's are done before actual sleep of block drivers */ fsync_dev(0); + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + (HZ/2); time_before(jiffies, wait); ) + mb(); + /* Sleep can fail now. May not be very robust but useful for debugging */ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); if (ret != PBOOK_SLEEP_OK) { @@ -1443,13 +1808,9 @@ return -EBUSY; } - /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + (HZ/2); time_before(jiffies, wait); ) - mb(); - /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete) + !bright_req_3.complete || !batt_req.complete) pmu_poll(); /* Turn off various things. Darwin does some retry tests here... */ @@ -1495,7 +1856,7 @@ /* The VIA is supposed not to be restored correctly*/ save_via_state(); /* We shut down some HW */ - feature_prepare_for_sleep(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); pci_read_config_word(grackle, 0x70, &pmcr1); /* Apparently, MacOS uses NAP mode for Grackle ??? */ @@ -1512,7 +1873,7 @@ pci_write_config_word(grackle, 0x70, pmcr1); /* Make sure the PMU is idle */ - feature_wake_up(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); restore_via_state(); /* Restore L2 cache */ @@ -1522,11 +1883,6 @@ /* Restore userland MMU context */ set_context(current->active_mm->context, current->active_mm->pgd); - /* Re-enable DEC interrupts and kick DEC */ - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - sti(); - asm volatile("mtdec %0" : : "r" (0x10000000)); - /* Power things up */ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); while (!req.complete) @@ -1558,6 +1914,10 @@ /* Leave some time for HW to settle down */ mdelay(100); + /* Restart jiffies & scheduling */ + wakeup_decrementer(); + sti(); + /* Notify drivers */ broadcast_wake(); @@ -1571,7 +1931,7 @@ struct adb_request req; int ret, timeout; - if (!feature_can_sleep()) { + if (!can_sleep) { printk(KERN_ERR "Sleep mode not supported on this machine\n"); return -ENOSYS; } @@ -1591,20 +1951,19 @@ * vmalloc's are done before actual sleep of block drivers */ fsync_dev(0); + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + HZ; time_before(jiffies, wait); ) + mb(); + /* Sleep can fail now. May not be very robust but useful for debugging */ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); if (ret != PBOOK_SLEEP_OK) { printk("pmu: sleep failed\n"); return -EBUSY; } - - /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + HZ; time_before(jiffies, wait); ) - mb(); - /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete) + !bright_req_3.complete || !batt_req.complete) pmu_poll(); /* Tell PMU what events will wake us up */ @@ -1614,7 +1973,8 @@ pmu_poll(); pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS, - 0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN); + 0, PMU_PWR_WAKEUP_KEY | + (option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0)); while (!req.complete) pmu_poll(); @@ -1651,10 +2011,12 @@ /* Save the state of PCI config space for some slots */ //pbook_pci_save(); - /* Ask the PMU to put us to sleep */ - pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); - while (!req.complete && pmu_state != idle) - pmu_poll(); + if (!__fake_sleep) { + /* Ask the PMU to put us to sleep */ + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete && pmu_state != idle) + pmu_poll(); + } out_8(&via[B], in_8(&via[B]) | TREQ); wait_for_ack(); @@ -1666,13 +2028,16 @@ * talk to the PMU after this, so I moved it to _after_ sending the * sleep command to it. Still need to be checked. */ - feature_prepare_for_sleep(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); /* Call low-level ASM sleep handler */ - low_sleep_handler(); + if (__fake_sleep) + mdelay(5000); + else + low_sleep_handler(); /* Restore Apple core ASICs state */ - feature_wake_up(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); /* Restore VIA */ restore_via_state(); @@ -1694,11 +2059,6 @@ /* Restore userland MMU context */ set_context(current->active_mm->context, current->active_mm->pgd); - /* Re-enable DEC interrupts and kick DEC */ - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - sti(); - asm volatile("mtdec %0" : : "r" (0x10000000)); - /* Tell PMU we are ready */ pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); while (!req.complete) @@ -1725,6 +2085,10 @@ /* Leave some time for HW to settle down */ mdelay(100); + /* Restart jiffies & scheduling */ + wakeup_decrementer(); + sti(); + /* Notify drivers */ broadcast_wake(); @@ -1766,6 +2130,10 @@ * vmalloc's are done before actual sleep of block drivers */ fsync_dev(0); + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) + mb(); + /* Sleep can fail now. May not be very robust but useful for debugging */ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); if (ret != PBOOK_SLEEP_OK) { @@ -1773,13 +2141,9 @@ return -EBUSY; } - /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) - mb(); - /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete) + !bright_req_3.complete || !batt_req.complete) pmu_poll(); /* Disable all interrupts except pmu */ @@ -1811,6 +2175,8 @@ while (!sleep_req.complete) mb(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); + /* displacement-flush the L2 cache - necessary? */ for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000) i = *(volatile int *)p; @@ -1825,20 +2191,23 @@ /* OK, we're awake again, start restoring things */ out_be32(mem_ctrl_sleep, 0x3f); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); pbook_pci_restore(); /* wait for the PMU interrupt sequence to complete */ while (asleep) mb(); - /* Re-enable DEC interrupts and kick DEC */ - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - sti(); - asm volatile("mtdec %0" : : "r" (0x10000000)); - /* reenable interrupts */ pmac_sleep_restore_intrs(); + /* Leave some time for HW to settle down */ + mdelay(100); + + /* Restart jiffies & scheduling */ + wakeup_decrementer(); + sti(); + /* Notify drivers */ broadcast_wake(); @@ -1877,6 +2246,7 @@ spin_lock_irqsave(&all_pvt_lock, flags); for (list = &all_pmu_pvt; (list = list->next) != &all_pmu_pvt; ) { pp = list_entry(list, struct pmu_private, list); + spin_lock(&pp->lock); i = pp->rb_put + 1; if (i >= RB_SIZE) i = 0; @@ -1887,6 +2257,7 @@ pp->rb_put = i; wake_up_interruptible(&pp->wait); } + spin_unlock(&pp->lock); } spin_unlock_irqrestore(&all_pvt_lock, flags); } @@ -1914,6 +2285,7 @@ { struct pmu_private *pp = file->private_data; DECLARE_WAITQUEUE(wait, current); + unsigned long flags; int ret; if (count < 1 || pp == 0) @@ -1922,38 +2294,41 @@ if (ret) return ret; + spin_lock_irqsave(&pp->lock, flags); add_wait_queue(&pp->wait, &wait); current->state = TASK_INTERRUPTIBLE; for (;;) { ret = -EAGAIN; - spin_lock(&pp->lock); if (pp->rb_get != pp->rb_put) { int i = pp->rb_get; struct rb_entry *rp = &pp->rb_buf[i]; ret = rp->len; + spin_unlock_irqrestore(&pp->lock, flags); if (ret > count) ret = count; if (ret > 0 && copy_to_user(buf, rp->data, ret)) ret = -EFAULT; if (++i >= RB_SIZE) i = 0; + spin_lock_irqsave(&pp->lock, flags); pp->rb_get = i; } - spin_unlock(&pp->lock); if (ret >= 0) break; - if (file->f_flags & O_NONBLOCK) break; ret = -ERESTARTSYS; if (signal_pending(current)) break; + spin_unlock_irqrestore(&pp->lock, flags); schedule(); + spin_lock_irqsave(&pp->lock, flags); } current->state = TASK_RUNNING; remove_wait_queue(&pp->wait, &wait); - + spin_unlock_irqrestore(&pp->lock, flags); + return ret; } @@ -1967,14 +2342,15 @@ { struct pmu_private *pp = filp->private_data; unsigned int mask = 0; - + unsigned long flags; + if (pp == 0) return 0; poll_wait(filp, &pp->wait, wait); - spin_lock(&pp->lock); + spin_lock_irqsave(&pp->lock, flags); if (pp->rb_get != pp->rb_put) mask |= POLLIN; - spin_unlock(&pp->lock); + spin_unlock_irqrestore(&pp->lock, flags); return mask; } @@ -2023,7 +2399,7 @@ sleep_in_progress = 0; return error; case PMU_IOC_CAN_SLEEP: - return put_user(feature_can_sleep(), (__u32 *)arg); + return put_user((u32)can_sleep, (__u32 *)arg); #ifdef CONFIG_PMAC_BACKLIGHT /* Backlight should have its own device or go via @@ -2153,5 +2529,8 @@ EXPORT_SYMBOL(pmu_register_sleep_notifier); EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); +EXPORT_SYMBOL(pmu_battery_count); +EXPORT_SYMBOL(pmu_batteries); +EXPORT_SYMBOL(pmu_power_flags); #endif /* CONFIG_PMAC_PBOOK */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/md/lvm-fs.c linux-2.5/drivers/md/lvm-fs.c --- linux-2.5.1/drivers/md/lvm-fs.c Sun Nov 11 18:09:32 2001 +++ linux-2.5/drivers/md/lvm-fs.c Sun Jan 13 22:23:13 2002 @@ -30,6 +30,7 @@ * 04/10/2001 - corrected devfs_register() call in lvm_init_fs() * 11/04/2001 - don't devfs_register("lvm") as user-space always does it * 10/05/2001 - show more of PV name in /proc/lvm/global + * 16/12/2001 - fix devfs unregister order and prevent duplicate unreg (REG) * */ @@ -138,7 +139,7 @@ int i; devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]); - devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]); + ch_devfs_handle[vg_ptr->vg_number] = NULL; /* remove lv's */ for(i = 0; i < vg_ptr->lv_max; i++) @@ -148,6 +149,10 @@ for(i = 0; i < vg_ptr->pv_max; i++) if(vg_ptr->pv[i]) lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]); + /* must not remove directory before leaf nodes */ + devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]); + vg_devfs_handle[vg_ptr->vg_number] = NULL; + if(vg_ptr->vg_dir_pde) { remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde); vg_ptr->lv_subdir_pde = NULL; @@ -171,11 +176,11 @@ devfs_handle_t lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv) { struct proc_dir_entry *pde; - const char *name = _basename(lv->lv_name); + const char *name = _basename(lv->u.lv_name); - lv_devfs_handle[MINOR(lv->lv_dev)] = devfs_register( + lv_devfs_handle[minor(lv->u.lv_dev)] = devfs_register( vg_devfs_handle[vg_ptr->vg_number], name, - DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, MINOR(lv->lv_dev), + DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, minor(lv->u.lv_dev), S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, &lvm_blk_dops, NULL); @@ -184,14 +189,15 @@ pde->read_proc = _proc_read_lv; pde->data = lv; } - return lv_devfs_handle[MINOR(lv->lv_dev)]; + return lv_devfs_handle[minor(lv->u.lv_dev)]; } void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv) { - devfs_unregister(lv_devfs_handle[MINOR(lv->lv_dev)]); + devfs_unregister(lv_devfs_handle[minor(lv->u.lv_dev)]); + lv_devfs_handle[minor(lv->u.lv_dev)] = NULL; if(vg_ptr->lv_subdir_pde) { - const char *name = _basename(lv->lv_name); + const char *name = _basename(lv->u.lv_name); remove_proc_entry(name, vg_ptr->lv_subdir_pde); } } @@ -269,21 +275,21 @@ int sz = 0; lv_t *lv = data; - sz += sprintf(page + sz, "name: %s\n", lv->lv_name); - sz += sprintf(page + sz, "size: %u\n", lv->lv_size); - sz += sprintf(page + sz, "access: %u\n", lv->lv_access); - sz += sprintf(page + sz, "status: %u\n", lv->lv_status); - sz += sprintf(page + sz, "number: %u\n", lv->lv_number); - sz += sprintf(page + sz, "open: %u\n", lv->lv_open); - sz += sprintf(page + sz, "allocation: %u\n", lv->lv_allocation); - if(lv->lv_stripes > 1) { + sz += sprintf(page + sz, "name: %s\n", lv->u.lv_name); + sz += sprintf(page + sz, "size: %u\n", lv->u.lv_size); + sz += sprintf(page + sz, "access: %u\n", lv->u.lv_access); + sz += sprintf(page + sz, "status: %u\n", lv->u.lv_status); + sz += sprintf(page + sz, "number: %u\n", lv->u.lv_number); + sz += sprintf(page + sz, "open: %u\n", lv->u.lv_open); + sz += sprintf(page + sz, "allocation: %u\n", lv->u.lv_allocation); + if(lv->u.lv_stripes > 1) { sz += sprintf(page + sz, "stripes: %u\n", - lv->lv_stripes); + lv->u.lv_stripes); sz += sprintf(page + sz, "stripesize: %u\n", - lv->lv_stripesize); + lv->u.lv_stripesize); } sz += sprintf(page + sz, "device: %02u:%02u\n", - MAJOR(lv->lv_dev), MINOR(lv->lv_dev)); + major(lv->u.lv_dev), minor(lv->u.lv_dev)); return sz; } @@ -304,7 +310,7 @@ sz += sprintf(page + sz, "PE total: %u\n", pv->pe_total); sz += sprintf(page + sz, "PE allocated: %u\n", pv->pe_allocated); sz += sprintf(page + sz, "device: %02u:%02u\n", - MAJOR(pv->pv_dev), MINOR(pv->pv_dev)); + major(pv->pv_dev), minor(pv->pv_dev)); _show_uuid(pv->pv_uuid, uuid, uuid + sizeof(uuid)); sz += sprintf(page + sz, "uuid: %s\n", uuid); @@ -350,13 +356,13 @@ if (vg_ptr->lv_cur > 0) { for (l = 0; l < vg[v]->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) != NULL) { - pe_t_bytes += lv_ptr->lv_allocated_le; + pe_t_bytes += lv_ptr->u.lv_allocated_le; hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size; - if (lv_ptr->lv_block_exception != NULL) - lv_block_exception_t_bytes += lv_ptr->lv_remap_end; - if (lv_ptr->lv_open > 0) { + if (lv_ptr->u.lv_block_exception != NULL) + lv_block_exception_t_bytes += lv_ptr->u.lv_remap_end; + if (lv_ptr->u.lv_open > 0) { lv_open_counter++; - lv_open_total += lv_ptr->lv_open; + lv_open_total += lv_ptr->u.lv_open; } } } @@ -532,16 +538,16 @@ char inactive_flag = 'A', allocation_flag = ' ', stripes_flag = ' ', rw_flag = ' ', *basename; - if (!(lv_ptr->lv_status & LV_ACTIVE)) + if (!(lv_ptr->u.lv_status & LV_ACTIVE)) inactive_flag = 'I'; rw_flag = 'R'; - if (lv_ptr->lv_access & LV_WRITE) + if (lv_ptr->u.lv_access & LV_WRITE) rw_flag = 'W'; allocation_flag = 'D'; - if (lv_ptr->lv_allocation & LV_CONTIGUOUS) + if (lv_ptr->u.lv_allocation & LV_CONTIGUOUS) allocation_flag = 'C'; stripes_flag = 'L'; - if (lv_ptr->lv_stripes > 1) + if (lv_ptr->u.lv_stripes > 1) stripes_flag = 'S'; sz += sprintf(buf+sz, "[%c%c%c%c", @@ -549,29 +555,29 @@ rw_flag, allocation_flag, stripes_flag); - if (lv_ptr->lv_stripes > 1) + if (lv_ptr->u.lv_stripes > 1) sz += sprintf(buf+sz, "%-2d", - lv_ptr->lv_stripes); + lv_ptr->u.lv_stripes); else sz += sprintf(buf+sz, " "); /* FIXME: use _basename */ - basename = strrchr(lv_ptr->lv_name, '/'); - if ( basename == 0) basename = lv_ptr->lv_name; + basename = strrchr(lv_ptr->u.lv_name, '/'); + if ( basename == 0) basename = lv_ptr->u.lv_name; else basename++; sz += sprintf(buf+sz, "] %-25s", basename); if (strlen(basename) > 25) sz += sprintf(buf+sz, "\n "); sz += sprintf(buf+sz, "%9d /%-6d ", - lv_ptr->lv_size >> 1, - lv_ptr->lv_size / vg_ptr->pe_size); + lv_ptr->u.lv_size >> 1, + lv_ptr->u.lv_size / vg_ptr->pe_size); - if (lv_ptr->lv_open == 0) + if (lv_ptr->u.lv_open == 0) sz += sprintf(buf+sz, "close"); else sz += sprintf(buf+sz, "%dx open", - lv_ptr->lv_open); + lv_ptr->u.lv_open); return sz; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/md/lvm-snap.c linux-2.5/drivers/md/lvm-snap.c --- linux-2.5.1/drivers/md/lvm-snap.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/md/lvm-snap.c Sun Jan 13 22:23:13 2002 @@ -68,7 +68,7 @@ if(vg->pv[p] == NULL) continue; - if(vg->pv[p]->pv_dev == rdev) + if(kdev_same(vg->pv[p]->pv_dev, rdev)) break; } @@ -77,7 +77,7 @@ /* bad news, the snapshot COW table is probably corrupt */ printk(KERN_ERR "%s -- _pv_get_number failed for rdev = %u\n", - lvm_name, rdev); + lvm_name, kdev_t_to_nr(rdev)); return -1; } @@ -93,7 +93,7 @@ { struct list_head * hash_table = lv->lv_snapshot_hash_table, * next; unsigned long mask = lv->lv_snapshot_hash_mask; - int chunk_size = lv->lv_chunk_size; + int chunk_size = lv->u.lv_chunk_size; lv_block_exception_t * ret; int i = 0; @@ -105,7 +105,7 @@ exception = list_entry(next, lv_block_exception_t, hash); if (exception->rsector_org == org_start && - exception->rdev_org == org_dev) + kdev_same(exception->rdev_org, org_dev)) { if (i) { @@ -127,7 +127,7 @@ { struct list_head * hash_table = lv->lv_snapshot_hash_table; unsigned long mask = lv->lv_snapshot_hash_mask; - int chunk_size = lv->lv_chunk_size; + int chunk_size = lv->u.lv_chunk_size; hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)]; list_add(&exception->hash, hash_table); @@ -139,7 +139,7 @@ int ret; unsigned long pe_off, pe_adjustment, __org_start; kdev_t __org_dev; - int chunk_size = lv->lv_chunk_size; + int chunk_size = lv->u.lv_chunk_size; lv_block_exception_t * exception; pe_off = pe_start % chunk_size; @@ -164,24 +164,26 @@ /* no exception storage space available for this snapshot or error on this snapshot --> release it */ - invalidate_buffers(lv_snap->lv_dev); + invalidate_buffers(lv_snap->u.lv_dev); /* wipe the snapshot since it's inconsistent now */ _disable_snapshot(vg, lv_snap); - for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) { - if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) { - last_dev = lv_snap->lv_block_exception[i].rdev_new; + last_dev = NODEV; + for (i = 0; i < lv_snap->u.lv_remap_ptr; i++) { + if ( !kdev_same(lv_snap->u.lv_block_exception[i].rdev_new, + last_dev)) { + last_dev = lv_snap->u.lv_block_exception[i].rdev_new; invalidate_buffers(last_dev); } } lvm_snapshot_release(lv_snap); - lv_snap->lv_status &= ~LV_ACTIVE; + lv_snap->u.lv_status &= ~LV_ACTIVE; printk(KERN_INFO "%s -- giving up to snapshot %s on %s: %s\n", - lvm_name, lv_snap->lv_snapshot_org->lv_name, lv_snap->lv_name, + lvm_name, lv_snap->u.lv_snapshot_org->u.lv_name, lv_snap->u.lv_name, reason); } @@ -206,20 +208,6 @@ return 1; } -inline int lvm_get_blksize(kdev_t dev) -{ - int correct_size = BLOCK_SIZE, i, major; - - major = MAJOR(dev); - if (blksize_size[major]) - { - i = blksize_size[major][MINOR(dev)]; - if (i) - correct_size = i; - } - return correct_size; -} - #ifdef DEBUG_SNAPSHOT static inline void invalidate_snap_cache(unsigned long start, unsigned long nr, kdev_t dev) @@ -227,7 +215,7 @@ struct buffer_head * bh; int sectors_per_block, i, blksize, minor; - minor = MINOR(dev); + minor = minor(dev); blksize = lvm_blocksizes[minor]; sectors_per_block = blksize >> 9; nr /= sectors_per_block; @@ -246,7 +234,7 @@ int lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_snap) { uint pvn; - int id = 0, is = lv_snap->lv_remap_ptr; + int id = 0, is = lv_snap->u.lv_remap_ptr; ulong blksize_snap; lv_COW_table_disk_t * lv_COW_table = (lv_COW_table_disk_t *) page_address(lv_snap->lv_COW_table_iobuf->maplist[0]); @@ -256,13 +244,13 @@ is--; blksize_snap = - lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new); + block_size(lv_snap->u.lv_block_exception[is].rdev_new); is -= is % (blksize_snap / sizeof(lv_COW_table_disk_t)); memset(lv_COW_table, 0, blksize_snap); - for ( ; is < lv_snap->lv_remap_ptr; is++, id++) { + for ( ; is < lv_snap->u.lv_remap_ptr; is++, id++) { /* store new COW_table entry */ - lv_block_exception_t *be = lv_snap->lv_block_exception + is; + lv_block_exception_t *be = lv_snap->u.lv_block_exception + is; if(_pv_get_number(vg, be->rdev_org, &pvn)) goto bad; @@ -293,7 +281,7 @@ int r; const char *err; if((r = _write_COW_table_block(vg, lv_snap, - lv_snap->lv_remap_ptr - 1, &err))) + lv_snap->u.lv_remap_ptr - 1, &err))) lvm_drop_snapshot(vg, lv_snap, err); return r; } @@ -313,14 +301,15 @@ vg_t *vg, lv_t* lv_snap) { const char * reason; - unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off; - int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size; + kdev_t snap_phys_dev; + unsigned long org_start, snap_start, virt_start, pe_off; + int idx = lv_snap->u.lv_remap_ptr, chunk_size = lv_snap->u.lv_chunk_size; struct kiobuf * iobuf; int blksize_snap, blksize_org, min_blksize, max_blksize; int max_sectors, nr_sectors; /* check if we are out of snapshot space */ - if (idx >= lv_snap->lv_remap_end) + if (idx >= lv_snap->u.lv_remap_end) goto fail_out_of_space; /* calculate physical boundaries of source chunk */ @@ -329,8 +318,8 @@ virt_start = org_virt_sector - (org_phys_sector - org_start); /* calculate physical boundaries of destination chunk */ - snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; - snap_start = lv_snap->lv_block_exception[idx].rsector_new; + snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new; + snap_start = lv_snap->u.lv_block_exception[idx].rsector_new; #ifdef DEBUG_SNAPSHOT printk(KERN_INFO @@ -347,8 +336,8 @@ iobuf = lv_snap->lv_iobuf; - blksize_org = lvm_get_blksize(org_phys_dev); - blksize_snap = lvm_get_blksize(snap_phys_dev); + blksize_org = block_size(org_phys_dev); + blksize_snap = block_size(snap_phys_dev); max_blksize = max(blksize_org, blksize_snap); min_blksize = min(blksize_org, blksize_snap); max_sectors = LVM_MAX_SECTORS * (min_blksize>>9); @@ -382,20 +371,20 @@ #ifdef DEBUG_SNAPSHOT /* invalidate the logical snapshot buffer cache */ - invalidate_snap_cache(virt_start, lv_snap->lv_chunk_size, - lv_snap->lv_dev); + invalidate_snap_cache(virt_start, lv_snap->u.lv_chunk_size, + lv_snap->u.lv_dev); #endif /* the original chunk is now stored on the snapshot volume so update the execption table */ - lv_snap->lv_block_exception[idx].rdev_org = org_phys_dev; - lv_snap->lv_block_exception[idx].rsector_org = org_start; + lv_snap->u.lv_block_exception[idx].rdev_org = org_phys_dev; + lv_snap->u.lv_block_exception[idx].rsector_org = org_start; - lvm_hash_link(lv_snap->lv_block_exception + idx, + lvm_hash_link(lv_snap->u.lv_block_exception + idx, org_phys_dev, org_start, lv_snap); - lv_snap->lv_remap_ptr = idx + 1; + lv_snap->u.lv_remap_ptr = idx + 1; if (lv_snap->lv_snapshot_use_rate > 0) { - if (lv_snap->lv_remap_ptr * 100 / lv_snap->lv_remap_end >= lv_snap->lv_snapshot_use_rate) + if (lv_snap->u.lv_remap_ptr * 100 / lv_snap->u.lv_remap_end >= lv_snap->lv_snapshot_use_rate) wake_up_interruptible(&lv_snap->lv_snapshot_wait); } return 0; @@ -473,7 +462,7 @@ unsigned long buckets, max_buckets, size; struct list_head * hash; - buckets = lv->lv_remap_end; + buckets = lv->u.lv_remap_end; max_buckets = calc_max_buckets(); buckets = min(buckets, max_buckets); while (buckets & (buckets-1)) @@ -542,10 +531,10 @@ void lvm_snapshot_release(lv_t * lv) { - if (lv->lv_block_exception) + if (lv->u.lv_block_exception) { - vfree(lv->lv_block_exception); - lv->lv_block_exception = NULL; + vfree(lv->u.lv_block_exception); + lv->u.lv_block_exception = NULL; } if (lv->lv_snapshot_hash_table) { @@ -589,10 +578,10 @@ COW_entries_per_pe = LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg, lv_snap); /* get physical addresse of destination chunk */ - snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; - snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size; + snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new; + snap_pe_start = lv_snap->u.lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->u.lv_chunk_size; - blksize_snap = lvm_get_blksize(snap_phys_dev); + blksize_snap = block_size(snap_phys_dev); COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t); idx_COW_table = idx % COW_entries_per_pe % COW_entries_per_block; @@ -606,7 +595,7 @@ blocks[0] = (snap_pe_start + COW_table_sector_offset) >> (blksize_snap >> 10); /* store new COW_table entry */ - be = lv_snap->lv_block_exception + idx; + be = lv_snap->u.lv_block_exception + idx; if(_pv_get_number(vg, be->rdev_org, &pvn)) goto fail_pv_get_number; @@ -631,16 +620,16 @@ if (idx_COW_table % COW_entries_per_block == COW_entries_per_block - 1 || end_of_table) { /* don't go beyond the end */ - if (idx + 1 >= lv_snap->lv_remap_end) goto out; + if (idx + 1 >= lv_snap->u.lv_remap_end) goto out; memset(lv_COW_table, 0, blksize_snap); if (end_of_table) { idx++; - snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; - snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size; - blksize_snap = lvm_get_blksize(snap_phys_dev); + snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new; + snap_pe_start = lv_snap->u.lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->u.lv_chunk_size; + blksize_snap = block_size(snap_phys_dev); blocks[0] = snap_pe_start >> (blksize_snap >> 10); } else blocks[0]++; @@ -675,7 +664,7 @@ static void _disable_snapshot(vg_t *vg, lv_t *lv) { const char *err; - lv->lv_block_exception[0].rsector_org = LVM_SNAPSHOT_DROPPED_SECTOR; + lv->u.lv_block_exception[0].rsector_org = LVM_SNAPSHOT_DROPPED_SECTOR; if(_write_COW_table_block(vg, lv, 0, &err) < 0) { printk(KERN_ERR "%s -- couldn't disable snapshot: %s\n", lvm_name, err); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/md/lvm.c linux-2.5/drivers/md/lvm.c --- linux-2.5.1/drivers/md/lvm.c Thu Nov 29 15:48:43 2001 +++ linux-2.5/drivers/md/lvm.c Sun Jan 13 22:23:13 2002 @@ -179,6 +179,12 @@ * (Jens Axboe) * - Defer writes to an extent that is being moved [JT + AD] * 28/05/2001 - implemented missing BLKSSZGET ioctl [AD] + * 28/12/2001 - buffer_head -> bio + * removed huge allocation of a lv_t on stack + * (Anders Gustafsson) + * 07/01/2002 - fixed sizeof(lv_t) differences in user/kernel-space + * removed another huge allocation of a lv_t on stack + * (Anders Gustafsson) * */ @@ -209,7 +215,6 @@ #include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> #include <asm/ioctl.h> -#include <asm/segment.h> #include <asm/uaccess.h> #ifdef CONFIG_KERNELD @@ -268,10 +273,10 @@ static int lvm_do_pv_create(pv_t *, vg_t *, ulong); static int lvm_do_pv_remove(vg_t *, ulong); -static int lvm_do_lv_create(int, char *, lv_t *); -static int lvm_do_lv_extend_reduce(int, char *, lv_t *); +static int lvm_do_lv_create(int, char *, userlv_t *); +static int lvm_do_lv_extend_reduce(int, char *, userlv_t *); static int lvm_do_lv_remove(int, char *, int); -static int lvm_do_lv_rename(vg_t *, lv_req_t *, lv_t *); +static int lvm_do_lv_rename(vg_t *, lv_req_t *, userlv_t *); static int lvm_do_lv_status_byname(vg_t *r, void *); static int lvm_do_lv_status_byindex(vg_t *, void *); static int lvm_do_lv_status_bydev(vg_t *, void *); @@ -376,7 +381,6 @@ major: MAJOR_NR, major_name: LVM_NAME, minor_shift: 0, - max_p: 1, part: lvm_hd_struct, sizes: lvm_size, nr_real: MAX_LV, @@ -479,8 +483,8 @@ lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; pe_lock_req.lock = UNLOCK_PE; - pe_lock_req.data.lv_dev = 0; - pe_lock_req.data.pv_dev = 0; + pe_lock_req.data.lv_dev = NODEV; + pe_lock_req.data.pv_dev = NODEV; pe_lock_req.data.pv_offset = 0; /* Initialize VG pointers */ @@ -511,7 +515,7 @@ */ static int lvm_chr_open(struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); P_DEV("chr_open MINOR: %d VG#: %d mode: %s%s lock: %d\n", minor, VG_CHR(minor), MODE_TO_STR(file->f_mode), lock); @@ -545,10 +549,10 @@ static int lvm_chr_ioctl(struct inode *inode, struct file *file, uint command, ulong a) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); uint extendable, l, v; void *arg = (void *) a; - lv_t lv; + userlv_t ulv; vg_t* vg_ptr = vg[VG_CHR(minor)]; /* otherwise cc will complain about unused variables */ @@ -684,21 +688,21 @@ return -EFAULT; if (command != LV_REMOVE) { - if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0) + if (copy_from_user(&ulv, lv_req.lv, sizeof(userlv_t)) != 0) return -EFAULT; } switch (command) { case LV_CREATE: - return lvm_do_lv_create(minor, lv_req.lv_name, &lv); + return lvm_do_lv_create(minor, lv_req.lv_name, &ulv); case LV_EXTEND: case LV_REDUCE: - return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv); + return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &ulv); case LV_REMOVE: return lvm_do_lv_remove(minor, lv_req.lv_name, -1); case LV_RENAME: - return lvm_do_lv_rename(vg_ptr, &lv_req, &lv); + return lvm_do_lv_rename(vg_ptr, &lv_req, &ulv); } @@ -751,7 +755,7 @@ static int lvm_chr_close(struct inode *inode, struct file *file) { P_DEV("chr_close MINOR: %d VG#: %d\n", - MINOR(inode->i_rdev), VG_CHR(MINOR(inode->i_rdev))); + minor(inode->i_rdev), VG_CHR(minor(inode->i_rdev))); #ifdef LVM_TOTAL_RESET if (lvm_reset_spindown > 0) { @@ -791,7 +795,7 @@ */ static int lvm_blk_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); lv_t *lv_ptr; vg_t *vg_ptr = vg[VG_BLK(minor)]; @@ -810,27 +814,27 @@ LV_BLK(minor) < vg_ptr->lv_max) { /* Check parallel LV spindown (LV remove) */ - if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; + if (lv_ptr->u.lv_status & LV_SPINDOWN) return -EPERM; /* Check inactive LV and open for read/write */ /* We need to be able to "read" an inactive LV to re-activate it again */ if ((file->f_mode & FMODE_WRITE) && - (!(lv_ptr->lv_status & LV_ACTIVE))) + (!(lv_ptr->u.lv_status & LV_ACTIVE))) return -EPERM; - if (!(lv_ptr->lv_access & LV_WRITE) && + if (!(lv_ptr->u.lv_access & LV_WRITE) && (file->f_mode & FMODE_WRITE)) return -EACCES; /* be sure to increment VG counter */ - if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; - lv_ptr->lv_open++; + if (lv_ptr->u.lv_open == 0) vg_ptr->lv_open++; + lv_ptr->u.lv_open++; MOD_INC_USE_COUNT; - P_DEV("blk_open OK, LV size %d\n", lv_ptr->lv_size); + P_DEV("blk_open OK, LV size %d\n", lv_ptr->u.lv_size); return 0; } @@ -844,7 +848,7 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file, uint command, ulong a) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); vg_t *vg_ptr = vg[VG_BLK(minor)]; lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; void *arg = (void *) a; @@ -861,13 +865,13 @@ case BLKGETSIZE: /* return device size */ - P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->lv_size); - if (put_user(lv_ptr->lv_size, (unsigned long *)arg)) + P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->u.lv_size); + if (put_user(lv_ptr->u.lv_size, (unsigned long *)arg)) return -EFAULT; break; case BLKGETSIZE64: - if (put_user((u64)lv_ptr->lv_size << 9, (u64 *)arg)) + if (put_user((u64)lv_ptr->u.lv_size << 9, (u64 *)arg)) return -EFAULT; break; @@ -893,14 +897,14 @@ if ((long) arg < LVM_MIN_READ_AHEAD || (long) arg > LVM_MAX_READ_AHEAD) return -EINVAL; - lv_ptr->lv_read_ahead = (long) arg; + lv_ptr->u.lv_read_ahead = (long) arg; break; case BLKRAGET: /* get current read ahead setting */ - P_IOCTL("BLKRAGET %d\n", lv_ptr->lv_read_ahead); - if (put_user(lv_ptr->lv_read_ahead, (long *)arg)) + P_IOCTL("BLKRAGET %d\n", lv_ptr->u.lv_read_ahead); + if (put_user(lv_ptr->u.lv_read_ahead, (long *)arg)) return -EFAULT; break; @@ -914,7 +918,7 @@ unsigned char heads = 64; unsigned char sectors = 32; long start = 0; - short cylinders = lv_ptr->lv_size / heads / sectors; + short cylinders = lv_ptr->u.lv_size / heads / sectors; if (copy_to_user((char *) &hd->heads, &heads, sizeof(heads)) != 0 || @@ -935,26 +939,26 @@ case LV_SET_ACCESS: /* set access flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lv_ptr->lv_access = (ulong) arg; - if ( lv_ptr->lv_access & LV_WRITE) - set_device_ro(lv_ptr->lv_dev, 0); + lv_ptr->u.lv_access = (ulong) arg; + if ( lv_ptr->u.lv_access & LV_WRITE) + set_device_ro(lv_ptr->u.lv_dev, 0); else - set_device_ro(lv_ptr->lv_dev, 1); + set_device_ro(lv_ptr->u.lv_dev, 1); break; case LV_SET_STATUS: /* set status flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1) + if (!((ulong) arg & LV_ACTIVE) && lv_ptr->u.lv_open > 1) return -EPERM; - lv_ptr->lv_status = (ulong) arg; + lv_ptr->u.lv_status = (ulong) arg; break; case LV_BMAP: /* turn logical block into (dev_t, block). non privileged. */ /* don't bmap a snapshot, since the mapping can change */ - if(lv_ptr->lv_access & LV_SNAPSHOT) + if(lv_ptr->u.lv_access & LV_SNAPSHOT) return -EPERM; return lvm_user_bmap(inode, (struct lv_bmap *) arg); @@ -962,7 +966,7 @@ case LV_SET_ALLOCATION: /* set allocation flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lv_ptr->lv_allocation = (ulong) arg; + lv_ptr->u.lv_allocation = (ulong) arg; break; case LV_SNAPSHOT_USE_RATE: @@ -984,15 +988,15 @@ */ static int lvm_blk_close(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); vg_t *vg_ptr = vg[VG_BLK(minor)]; lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; P_DEV("blk_close MINOR: %d VG#: %d LV#: %d\n", minor, VG_BLK(minor), LV_BLK(minor)); - if (lv_ptr->lv_open == 1) vg_ptr->lv_open--; - lv_ptr->lv_open--; + if (lv_ptr->u.lv_open == 1) vg_ptr->lv_open--; + lv_ptr->u.lv_open--; MOD_DEC_USE_COUNT; @@ -1003,7 +1007,7 @@ { lv_snapshot_use_rate_req_t lv_rate_req; - if (!(lv->lv_access & LV_SNAPSHOT)) + if (!(lv->u.lv_access & LV_SNAPSHOT)) return -EPERM; if (copy_from_user(&lv_rate_req, arg, sizeof(lv_rate_req))) @@ -1015,7 +1019,7 @@ switch (lv_rate_req.block) { case 0: lv->lv_snapshot_use_rate = lv_rate_req.rate; - if (lv->lv_remap_ptr * 100 / lv->lv_remap_end < + if (lv->u.lv_remap_ptr * 100 / lv->u.lv_remap_end < lv->lv_snapshot_use_rate) interruptible_sleep_on(&lv->lv_snapshot_wait); break; @@ -1026,7 +1030,7 @@ default: return -EINVAL; } - lv_rate_req.rate = lv->lv_remap_ptr * 100 / lv->lv_remap_end; + lv_rate_req.rate = lv->u.lv_remap_ptr * 100 / lv->u.lv_remap_end; return copy_to_user(arg, &lv_rate_req, sizeof(lv_rate_req)) ? -EFAULT : 0; @@ -1043,7 +1047,7 @@ memset(&bio,0,sizeof(bio)); bio.bi_dev = inode->i_rdev; - bio.bi_io_vec.bv_len = lvm_get_blksize(bio.bi_dev); + bio.bi_size = block_size(bio.bi_dev); /* NEEDED by bio_sectors */ bio.bi_sector = block * bio_sectors(&bio); bio.bi_rw = READ; if ((err=lvm_map(&bio)) < 0) { @@ -1096,7 +1100,7 @@ */ static inline int _should_defer(kdev_t pv, ulong sector, uint32_t pe_size) { return ((pe_lock_req.lock == LOCK_PE) && - (pv == pe_lock_req.data.pv_dev) && + kdev_same(pv, pe_lock_req.data.pv_dev) && (sector >= pe_lock_req.data.pv_offset) && (sector < (pe_lock_req.data.pv_offset + pe_size))); } @@ -1119,42 +1123,41 @@ return 0; } -static int lvm_map(struct bio *bh) +static int lvm_map(struct bio *bi) { - int minor = MINOR(bh->bi_dev); + int minor = minor(bi->bi_dev); ulong index; ulong pe_start; - ulong size = bio_sectors(bh); - ulong rsector_org = bh->bi_sector; + ulong size = bio_sectors(bi); + ulong rsector_org = bi->bi_sector; ulong rsector_map; kdev_t rdev_map; vg_t *vg_this = vg[VG_BLK(minor)]; lv_t *lv = vg_this->lv[LV_BLK(minor)]; - int rw = bio_data_dir(bh); - + int rw = bio_rw(bi); down_read(&lv->lv_lock); - if (!(lv->lv_status & LV_ACTIVE)) { + if (!(lv->u.lv_status & LV_ACTIVE)) { printk(KERN_ALERT "%s - lvm_map: ll_rw_blk for inactive LV %s\n", - lvm_name, lv->lv_name); + lvm_name, lv->u.lv_name); goto bad; } if ((rw == WRITE || rw == WRITEA) && - !(lv->lv_access & LV_WRITE)) { + !(lv->u.lv_access & LV_WRITE)) { printk(KERN_CRIT "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", - lvm_name, lv->lv_name); + lvm_name, lv->u.lv_name); goto bad; } P_MAP("%s - lvm_map minor: %d *rdev: %s *rsector: %lu size:%lu\n", lvm_name, minor, - kdevname(bh->bi_dev), + kdevname(bi->bi_dev), rsector_org, size); - if (rsector_org + size > lv->lv_size) { + if (rsector_org + size > lv->u.lv_size) { printk(KERN_ALERT "%s - lvm_map access beyond end of device; *rsector: " "%lu or size: %lu wrong for minor: %2d\n", @@ -1163,39 +1166,39 @@ } - if (lv->lv_stripes < 2) { /* linear mapping */ + if (lv->u.lv_stripes < 2) { /* linear mapping */ /* get the index */ index = rsector_org / vg_this->pe_size; - pe_start = lv->lv_current_pe[index].pe; - rsector_map = lv->lv_current_pe[index].pe + + pe_start = lv->u.lv_current_pe[index].pe; + rsector_map = lv->u.lv_current_pe[index].pe + (rsector_org % vg_this->pe_size); - rdev_map = lv->lv_current_pe[index].dev; + rdev_map = lv->u.lv_current_pe[index].dev; - P_MAP("lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n", - index, lv->lv_current_pe[index].pe, + P_MAP("u.lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n", + index, lv->u.lv_current_pe[index].pe, kdevname(rdev_map), rsector_map); } else { /* striped mapping */ ulong stripe_index; ulong stripe_length; - stripe_length = vg_this->pe_size * lv->lv_stripes; + stripe_length = vg_this->pe_size * lv->u.lv_stripes; stripe_index = (rsector_org % stripe_length) / - lv->lv_stripesize; + lv->u.lv_stripesize; index = rsector_org / stripe_length + - (stripe_index % lv->lv_stripes) * - (lv->lv_allocated_le / lv->lv_stripes); - pe_start = lv->lv_current_pe[index].pe; - rsector_map = lv->lv_current_pe[index].pe + + (stripe_index % lv->u.lv_stripes) * + (lv->u.lv_allocated_le / lv->u.lv_stripes); + pe_start = lv->u.lv_current_pe[index].pe; + rsector_map = lv->u.lv_current_pe[index].pe + (rsector_org % stripe_length) - - (stripe_index % lv->lv_stripes) * lv->lv_stripesize - - stripe_index / lv->lv_stripes * - (lv->lv_stripes - 1) * lv->lv_stripesize; - rdev_map = lv->lv_current_pe[index].dev; + (stripe_index % lv->u.lv_stripes) * lv->u.lv_stripesize - + stripe_index / lv->u.lv_stripes * + (lv->u.lv_stripes - 1) * lv->u.lv_stripesize; + rdev_map = lv->u.lv_current_pe[index].dev; - P_MAP("lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n" + P_MAP("u.lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n" "stripe_length: %ld stripe_index: %ld\n", - index, lv->lv_current_pe[index].pe, kdevname(rdev_map), + index, lv->u.lv_current_pe[index].pe, kdevname(rdev_map), rsector_map, stripe_length, stripe_index); } @@ -1205,23 +1208,23 @@ * we need to queue this request, because this is in the fast path. */ if (rw == WRITE || rw == WRITEA) { - if(_defer_extent(bh, rw, rdev_map, + if(_defer_extent(bi, rw, rdev_map, rsector_map, vg_this->pe_size)) { up_read(&lv->lv_lock); return 0; } - lv->lv_current_pe[index].writes++; /* statistic */ + lv->u.lv_current_pe[index].writes++; /* statistic */ } else - lv->lv_current_pe[index].reads++; /* statistic */ + lv->u.lv_current_pe[index].reads++; /* statistic */ /* snapshot volume exception handling on physical device address base */ - if (!(lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG))) + if (!(lv->u.lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG))) goto out; - if (lv->lv_access & LV_SNAPSHOT) { /* remap snapshot */ - if (lv->lv_block_exception) + if (lv->u.lv_access & LV_SNAPSHOT) { /* remap snapshot */ + if (lv->u.lv_block_exception) lvm_snapshot_remap_block(&rdev_map, &rsector_map, pe_start, lv); else @@ -1232,10 +1235,10 @@ /* start with first snapshot and loop through all of them */ - for (snap = lv->lv_snapshot_next; snap; - snap = snap->lv_snapshot_next) { + for (snap = lv->u.lv_snapshot_next; snap; + snap = snap->u.lv_snapshot_next) { /* Check for inactive snapshot */ - if (!(snap->lv_status & LV_ACTIVE)) + if (!(snap->u.lv_status & LV_ACTIVE)) continue; /* Serializes the COW with the accesses to the @@ -1246,13 +1249,13 @@ } out: - bh->bi_dev = rdev_map; - bh->bi_sector = rsector_map; + bi->bi_dev = rdev_map; + bi->bi_sector = rsector_map; up_read(&lv->lv_lock); return 1; bad: - bio_io_error(bh); + bio_io_error(bi); up_read(&lv->lv_lock); return -1; } /* lvm_map() */ @@ -1274,8 +1277,8 @@ if (vg[VG_BLK(minor)] == NULL || (lv_ptr = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]) == NULL) return; - len = strlen(lv_ptr->lv_name) - 5; - memcpy(buf, &lv_ptr->lv_name[5], len); + len = strlen(lv_ptr->u.lv_name) - 5; + memcpy(buf, &lv_ptr->u.lv_name[5], len); buf[len] = 0; return; } @@ -1339,7 +1342,8 @@ case LOCK_PE: for (p = 0; p < vg_ptr->pv_max; p++) { if (vg_ptr->pv[p] != NULL && - new_lock.data.pv_dev == vg_ptr->pv[p]->pv_dev) + kdev_same(new_lock.data.pv_dev, + vg_ptr->pv[p]->pv_dev)) break; } if (p == vg_ptr->pv_max) return -ENXIO; @@ -1359,7 +1363,7 @@ return -EBUSY; } - /* Should we do to_kdev_t() on the pv_dev and lv_dev??? */ + /* Should we do to_kdev_t() on the pv_dev and u.lv_dev??? */ pe_lock_req.lock = LOCK_PE; pe_lock_req.data.lv_dev = new_lock.data.lv_dev; pe_lock_req.data.pv_dev = new_lock.data.pv_dev; @@ -1373,8 +1377,8 @@ case UNLOCK_PE: down_write(&_pe_lock); pe_lock_req.lock = UNLOCK_PE; - pe_lock_req.data.lv_dev = 0; - pe_lock_req.data.pv_dev = 0; + pe_lock_req.data.lv_dev = NODEV; + pe_lock_req.data.pv_dev = NODEV; pe_lock_req.data.pv_offset = 0; bh = _dequeue_io(); up_write(&_pe_lock); @@ -1406,16 +1410,16 @@ for (l = 0; l < vg_ptr->lv_max; l++) { lv_ptr = vg_ptr->lv[l]; if (lv_ptr != NULL && - strcmp(lv_ptr->lv_name, + strcmp(lv_ptr->u.lv_name, le_remap_req.lv_name) == 0) { - for (le = 0; le < lv_ptr->lv_allocated_le; le++) { - if (lv_ptr->lv_current_pe[le].dev == - le_remap_req.old_dev && - lv_ptr->lv_current_pe[le].pe == + for (le = 0; le < lv_ptr->u.lv_allocated_le; le++) { + if (kdev_same(lv_ptr->u.lv_current_pe[le].dev, + le_remap_req.old_dev) && + lv_ptr->u.lv_current_pe[le].pe == le_remap_req.old_pe) { - lv_ptr->lv_current_pe[le].dev = + lv_ptr->u.lv_current_pe[le].dev = le_remap_req.new_dev; - lv_ptr->lv_current_pe[le].pe = + lv_ptr->u.lv_current_pe[le].pe = le_remap_req.new_pe; __update_hardsectsize(lv_ptr); @@ -1436,9 +1440,9 @@ { int ret = 0; ulong l, ls = 0, p, size; - lv_t lv; vg_t *vg_ptr; lv_t **snap_lv_ptr; + lv_t *tmplv; if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) { printk(KERN_CRIT @@ -1446,6 +1450,7 @@ lvm_name, __LINE__); return -ENOMEM; } + /* get the volume group structure */ if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) { P_IOCTL("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n", @@ -1454,6 +1459,8 @@ return -EFAULT; } + + /* VG_CREATE now uses minor number in VG structure */ if (minor == -1) minor = vg_ptr->vg_number; @@ -1513,19 +1520,30 @@ } memset(snap_lv_ptr, 0, size); + if ((tmplv = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) { + printk(KERN_CRIT + "%s -- VG_CREATE: kmalloc error LV at line %d\n", + lvm_name, __LINE__); + vfree(snap_lv_ptr); + return -ENOMEM; + } + /* get the logical volume structures */ vg_ptr->lv_cur = 0; for (l = 0; l < vg_ptr->lv_max; l++) { lv_t *lvp; + /* user space address */ if ((lvp = vg_ptr->lv[l]) != NULL) { - if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) { + if (copy_from_user(tmplv, lvp, sizeof(userlv_t)) != 0) { P_IOCTL("ERROR: copying LV ptr %p (%d bytes)\n", lvp, sizeof(lv_t)); lvm_do_vg_remove(minor); + vfree(snap_lv_ptr); + kfree(tmplv); return -EFAULT; } - if ( lv.lv_access & LV_SNAPSHOT) { + if ( tmplv->u.lv_access & LV_SNAPSHOT) { snap_lv_ptr[ls] = lvp; vg_ptr->lv[l] = NULL; ls++; @@ -1533,8 +1551,10 @@ } vg_ptr->lv[l] = NULL; /* only create original logical volumes for now */ - if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) { + if (lvm_do_lv_create(minor, tmplv->u.lv_name, &tmplv->u) != 0) { lvm_do_vg_remove(minor); + vfree(snap_lv_ptr); + kfree(tmplv); return -EFAULT; } } @@ -1544,18 +1564,22 @@ in place during first path above */ for (l = 0; l < ls; l++) { lv_t *lvp = snap_lv_ptr[l]; - if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) { + if (copy_from_user(tmplv, lvp, sizeof(userlv_t)) != 0) { lvm_do_vg_remove(minor); + vfree(snap_lv_ptr); + kfree(tmplv); return -EFAULT; } - if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) { + if (lvm_do_lv_create(minor, tmplv->u.lv_name, &tmplv->u) != 0) { lvm_do_vg_remove(minor); + vfree(snap_lv_ptr); + kfree(tmplv); return -EFAULT; } } vfree(snap_lv_ptr); - + kfree(tmplv); vg_count++; @@ -1645,15 +1669,15 @@ for ( l = 0; l < vg_ptr->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) == NULL) continue; - strncpy(lv_ptr->vg_name, vg_name, sizeof ( vg_name)); - ptr = strrchr(lv_ptr->lv_name, '/'); - if (ptr == NULL) ptr = lv_ptr->lv_name; + strncpy(lv_ptr->u.vg_name, vg_name, sizeof ( vg_name)); + ptr = strrchr(lv_ptr->u.lv_name, '/'); + if (ptr == NULL) ptr = lv_ptr->u.lv_name; strncpy(lv_name, ptr, sizeof ( lv_name)); len = sizeof(LVM_DIR_PREFIX); - strcpy(lv_ptr->lv_name, LVM_DIR_PREFIX); - strncat(lv_ptr->lv_name, vg_name, NAME_LEN - len); + strcpy(lv_ptr->u.lv_name, LVM_DIR_PREFIX); + strncat(lv_ptr->u.lv_name, vg_name, NAME_LEN - len); len += strlen ( vg_name); - strncat(lv_ptr->lv_name, lv_name, NAME_LEN - len); + strncat(lv_ptr->u.lv_name, lv_name, NAME_LEN - len); } for ( p = 0; p < vg_ptr->pv_max; p++) { @@ -1695,7 +1719,7 @@ /* first free snapshot logical volumes */ for (i = 0; i < vg_ptr->lv_max; i++) { if (vg_ptr->lv[i] != NULL && - vg_ptr->lv[i]->lv_access & LV_SNAPSHOT) { + vg_ptr->lv[i]->u.lv_access & LV_SNAPSHOT) { lvm_do_lv_remove(minor, NULL, i); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(1); @@ -1798,8 +1822,8 @@ int le, e; int max_hardsectsize = 0, hardsectsize; - for (le = 0; le < lv->lv_allocated_le; le++) { - hardsectsize = get_hardsect_size(lv->lv_current_pe[le].dev); + for (le = 0; le < lv->u.lv_allocated_le; le++) { + hardsectsize = get_hardsect_size(lv->u.lv_current_pe[le].dev); if (hardsectsize == 0) hardsectsize = 512; if (hardsectsize > max_hardsectsize) @@ -1807,10 +1831,10 @@ } /* only perform this operation on active snapshots */ - if ((lv->lv_access & LV_SNAPSHOT) && - (lv->lv_status & LV_ACTIVE)) { - for (e = 0; e < lv->lv_remap_end; e++) { - hardsectsize = get_hardsect_size( lv->lv_block_exception[e].rdev_new); + if ((lv->u.lv_access & LV_SNAPSHOT) && + (lv->u.lv_status & LV_ACTIVE)) { + for (e = 0; e < lv->u.lv_remap_end; e++) { + hardsectsize = get_hardsect_size( lv->u.lv_block_exception[e].rdev_new); if (hardsectsize == 0) hardsectsize = 512; if (hardsectsize > max_hardsectsize) @@ -1822,31 +1846,31 @@ /* * character device support function logical volume create */ -static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) +static int lvm_do_lv_create(int minor, char *lv_name, userlv_t *ulv) { int e, ret, l, le, l_new, p, size, activate = 1; ulong lv_status_save; - lv_block_exception_t *lvbe = lv->lv_block_exception; + lv_block_exception_t *lvbe = ulv->lv_block_exception; vg_t *vg_ptr = vg[VG_CHR(minor)]; lv_t *lv_ptr = NULL; pe_t *pep; - if (!(pep = lv->lv_current_pe)) + if (!(pep = ulv->lv_current_pe)) return -EINVAL; - if (_sectors_to_k(lv->lv_chunk_size) > LVM_SNAPSHOT_MAX_CHUNK) + if (_sectors_to_k(ulv->lv_chunk_size) > LVM_SNAPSHOT_MAX_CHUNK) return -EINVAL; for (l = 0; l < vg_ptr->lv_cur; l++) { if (vg_ptr->lv[l] != NULL && - strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) + strcmp(vg_ptr->lv[l]->u.lv_name, lv_name) == 0) return -EEXIST; } /* in case of lv_remove(), lv_create() pair */ l_new = -1; - if (vg_ptr->lv[lv->lv_number] == NULL) - l_new = lv->lv_number; + if (vg_ptr->lv[ulv->lv_number] == NULL) + l_new = ulv->lv_number; else { for (l = 0; l < vg_ptr->lv_max; l++) { if (vg_ptr->lv[l] == NULL) @@ -1862,16 +1886,16 @@ return -ENOMEM; } /* copy preloaded LV */ - memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t)); + memcpy((char *) lv_ptr, (char *) ulv, sizeof(userlv_t)); - lv_status_save = lv_ptr->lv_status; - lv_ptr->lv_status &= ~LV_ACTIVE; - lv_ptr->lv_snapshot_org = NULL; - lv_ptr->lv_snapshot_prev = NULL; - lv_ptr->lv_snapshot_next = NULL; - lv_ptr->lv_block_exception = NULL; + lv_status_save = lv_ptr->u.lv_status; + lv_ptr->u.lv_status &= ~LV_ACTIVE; + lv_ptr->u.lv_snapshot_org = NULL; + lv_ptr->u.lv_snapshot_prev = NULL; + lv_ptr->u.lv_snapshot_next = NULL; + lv_ptr->u.lv_block_exception = NULL; lv_ptr->lv_iobuf = NULL; - lv_ptr->lv_COW_table_iobuf = NULL; + lv_ptr->lv_COW_table_iobuf = NULL; lv_ptr->lv_snapshot_hash_table = NULL; lv_ptr->lv_snapshot_hash_table_size = 0; lv_ptr->lv_snapshot_hash_mask = 0; @@ -1883,10 +1907,10 @@ /* get the PE structures from user space if this is not a snapshot logical volume */ - if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { - size = lv_ptr->lv_allocated_le * sizeof(pe_t); + if (!(lv_ptr->u.lv_access & LV_SNAPSHOT)) { + size = lv_ptr->u.lv_allocated_le * sizeof(pe_t); - if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) { + if ((lv_ptr->u.lv_current_pe = vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte " "at line %d\n", @@ -1896,30 +1920,30 @@ vg_ptr->lv[l] = NULL; return -ENOMEM; } - if (copy_from_user(lv_ptr->lv_current_pe, pep, size)) { + if (copy_from_user(lv_ptr->u.lv_current_pe, pep, size)) { P_IOCTL("ERROR: copying PE ptr %p (%d bytes)\n", pep, sizeof(size)); - vfree(lv_ptr->lv_current_pe); + vfree(lv_ptr->u.lv_current_pe); kfree(lv_ptr); vg_ptr->lv[l] = NULL; return -EFAULT; } /* correct the PE count in PVs */ - for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + for (le = 0; le < lv_ptr->u.lv_allocated_le; le++) { vg_ptr->pe_allocated++; for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - lv_ptr->lv_current_pe[le].dev) + if (kdev_same(vg_ptr->pv[p]->pv_dev, + lv_ptr->u.lv_current_pe[le].dev)) vg_ptr->pv[p]->pe_allocated++; } } } else { /* Get snapshot exception data and block list */ if (lvbe != NULL) { - lv_ptr->lv_snapshot_org = - vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)]; - if (lv_ptr->lv_snapshot_org != NULL) { - size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t); + lv_ptr->u.lv_snapshot_org = + vg_ptr->lv[LV_BLK(lv_ptr->u.lv_snapshot_minor)]; + if (lv_ptr->u.lv_snapshot_org != NULL) { + size = lv_ptr->u.lv_remap_end * sizeof(lv_block_exception_t); if(!size) { printk(KERN_WARNING @@ -1929,7 +1953,7 @@ return -EINVAL; } - if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) { + if ((lv_ptr->u.lv_block_exception = vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION " "of %d byte at line %d\n", @@ -1940,14 +1964,14 @@ vg_ptr->lv[l] = NULL; return -ENOMEM; } - if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) { - vfree(lv_ptr->lv_block_exception); + if (copy_from_user(lv_ptr->u.lv_block_exception, lvbe, size)) { + vfree(lv_ptr->u.lv_block_exception); kfree(lv_ptr); vg_ptr->lv[l] = NULL; return -EFAULT; } - if(lv_ptr->lv_block_exception[0].rsector_org == + if(lv_ptr->u.lv_block_exception[0].rsector_org == LVM_SNAPSHOT_DROPPED_SECTOR) { printk(KERN_WARNING @@ -1958,36 +1982,36 @@ /* point to the original logical volume */ - lv_ptr = lv_ptr->lv_snapshot_org; + lv_ptr = lv_ptr->u.lv_snapshot_org; - lv_ptr->lv_snapshot_minor = 0; - lv_ptr->lv_snapshot_org = lv_ptr; + lv_ptr->u.lv_snapshot_minor = 0; + lv_ptr->u.lv_snapshot_org = lv_ptr; /* our new one now back points to the previous last in the chain which can be the original logical volume */ lv_ptr = vg_ptr->lv[l]; /* now lv_ptr points to our new last snapshot logical volume */ - lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe; - lv_ptr->lv_allocated_snapshot_le = lv_ptr->lv_allocated_le; - lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le; - lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le; - lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size; - lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes; - lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize; + lv_ptr->u.lv_current_pe = lv_ptr->u.lv_snapshot_org->u.lv_current_pe; + lv_ptr->lv_allocated_snapshot_le = lv_ptr->u.lv_allocated_le; + lv_ptr->u.lv_allocated_le = lv_ptr->u.lv_snapshot_org->u.lv_allocated_le; + lv_ptr->u.lv_current_le = lv_ptr->u.lv_snapshot_org->u.lv_current_le; + lv_ptr->u.lv_size = lv_ptr->u.lv_snapshot_org->u.lv_size; + lv_ptr->u.lv_stripes = lv_ptr->u.lv_snapshot_org->u.lv_stripes; + lv_ptr->u.lv_stripesize = lv_ptr->u.lv_snapshot_org->u.lv_stripesize; /* Update the VG PE(s) used by snapshot reserve space. */ vg_ptr->pe_allocated += lv_ptr->lv_allocated_snapshot_le; if ((ret = lvm_snapshot_alloc(lv_ptr)) != 0) { - vfree(lv_ptr->lv_block_exception); + vfree(lv_ptr->u.lv_block_exception); kfree(lv_ptr); vg_ptr->lv[l] = NULL; return ret; } - for ( e = 0; e < lv_ptr->lv_remap_ptr; e++) - lvm_hash_link (lv_ptr->lv_block_exception + e, - lv_ptr->lv_block_exception[e].rdev_org, - lv_ptr->lv_block_exception[e].rsector_org, lv_ptr); + for ( e = 0; e < lv_ptr->u.lv_remap_ptr; e++) + lvm_hash_link (lv_ptr->u.lv_block_exception + e, + lv_ptr->u.lv_block_exception[e].rdev_org, + lv_ptr->u.lv_block_exception[e].rsector_org, lv_ptr); /* need to fill the COW exception table data into the page for disk i/o */ if(lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr)) { @@ -2006,62 +2030,62 @@ vg_ptr->lv[l] = NULL; return -EINVAL; } - } /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */ + } /* if ( vg[VG_CHR(minor)]->lv[l]->u.lv_access & LV_SNAPSHOT) */ lv_ptr = vg_ptr->lv[l]; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size; - lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; - vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number; - vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number; - LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].start_sect = 0; + lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].nr_sects = lv_ptr->u.lv_size; + lvm_size[minor(lv_ptr->u.lv_dev)] = lv_ptr->u.lv_size >> 1; + vg_lv_map[minor(lv_ptr->u.lv_dev)].vg_number = vg_ptr->vg_number; + vg_lv_map[minor(lv_ptr->u.lv_dev)].lv_number = lv_ptr->u.lv_number; + LVM_CORRECT_READ_AHEAD(lv_ptr->u.lv_read_ahead); vg_ptr->lv_cur++; - lv_ptr->lv_status = lv_status_save; + lv_ptr->u.lv_status = lv_status_save; __update_hardsectsize(lv_ptr); /* optionally add our new snapshot LV */ - if (lv_ptr->lv_access & LV_SNAPSHOT) { - lv_t *org = lv_ptr->lv_snapshot_org, *last; + if (lv_ptr->u.lv_access & LV_SNAPSHOT) { + lv_t *org = lv_ptr->u.lv_snapshot_org, *last; /* sync the original logical volume */ - fsync_dev(org->lv_dev); + fsync_dev(org->u.lv_dev); #ifdef LVM_VFS_ENHANCEMENT /* VFS function call to sync and lock the filesystem */ - fsync_dev_lockfs(org->lv_dev); + fsync_dev_lockfs(org->u.lv_dev); #endif down_write(&org->lv_lock); - org->lv_access |= LV_SNAPSHOT_ORG; - lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */ + org->u.lv_access |= LV_SNAPSHOT_ORG; + lv_ptr->u.lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */ /* Link in the list of snapshot volumes */ - for (last = org; last->lv_snapshot_next; last = last->lv_snapshot_next); - lv_ptr->lv_snapshot_prev = last; - last->lv_snapshot_next = lv_ptr; + for (last = org; last->u.lv_snapshot_next; last = last->u.lv_snapshot_next); + lv_ptr->u.lv_snapshot_prev = last; + last->u.lv_snapshot_next = lv_ptr; up_write(&org->lv_lock); } /* activate the logical volume */ if(activate) - lv_ptr->lv_status |= LV_ACTIVE; + lv_ptr->u.lv_status |= LV_ACTIVE; else - lv_ptr->lv_status &= ~LV_ACTIVE; + lv_ptr->u.lv_status &= ~LV_ACTIVE; - if ( lv_ptr->lv_access & LV_WRITE) - set_device_ro(lv_ptr->lv_dev, 0); + if ( lv_ptr->u.lv_access & LV_WRITE) + set_device_ro(lv_ptr->u.lv_dev, 0); else - set_device_ro(lv_ptr->lv_dev, 1); + set_device_ro(lv_ptr->u.lv_dev, 1); #ifdef LVM_VFS_ENHANCEMENT /* VFS function call to unlock the filesystem */ - if (lv_ptr->lv_access & LV_SNAPSHOT) - unlockfs(lv_ptr->lv_snapshot_org->lv_dev); + if (lv_ptr->u.lv_access & LV_SNAPSHOT) + unlockfs(lv_ptr->u.lv_snapshot_org->u.lv_dev); #endif lv_ptr->vg = vg_ptr; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de = + lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].de = lvm_fs_create_lv(vg_ptr, lv_ptr); return 0; @@ -2080,7 +2104,7 @@ if (l == -1) { for (l = 0; l < vg_ptr->lv_max; l++) { if (vg_ptr->lv[l] != NULL && - strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) { + strcmp(vg_ptr->lv[l]->u.lv_name, lv_name) == 0) { break; } } @@ -2089,38 +2113,38 @@ lv_ptr = vg_ptr->lv[l]; #ifdef LVM_TOTAL_RESET - if (lv_ptr->lv_open > 0 && lvm_reset_spindown == 0) + if (lv_ptr->u.lv_open > 0 && lvm_reset_spindown == 0) #else - if (lv_ptr->lv_open > 0) + if (lv_ptr->u.lv_open > 0) #endif return -EBUSY; /* check for deletion of snapshot source while snapshot volume still exists */ - if ((lv_ptr->lv_access & LV_SNAPSHOT_ORG) && - lv_ptr->lv_snapshot_next != NULL) + if ((lv_ptr->u.lv_access & LV_SNAPSHOT_ORG) && + lv_ptr->u.lv_snapshot_next != NULL) return -EPERM; lvm_fs_remove_lv(vg_ptr, lv_ptr); - if (lv_ptr->lv_access & LV_SNAPSHOT) { + if (lv_ptr->u.lv_access & LV_SNAPSHOT) { /* * Atomically make the the snapshot invisible * to the original lv before playing with it. */ - lv_t * org = lv_ptr->lv_snapshot_org; + lv_t * org = lv_ptr->u.lv_snapshot_org; down_write(&org->lv_lock); /* remove this snapshot logical volume from the chain */ - lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next; - if (lv_ptr->lv_snapshot_next != NULL) { - lv_ptr->lv_snapshot_next->lv_snapshot_prev = - lv_ptr->lv_snapshot_prev; + lv_ptr->u.lv_snapshot_prev->u.lv_snapshot_next = lv_ptr->u.lv_snapshot_next; + if (lv_ptr->u.lv_snapshot_next != NULL) { + lv_ptr->u.lv_snapshot_next->u.lv_snapshot_prev = + lv_ptr->u.lv_snapshot_prev; } /* no more snapshots? */ - if (!org->lv_snapshot_next) { - org->lv_access &= ~LV_SNAPSHOT_ORG; + if (!org->u.lv_snapshot_next) { + org->u.lv_access &= ~LV_SNAPSHOT_ORG; } up_write(&org->lv_lock); @@ -2130,41 +2154,41 @@ vg_ptr->pe_allocated -= lv_ptr->lv_allocated_snapshot_le; } - lv_ptr->lv_status |= LV_SPINDOWN; + lv_ptr->u.lv_status |= LV_SPINDOWN; /* sync the buffers */ - fsync_dev(lv_ptr->lv_dev); + fsync_dev(lv_ptr->u.lv_dev); - lv_ptr->lv_status &= ~LV_ACTIVE; + lv_ptr->u.lv_status &= ~LV_ACTIVE; /* invalidate the buffers */ - invalidate_buffers(lv_ptr->lv_dev); + invalidate_buffers(lv_ptr->u.lv_dev); /* reset generic hd */ - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = -1; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = 0; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de = 0; - lvm_size[MINOR(lv_ptr->lv_dev)] = 0; + lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].start_sect = -1; + lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].nr_sects = 0; + lvm_gendisk.part[minor(lv_ptr->u.lv_dev)].de = 0; + lvm_size[minor(lv_ptr->u.lv_dev)] = 0; /* reset VG/LV mapping */ - vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = ABS_MAX_VG; - vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1; + vg_lv_map[minor(lv_ptr->u.lv_dev)].vg_number = ABS_MAX_VG; + vg_lv_map[minor(lv_ptr->u.lv_dev)].lv_number = -1; /* correct the PE count in PVs if this is not a snapshot logical volume */ - if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { + if (!(lv_ptr->u.lv_access & LV_SNAPSHOT)) { /* only if this is no snapshot logical volume because - we share the lv_current_pe[] structs with the + we share the u.lv_current_pe[] structs with the original logical volume */ - for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + for (le = 0; le < lv_ptr->u.lv_allocated_le; le++) { vg_ptr->pe_allocated--; for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - lv_ptr->lv_current_pe[le].dev) + if (kdev_same(vg_ptr->pv[p]->pv_dev, + lv_ptr->u.lv_current_pe[le].dev)) vg_ptr->pv[p]->pe_allocated--; } } - vfree(lv_ptr->lv_current_pe); + vfree(lv_ptr->u.lv_current_pe); } P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__); @@ -2182,10 +2206,10 @@ ulong size; lv_block_exception_t *lvbe; - if (!new_lv->lv_block_exception) + if (!new_lv->u.lv_block_exception) return -ENXIO; - size = new_lv->lv_remap_end * sizeof(lv_block_exception_t); + size = new_lv->u.lv_remap_end * sizeof(lv_block_exception_t); if ((lvbe = vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- lvm_do_lv_extend_reduce: vmalloc " @@ -2194,15 +2218,15 @@ return -ENOMEM; } - if ((new_lv->lv_remap_end > old_lv->lv_remap_end) && - (copy_from_user(lvbe, new_lv->lv_block_exception, size))) { + if ((new_lv->u.lv_remap_end > old_lv->u.lv_remap_end) && + (copy_from_user(lvbe, new_lv->u.lv_block_exception, size))) { vfree(lvbe); return -EFAULT; } - new_lv->lv_block_exception = lvbe; + new_lv->u.lv_block_exception = lvbe; if (lvm_snapshot_alloc_hash_table(new_lv)) { - vfree(new_lv->lv_block_exception); + vfree(new_lv->u.lv_block_exception); return -ENOMEM; } @@ -2214,7 +2238,7 @@ pe_t *pe; /* allocate space for new pe structures */ - size = new_lv->lv_current_le * sizeof(pe_t); + size = new_lv->u.lv_current_le * sizeof(pe_t); if ((pe = vmalloc(size)) == NULL) { printk(KERN_CRIT "%s -- lvm_do_lv_extend_reduce: " @@ -2224,21 +2248,21 @@ } /* get the PE structures from user space */ - if (copy_from_user(pe, new_lv->lv_current_pe, size)) { - if(old_lv->lv_access & LV_SNAPSHOT) + if (copy_from_user(pe, new_lv->u.lv_current_pe, size)) { + if(old_lv->u.lv_access & LV_SNAPSHOT) vfree(new_lv->lv_snapshot_hash_table); vfree(pe); return -EFAULT; } - new_lv->lv_current_pe = pe; + new_lv->u.lv_current_pe = pe; /* reduce allocation counters on PV(s) */ - for (l = 0; l < old_lv->lv_allocated_le; l++) { + for (l = 0; l < old_lv->u.lv_allocated_le; l++) { vg_ptr->pe_allocated--; for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - old_lv->lv_current_pe[l].dev) { + if (kdev_same(vg_ptr->pv[p]->pv_dev, + old_lv->u.lv_current_pe[l].dev)) { vg_ptr->pv[p]->pe_allocated--; break; } @@ -2246,11 +2270,11 @@ } /* extend the PE count in PVs */ - for (l = 0; l < new_lv->lv_allocated_le; l++) { + for (l = 0; l < new_lv->u.lv_allocated_le; l++) { vg_ptr->pe_allocated++; for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - new_lv->lv_current_pe[l].dev) { + if (kdev_same(vg_ptr->pv[p]->pv_dev, + new_lv->u.lv_current_pe[l].dev)) { vg_ptr->pv[p]->pe_allocated++; break; } @@ -2258,30 +2282,30 @@ } /* save availiable i/o statistic data */ - if (old_lv->lv_stripes < 2) { /* linear logical volume */ - end = min(old_lv->lv_current_le, new_lv->lv_current_le); + if (old_lv->u.lv_stripes < 2) { /* linear logical volume */ + end = min(old_lv->u.lv_current_le, new_lv->u.lv_current_le); for (l = 0; l < end; l++) { - new_lv->lv_current_pe[l].reads += - old_lv->lv_current_pe[l].reads; + new_lv->u.lv_current_pe[l].reads += + old_lv->u.lv_current_pe[l].reads; - new_lv->lv_current_pe[l].writes += - old_lv->lv_current_pe[l].writes; + new_lv->u.lv_current_pe[l].writes += + old_lv->u.lv_current_pe[l].writes; } } else { /* striped logical volume */ uint i, j, source, dest, end, old_stripe_size, new_stripe_size; - old_stripe_size = old_lv->lv_allocated_le / old_lv->lv_stripes; - new_stripe_size = new_lv->lv_allocated_le / new_lv->lv_stripes; + old_stripe_size = old_lv->u.lv_allocated_le / old_lv->u.lv_stripes; + new_stripe_size = new_lv->u.lv_allocated_le / new_lv->u.lv_stripes; end = min(old_stripe_size, new_stripe_size); for (i = source = dest = 0; - i < new_lv->lv_stripes; i++) { + i < new_lv->u.lv_stripes; i++) { for (j = 0; j < end; j++) { - new_lv->lv_current_pe[dest + j].reads += - old_lv->lv_current_pe[source + j].reads; - new_lv->lv_current_pe[dest + j].writes += - old_lv->lv_current_pe[source + j].writes; + new_lv->u.lv_current_pe[dest + j].reads += + old_lv->u.lv_current_pe[source + j].reads; + new_lv->u.lv_current_pe[dest + j].writes += + old_lv->u.lv_current_pe[source + j].writes; } source += old_stripe_size; dest += new_stripe_size; @@ -2291,19 +2315,29 @@ return 0; } -static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *new_lv) +static int lvm_do_lv_extend_reduce(int minor, char *lv_name, userlv_t *ulv) { int r; ulong l, e, size; vg_t *vg_ptr = vg[VG_CHR(minor)]; lv_t *old_lv; + lv_t *new_lv; pe_t *pe; - if ((pe = new_lv->lv_current_pe) == NULL) + if((new_lv = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL){ + printk(KERN_CRIT + "%s -- LV_EXTEND/REDUCE: kmallor error LV at line %d\n", + lvm_name,__LINE__); + return -ENOMEM; + } + memset(new_lv,0,sizeof(lv_t)); + memcpy(&new_lv->u,ulv,sizeof(userlv_t)); + + if ((pe = new_lv->u.lv_current_pe) == NULL) return -EINVAL; for (l = 0; l < vg_ptr->lv_max; l++) - if (vg_ptr->lv[l] && !strcmp(vg_ptr->lv[l]->lv_name, lv_name)) + if (vg_ptr->lv[l] && !strcmp(vg_ptr->lv[l]->u.lv_name, lv_name)) break; if (l == vg_ptr->lv_max) @@ -2311,9 +2345,9 @@ old_lv = vg_ptr->lv[l]; - if (old_lv->lv_access & LV_SNAPSHOT) { + if (old_lv->u.lv_access & LV_SNAPSHOT) { /* only perform this operation on active snapshots */ - if (old_lv->lv_status & LV_ACTIVE) + if (old_lv->u.lv_status & LV_ACTIVE) r = __extend_reduce_snapshot(vg_ptr, old_lv, new_lv); else r = -EPERM; @@ -2327,15 +2361,15 @@ /* copy relevent fields */ down_write(&old_lv->lv_lock); - if(new_lv->lv_access & LV_SNAPSHOT) { - size = (new_lv->lv_remap_end > old_lv->lv_remap_end) ? - old_lv->lv_remap_ptr : new_lv->lv_remap_end; + if(new_lv->u.lv_access & LV_SNAPSHOT) { + size = (new_lv->u.lv_remap_end > old_lv->u.lv_remap_end) ? + old_lv->u.lv_remap_ptr : new_lv->u.lv_remap_end; size *= sizeof(lv_block_exception_t); - memcpy(new_lv->lv_block_exception, - old_lv->lv_block_exception, size); + memcpy(new_lv->u.lv_block_exception, + old_lv->u.lv_block_exception, size); - old_lv->lv_remap_end = new_lv->lv_remap_end; - old_lv->lv_block_exception = new_lv->lv_block_exception; + old_lv->u.lv_remap_end = new_lv->u.lv_remap_end; + old_lv->u.lv_block_exception = new_lv->u.lv_block_exception; old_lv->lv_snapshot_hash_table = new_lv->lv_snapshot_hash_table; old_lv->lv_snapshot_hash_table_size = @@ -2343,40 +2377,40 @@ old_lv->lv_snapshot_hash_mask = new_lv->lv_snapshot_hash_mask; - for (e = 0; e < new_lv->lv_remap_ptr; e++) - lvm_hash_link(new_lv->lv_block_exception + e, - new_lv->lv_block_exception[e].rdev_org, - new_lv->lv_block_exception[e].rsector_org, + for (e = 0; e < new_lv->u.lv_remap_ptr; e++) + lvm_hash_link(new_lv->u.lv_block_exception + e, + new_lv->u.lv_block_exception[e].rdev_org, + new_lv->u.lv_block_exception[e].rsector_org, new_lv); } else { - vfree(old_lv->lv_current_pe); + vfree(old_lv->u.lv_current_pe); vfree(old_lv->lv_snapshot_hash_table); - old_lv->lv_size = new_lv->lv_size; - old_lv->lv_allocated_le = new_lv->lv_allocated_le; - old_lv->lv_current_le = new_lv->lv_current_le; - old_lv->lv_current_pe = new_lv->lv_current_pe; - lvm_gendisk.part[MINOR(old_lv->lv_dev)].nr_sects = - old_lv->lv_size; - lvm_size[MINOR(old_lv->lv_dev)] = old_lv->lv_size >> 1; + old_lv->u.lv_size = new_lv->u.lv_size; + old_lv->u.lv_allocated_le = new_lv->u.lv_allocated_le; + old_lv->u.lv_current_le = new_lv->u.lv_current_le; + old_lv->u.lv_current_pe = new_lv->u.lv_current_pe; + lvm_gendisk.part[minor(old_lv->u.lv_dev)].nr_sects = + old_lv->u.lv_size; + lvm_size[minor(old_lv->u.lv_dev)] = old_lv->u.lv_size >> 1; - if (old_lv->lv_access & LV_SNAPSHOT_ORG) { + if (old_lv->u.lv_access & LV_SNAPSHOT_ORG) { lv_t *snap; - for(snap = old_lv->lv_snapshot_next; snap; - snap = snap->lv_snapshot_next) { + for(snap = old_lv->u.lv_snapshot_next; snap; + snap = snap->u.lv_snapshot_next) { down_write(&snap->lv_lock); - snap->lv_current_pe = old_lv->lv_current_pe; - snap->lv_allocated_le = - old_lv->lv_allocated_le; - snap->lv_current_le = old_lv->lv_current_le; - snap->lv_size = old_lv->lv_size; - - lvm_gendisk.part[MINOR(snap->lv_dev)].nr_sects - = old_lv->lv_size; - lvm_size[MINOR(snap->lv_dev)] = - old_lv->lv_size >> 1; + snap->u.lv_current_pe = old_lv->u.lv_current_pe; + snap->u.lv_allocated_le = + old_lv->u.lv_allocated_le; + snap->u.lv_current_le = old_lv->u.lv_current_le; + snap->u.lv_size = old_lv->u.lv_size; + + lvm_gendisk.part[minor(snap->u.lv_dev)].nr_sects + = old_lv->u.lv_size; + lvm_size[minor(snap->u.lv_dev)] = + old_lv->u.lv_size >> 1; __update_hardsectsize(snap); up_write(&snap->lv_lock); } @@ -2410,27 +2444,27 @@ for (l = 0; l < vg_ptr->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) != NULL && - strcmp(lv_ptr->lv_name, + strcmp(lv_ptr->u.lv_name, lv_status_byname_req.lv_name) == 0) { /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_byname_req.lv->lv_current_pe, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr1, &lv_status_byname_req.lv->u.lv_current_pe, sizeof(void*)) != 0) return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_byname_req.lv->lv_block_exception, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr2, &lv_status_byname_req.lv->u.lv_block_exception, sizeof(void*)) != 0) return -EFAULT; if (copy_to_user(lv_status_byname_req.lv, lv_ptr, - sizeof(lv_t)) != 0) + sizeof(userlv_t)) != 0) return -EFAULT; if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, - lv_ptr->lv_current_pe, - lv_ptr->lv_allocated_le * + lv_ptr->u.lv_current_pe, + lv_ptr->u.lv_allocated_le * sizeof(pe_t)) != 0) return -EFAULT; } /* Restore usermode pointers */ - if (copy_to_user(&lv_status_byname_req.lv->lv_current_pe, &saved_ptr1, sizeof(void*)) != 0) + if (copy_to_user(&lv_status_byname_req.lv->u.lv_current_pe, &saved_ptr1, sizeof(void*)) != 0) return -EFAULT; return 0; } @@ -2463,23 +2497,23 @@ return -ENXIO; /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_byindex_req.lv->lv_current_pe, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr1, &lv_status_byindex_req.lv->u.lv_current_pe, sizeof(void*)) != 0) return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_byindex_req.lv->lv_block_exception, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr2, &lv_status_byindex_req.lv->u.lv_block_exception, sizeof(void*)) != 0) return -EFAULT; - if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(lv_t)) != 0) + if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(userlv_t)) != 0) return -EFAULT; if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, - lv_ptr->lv_current_pe, - lv_ptr->lv_allocated_le * + lv_ptr->u.lv_current_pe, + lv_ptr->u.lv_allocated_le * sizeof(pe_t)) != 0) return -EFAULT; } /* Restore usermode pointers */ - if (copy_to_user(&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) + if (copy_to_user(&lv_status_byindex_req.lv->u.lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) return -EFAULT; return 0; @@ -2503,29 +2537,31 @@ for ( l = 0; l < vg_ptr->lv_max; l++) { if ( vg_ptr->lv[l] == NULL) continue; - if ( vg_ptr->lv[l]->lv_dev == lv_status_bydev_req.dev) break; + if ( kdev_same(vg_ptr->lv[l]->u.lv_dev, + to_kdev_t(lv_status_bydev_req.dev))) + break; } if ( l == vg_ptr->lv_max) return -ENXIO; lv_ptr = vg_ptr->lv[l]; /* Save usermode pointers */ - if (copy_from_user(&saved_ptr1, &lv_status_bydev_req.lv->lv_current_pe, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr1, &lv_status_bydev_req.lv->u.lv_current_pe, sizeof(void*)) != 0) return -EFAULT; - if (copy_from_user(&saved_ptr2, &lv_status_bydev_req.lv->lv_block_exception, sizeof(void*)) != 0) + if (copy_from_user(&saved_ptr2, &lv_status_bydev_req.lv->u.lv_block_exception, sizeof(void*)) != 0) return -EFAULT; if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) != 0) return -EFAULT; if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, - lv_ptr->lv_current_pe, - lv_ptr->lv_allocated_le * + lv_ptr->u.lv_current_pe, + lv_ptr->u.lv_allocated_le * sizeof(pe_t)) != 0) return -EFAULT; } /* Restore usermode pointers */ - if (copy_to_user(&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) + if (copy_to_user(&lv_status_bydev_req.lv->u.lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) return -EFAULT; return 0; @@ -2535,7 +2571,7 @@ /* * character device support function rename a logical volume */ -static int lvm_do_lv_rename(vg_t *vg_ptr, lv_req_t *lv_req, lv_t *lv) +static int lvm_do_lv_rename(vg_t *vg_ptr, lv_req_t *lv_req, userlv_t *ulv) { int l = 0; int ret = 0; @@ -2544,10 +2580,10 @@ for (l = 0; l < vg_ptr->lv_max; l++) { if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue; - if (lv_ptr->lv_dev == lv->lv_dev) + if (kdev_same(lv_ptr->u.lv_dev, ulv->lv_dev)) { lvm_fs_remove_lv(vg_ptr, lv_ptr); - strncpy(lv_ptr->lv_name, + strncpy(lv_ptr->u.lv_name, lv_req->lv_name, NAME_LEN); lvm_fs_create_lv(vg_ptr, lv_ptr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/md/md.c linux-2.5/drivers/md/md.c --- linux-2.5.1/drivers/md/md.c Tue Dec 11 21:47:35 2001 +++ linux-2.5/drivers/md/md.c Sat Jan 12 12:32:40 2002 @@ -30,6 +30,7 @@ #include <linux/module.h> #include <linux/config.h> +#include <linux/linkage.h> #include <linux/raid/md.h> #include <linux/sysctl.h> #include <linux/raid/xor.h> @@ -66,7 +67,7 @@ /* * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' - * is 100 KB/sec, so the extra system load does not show up that much. + * is 1000 KB/sec, so the extra system load does not show up that much. * Increase it if you want to have more _guaranteed_ speed. Note that * the RAID driver will use the maximum available bandwith if the IO * subsystem is idle. There is also an 'absolute maximum' reconstruction @@ -76,8 +77,8 @@ * you can change it via /proc/sys/dev/raid/speed_limit_min and _max. */ -static int sysctl_speed_limit_min = 100; -static int sysctl_speed_limit_max = 100000; +static int sysctl_speed_limit_min = 1000; +static int sysctl_speed_limit_max = 200000; static struct ctl_table_header *raid_table_header; @@ -118,11 +119,9 @@ major: MD_MAJOR, major_name: "md", minor_shift: 0, - max_p: 1, part: md_hd_struct, sizes: md_size, nr_real: MAX_MD_DEVS, - real_devices: NULL, next: NULL, fops: &md_fops, }; @@ -141,9 +140,9 @@ void add_mddev_mapping(mddev_t * mddev, kdev_t dev, void *data) { - unsigned int minor = MINOR(dev); + unsigned int minor = minor(dev); - if (MAJOR(dev) != MD_MAJOR) { + if (major(dev) != MD_MAJOR) { MD_BUG(); return; } @@ -157,9 +156,9 @@ void del_mddev_mapping(mddev_t * mddev, kdev_t dev) { - unsigned int minor = MINOR(dev); + unsigned int minor = minor(dev); - if (MAJOR(dev) != MD_MAJOR) { + if (major(dev) != MD_MAJOR) { MD_BUG(); return; } @@ -187,7 +186,7 @@ { mddev_t *mddev; - if (MAJOR(dev) != MD_MAJOR) { + if (major(dev) != MD_MAJOR) { MD_BUG(); return 0; } @@ -197,7 +196,7 @@ memset(mddev, 0, sizeof(*mddev)); - mddev->__minor = MINOR(dev); + mddev->__minor = minor(dev); init_MUTEX(&mddev->reconfig_sem); init_MUTEX(&mddev->recovery_sem); init_MUTEX(&mddev->resync_sem); @@ -236,7 +235,7 @@ mdk_rdev_t *rdev; ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->dev == dev) + if (kdev_same(rdev->dev, dev)) return rdev; } return NULL; @@ -253,7 +252,7 @@ while (tmp != &device_names) { dname = list_entry(tmp, dev_name_t, list); - if (dname->dev == dev) + if (kdev_same(dname->dev, dev)) return dname->name; tmp = tmp->next; } @@ -268,7 +267,7 @@ hd = get_gendisk (dev); dname->name = NULL; if (hd) - dname->name = disk_name (hd, MINOR(dev), dname->namebuf); + dname->name = disk_name (hd, minor(dev), dname->namebuf); if (!dname->name) { sprintf (dname->namebuf, "[dev %s]", kdevname(dev)); dname->name = dname->namebuf; @@ -286,8 +285,8 @@ { unsigned int size = 0; - if (blk_size[MAJOR(dev)]) - size = blk_size[MAJOR(dev)][MINOR(dev)]; + if (blk_size[major(dev)]) + size = blk_size[major(dev)][minor(dev)]; if (persistent) size = MD_NEW_SIZE_BLOCKS(size); return size; @@ -469,40 +468,45 @@ static int read_disk_sb(mdk_rdev_t * rdev) { - int ret = -EINVAL; - struct buffer_head *bh = NULL; - kdev_t dev = rdev->dev; - mdp_super_t *sb; + struct address_space *mapping = rdev->bdev->bd_inode->i_mapping; + struct page *page; + char *p; unsigned long sb_offset; + int n = PAGE_CACHE_SIZE / BLOCK_SIZE; if (!rdev->sb) { MD_BUG(); - goto abort; + return -EINVAL; } /* * Calculate the position of the superblock, - * it's at the end of the disk + * it's at the end of the disk. + * + * It also happens to be a multiple of 4Kb. */ sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1); rdev->sb_offset = sb_offset; - fsync_dev(dev); - set_blocksize (dev, MD_SB_BYTES); - bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); - - if (bh) { - sb = (mdp_super_t *) bh->b_data; - memcpy (rdev->sb, sb, MD_SB_BYTES); - } else { - printk(NO_SB,partition_name(rdev->dev)); - goto abort; - } + page = read_cache_page(mapping, sb_offset/n, + (filler_t *)mapping->a_ops->readpage, NULL); + if (IS_ERR(page)) + goto out; + wait_on_page(page); + if (!Page_Uptodate(page)) + goto fail; + if (PageError(page)) + goto fail; + p = (char *)page_address(page) + BLOCK_SIZE * (sb_offset % n); + memcpy((char*)rdev->sb, p, MD_SB_BYTES); + page_cache_release(page); printk(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo); - ret = 0; -abort: - if (bh) - brelse (bh); - return ret; + return 0; + +fail: + page_cache_release(page); +out: + printk(NO_SB,partition_name(rdev->dev)); + return -EINVAL; } static unsigned int calc_sb_csum(mdp_super_t * sb) @@ -556,10 +560,10 @@ struct gendisk *hd = get_gendisk(dev); if (!hd) - return 0; + return NODEV; mask = ~((1 << hd->minor_shift) - 1); - return MKDEV(MAJOR(dev), MINOR(dev) & mask); + return mk_kdev(major(dev), minor(dev) & mask); } static mdk_rdev_t * match_dev_unit(mddev_t *mddev, kdev_t dev) @@ -568,7 +572,7 @@ mdk_rdev_t *rdev; ITERATE_RDEV(mddev,rdev,tmp) - if (dev_unit(rdev->dev) == dev_unit(dev)) + if (kdev_same(dev_unit(rdev->dev), dev_unit(dev))) return rdev; return NULL; @@ -637,7 +641,7 @@ int err = 0; struct block_device *bdev; - bdev = bdget(rdev->dev); + bdev = bdget(kdev_t_to_nr(rdev->dev)); if (!bdev) return -ENOMEM; err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW); @@ -675,7 +679,7 @@ #ifndef MODULE md_autodetect_dev(rdev->dev); #endif - rdev->dev = 0; + rdev->dev = NODEV; rdev->faulty = 0; kfree(rdev); } @@ -728,7 +732,7 @@ while (atomic_read(&mddev->recovery_sem.count) != 1) schedule(); - del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); + del_mddev_mapping(mddev, mk_kdev(MD_MAJOR, mdidx(mddev))); list_del(&mddev->all_mddevs); INIT_LIST_HEAD(&mddev->all_mddevs); kfree(mddev); @@ -743,7 +747,7 @@ static void print_desc(mdp_disk_t *desc) { printk(" DISK<N:%d,%s(%d,%d),R:%d,S:%d>\n", desc->number, - partition_name(MKDEV(desc->major,desc->minor)), + partition_name(mk_kdev(desc->major,desc->minor)), desc->major,desc->minor,desc->raid_disk,desc->state); } @@ -877,22 +881,21 @@ tmp = all_raid_disks.next; while (tmp != &all_raid_disks) { rdev = list_entry(tmp, mdk_rdev_t, all); - if (rdev->dev == dev) + if (kdev_same(rdev->dev, dev)) return rdev; tmp = tmp->next; } return NULL; } -#define GETBLK_FAILED KERN_ERR \ -"md: getblk failed for device %s\n" - static int write_disk_sb(mdk_rdev_t * rdev) { - struct buffer_head *bh; - kdev_t dev; + struct address_space *mapping = rdev->bdev->bd_inode->i_mapping; + struct page *page; + unsigned offs; + int error; + kdev_t dev = rdev->dev; unsigned long sb_offset, size; - mdp_super_t *sb; if (!rdev->sb) { MD_BUG(); @@ -907,7 +910,6 @@ return 1; } - dev = rdev->dev; sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1); if (rdev->sb_offset != sb_offset) { printk(KERN_INFO "%s's sb offset has changed from %ld to %ld, skipping\n", @@ -928,26 +930,32 @@ printk(KERN_INFO "(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset); fsync_dev(dev); - set_blocksize(dev, MD_SB_BYTES); - bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); - if (!bh) { - printk(GETBLK_FAILED, partition_name(dev)); - return 1; - } - memset(bh->b_data,0,bh->b_size); - sb = (mdp_super_t *) bh->b_data; - memcpy(sb, rdev->sb, MD_SB_BYTES); - - mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); - wait_on_buffer(bh); - brelse(bh); + page = grab_cache_page(mapping, sb_offset/(PAGE_CACHE_SIZE/BLOCK_SIZE)); + offs = sb_offset % (PAGE_CACHE_SIZE/BLOCK_SIZE); + if (!page) + goto fail; + error = mapping->a_ops->prepare_write(NULL, page, offs, + offs + MD_SB_BYTES); + if (error) + goto unlock; + memcpy((char *)page_address(page) + offs, rdev->sb, MD_SB_BYTES); + error = mapping->a_ops->commit_write(NULL, page, offs, + offs + MD_SB_BYTES); + if (error) + goto unlock; + UnlockPage(page); + wait_on_page(page); + page_cache_release(page); fsync_dev(dev); skip: return 0; +unlock: + UnlockPage(page); + page_cache_release(page); +fail: + printk("md: write_disk_sb failed for device %s\n", partition_name(dev)); + return 1; } -#undef GETBLK_FAILED static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev) { @@ -958,12 +966,12 @@ desc = mddev->sb->disks + i; #if 0 if (disk_faulty(desc)) { - if (MKDEV(desc->major,desc->minor) == rdev->dev) + if (mk_kdev(desc->major,desc->minor) == rdev->dev) ok = 1; continue; } #endif - if (MKDEV(desc->major,desc->minor) == rdev->dev) { + if (kdev_same(mk_kdev(desc->major,desc->minor), rdev->dev)) { rdev->sb->this_disk = *desc; rdev->desc_nr = desc->number; ok = 1; @@ -1098,8 +1106,8 @@ rdev->faulty = 0; size = 0; - if (blk_size[MAJOR(newdev)]) - size = blk_size[MAJOR(newdev)][MINOR(newdev)]; + if (blk_size[major(newdev)]) + size = blk_size[major(newdev)][minor(newdev)]; if (!size) { printk(KERN_WARNING "md: %s has zero size, marking faulty!\n", partition_name(newdev)); @@ -1120,11 +1128,11 @@ } if (rdev->sb->level != -4) { - rdev->old_dev = MKDEV(rdev->sb->this_disk.major, + rdev->old_dev = mk_kdev(rdev->sb->this_disk.major, rdev->sb->this_disk.minor); rdev->desc_nr = rdev->sb->this_disk.number; } else { - rdev->old_dev = MKDEV(0, 0); + rdev->old_dev = NODEV; rdev->desc_nr = -1; } } @@ -1290,7 +1298,7 @@ ev2 = md_event(sb); ev3 = ev2; --ev3; - if ((rdev->dev != rdev->old_dev) && + if (!kdev_same(rdev->dev, rdev->old_dev) && ((ev1 == ev2) || (ev1 == ev3))) { mdp_disk_t *desc; @@ -1301,15 +1309,15 @@ goto abort; } desc = &sb->disks[rdev->desc_nr]; - if (rdev->old_dev != MKDEV(desc->major, desc->minor)) { + if (!kdev_same( rdev->old_dev, mk_kdev(desc->major, desc->minor))) { MD_BUG(); goto abort; } - desc->major = MAJOR(rdev->dev); - desc->minor = MINOR(rdev->dev); + desc->major = major(rdev->dev); + desc->minor = minor(rdev->dev); desc = &rdev->sb->this_disk; - desc->major = MAJOR(rdev->dev); - desc->minor = MINOR(rdev->dev); + desc->major = major(rdev->dev); + desc->minor = minor(rdev->dev); } } @@ -1327,7 +1335,7 @@ kdev_t dev; desc = sb->disks + i; - dev = MKDEV(desc->major, desc->minor); + dev = mk_kdev(desc->major, desc->minor); /* * We kick faulty devices/descriptors immediately. @@ -1349,7 +1357,7 @@ break; } if (!found) { - if (dev == MKDEV(0,0)) + if (kdev_none(dev)) continue; printk(KERN_WARNING "md%d: removing former faulty %s!\n", mdidx(mddev), partition_name(dev)); @@ -1367,7 +1375,7 @@ remove_descriptor(desc, sb); } - if (dev == MKDEV(0,0)) + if (kdev_none(dev)) continue; /* * Is this device present in the rdev ring? @@ -1380,8 +1388,9 @@ * we cannot check rdev->number. * We can check the device though. */ - if ((sb->level == -4) && (rdev->dev == - MKDEV(desc->major,desc->minor))) { + if ((sb->level == -4) && + kdev_same(rdev->dev, + mk_kdev(desc->major,desc->minor))) { found = 1; break; } @@ -1408,9 +1417,9 @@ kdev_t dev; desc = sb->disks + i; - dev = MKDEV(desc->major, desc->minor); + dev = mk_kdev(desc->major, desc->minor); - if (dev == MKDEV(0,0)) + if (kdev_none(dev)) continue; if (disk_faulty(desc)) { @@ -1474,8 +1483,8 @@ * is the device unique? */ ITERATE_RDEV(mddev,rdev2,tmp2) { - if ((rdev2 != rdev) && - (rdev2->dev == rdev->dev)) { + if (rdev2 != rdev && + kdev_same(rdev2->dev, rdev->dev)) { MD_BUG(); goto abort; } @@ -1725,7 +1734,7 @@ * twice as large as sectors. */ md_hd_struct[mdidx(mddev)].start_sect = 0; - register_disk(&md_gendisk, MKDEV(MAJOR_NR,mdidx(mddev)), + register_disk(&md_gendisk, mk_kdev(MAJOR_NR,mdidx(mddev)), 1, &md_fops, md_size[mdidx(mddev)]<<1); read_ahead[MD_MAJOR] = 1024; @@ -1945,7 +1954,7 @@ * mostly sane superblocks. It's time to allocate the * mddev. */ - md_kdev = MKDEV(MD_MAJOR, rdev0->sb->md_minor); + md_kdev = mk_kdev(MD_MAJOR, rdev0->sb->md_minor); mddev = kdev_to_mddev(md_kdev); if (mddev) { printk(KERN_WARNING "md: md%d already running, cannot run %s\n", @@ -1959,7 +1968,7 @@ printk(KERN_ERR "md: cannot allocate memory for md drive.\n"); break; } - if (md_kdev == countdev) + if (kdev_same(md_kdev, countdev)) atomic_inc(&mddev->active); printk(KERN_INFO "md: created md%d\n", mdidx(mddev)); ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { @@ -2042,11 +2051,11 @@ kdev_t dev; desc = sb->disks + i; - dev = MKDEV(desc->major, desc->minor); + dev = mk_kdev(desc->major, desc->minor); - if (dev == MKDEV(0,0)) + if (kdev_none(dev)) continue; - if (dev == startdev) + if (kdev_same(dev, startdev)) continue; if (md_import_device(dev, 1)) { printk(KERN_WARNING "md: could not import %s, trying to run array nevertheless.\n", @@ -2171,7 +2180,7 @@ mdk_rdev_t *rdev; unsigned int nr; kdev_t dev; - dev = MKDEV(info->major,info->minor); + dev = mk_kdev(info->major,info->minor); if (find_rdev_all(dev)) { printk(KERN_WARNING "md: device %s already used in a RAID array!\n", @@ -2443,8 +2452,8 @@ } disk->raid_disk = disk->number; - disk->major = MAJOR(dev); - disk->minor = MINOR(dev); + disk->major = major(dev); + disk->minor = minor(dev); if (mddev->pers->diskop(mddev, &disk, DISKOP_HOT_ADD_DISK)) { MD_BUG(); @@ -2570,7 +2579,7 @@ return -EACCES; dev = inode->i_rdev; - minor = MINOR(dev); + minor = minor(dev); if (minor >= MAX_MD_DEVS) { MD_BUG(); return -EINVAL; @@ -2686,10 +2695,10 @@ /* * possibly make it lock the array ... */ - err = autostart_array((kdev_t)arg, dev); + err = autostart_array(val_to_kdev(arg), dev); if (err) { printk(KERN_WARNING "md: autostart %s failed!\n", - partition_name((kdev_t)arg)); + partition_name(val_to_kdev(arg))); goto abort; } goto done; @@ -2794,14 +2803,14 @@ goto done_unlock; } case HOT_GENERATE_ERROR: - err = hot_generate_error(mddev, (kdev_t)arg); + err = hot_generate_error(mddev, val_to_kdev(arg)); goto done_unlock; case HOT_REMOVE_DISK: - err = hot_remove_disk(mddev, (kdev_t)arg); + err = hot_remove_disk(mddev, val_to_kdev(arg)); goto done_unlock; case HOT_ADD_DISK: - err = hot_add_disk(mddev, (kdev_t)arg); + err = hot_add_disk(mddev, val_to_kdev(arg)); goto done_unlock; case SET_DISK_INFO: @@ -2821,7 +2830,7 @@ goto done_unlock; case SET_DISK_FAULTY: - err = set_disk_faulty(mddev, (kdev_t)arg); + err = set_disk_faulty(mddev, val_to_kdev(arg)); goto done_unlock; case RUN_ARRAY: @@ -2932,8 +2941,6 @@ * bdflush, otherwise bdflush will deadlock if there are too * many dirty RAID5 blocks. */ - current->policy = SCHED_OTHER; - current->nice = -20; unlock_kernel(); complete(thread->event); @@ -3039,7 +3046,7 @@ mdk_rdev_t * rrdev; dprintk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n", - MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), + major(dev),minor(dev),major(rdev),minor(rdev), __builtin_return_address(0),__builtin_return_address(1), __builtin_return_address(2),__builtin_return_address(3)); @@ -3283,7 +3290,7 @@ static unsigned int sync_io[DK_MAX_MAJOR][DK_MAX_DISK]; void md_sync_acct(kdev_t dev, unsigned long nr_sectors) { - unsigned int major = MAJOR(dev); + unsigned int major = major(dev); unsigned int index; index = disk_index(dev); @@ -3302,7 +3309,7 @@ idle = 1; ITERATE_RDEV(mddev,rdev,tmp) { - int major = MAJOR(rdev->dev); + int major = major(rdev->dev); int idx = disk_index(rdev->dev); if ((idx >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) @@ -3336,7 +3343,7 @@ int md_do_sync(mddev_t *mddev, mdp_disk_t *spare) { mddev_t *mddev2; - unsigned int max_sectors, currspeed, + unsigned int max_sectors, currspeed = 0, j, window, err, serialize; unsigned long mark[SYNC_MARKS]; unsigned long mark_cnt[SYNC_MARKS]; @@ -3376,17 +3383,11 @@ max_sectors = mddev->sb->size << 1; printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev)); - printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n", - sysctl_speed_limit_min); + printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n", sysctl_speed_limit_min); printk(KERN_INFO "md: using maximum available idle IO bandwith " "(but not more than %d KB/sec) for reconstruction.\n", sysctl_speed_limit_max); - /* - * Resync has low priority. - */ - current->nice = 19; - is_mddev_idle(mddev); /* this also initializes IO event counters */ for (m = 0; m < SYNC_MARKS; m++) { mark[m] = jiffies; @@ -3409,7 +3410,7 @@ for (j = 0; j < max_sectors;) { int sectors; - sectors = mddev->pers->sync_request(mddev, j); + sectors = mddev->pers->sync_request(mddev, j, currspeed < sysctl_speed_limit_min); if (sectors < 0) { err = sectors; goto out; @@ -3463,16 +3464,13 @@ currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1; if (currspeed > sysctl_speed_limit_min) { - current->nice = 19; - if ((currspeed > sysctl_speed_limit_max) || !is_mddev_idle(mddev)) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/4); goto repeat; } - } else - current->nice = -20; + } } printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); err = 0; @@ -3527,7 +3525,7 @@ if (!spare) continue; printk(KERN_INFO "md%d: resyncing spare disk %s to replace failed disk\n", - mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); + mdidx(mddev), partition_name(mk_kdev(spare->major,spare->minor))); if (!mddev->pers->diskop) continue; if (mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_WRITE)) @@ -3537,7 +3535,7 @@ err = md_do_sync(mddev, spare); if (err == -EIO) { printk(KERN_INFO "md%d: spare disk %s failed, skipping to next spare.\n", - mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); + mdidx(mddev), partition_name(mk_kdev(spare->major,spare->minor))); if (!disk_faulty(spare)) { mddev->pers->diskop(mddev,&spare,DISKOP_SPARE_INACTIVE); mark_disk_faulty(spare); @@ -3699,7 +3697,7 @@ * Searches all registered partitions for autorun RAID arrays * at boot time. */ -static int detected_devices[128]; +static kdev_t detected_devices[128]; static int dev_cnt; void md_autodetect_dev(kdev_t dev) @@ -3784,7 +3782,7 @@ printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor); return 0; } else if (md_setup_args.device_names[minor]) { - printk(KERN_WARNING "md: md=%d, Specified more then once. " + printk(KERN_WARNING "md: md=%d, Specified more than once. " "Replacing previous definition.\n", minor); } switch (get_option(&str, &level)) { /* RAID Personality */ @@ -3857,14 +3855,14 @@ *p++ = 0; dev = name_to_kdev_t(devname); - handle = devfs_find_handle(NULL, devname, MAJOR (dev), MINOR (dev), + handle = devfs_find_handle(NULL, devname, major (dev), minor (dev), DEVFS_SPECIAL_BLK, 1); if (handle != 0) { unsigned major, minor; devfs_get_maj_min(handle, &major, &minor); - dev = MKDEV(major, minor); + dev = mk_kdev(major, minor); } - if (!dev) { + if (kdev_none(dev)) { printk(KERN_WARNING "md: Unknown device name: %s\n", devname); break; } @@ -3874,7 +3872,7 @@ devname = p; } - devices[i] = 0; + devices[i] = NODEV; if (!md_setup_args.device_set[minor]) continue; @@ -3887,7 +3885,7 @@ } printk(KERN_INFO "md: Loading md%d: %s\n", minor, md_setup_args.device_names[minor]); - mddev = alloc_mddev(MKDEV(MD_MAJOR,minor)); + mddev = alloc_mddev(mk_kdev(MD_MAJOR,minor)); if (!mddev) { printk(KERN_ERR "md: kmalloc failed - cannot start array %d\n", minor); continue; @@ -3914,8 +3912,8 @@ dinfo.number = i; dinfo.raid_disk = i; dinfo.state = (1<<MD_DISK_ACTIVE)|(1<<MD_DISK_SYNC); - dinfo.major = MAJOR(dev); - dinfo.minor = MINOR(dev); + dinfo.major = major(dev); + dinfo.minor = minor(dev); mddev->sb->nr_disks++; mddev->sb->raid_disks++; mddev->sb->active_disks++; @@ -3925,8 +3923,8 @@ } else { /* persistent */ for (i = 0; (dev = devices[i]); i++) { - dinfo.major = MAJOR(dev); - dinfo.minor = MINOR(dev); + dinfo.major = major(dev); + dinfo.minor = minor(dev); add_new_disk (mddev, &dinfo); } } @@ -4034,4 +4032,4 @@ EXPORT_SYMBOL(mddev_map); EXPORT_SYMBOL(md_check_ordering); EXPORT_SYMBOL(get_spare); - +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/md/multipath.c linux-2.5/drivers/md/multipath.c --- linux-2.5.1/drivers/md/multipath.c Mon Nov 12 17:51:56 2001 +++ linux-2.5/drivers/md/multipath.c Sun Jan 6 01:38:27 2002 @@ -21,6 +21,7 @@ #include <linux/module.h> #include <linux/slab.h> +#include <linux/spinlock.h> #include <linux/raid/multipath.h> #include <asm/atomic.h> @@ -353,7 +354,7 @@ * which has just failed. */ for (i = 0; i < disks; i++) { - if (multipaths[i].dev==dev && !multipaths[i].operational) + if (kdev_same(multipaths[i].dev, dev) && !multipaths[i].operational) return 0; } printk (LAST_DISK); @@ -362,7 +363,7 @@ * Mark disk as unusable */ for (i = 0; i < disks; i++) { - if (multipaths[i].dev==dev && multipaths[i].operational) { + if (kdev_same(multipaths[i].dev,dev) && multipaths[i].operational) { mark_disk_bad(mddev, i); break; } @@ -605,7 +606,7 @@ *d = failed_desc; - if (sdisk->dev == MKDEV(0,0)) + if (kdev_none(sdisk->dev)) sdisk->used_slot = 0; /* * this really activates the spare. @@ -630,7 +631,7 @@ err = 1; goto abort; } - rdisk->dev = MKDEV(0,0); + rdisk->dev = NODEV; rdisk->used_slot = 0; conf->nr_disks--; break; @@ -647,7 +648,7 @@ adisk->number = added_desc->number; adisk->raid_disk = added_desc->raid_disk; - adisk->dev = MKDEV(added_desc->major,added_desc->minor); + adisk->dev = mk_kdev(added_desc->major,added_desc->minor); adisk->operational = 0; adisk->spare = 1; @@ -710,7 +711,7 @@ dev = bh->b_dev; multipath_map (mddev, &bh->b_dev); - if (bh->b_dev == dev) { + if (kdev_same(bh->b_dev, dev)) { printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); multipath_end_bh_io(mp_bh, 0); } else { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/md/raid1.c linux-2.5/drivers/md/raid1.c --- linux-2.5.1/drivers/md/raid1.c Tue Dec 11 21:47:35 2001 +++ linux-2.5/drivers/md/raid1.c Thu Jan 3 23:11:48 2002 @@ -28,7 +28,6 @@ #define MD_DRIVER #define MD_PERSONALITY -#define MAX_WORK_PER_DISK 128 /* * Number of guaranteed r1bios in case of extreme VM load: */ @@ -38,24 +37,6 @@ static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(retry_list_head); -static inline void check_all_w_bios_empty(r1bio_t *r1_bio) -{ - int i; - - return; - for (i = 0; i < MD_SB_DISKS; i++) - if (r1_bio->write_bios[i]) - BUG(); -} - -static inline void check_all_bios_empty(r1bio_t *r1_bio) -{ - return; - if (r1_bio->read_bio) - BUG(); - check_all_w_bios_empty(r1_bio); -} - static void * r1bio_pool_alloc(int gfp_flags, void *data) { r1bio_t *r1_bio; @@ -69,11 +50,11 @@ static void r1bio_pool_free(void *r1_bio, void *data) { - check_all_bios_empty(r1_bio); kfree(r1_bio); } #define RESYNC_BLOCK_SIZE (64*1024) +#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9) #define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE) #define RESYNC_WINDOW (2048*1024) @@ -86,7 +67,6 @@ int i, j; r1_bio = mempool_alloc(conf->r1bio_pool, gfp_flags); - check_all_bios_empty(r1_bio); bio = bio_alloc(gfp_flags, RESYNC_PAGES); if (!bio) @@ -131,7 +111,6 @@ r1bio_t *r1bio = __r1_bio; struct bio *bio = r1bio->master_bio; - check_all_bios_empty(r1bio); if (atomic_read(&bio->bi_cnt) != 1) BUG(); for (i = 0; i < RESYNC_PAGES; i++) { @@ -163,13 +142,25 @@ } *bio = NULL; } - check_all_bios_empty(r1_bio); } static inline void free_r1bio(r1bio_t *r1_bio) { + unsigned long flags; + conf_t *conf = mddev_to_conf(r1_bio->mddev); + /* + * Wake up any possible resync thread that waits for the device + * to go idle. + */ + spin_lock_irqsave(&conf->resync_lock, flags); + if (!--conf->nr_pending) { + wake_up(&conf->wait_idle); + wake_up(&conf->wait_resume); + } + spin_unlock_irqrestore(&conf->resync_lock, flags); + put_all_bios(conf, r1_bio); mempool_free(r1_bio, conf->r1bio_pool); } @@ -178,7 +169,14 @@ { conf_t *conf = mddev_to_conf(r1_bio->mddev); struct bio *bio = r1_bio->master_bio; + unsigned long flags; + spin_lock_irqsave(&conf->resync_lock, flags); + if (!--conf->nr_pending) { + wake_up(&conf->wait_idle); + wake_up(&conf->wait_resume); + } + spin_unlock_irqrestore(&conf->resync_lock, flags); /* * undo any possible partial request fixup magic: */ @@ -222,37 +220,6 @@ md_wakeup_thread(conf->thread); } - -static void inline raid_request_done(unsigned long sector, conf_t *conf, int phase) -{ - unsigned long flags; - spin_lock_irqsave(&conf->segment_lock, flags); - if (sector < conf->start_active) - conf->cnt_done--; - else if (sector >= conf->start_future && conf->phase == phase) - conf->cnt_future--; - else if (!--conf->cnt_pending) - wake_up(&conf->wait_ready); - - spin_unlock_irqrestore(&conf->segment_lock, flags); -} - -static void inline sync_request_done(sector_t sector, conf_t *conf) -{ - unsigned long flags; - - spin_lock_irqsave(&conf->segment_lock, flags); - if (sector >= conf->start_ready) - --conf->cnt_ready; - else if (sector >= conf->start_active) { - if (!--conf->cnt_active) { - conf->start_active = conf->start_ready; - wake_up(&conf->wait_done); - } - } - spin_unlock_irqrestore(&conf->segment_lock, flags); -} - /* * raid_end_bio_io() is called when we have finished servicing a mirrored * operation and are ready to return a success/failure code to the buffer @@ -262,19 +229,29 @@ { struct bio *bio = r1_bio->master_bio; - raid_request_done(bio->bi_sector, mddev_to_conf(r1_bio->mddev), - test_bit(R1BIO_SyncPhase, &r1_bio->state)); - bio_endio(bio, uptodate, nr_sectors); free_r1bio(r1_bio); return 0; } +/* + * Update disk head position estimator based on IRQ completion info. + */ +static void inline update_head_pos(int disk, r1bio_t *r1_bio) +{ + conf_t *conf = mddev_to_conf(r1_bio->mddev); + + conf->mirrors[disk].head_position = + r1_bio->sector + (r1_bio->master_bio->bi_size >> 9); + atomic_dec(&conf->mirrors[disk].nr_pending); +} + static int end_request(struct bio *bio, int nr_sectors) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); + int i; /* * this branch is our 'one mirror IO has finished' event handler: @@ -287,20 +264,16 @@ * we will return a good error code for to the higher * levels even if IO on some other mirrored buffer fails. * - * The 'master' represents the complex operation to + * The 'master' represents the composite IO operation to * user-side. So if something waits for IO, then it will * wait for the 'master' bio. */ set_bit(R1BIO_Uptodate, &r1_bio->state); - /* - * We split up the read and write side, imho they are - * conceptually different. - */ - if ((r1_bio->cmd == READ) || (r1_bio->cmd == READA)) { if (!r1_bio->read_bio) BUG(); + update_head_pos(r1_bio->read_disk, r1_bio); /* * we have only one bio on the read side */ @@ -322,6 +295,14 @@ /* * WRITE: * + * First, find the disk this bio belongs to. + */ + for (i = 0; i < MD_SB_DISKS; i++) + if (r1_bio->write_bios[i] == bio) { + update_head_pos(i, r1_bio); + break; + } + /* * Let's see if all mirrored write operations have finished * already. */ @@ -332,44 +313,49 @@ /* * This routine returns the disk from which the requested read should - * be done. It bookkeeps the last read position for every disk - * in array and when new read requests come, the disk which last - * position is nearest to the request, is chosen. + * be done. There is a per-array 'next expected sequential IO' sector + * number - if this matches on the next IO then we use the last disk. + * There is also a per-disk 'last know head position' sector that is + * maintained from IRQ contexts, both the normal and the resync IO + * completion handlers update this position correctly. If there is no + * perfect sequential match then we pick the disk whose head is closest. * - * TODO: now if there are 2 mirrors in the same 2 devices, performance - * degrades dramatically because position is mirror, not device based. - * This should be changed to be device based. Also atomic sequential - * reads should be somehow balanced. + * If there are 2 mirrors in the same 2 devices, performance degrades + * because position is mirror, not device based. */ - static int read_balance(conf_t *conf, struct bio *bio, r1bio_t *r1_bio) { - const int sectors = bio->bi_size >> 9; const unsigned long this_sector = r1_bio->sector; - unsigned long new_distance, current_distance; int new_disk = conf->last_used, disk = new_disk; + const int sectors = bio->bi_size >> 9; + sector_t new_distance, current_distance; /* - * Check if it is sane at all to balance - */ - - if (conf->resync_mirrors) + * Check if it if we can balance. We can balance on the whole + * device if no resync is going on, or below the resync window. + * We take the first readable disk when above the resync window. + */ + if (conf->resync_mirrors && (this_sector + sectors >= conf->next_resync)) { + /* make sure that disk is operational */ + new_disk = 0; + while (!conf->mirrors[new_disk].operational || conf->mirrors[new_disk].write_only) { + new_disk++; + if (new_disk == conf->raid_disks) { + new_disk = 0; + break; + } + } goto rb_out; + } - /* make sure that disk is operational */ - while( !conf->mirrors[new_disk].operational) { - if (new_disk <= 0) new_disk = conf->raid_disks; + /* make sure the disk is operational */ + while (!conf->mirrors[new_disk].operational) { + if (new_disk <= 0) + new_disk = conf->raid_disks; new_disk--; if (new_disk == disk) { - /* - * This means no working disk was found - * Nothing much to do, lets not change anything - * and hope for the best... - */ - new_disk = conf->last_used; - goto rb_out; } } @@ -377,36 +363,16 @@ /* now disk == new_disk == starting point for search */ /* - * Don't touch anything for sequential reads. + * Don't change to another disk for sequential reads: */ - if (this_sector == conf->mirrors[new_disk].head_position) + if (conf->next_seq_sect == this_sector) goto rb_out; - - /* - * If reads have been done only on a single disk - * for a time, lets give another disk a change. - * This is for kicking those idling disks so that - * they would find work near some hotspot. - */ - if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) { - conf->sect_count = 0; - - do { - if (new_disk <= 0) - new_disk = conf->raid_disks; - new_disk--; - if (new_disk == disk) - break; - } while ((conf->mirrors[new_disk].write_only) || - (!conf->mirrors[new_disk].operational)); - + if (this_sector == conf->mirrors[new_disk].head_position) goto rb_out; - } - current_distance = abs(this_sector - - conf->mirrors[disk].head_position); + current_distance = abs(this_sector - conf->mirrors[disk].head_position); - /* Find the disk which is closest */ + /* Find the disk whose head is closest */ do { if (disk <= 0) @@ -417,44 +383,56 @@ (!conf->mirrors[disk].operational)) continue; - new_distance = abs(this_sector - - conf->mirrors[disk].head_position); - + if (!atomic_read(&conf->mirrors[disk].nr_pending)) { + new_disk = disk; + break; + } + new_distance = abs(this_sector - conf->mirrors[disk].head_position); if (new_distance < current_distance) { - conf->sect_count = 0; current_distance = new_distance; new_disk = disk; } } while (disk != conf->last_used); rb_out: - conf->mirrors[new_disk].head_position = this_sector + sectors; + r1_bio->read_disk = new_disk; + conf->next_seq_sect = this_sector + sectors; conf->last_used = new_disk; - conf->sect_count += sectors; return new_disk; } /* - * Wait if the reconstruction state machine puts up a bar for - * new requests in this sector range: + * Throttle resync depth, so that we can both get proper overlapping of + * requests, but are still able to handle normal requests quickly. */ -static inline void new_request(conf_t *conf, r1bio_t *r1_bio) +#define RESYNC_DEPTH 32 + +static void device_barrier(conf_t *conf, sector_t sect) { - spin_lock_irq(&conf->segment_lock); - wait_event_lock_irq(conf->wait_done, - r1_bio->sector < conf->start_active || - r1_bio->sector >= conf->start_future, - conf->segment_lock); - if (r1_bio->sector < conf->start_active) - conf->cnt_done++; - else { - conf->cnt_future++; - if (conf->phase) - set_bit(R1BIO_SyncPhase, &r1_bio->state); + spin_lock_irq(&conf->resync_lock); + wait_event_lock_irq(conf->wait_idle, !waitqueue_active(&conf->wait_resume), conf->resync_lock); + + if (!conf->barrier++) { + wait_event_lock_irq(conf->wait_idle, !conf->nr_pending, conf->resync_lock); + if (conf->nr_pending) + BUG(); } - spin_unlock_irq(&conf->segment_lock); + wait_event_lock_irq(conf->wait_resume, conf->barrier < RESYNC_DEPTH, conf->resync_lock); + conf->next_resync = sect; + spin_unlock_irq(&conf->resync_lock); +} + +static void resume_device(conf_t *conf) +{ + spin_lock_irq(&conf->resync_lock); + if (!conf->barrier) + BUG(); + --conf->barrier; + wake_up(&conf->wait_resume); + wake_up(&conf->wait_idle); + spin_unlock_irq(&conf->resync_lock); } static int make_request(mddev_t *mddev, int rw, struct bio * bio) @@ -466,6 +444,16 @@ int i, sum_bios = 0, disks = MD_SB_DISKS; /* + * Register the new request and wait if the reconstruction + * thread has put up a bar for new requests. + * Continue immediately if no resync is active currently. + */ + spin_lock_irq(&conf->resync_lock); + wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock); + conf->nr_pending++; + spin_unlock_irq(&conf->resync_lock); + + /* * make_request() can abort the operation when READA is being * used and no empty request is available. * @@ -475,7 +463,6 @@ rw = READ; r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO); - check_all_bios_empty(r1_bio); r1_bio->master_bio = bio; @@ -483,8 +470,6 @@ r1_bio->sector = bio->bi_sector; r1_bio->cmd = rw; - new_request(conf, r1_bio); - if (rw == READ) { /* * read balancing logic: @@ -503,15 +488,13 @@ read_bio->bi_private = r1_bio; generic_make_request(read_bio); + atomic_inc(&conf->mirrors[r1_bio->read_disk].nr_pending); return 0; } /* * WRITE: */ - - check_all_w_bios_empty(r1_bio); - for (i = 0; i < disks; i++) { struct bio *mbio; if (!conf->mirrors[i].operational) @@ -542,14 +525,13 @@ /* * We have to be a bit careful about the semaphore above, thats - * why we start the requests separately. Since kmalloc() could - * fail, sleep and make_request() can sleep too, this is the - * safer solution. Imagine, end_request decreasing the semaphore - * before we could have set it up ... We could play tricks with - * the semaphore (presetting it and correcting at the end if - * sum_bios is not 'n' but we have to do end_request by hand if - * all requests finish until we had a chance to set up the - * semaphore correctly ... lots of races). + * why we start the requests separately. Since generic_make_request() + * can sleep, this is the safer solution. Imagine, end_request + * decreasing the semaphore before we could have set it up ... + * We could play tricks with the semaphore (presetting it and + * correcting at the end if sum_bios is not 'n' but we have to + * do end_request by hand if all requests finish until we had a + * chance to set up the semaphore correctly ... lots of races). */ for (i = 0; i < disks; i++) { struct bio *mbio; @@ -558,6 +540,7 @@ continue; generic_make_request(mbio); + atomic_inc(&conf->mirrors[i].nr_pending); } return 0; } @@ -610,8 +593,7 @@ md_wakeup_thread(conf->thread); if (!mirror->write_only) conf->working_disks--; - printk(DISK_FAILED, partition_name(mirror->dev), - conf->working_disks); + printk(DISK_FAILED, partition_name(mirror->dev), conf->working_disks); } static int error(mddev_t *mddev, kdev_t dev) @@ -629,7 +611,7 @@ * else mark the drive as failed */ for (i = 0; i < disks; i++) - if (mirrors[i].dev == dev && mirrors[i].operational) + if (kdev_same(mirrors[i].dev, dev) && mirrors[i].operational) break; if (i == disks) return 0; @@ -644,12 +626,6 @@ return 0; } -#undef LAST_DISK -#undef NO_SPARE_DISK -#undef DISK_FAILED -#undef START_SYNCING - - static void print_conf(conf_t *conf) { int i; @@ -674,29 +650,13 @@ static void close_sync(conf_t *conf) { - mddev_t *mddev = conf->mddev; - /* - * If reconstruction was interrupted, we need to close the "active" - * and "pending" holes. - * we know that there are no active rebuild requests, - * os cnt_active == cnt_ready == 0 - */ - spin_lock_irq(&conf->segment_lock); - conf->start_active = conf->start_pending; - conf->start_ready = conf->start_pending; - wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); - conf->start_active = conf->start_ready = conf->start_pending = conf->start_future; - conf->start_future = mddev->sb->size+1; - conf->cnt_pending = conf->cnt_future; - conf->cnt_future = 0; - conf->phase = conf->phase ^1; - wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); - conf->start_active = conf->start_ready = conf->start_pending = conf->start_future = 0; - conf->phase = 0; - conf->cnt_future = conf->cnt_done;; - conf->cnt_done = 0; - spin_unlock_irq(&conf->segment_lock); - wake_up(&conf->wait_done); + spin_lock_irq(&conf->resync_lock); + wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock); + spin_unlock_irq(&conf->resync_lock); + + if (conf->barrier) BUG(); + if (waitqueue_active(&conf->wait_idle)) BUG(); + if (waitqueue_active(&conf->wait_resume)) BUG(); } static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) @@ -893,7 +853,7 @@ *d = failed_desc; - if (sdisk->dev == MKDEV(0,0)) + if (kdev_same (sdisk->dev,mk_kdev(0,0))) sdisk->used_slot = 0; /* * this really activates the spare. @@ -919,7 +879,7 @@ err = 1; goto abort; } - rdisk->dev = MKDEV(0,0); + rdisk->dev = mk_kdev(0,0); rdisk->used_slot = 0; conf->nr_disks--; break; @@ -936,7 +896,7 @@ adisk->number = added_desc->number; adisk->raid_disk = added_desc->raid_disk; - adisk->dev = MKDEV(added_desc->major, added_desc->minor); + adisk->dev = mk_kdev(added_desc->major, added_desc->minor); adisk->operational = 0; adisk->write_only = 0; @@ -975,9 +935,9 @@ int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); - check_all_w_bios_empty(r1_bio); if (r1_bio->read_bio != bio) BUG(); + update_head_pos(r1_bio->read_disk, r1_bio); /* * we have read a block, now it needs to be re-written, * or re-read if the read failed. @@ -997,13 +957,21 @@ int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); mddev_t *mddev = r1_bio->mddev; + int i; if (!uptodate) md_error(mddev, bio->bi_dev); + for (i = 0; i < MD_SB_DISKS; i++) + if (r1_bio->write_bios[i] == bio) { + update_head_pos(i, r1_bio); + break; + } + if (atomic_dec_and_test(&r1_bio->remaining)) { - sync_request_done(r1_bio->sector, mddev_to_conf(mddev)); + conf_t *conf = mddev_to_conf(mddev); md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, uptodate); + resume_device(conf); put_buf(r1_bio); } return 0; @@ -1029,11 +997,11 @@ */ printk(IO_ERROR, partition_name(bio->bi_dev), r1_bio->sector); md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0); + resume_device(conf); + put_buf(r1_bio); return; } - check_all_w_bios_empty(r1_bio); - for (i = 0; i < disks ; i++) { if (!conf->mirrors[i].operational) continue; @@ -1071,8 +1039,8 @@ * must be done */ printk(IO_ERROR, partition_name(bio->bi_dev), r1_bio->sector); - sync_request_done(r1_bio->sector, conf); md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0); + resume_device(conf); put_buf(r1_bio); return; } @@ -1083,6 +1051,7 @@ md_sync_acct(mbio->bi_dev, mbio->bi_size >> 9); generic_make_request(mbio); + atomic_inc(&conf->mirrors[i].nr_pending); } } @@ -1101,6 +1070,7 @@ struct bio *bio; unsigned long flags; mddev_t *mddev; + conf_t *conf; kdev_t dev; @@ -1111,9 +1081,9 @@ r1_bio = list_entry(head->prev, r1bio_t, retry_list); list_del(head->prev); spin_unlock_irqrestore(&retry_list_lock, flags); - check_all_w_bios_empty(r1_bio); mddev = r1_bio->mddev; + conf = mddev_to_conf(mddev); if (mddev->sb_dirty) { printk(KERN_INFO "raid1: dirty sb detected, updating.\n"); mddev->sb_dirty = 0; @@ -1128,8 +1098,9 @@ case READA: dev = bio->bi_dev; map(mddev, &bio->bi_dev); - if (bio->bi_dev == dev) { - printk(IO_ERROR, partition_name(bio->bi_dev), r1_bio->sector); + if (kdev_same(bio->bi_dev, dev)) { + printk(IO_ERROR, partition_name(bio->bi_dev), + r1_bio->sector); raid_end_bio_io(r1_bio, 0, 0); break; } @@ -1139,13 +1110,12 @@ bio->bi_rw = r1_bio->cmd; generic_make_request(bio); + atomic_inc(&conf->mirrors[r1_bio->read_disk].nr_pending); break; } } spin_unlock_irqrestore(&retry_list_lock, flags); } -#undef IO_ERROR -#undef REDIRECT_SECTOR /* * Private kernel thread to reconstruct mirrors after an unclean @@ -1177,101 +1147,27 @@ { int buffs; - conf->start_active = 0; - conf->start_ready = 0; - conf->start_pending = 0; - conf->start_future = 0; - conf->phase = 0; - buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE; if (conf->r1buf_pool) BUG(); conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free, conf); if (!conf->r1buf_pool) return -ENOMEM; - conf->window = 2048; - conf->cnt_future += conf->cnt_done+conf->cnt_pending; - conf->cnt_done = conf->cnt_pending = 0; - if (conf->cnt_ready || conf->cnt_active) - MD_BUG(); + conf->next_resync = 0; return 0; } -static void wait_sync_pending(conf_t *conf, sector_t sector_nr) -{ - spin_lock_irq(&conf->segment_lock); - while (sector_nr >= conf->start_pending) { -// printk("wait .. sect=%lu start_active=%d ready=%d pending=%d future=%d, cnt_done=%d active=%d ready=%d pending=%d future=%d\n", sector_nr, conf->start_active, conf->start_ready, conf->start_pending, conf->start_future, conf->cnt_done, conf->cnt_active, conf->cnt_ready, conf->cnt_pending, conf->cnt_future); - wait_event_lock_irq(conf->wait_done, !conf->cnt_active, - conf->segment_lock); - wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, - conf->segment_lock); - conf->start_active = conf->start_ready; - conf->start_ready = conf->start_pending; - conf->start_pending = conf->start_future; - conf->start_future = conf->start_future+conf->window; - - // Note: falling off the end is not a problem - conf->phase = conf->phase ^1; - conf->cnt_active = conf->cnt_ready; - conf->cnt_ready = 0; - conf->cnt_pending = conf->cnt_future; - conf->cnt_future = 0; - wake_up(&conf->wait_done); - } - conf->cnt_ready++; - spin_unlock_irq(&conf->segment_lock); -} - /* * perform a "sync" on one "block" * * We need to make sure that no normal I/O request - particularly write * requests - conflict with active sync requests. - * This is achieved by conceptually dividing the block space into a - * number of sections: - * DONE: 0 .. a-1 These blocks are in-sync - * ACTIVE: a.. b-1 These blocks may have active sync requests, but - * no normal IO requests - * READY: b .. c-1 These blocks have no normal IO requests - sync - * request may be happening - * PENDING: c .. d-1 These blocks may have IO requests, but no new - * ones will be added - * FUTURE: d .. end These blocks are not to be considered yet. IO may - * be happening, but not sync - * - * We keep a - * phase which flips (0 or 1) each time d moves and - * a count of: - * z = active io requests in FUTURE since d moved - marked with - * current phase - * y = active io requests in FUTURE before d moved, or PENDING - - * marked with previous phase - * x = active sync requests in READY - * w = active sync requests in ACTIVE - * v = active io requests in DONE * - * Normally, a=b=c=d=0 and z= active io requests - * or a=b=c=d=END and v= active io requests - * Allowed changes to a,b,c,d: - * A: c==d && y==0 -> d+=window, y=z, z=0, phase=!phase - * B: y==0 -> c=d - * C: b=c, w+=x, x=0 - * D: w==0 -> a=b - * E: a==b==c==d==end -> a=b=c=d=0, z=v, v=0 - * - * At start of sync we apply A. - * When y reaches 0, we apply B then A then being sync requests - * When sync point reaches c-1, we wait for y==0, and W==0, and - * then apply apply B then A then D then C. - * Finally, we apply E - * - * The sync request simply issues a "read" against a working drive - * This is marked so that on completion the raid1d thread is woken to - * issue suitable write requests + * This is achieved by tracking pending requests and a 'barrier' concept + * that can be installed to exclude normal IO requests. */ -static int sync_request(mddev_t *mddev, sector_t sector_nr) +static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) { conf_t *conf = mddev_to_conf(mddev); mirror_info_t *mirror; @@ -1283,8 +1179,13 @@ if (!sector_nr) if (init_resync(conf)) return -ENOMEM; - - wait_sync_pending(conf, sector_nr); + /* + * If there is non-resync activity waiting for us then + * put in a delay to throttle resync. + */ + if (!go_faster && waitqueue_active(&conf->wait_resume)) + schedule_timeout(HZ); + device_barrier(conf, sector_nr + RESYNC_SECTORS); /* * If reconstructing, and >1 working disc, @@ -1302,10 +1203,13 @@ } conf->last_used = disk; - mirror = conf->mirrors+conf->last_used; + mirror = conf->mirrors + conf->last_used; r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO); - check_all_bios_empty(r1_bio); + + spin_lock_irq(&conf->resync_lock); + conf->nr_pending++; + spin_unlock_irq(&conf->resync_lock); r1_bio->mddev = mddev; r1_bio->sector = sector_nr; @@ -1344,6 +1248,7 @@ md_sync_acct(read_bio->bi_dev, nr_sectors); generic_make_request(read_bio); + atomic_inc(&conf->mirrors[conf->last_used].nr_pending); return nr_sectors; } @@ -1447,7 +1352,6 @@ disk->number = descriptor->number; disk->raid_disk = disk_idx; disk->dev = rdev->dev; - disk->sect_limit = MAX_WORK_PER_DISK; disk->operational = 0; disk->write_only = 0; disk->spare = 0; @@ -1479,7 +1383,6 @@ disk->number = descriptor->number; disk->raid_disk = disk_idx; disk->dev = rdev->dev; - disk->sect_limit = MAX_WORK_PER_DISK; disk->operational = 1; disk->write_only = 0; disk->spare = 0; @@ -1494,7 +1397,6 @@ disk->number = descriptor->number; disk->raid_disk = disk_idx; disk->dev = rdev->dev; - disk->sect_limit = MAX_WORK_PER_DISK; disk->operational = 0; disk->write_only = 0; disk->spare = 1; @@ -1507,9 +1409,9 @@ conf->mddev = mddev; conf->device_lock = SPIN_LOCK_UNLOCKED; - conf->segment_lock = SPIN_LOCK_UNLOCKED; - init_waitqueue_head(&conf->wait_done); - init_waitqueue_head(&conf->wait_ready); + conf->resync_lock = SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&conf->wait_idle); + init_waitqueue_head(&conf->wait_resume); if (!conf->working_disks) { printk(NONE_OPERATIONAL, mdidx(mddev)); @@ -1527,7 +1429,7 @@ disk->number = descriptor->number; disk->raid_disk = disk_idx; - disk->dev = MKDEV(0,0); + disk->dev = mk_kdev(0,0); disk->operational = 0; disk->write_only = 0; @@ -1610,17 +1512,6 @@ MOD_DEC_USE_COUNT; return -EIO; } - -#undef INVALID_LEVEL -#undef NO_SB -#undef ERRORS -#undef NOT_IN_SYNC -#undef INCONSISTENT -#undef ALREADY_RUNNING -#undef OPERATIONAL -#undef SPARE -#undef NONE_OPERATIONAL -#undef ARRAY_IS_ACTIVE static int stop_resync(mddev_t *mddev) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/md/raid5.c linux-2.5/drivers/md/raid5.c --- linux-2.5.1/drivers/md/raid5.c Wed Oct 17 21:21:00 2001 +++ linux-2.5/drivers/md/raid5.c Sun Jan 6 01:38:27 2002 @@ -487,7 +487,7 @@ PRINTK("raid5_error called\n"); for (i = 0, disk = conf->disks; i < conf->raid_disks; i++, disk++) { - if (disk->dev == dev) { + if (kdev_same(disk->dev, dev)) { if (disk->operational) { disk->operational = 0; mark_disk_faulty(sb->disks+disk->number); @@ -513,7 +513,7 @@ */ if (conf->spare) { disk = conf->spare; - if (disk->dev == dev) { + if (kdev_same(disk->dev, dev)) { printk (KERN_ALERT "raid5: Disk failure on spare %s\n", partition_name (dev)); @@ -1226,23 +1226,6 @@ return 0; } -/* - * Determine correct block size for this device. - */ -unsigned int device_bsize (kdev_t dev) -{ - unsigned int i, correct_size; - - correct_size = BLOCK_SIZE; - if (blksize_size[MAJOR(dev)]) { - i = blksize_size[MAJOR(dev)][MINOR(dev)]; - if (i) - correct_size = i; - } - - return correct_size; -} - static int raid5_sync_request (mddev_t *mddev, unsigned long sector_nr) { raid5_conf_t *conf = (raid5_conf_t *) mddev->private; @@ -1477,7 +1460,7 @@ disk->number = desc->number; disk->raid_disk = raid_disk; - disk->dev = MKDEV(0,0); + disk->dev = NODEV; disk->operational = 0; disk->write_only = 0; @@ -1936,7 +1919,7 @@ *d = failed_desc; - if (sdisk->dev == MKDEV(0,0)) + if (kdev_none(sdisk->dev)) sdisk->used_slot = 0; /* @@ -1964,7 +1947,7 @@ err = 1; goto abort; } - rdisk->dev = MKDEV(0,0); + rdisk->dev = NODEV; rdisk->used_slot = 0; break; @@ -1981,7 +1964,7 @@ adisk->number = added_desc->number; adisk->raid_disk = added_desc->raid_disk; - adisk->dev = MKDEV(added_desc->major,added_desc->minor); + adisk->dev = mk_kdev(added_desc->major,added_desc->minor); adisk->operational = 0; adisk->write_only = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/md/xor.c linux-2.5/drivers/md/xor.c --- linux-2.5.1/drivers/md/xor.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/md/xor.c Sun Jan 6 01:38:27 2002 @@ -19,6 +19,7 @@ #define BH_TRACE 0 #include <linux/module.h> #include <linux/raid/md.h> +#include <linux/raid/md_compatible.h> #include <linux/raid/xor.h> #include <asm/xor.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/radio/radio-gemtek-pci.c linux-2.5/drivers/media/radio/radio-gemtek-pci.c --- linux-2.5.1/drivers/media/radio/radio-gemtek-pci.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/media/radio/radio-gemtek-pci.c Mon Jan 14 23:44:46 2002 @@ -221,6 +221,7 @@ case VIDIOCGTUNER: { struct video_tuner t; + int signal; if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) ) return -EFAULT; @@ -228,11 +229,12 @@ if ( t.tuner ) return -EINVAL; + signal = gemtek_pci_getsignal( card ); t.rangelow = GEMTEK_PCI_RANGE_LOW; t.rangehigh = GEMTEK_PCI_RANGE_HIGH; - t.flags = VIDEO_TUNER_LOW; + t.flags = VIDEO_TUNER_LOW | (7 << signal) ; t.mode = VIDEO_MODE_AUTO; - t.signal = 0xFFFF * gemtek_pci_getsignal( card ); + t.signal = 0xFFFF * signal; strcpy( t.name, "FM" ); if ( copy_to_user( arg, &t, sizeof( struct video_tuner ) ) ) @@ -282,6 +284,7 @@ a.flags |= VIDEO_AUDIO_MUTABLE; a.volume = 1; a.step = 65535; + a.mode = (1 << gemtek_pci_getsignal( card )); strcpy( a.name, "Radio" ); if ( copy_to_user( arg, &a, sizeof( struct video_audio ) ) ) @@ -424,7 +427,7 @@ name: "gemtek_pci", id_table: gemtek_pci_id, probe: gemtek_pci_probe, - remove: gemtek_pci_remove + remove: __devexit_p(gemtek_pci_remove), }; static int __init gemtek_pci_init_module( void ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/radio/radio-maxiradio.c linux-2.5/drivers/media/radio/radio-maxiradio.c --- linux-2.5.1/drivers/media/radio/radio-maxiradio.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/media/radio/radio-maxiradio.c Thu Dec 13 16:32:36 2001 @@ -376,7 +376,7 @@ name: "radio-maxiradio", id_table: maxiradio_pci_tbl, probe: maxiradio_init_one, - remove: maxiradio_remove_one, + remove: __devexit_p(maxiradio_remove_one), }; int __init maxiradio_radio_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/radio/radio-sf16fmi.c linux-2.5/drivers/media/radio/radio-sf16fmi.c --- linux-2.5.1/drivers/media/radio/radio-sf16fmi.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/media/radio/radio-sf16fmi.c Mon Jan 14 22:39:45 2002 @@ -299,6 +299,7 @@ while (id_table[i].card_vendor != 0 && dev == NULL) { dev = isapnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, NULL); + i++; } if (!dev) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/Config.in linux-2.5/drivers/media/video/Config.in --- linux-2.5.1/drivers/media/video/Config.in Fri Nov 9 22:01:22 2001 +++ linux-2.5/drivers/media/video/Config.in Thu Dec 13 16:32:36 2001 @@ -22,10 +22,8 @@ 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 + if [ "$CONFIG_PARPORT_1284" != "n" ]; then + dep_tristate ' W9966CF Webcam (FlyCam Supra and others) Video For Linux' CONFIG_VIDEO_W9966 $CONFIG_VIDEO_DEV $CONFIG_PARPORT fi fi dep_tristate ' CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/adv7175.c linux-2.5/drivers/media/video/adv7175.c --- linux-2.5.1/drivers/media/video/adv7175.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/media/video/adv7175.c Sun Dec 30 21:17:30 2001 @@ -38,7 +38,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/wrapper.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/bt856.c linux-2.5/drivers/media/video/bt856.c --- linux-2.5.1/drivers/media/video/bt856.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/media/video/bt856.c Sun Dec 30 21:17:30 2001 @@ -40,7 +40,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/wrapper.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/bttv-driver.c linux-2.5/drivers/media/video/bttv-driver.c --- linux-2.5.1/drivers/media/video/bttv-driver.c Wed Oct 17 21:19:20 2001 +++ linux-2.5/drivers/media/video/bttv-driver.c Sun Dec 30 21:17:30 2001 @@ -37,7 +37,6 @@ #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/interrupt.h> @@ -2820,7 +2819,7 @@ * Scan for a Bt848 card, request the irq and map the io memory */ -static void __devexit bttv_remove(struct pci_dev *pci_dev) +static void bttv_remove(struct pci_dev *pci_dev) { u8 command; int j; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/cpia.c linux-2.5/drivers/media/video/cpia.c --- linux-2.5.1/drivers/media/video/cpia.c Thu Oct 25 20:53:47 2001 +++ linux-2.5/drivers/media/video/cpia.c Wed Jan 2 17:23:52 2002 @@ -2386,7 +2386,7 @@ goto_high_power(cam); do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0); if (goto_low_power(cam)) - return -NODEV; + return -ENODEV; } /* procedure described in developer's guide p3-28 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/meye.c linux-2.5/drivers/media/video/meye.c --- linux-2.5.1/drivers/media/video/meye.c Thu Oct 25 20:53:47 2001 +++ linux-2.5/drivers/media/video/meye.c Thu Dec 13 16:32:36 2001 @@ -1460,7 +1460,7 @@ name: "meye", id_table: meye_pci_tbl, probe: meye_probe, - remove: meye_remove, + remove: __devexit_p(meye_remove), }; static int __init meye_init_module(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/planb.c linux-2.5/drivers/media/video/planb.c --- linux-2.5.1/drivers/media/video/planb.c Thu Oct 25 20:53:47 2001 +++ linux-2.5/drivers/media/video/planb.c Thu Jan 10 22:41:07 2002 @@ -90,11 +90,10 @@ static int planb_open(struct video_device *, int); static void planb_close(struct video_device *); static int planb_ioctl(struct video_device *, unsigned int, void *); -static int planb_init_done(struct video_device *); static int planb_mmap(struct video_device *, const char *, unsigned long); static void planb_irq(int, void *, struct pt_regs *); static void release_planb(void); -int init_planbs(struct video_init *); +static int init_planbs(void); /* ------------------ PlanB Internal Functions ------------------ */ static int planb_prepare_open(struct planb *); @@ -2079,7 +2078,6 @@ #endif pb->tab_size = PLANB_MAXLINES + 40; pb->suspend = 0; - pb->lock = 0; init_MUTEX(&pb->lock); pb->ch1_cmd = 0; pb->ch2_cmd = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/saa7185.c linux-2.5/drivers/media/video/saa7185.c --- linux-2.5.1/drivers/media/video/saa7185.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/media/video/saa7185.c Sun Dec 30 21:17:30 2001 @@ -36,7 +36,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/wrapper.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/stradis.c linux-2.5/drivers/media/video/stradis.c --- linux-2.5.1/drivers/media/video/stradis.c Thu Dec 6 22:07:57 2001 +++ linux-2.5/drivers/media/video/stradis.c Sun Dec 30 21:17:30 2001 @@ -37,7 +37,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <asm/types.h> #include <linux/types.h> #include <linux/wrapper.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/tvmixer.c linux-2.5/drivers/media/video/tvmixer.c --- linux-2.5.1/drivers/media/video/tvmixer.c Wed Oct 17 21:19:20 2001 +++ linux-2.5/drivers/media/video/tvmixer.c Wed Jan 2 01:30:12 2002 @@ -177,7 +177,7 @@ static int tvmixer_open(struct inode *inode, struct file *file) { - int i, minor = MINOR(inode->i_rdev); + int i, minor = minor(inode->i_rdev); struct TVMIXER *mix = NULL; struct i2c_client *client = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/videodev.c linux-2.5/drivers/media/video/videodev.c --- linux-2.5.1/drivers/media/video/videodev.c Thu Oct 11 16:14:32 2001 +++ linux-2.5/drivers/media/video/videodev.c Wed Jan 2 01:30:12 2002 @@ -70,7 +70,7 @@ static ssize_t video_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)]; if(vfl->read) return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK); else @@ -86,7 +86,7 @@ static ssize_t video_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)]; if(vfl->write) return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK); else @@ -100,7 +100,7 @@ static unsigned int video_poll(struct file *file, poll_table * wait) { - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)]; if(vfl->poll) return vfl->poll(vfl, file, wait); else @@ -114,7 +114,7 @@ static int video_open(struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); int err, retval = 0; struct video_device *vfl; @@ -170,7 +170,7 @@ { struct video_device *vfl; lock_kernel(); - vfl=video_device[MINOR(inode->i_rdev)]; + vfl=video_device[minor(inode->i_rdev)]; if(vfl->close) vfl->close(vfl); vfl->busy=0; @@ -183,7 +183,7 @@ static int video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct video_device *vfl=video_device[MINOR(inode->i_rdev)]; + struct video_device *vfl=video_device[minor(inode->i_rdev)]; int err=vfl->ioctl(vfl, cmd, (void *)arg); if(err!=-ENOIOCTLCMD) @@ -203,7 +203,7 @@ int video_mmap(struct file *file, struct vm_area_struct *vma) { int ret = -EINVAL; - struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)]; if(vfl->mmap) { lock_kernel(); ret = vfl->mmap(vfl, (char *)vma->vm_start, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/w9966.c linux-2.5/drivers/media/video/w9966.c --- linux-2.5.1/drivers/media/video/w9966.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/media/video/w9966.c Thu Dec 13 16:32:36 2001 @@ -1,9 +1,7 @@ /* Winbond w9966cf Webcam parport driver. - Version 0.32 - - Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se> + Copyright (C) 2001 Jakob Kemi <jakob.kemi@telia.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 @@ -21,33 +19,16 @@ */ /* Supported devices: - *Lifeview FlyCam Supra (using the Philips saa7111a chip) - - Does any other model using the w9966 interface chip exist ? + * Lifeview FlyCam Supra (using the Philips saa7111a chip) 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 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 + * Add a working EPP mode + * Support other ccd-control chips than the saa7111 + (what combinations exists?) + * Add proper probing. IEEE1284 probing of w9966 chips haven't + worked since parport drivers changed in 2.4.x. + * Probe for onboard SRAM, port directions etc. (if possible) - Please support me by sending feedback! - Changes: Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE @@ -59,6 +40,8 @@ #include <linux/delay.h> #include <linux/videodev.h> #include <linux/parport.h> +#include <linux/types.h> +#include <linux/slab.h> //#define DEBUG // Undef me for production @@ -99,43 +82,44 @@ #define W9966_I2C_W_CLOCK 0x01 struct w9966_dev { - unsigned char dev_state; - unsigned char i2c_state; - unsigned short ppmode; + u8 dev_state; + u8 i2c_state; + int ppmode; struct parport* pport; struct pardevice* pdev; struct video_device vdev; - unsigned short width; - unsigned short height; - unsigned char brightness; - signed char contrast; - signed char color; - signed char hue; + u16 width; + u16 height; + u8 brightness; + s8 contrast; + s8 color; + s8 hue; + u8* buffer; }; /* * Module specific properties */ -MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>"); -MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)"); +MODULE_AUTHOR("Jakob Kemi <jakob.kemi@telia.com>"); +MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (FlyCam Supra and others)"); MODULE_LICENSE("GPL"); -#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 const char* pardev[] = {[0 ... W9966_MAXCAMS] = "auto"}; +MODULE_PARM(pardev, "0-" __MODULE_STRING(W9966_MAXCAMS) "s"); +MODULE_PARM_DESC(pardev,"\n\ +<auto|name|none[,...]> Where to find cameras.\n\ + auto = probe all parports for camera\n\ + name = name of parport (eg parport0)\n\ + none = don't search for this camera\n\ +You can specify all cameras this way, for example: + pardev=parport2,auto,none,parport0 would search for cam1 on parport2, search\n\ + for cam2 on all parports, skip cam3 and search for cam4 on parport0"); static int parmode = 0; MODULE_PARM(parmode, "i"); -MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); +MODULE_PARM_DESC(parmode, "\n<0|1|2> transfer mode (0=auto, 1=ecp, 2=epp)"); static int video_nr = -1; MODULE_PARM(video_nr, "i"); @@ -277,17 +261,23 @@ 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 if (port->modes & PARPORT_MODE_EPP) + cam->ppmode = IEEE1284_MODE_EPP;*/ else - cam->ppmode = IEEE1284_MODE_ECP; + cam->ppmode = IEEE1284_MODE_ECPSWE; break; case 1: // hw- or sw-ecp - cam->ppmode = IEEE1284_MODE_ECP; + if (port->modes & PARPORT_MODE_ECP) + cam->ppmode = IEEE1284_MODE_ECP; + else + cam->ppmode = IEEE1284_MODE_ECPSWE; break; case 2: // hw- or sw-epp - cam->ppmode = IEEE1284_MODE_EPP; - break; + if (port->modes & PARPORT_MODE_EPP) + cam->ppmode = IEEE1284_MODE_EPP; + else + cam->ppmode = IEEE1284_MODE_EPPSWE; + break; } // Tell the parport driver that we exists @@ -325,6 +315,8 @@ w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); + cam->buffer = NULL; + // All ok printk( "w9966cf: Found and initialized a webcam on %s.\n", @@ -337,6 +329,12 @@ // Terminate everything gracefully static void w9966_term(struct w9966_dev* cam) { +// Delete allocated buffer if needed + if (cam->buffer != NULL) { + kfree(cam->buffer); + cam->buffer = NULL; + } + // Unregister from v4l if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { video_unregister_device(&cam->vdev); @@ -431,9 +429,9 @@ { unsigned int i; unsigned int enh_s, enh_e; - unsigned char scale_x, scale_y; - unsigned char regs[0x1c]; - unsigned char saa7111_regs[] = { + u8 scale_x, scale_y; + u8 regs[0x1c]; + u8 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, @@ -664,6 +662,7 @@ return data; } + // Write a register to the i2c device. // Expects claimed pdev. -1 on error static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data) @@ -693,11 +692,23 @@ static int w9966_v4l_open(struct video_device *vdev, int flags) { + struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; + cam->buffer = (u8*)kmalloc(W9966_RBUFFER, GFP_KERNEL); + + if (cam->buffer == NULL) + return -EFAULT; + return 0; } static void w9966_v4l_close(struct video_device *vdev) { + struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; + + if (cam->buffer != NULL) { + kfree(cam->buffer); + cam->buffer = NULL; + } } static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) @@ -920,13 +931,12 @@ 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) { + if (parport_read(cam->pport, cam->buffer, tsize) < tsize) { w9966_pdev_release(cam); return -EFAULT; } - if (copy_to_user(dest, tbuf, tsize) != 0) { + if (copy_to_user(dest, cam->buffer, tsize) != 0) { w9966_pdev_release(cam); return -EFAULT; } @@ -948,14 +958,14 @@ for (i = 0; i < W9966_MAXCAMS; i++) { + if (strcmp(pardev[i], "none") == 0) // Skip if 'none' + continue; 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 (strcmp(pardev[i], "auto") == 0 || + strcmp(pardev[i], port->name) == 0) { if (w9966_init(&w9966_cams[i], port) != 0) - w9966_term(&w9966_cams[i]); + w9966_term(&w9966_cams[i]); break; // return } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/zr36067.c linux-2.5/drivers/media/video/zr36067.c --- linux-2.5.1/drivers/media/video/zr36067.c Fri Nov 9 22:01:22 2001 +++ linux-2.5/drivers/media/video/zr36067.c Sun Dec 30 21:17:30 2001 @@ -58,7 +58,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/wrapper.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/media/video/zr36120.c linux-2.5/drivers/media/video/zr36120.c --- linux-2.5.1/drivers/media/video/zr36120.c Fri Nov 9 22:01:22 2001 +++ linux-2.5/drivers/media/video/zr36120.c Sun Dec 30 21:17:30 2001 @@ -35,7 +35,6 @@ #include <asm/page.h> #include <linux/sched.h> #include <linux/video_decoder.h> -#include <asm/segment.h> #include <linux/version.h> #include <asm/uaccess.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/message/fusion/mptscsih.c linux-2.5/drivers/message/fusion/mptscsih.c --- linux-2.5.1/drivers/message/fusion/mptscsih.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/message/fusion/mptscsih.c Sun Jan 6 19:17:50 2002 @@ -246,9 +246,9 @@ mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK); if (mf_chk != NULL) { sc->result = DID_ABORT << 16; - spin_lock_irqsave(&sc->host->host_lock, flags); + spin_lock_irqsave(sc->host->host_lock, flags); sc->scsi_done(sc); - spin_unlock_irqrestore(&sc->host->host_lock, flags); + spin_unlock_irqrestore(sc->host->host_lock, flags); return 1; } } @@ -426,9 +426,9 @@ scsi_to_pci_dma_dir(sc->sc_data_direction)); } - spin_lock_irqsave(&sc->host->host_lock, flags); + spin_lock_irqsave(sc->host->host_lock, flags); sc->scsi_done(sc); - spin_unlock_irqrestore(&sc->host->host_lock, flags); + spin_unlock_irqrestore(sc->host->host_lock, flags); } return 1; @@ -928,9 +928,9 @@ } SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz; SCpnt->result = 0; -/* spin_lock(&SCpnt->host->host_lock); */ +/* spin_lock(SCpnt->host->host_lock); */ SCpnt->scsi_done(SCpnt); -/* spin_unlock(&SCpnt->host->host_lock); */ +/* spin_unlock(SCpnt->host->host_lock); */ return 0; } } @@ -1333,9 +1333,9 @@ if (ctx2abort == -1) { printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#2) for SCpnt=%p\n", SCpnt); SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); } else { dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort)); @@ -1352,9 +1352,9 @@ ": WARNING[2] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", i, mf, SCpnt); SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); } } @@ -1428,9 +1428,9 @@ ": WARNING[3] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", i, mf, SCpnt); SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); } @@ -1502,9 +1502,9 @@ ": WARNING[4] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", i, mf, SCpnt); SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); } @@ -1748,9 +1748,9 @@ if (ctx2abort == -1) { printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#1) for SCpnt=%p\n", SCpnt); SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); continue; } @@ -1797,9 +1797,9 @@ != 0) { printk(KERN_WARNING MYNAM ": WARNING[1] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", i, mf, SCpnt); SCpnt->result = DID_SOFT_ERROR << 16; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); SCpnt->scsi_done(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); } else { /* Spin-Wait for TaskMgmt complete!!! */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/message/i2o/i2o_block.c linux-2.5/drivers/message/i2o/i2o_block.c --- linux-2.5.1/drivers/message/i2o/i2o_block.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/message/i2o/i2o_block.c Mon Jan 7 21:20:24 2002 @@ -114,7 +114,7 @@ #define I2O_BSA_DSC_VOLUME_CHANGED 0x000D #define I2O_BSA_DSC_TIMEOUT 0x000E -#define I2O_UNIT(dev) (i2ob_dev[MINOR((dev)) & 0xf0]) +#define I2O_UNIT(dev) (i2ob_dev[minor((dev)) & 0xf0]) #define I2O_LOCK(unit) (i2ob_dev[(unit)].req_queue->queue_lock) /* @@ -758,7 +758,7 @@ { u64 size; - if(do_i2ob_revalidate(MKDEV(MAJOR_NR, unit),0) != -EBUSY) + if(do_i2ob_revalidate(mk_kdev(MAJOR_NR, unit),0) != -EBUSY) continue; if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 ) @@ -867,7 +867,7 @@ if(i2ob_backlog[c->unit] == NULL) i2ob_backlog_tail[c->unit] = NULL; - unit = MINOR(ireq->req->rq_dev); + unit = minor(ireq->req->rq_dev); i2ob_send(m, dev, ireq, i2ob[unit].start_sect, unit); } if(i2ob_backlog[c->unit]) @@ -903,7 +903,7 @@ if(req->rq_status == RQ_INACTIVE) return; - unit = MINOR(req->rq_dev); + unit = minor(req->rq_dev); dev = &i2ob_dev[(unit&0xF0)]; /* @@ -1036,7 +1036,7 @@ static int do_i2ob_revalidate(kdev_t dev, int maxu) { - int minor=MINOR(dev); + int minor=minor(dev); int i; minor&=0xF0; @@ -1051,7 +1051,7 @@ for( i = 15; i>=0 ; i--) { int m = minor+i; - invalidate_device(MKDEV(MAJOR_NR, m), 1); + invalidate_device(mk_kdev(MAJOR_NR, m), 1); i2ob_gendisk.part[m].start_sect = 0; i2ob_gendisk.part[m].nr_sects = 0; } @@ -1077,14 +1077,14 @@ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; switch (cmd) { case HDIO_GETGEO: { struct hd_geometry g; - int u = MINOR(inode->i_rdev) & 0xF0; + int u = minor(inode->i_rdev) & 0xF0; i2o_block_biosparam(i2ob_sizes[u]<<1, &g.cylinders, &g.heads, &g.sectors); g.start = get_start_sect(inode->i_rdev); @@ -1121,7 +1121,7 @@ struct i2ob_device *dev; int minor; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); if (minor >= (MAX_I2OB<<4)) return -ENODEV; dev = &i2ob_dev[(minor&0xF0)]; @@ -1193,7 +1193,7 @@ if (!inode) return -EINVAL; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); if (minor >= MAX_I2OB<<4) return -ENODEV; dev=&i2ob_dev[(minor&0xF0)]; @@ -1384,7 +1384,7 @@ */ dev->req_queue = &i2ob_queues[c->unit]->req_queue; - grok_partitions(MKDEV(MAJOR_NR, unit), (long)(size>>9)); + grok_partitions(mk_kdev(MAJOR_NR, unit), (long)(size>>9)); /* * Register for the events we're interested in and that the @@ -1704,7 +1704,7 @@ */ static int i2ob_media_change(kdev_t dev) { - int i=MINOR(dev); + int i=minor(dev); i>>=4; if(i2ob_media_change_flag[i]) { @@ -1778,7 +1778,6 @@ major: MAJOR_NR, major_name: "i2o/hd", minor_shift: 4, - max_p: 1<<4, part: i2ob, sizes: i2ob_sizes, nr_real: MAX_I2OB, @@ -1884,7 +1883,7 @@ * 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, + register_disk(&i2ob_gendisk, mk_kdev(MAJOR_NR,i<<4), 1<<4, &i2ob_fops, 0); i2ob_probe(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/message/i2o/i2o_config.c linux-2.5/drivers/message/i2o/i2o_config.c --- linux-2.5.1/drivers/message/i2o/i2o_config.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/message/i2o/i2o_config.c Fri Dec 28 01:41:21 2001 @@ -45,7 +45,7 @@ static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; struct wait_queue *i2o_wait_queue; -#define MODINC(x,y) (x = x++ % y) +#define MODINC(x,y) ((x) = ((x) + 1) % (y)) struct i2o_cfg_info { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/message/i2o/i2o_core.c linux-2.5/drivers/message/i2o/i2o_core.c --- linux-2.5.1/drivers/message/i2o/i2o_core.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/message/i2o/i2o_core.c Mon Jan 14 22:39:45 2002 @@ -1184,7 +1184,8 @@ { struct i2o_handler *i; /* Map the message from the page frame map to kernel virtual */ - m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame); + /* m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame); */ + m=(struct i2o_message *)bus_to_virt(mv); msg=(u32*)m; /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/message/i2o/i2o_scsi.c linux-2.5/drivers/message/i2o/i2o_scsi.c --- linux-2.5.1/drivers/message/i2o/i2o_scsi.c Wed Nov 28 16:49:22 2001 +++ linux-2.5/drivers/message/i2o/i2o_scsi.c Sun Jan 6 19:17:50 2002 @@ -189,7 +189,7 @@ { /* Create a scsi error for this */ current_command = (Scsi_Cmnd *)m[3]; - lock = ¤t_command->host->host_lock; + lock = current_command->host->host_lock; printk("Aborted %ld\n", current_command->serial_number); spin_lock_irq(lock); @@ -284,22 +284,17 @@ * It worked maybe ? */ current_command->result = DID_OK << 16 | ds; - lock = ¤t_command->host->host_lock; + lock = current_command->host->host_lock; spin_lock(lock); current_command->scsi_done(current_command); spin_unlock(lock); return; } -struct i2o_handler i2o_scsi_handler= -{ - i2o_scsi_reply, - NULL, - NULL, - NULL, - "I2O SCSI OSM", - 0, - I2O_CLASS_SCSI_PERIPHERAL +struct i2o_handler i2o_scsi_handler = { + reply: i2o_scsi_reply, + name: "I2O SCSI OSM", + class: I2O_CLASS_SCSI_PERIPHERAL, }; static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/mtd/devices/blkmtd.c linux-2.5/drivers/mtd/devices/blkmtd.c --- linux-2.5.1/drivers/mtd/devices/blkmtd.c Fri Oct 5 19:06:51 2001 +++ linux-2.5/drivers/mtd/devices/blkmtd.c Mon Jan 7 21:24:09 2002 @@ -1,10 +1,11 @@ /* - * $Id: blkmtd.c,v 1.3 2001/10/02 15:33:20 dwmw2 Exp $ + * $Id: blkmtd.c,v 1.7 2001/11/10 17:06:30 spse Exp $ + * * blkmtd.c - use a block device as a fake MTD * * Author: Simon Evans <spse@secret.org.uk> * - * Copyright (C) 2001 Simon Evans <spse@secret.org.uk> + * Copyright (C) 2001 Simon Evans * * Licence: GPL * @@ -13,7 +14,7 @@ * cache to cache access. Writes update the page cache with the * new data but make a copy of the new page(s) and then a kernel * thread writes pages out to the device in the background. This - * ensures tht writes are order even if a page is updated twice. + * ensures that writes are order even if a page is updated twice. * Also, since pages in the page cache are never marked as dirty, * we dont have to worry about writepage() being called on some * random page which may not be in the write order. @@ -30,7 +31,7 @@ * small memory systems and too small on large memory systems. * * Page cache usage may still be a bit wrong. Check we are doing - * everything proberly. + * everything properly. * * Somehow allow writes to dirty the page cache so we dont use too * much memory making copies of outgoing pages. Need to handle case @@ -39,15 +40,9 @@ * * Reading should read multiple pages at once rather than using * readpage() for each one. This is easy and will be fixed asap. - * - * Dont run the write_thread if readonly. This is also easy and will - * be fixed asap. - * - * Even though the multiple erase regions are used if the default erase - * block size doesnt match the device properly, erases currently wont - * work on the last page if it is not a full page. */ + #include <linux/config.h> #include <linux/module.h> @@ -59,20 +54,30 @@ #include <linux/mtd/compatmac.h> #include <linux/mtd/mtd.h> +#ifdef CONFIG_MTD_DEBUG +#ifdef CONFIG_PROC_FS +# include <linux/proc_fs.h> +# define BLKMTD_PROC_DEBUG + static struct proc_dir_entry *blkmtd_proc; +#endif +#endif + + /* Default erase size in K, always make it a multiple of PAGE_SIZE */ #define CONFIG_MTD_BLKDEV_ERASESIZE 128 -#define VERSION "1.1" +#define VERSION "1.7" extern int *blk_size[]; -extern int *blksize_size[]; /* Info for the block device */ typedef struct mtd_raw_dev_data_s { struct block_device *binding; - int sector_size, sector_bits, total_sectors; + int sector_size, sector_bits; + int partial_last_page; // 0 if device ends on page boundary, else page no of last page + int last_page_sectors; // Number of sectors in last page if partial_last_page != 0 size_t totalsize; int readonly; struct address_space as; - struct file *file; + struct mtd_info mtd_info; } mtd_raw_dev_data_t; /* Info for each queue item in the write queue */ @@ -85,24 +90,28 @@ } mtdblkdev_write_queue_t; +/* Our erase page - always remains locked. */ +static struct page *erase_page; + /* Static info about the MTD, used in cleanup_module */ -static struct mtd_info *mtd_info; +static mtd_raw_dev_data_t *mtd_rawdevice; /* Write queue fixed size */ #define WRITE_QUEUE_SZ 512 /* Storage for the write queue */ -static mtdblkdev_write_queue_t write_queue[WRITE_QUEUE_SZ]; +static mtdblkdev_write_queue_t *write_queue; +static int write_queue_sz = WRITE_QUEUE_SZ; static int volatile write_queue_head; static int volatile write_queue_tail; static int volatile write_queue_cnt; static spinlock_t mbd_writeq_lock = SPIN_LOCK_UNLOCKED; /* Tell the write thread to finish */ -static volatile int write_task_finish = 0; +static volatile int write_task_finish; /* ipc with the write thread */ -#if LINUX_VERSION_CODE > 0x020300 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) static DECLARE_MUTEX_LOCKED(thread_sem); static DECLARE_WAIT_QUEUE_HEAD(thr_wq); static DECLARE_WAIT_QUEUE_HEAD(mtbd_sync_wq); @@ -113,13 +122,14 @@ #endif - /* Module parameters passed by insmod/modprobe */ char *device; /* the block device to use */ int erasesz; /* optional default erase size */ int ro; /* optional read only flag */ int bs; /* optionally force the block size (avoid using) */ int count; /* optionally force the block count (avoid using) */ +int wqs; /* optionally set the write queue size */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) MODULE_LICENSE("GPL"); @@ -135,10 +145,10 @@ MODULE_PARM_DESC(bs, "force the block size in bytes"); MODULE_PARM(count, "i"); MODULE_PARM_DESC(count, "force the block count"); +MODULE_PARM(wqs, "i"); #endif - /* Page cache stuff */ /* writepage() - should never be called - catch it anyway */ @@ -150,13 +160,13 @@ /* readpage() - reads one page from the block device */ -static int blkmtd_readpage(struct file *file, struct page *page) +static int blkmtd_readpage(mtd_raw_dev_data_t *rawdevice, struct page *page) { int err; int sectornr, sectors, i; struct kiobuf *iobuf; - mtd_raw_dev_data_t *rawdevice = (mtd_raw_dev_data_t *)file->private_data; kdev_t dev; + unsigned long *blocks; if(!rawdevice) { printk("blkmtd: readpage: PANIC file->private_data == NULL\n"); @@ -168,7 +178,7 @@ bdevname(dev), page, page->index); if(Page_Uptodate(page)) { - DEBUG(1, "blkmtd: readpage page %ld is already upto date\n", page->index); + DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index); UnlockPage(page); return 0; } @@ -184,8 +194,9 @@ mtdblkdev_write_queue_t *item = &write_queue[i]; if(page->index >= item->pagenr && page->index < item->pagenr+item->pagecnt) { /* yes it is */ - int index = item->pagenr - page->index; - DEBUG(1, "blkmtd: readpage: found page %ld in outgoing write queue\n", + int index = page->index - item->pagenr; + + DEBUG(2, "blkmtd: readpage: found page %ld in outgoing write queue\n", page->index); if(item->iserase) { memset(page_address(page), 0xff, PAGE_SIZE); @@ -199,7 +210,7 @@ return 0; } i++; - i %= WRITE_QUEUE_SZ; + i %= write_queue_sz; } } spin_unlock(&mbd_writeq_lock); @@ -208,8 +219,24 @@ DEBUG(3, "blkmtd: readpage: getting kiovec\n"); err = alloc_kiovec(1, &iobuf); if (err) { + printk("blkmtd: cant allocate kiobuf\n"); + SetPageError(page); return err; } + + /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) + blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long)); + if(blocks == NULL) { + printk("blkmtd: cant allocate iobuf blocks\n"); + free_kiovec(1, &iobuf); + SetPageError(page); + return -ENOMEM; + } +#else + blocks = iobuf->blocks; +#endif + iobuf->offset = 0; iobuf->nr_pages = 1; iobuf->length = PAGE_SIZE; @@ -217,16 +244,34 @@ iobuf->maplist[0] = page; sectornr = page->index << (PAGE_SHIFT - rawdevice->sector_bits); sectors = 1 << (PAGE_SHIFT - rawdevice->sector_bits); + if(rawdevice->partial_last_page && page->index == rawdevice->partial_last_page) { + DEBUG(3, "blkmtd: handling partial last page\n"); + sectors = rawdevice->last_page_sectors; + } DEBUG(3, "blkmtd: readpage: sectornr = %d sectors = %d\n", sectornr, sectors); for(i = 0; i < sectors; i++) { - iobuf->blocks[i] = sectornr++; + blocks[i] = sectornr++; + } + /* If only a partial page read in, clear the rest of the page */ + if(rawdevice->partial_last_page && page->index == rawdevice->partial_last_page) { + int offset = rawdevice->last_page_sectors << rawdevice->sector_bits; + int count = PAGE_SIZE-offset; + DEBUG(3, "blkmtd: clear last partial page: offset = %d count = %d\n", offset, count); + memset(page_address(page)+offset, 0, count); + sectors = rawdevice->last_page_sectors; } + DEBUG(3, "bklmtd: readpage: starting brw_kiovec\n"); - err = brw_kiovec(READ, 1, &iobuf, dev, iobuf->blocks, rawdevice->sector_size); + err = brw_kiovec(READ, 1, &iobuf, dev, blocks, rawdevice->sector_size); DEBUG(3, "blkmtd: readpage: finished, err = %d\n", err); iobuf->locked = 0; free_kiovec(1, &iobuf); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) + kfree(blocks); +#endif + if(err != PAGE_SIZE) { printk("blkmtd: readpage: error reading page %ld\n", page->index); memset(page_address(page), 0, PAGE_SIZE); @@ -246,7 +291,7 @@ static struct address_space_operations blkmtd_aops = { writepage: blkmtd_writepage, - readpage: blkmtd_readpage, + readpage: NULL, }; @@ -256,6 +301,7 @@ int err; struct task_struct *tsk = current; struct kiobuf *iobuf; + unsigned long *blocks; DECLARE_WAITQUEUE(wait, tsk); DEBUG(1, "blkmtd: writetask: starting (pid = %d)\n", tsk->pid); @@ -268,8 +314,23 @@ spin_unlock_irq(&tsk->sigmask_lock); exit_sighand(tsk); - if(alloc_kiovec(1, &iobuf)) + if(alloc_kiovec(1, &iobuf)) { + printk("blkmtd: write_queue_task cant allocate kiobuf\n"); return 0; + } + + /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) + blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long)); + if(blocks == NULL) { + printk("blkmtd: write_queue_task cant allocate iobuf blocks\n"); + free_kiovec(1, &iobuf); + return 0; + } +#else + blocks = iobuf->blocks; +#endif + DEBUG(2, "blkmtd: writetask: entering main loop\n"); add_wait_queue(&thr_wq, &wait); @@ -280,30 +341,39 @@ /* If nothing in the queue, wake up anyone wanting to know when there is space in the queue then sleep for 2*HZ */ spin_unlock(&mbd_writeq_lock); - DEBUG(3, "blkmtd: writetask: queue empty\n"); + DEBUG(4, "blkmtd: writetask: queue empty\n"); if(waitqueue_active(&mtbd_sync_wq)) wake_up(&mtbd_sync_wq); interruptible_sleep_on_timeout(&thr_wq, 2*HZ); - DEBUG(3, "blkmtd: writetask: woken up\n"); + DEBUG(4, "blkmtd: writetask: woken up\n"); if(write_task_finish) break; } else { /* we have stuff to write */ mtdblkdev_write_queue_t *item = &write_queue[write_queue_tail]; struct page **pages = item->pages; - int pagecnt = item->pagecnt; - int pagenr = item->pagenr; + int i; + int sectornr = item->pagenr << (PAGE_SHIFT - item->rawdevice->sector_bits); + int sectorcnt = item->pagecnt << (PAGE_SHIFT - item->rawdevice->sector_bits); int max_sectors = KIO_MAX_SECTORS >> (item->rawdevice->sector_bits - 9); kdev_t dev = to_kdev_t(item->rawdevice->binding->bd_dev); - + + /* If we are writing to the last page on the device and it doesnt end + * on a page boundary, subtract the number of sectors that dont exist. + */ + if(item->rawdevice->partial_last_page && + (item->pagenr + item->pagecnt -1) == item->rawdevice->partial_last_page) { + sectorcnt -= (1 << (PAGE_SHIFT - item->rawdevice->sector_bits)); + sectorcnt += item->rawdevice->last_page_sectors; + } DEBUG(3, "blkmtd: writetask: got %d queue items\n", write_queue_cnt); set_current_state(TASK_RUNNING); spin_unlock(&mbd_writeq_lock); - DEBUG(2, "blkmtd: write_task: writing pagenr = %d pagecnt = %d", - item->pagenr, item->pagecnt); + DEBUG(2, "blkmtd: writetask: writing pagenr = %d pagecnt = %d sectornr = %d sectorcnt = %d\n", + item->pagenr, item->pagecnt, sectornr, sectorcnt); iobuf->offset = 0; iobuf->locked = 1; @@ -311,31 +381,33 @@ /* Loop through all the pages to be written in the queue item, remembering we can only write KIO_MAX_SECTORS at a time */ - while(pagecnt) { - int sectornr = pagenr << (PAGE_SHIFT - item->rawdevice->sector_bits); - int sectorcnt = pagecnt << (PAGE_SHIFT - item->rawdevice->sector_bits); + while(sectorcnt) { int cursectors = (sectorcnt < max_sectors) ? sectorcnt : max_sectors; int cpagecnt = (cursectors << item->rawdevice->sector_bits) + PAGE_SIZE-1; cpagecnt >>= PAGE_SHIFT; - for(i = 0; i < cpagecnt; i++) + for(i = 0; i < cpagecnt; i++) { + if(item->iserase) { + iobuf->maplist[i] = erase_page; + } else { iobuf->maplist[i] = *(pages++); + } + } for(i = 0; i < cursectors; i++) { - iobuf->blocks[i] = sectornr++; + blocks[i] = sectornr++; } iobuf->nr_pages = cpagecnt; iobuf->length = cursectors << item->rawdevice->sector_bits; DEBUG(3, "blkmtd: write_task: about to kiovec\n"); - err = brw_kiovec(WRITE, 1, &iobuf, dev, iobuf->blocks, item->rawdevice->sector_size); + err = brw_kiovec(WRITE, 1, &iobuf, dev, blocks, item->rawdevice->sector_size); DEBUG(3, "bklmtd: write_task: done, err = %d\n", err); if(err != (cursectors << item->rawdevice->sector_bits)) { /* if an error occured - set this to exit the loop */ - pagecnt = 0; + sectorcnt = 0; } else { - pagenr += cpagecnt; - pagecnt -= cpagecnt; + sectorcnt -= cursectors; } } @@ -345,12 +417,14 @@ spin_lock(&mbd_writeq_lock); write_queue_cnt--; write_queue_tail++; - write_queue_tail %= WRITE_QUEUE_SZ; - for(i = 0 ; i < item->pagecnt; i++) { - UnlockPage(item->pages[i]); - __free_pages(item->pages[i], 0); + write_queue_tail %= write_queue_sz; + if(!item->iserase) { + for(i = 0 ; i < item->pagecnt; i++) { + UnlockPage(item->pages[i]); + __free_pages(item->pages[i], 0); + } + kfree(item->pages); } - kfree(item->pages); item->pages = NULL; spin_unlock(&mbd_writeq_lock); /* Tell others there is some space in the write queue */ @@ -361,6 +435,11 @@ remove_wait_queue(&thr_wq, &wait); DEBUG(1, "blkmtd: writetask: exiting\n"); free_kiovec(1, &iobuf); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) + kfree(blocks); +#endif + /* Tell people we have exitd */ up(&thread_sem); return 0; @@ -372,43 +451,45 @@ int pagenr, int pagecnt, int iserase) { struct page *outpage; - struct page **new_pages; + struct page **new_pages = NULL; mtdblkdev_write_queue_t *item; int i; DECLARE_WAITQUEUE(wait, current); - DEBUG(2, "mtdblkdev: queue_page_write: adding pagenr = %d pagecnt = %d\n", pagenr, pagecnt); + DEBUG(2, "blkmtd: queue_page_write: adding pagenr = %d pagecnt = %d\n", pagenr, pagecnt); if(!pagecnt) return 0; - if(pages == NULL) + if(pages == NULL && !iserase) return -EINVAL; /* create a array for the list of pages */ - new_pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL); - if(new_pages == NULL) - return -ENOMEM; + if(!iserase) { + new_pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL); + if(new_pages == NULL) + return -ENOMEM; - /* make copies of the pages in the page cache */ - for(i = 0; i < pagecnt; i++) { - outpage = alloc_pages(GFP_KERNEL, 0); - if(!outpage) { - while(i--) { - UnlockPage(new_pages[i]); - __free_pages(new_pages[i], 0); + /* make copies of the pages in the page cache */ + for(i = 0; i < pagecnt; i++) { + outpage = alloc_pages(GFP_KERNEL, 0); + if(!outpage) { + while(i--) { + UnlockPage(new_pages[i]); + __free_pages(new_pages[i], 0); + } + kfree(new_pages); + return -ENOMEM; } - kfree(new_pages); - return -ENOMEM; + lock_page(outpage); + memcpy(page_address(outpage), page_address(pages[i]), PAGE_SIZE); + new_pages[i] = outpage; } - lock_page(outpage); - memcpy(page_address(outpage), page_address(pages[i]), PAGE_SIZE); - new_pages[i] = outpage; } /* wait until there is some space in the write queue */ test_lock: spin_lock(&mbd_writeq_lock); - if(write_queue_cnt == WRITE_QUEUE_SZ) { + if(write_queue_cnt == write_queue_sz) { spin_unlock(&mbd_writeq_lock); DEBUG(3, "blkmtd: queue_page: Queue full\n"); current->state = TASK_UNINTERRUPTIBLE; @@ -417,11 +498,11 @@ schedule(); current->state = TASK_RUNNING; remove_wait_queue(&mtbd_sync_wq, &wait); - DEBUG(3, "blkmtd: queue_page: Queue has %d items in it\n", write_queue_cnt); + DEBUG(3, "blkmtd: queue_page_write: Queue has %d items in it\n", write_queue_cnt); goto test_lock; } - DEBUG(3, "blkmtd: queue_write_page: qhead: %d qtail: %d qcnt: %d\n", + DEBUG(3, "blkmtd: queue_page_write: qhead: %d qtail: %d qcnt: %d\n", write_queue_head, write_queue_tail, write_queue_cnt); /* fix up the queue item */ @@ -433,9 +514,9 @@ item->iserase = iserase; write_queue_head++; - write_queue_head %= WRITE_QUEUE_SZ; + write_queue_head %= write_queue_sz; write_queue_cnt++; - DEBUG(3, "blkmtd: queue_write_page: qhead: %d qtail: %d qcnt: %d\n", + DEBUG(3, "blkmtd: queue_page_write: qhead: %d qtail: %d qcnt: %d\n", write_queue_head, write_queue_tail, write_queue_cnt); spin_unlock(&mbd_writeq_lock); DEBUG(2, "blkmtd: queue_page_write: finished\n"); @@ -447,6 +528,8 @@ static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr) { mtd_raw_dev_data_t *rawdevice = mtd->priv; + struct mtd_erase_region_info *einfo = mtd->eraseregions; + int numregions = mtd->numeraseregions; size_t from; u_long len; int err = 0; @@ -462,17 +545,23 @@ from = instr->addr; len = instr->len; - /* check page alignment of start and length */ - DEBUG(2, "blkmtd: erase: dev = `%s' from = %d len = %ld\n", + /* check erase region has valid start and length */ + DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n", bdevname(rawdevice->binding->bd_dev), from, len); - if(from % PAGE_SIZE) { - printk("blkmtd: erase: addr not page aligned (addr = %d)\n", from); - instr->state = MTD_ERASE_FAILED; - err = -EIO; + while(numregions) { + DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n", + einfo->offset, einfo->erasesize, einfo->numblocks); + if(from >= einfo->offset && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) { + if(len == einfo->erasesize && ( (from - einfo->offset) % einfo->erasesize == 0)) + break; + } + numregions--; + einfo++; } - if(len % PAGE_SIZE) { - printk("blkmtd: erase: len not a whole number of pages (len = %ld)\n", len); + if(!numregions) { + /* Not a valid erase block */ + printk("blkmtd: erase: invalid erase request 0x%lX @ 0x%08X\n", len, from); instr->state = MTD_ERASE_FAILED; err = -EIO; } @@ -483,9 +572,14 @@ struct page *page, **pages; int i = 0; + /* Handle the last page of the device not being whole */ + if(len < PAGE_SIZE) + len = PAGE_SIZE; + pagenr = from >> PAGE_SHIFT; pagecnt = len >> PAGE_SHIFT; DEBUG(3, "blkmtd: erase: pagenr = %d pagecnt = %d\n", pagenr, pagecnt); + pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL); if(pages == NULL) { err = -ENOMEM; @@ -493,9 +587,10 @@ goto erase_out; } + while(pagecnt) { /* get the page via the page cache */ - DEBUG(3, "blkmtd: erase: doing grap_cache_page() for page %d\n", pagenr); + DEBUG(3, "blkmtd: erase: doing grab_cache_page() for page %d\n", pagenr); page = grab_cache_page(&rawdevice->as, pagenr); if(!page) { DEBUG(3, "blkmtd: erase: grab_cache_page() failed for page %d\n", pagenr); @@ -511,7 +606,7 @@ i++; } DEBUG(3, "blkmtd: erase: queuing page write\n"); - err = queue_page_write(rawdevice, pages, from >> PAGE_SHIFT, len >> PAGE_SHIFT, 1); + err = queue_page_write(rawdevice, NULL, from >> PAGE_SHIFT, len >> PAGE_SHIFT, 1); pagecnt = len >> PAGE_SHIFT; if(!err) { while(pagecnt--) { @@ -567,7 +662,7 @@ struct page *page; int cpylen; DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr); - page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice->file); + page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice); if(IS_ERR(page)) { return PTR_ERR(page); } @@ -683,7 +778,7 @@ struct page *page; DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n", pagenr, len1, offset); - page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice->file); + page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice); if(IS_ERR(page)) { kfree(pages); @@ -716,6 +811,7 @@ memcpy(page_address(page), buf, PAGE_SIZE); pages[pagecnt++] = page; UnlockPage(page); + SetPageUptodate(page); pagenr++; pagesc--; buf += PAGE_SIZE; @@ -728,7 +824,7 @@ /* do the third region */ struct page *page; DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n", pagenr, len3); - page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice->file); + page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice); if(IS_ERR(page)) { err = PTR_ERR(page); goto write_err; @@ -766,6 +862,10 @@ static void blkmtd_sync(struct mtd_info *mtd) { DECLARE_WAITQUEUE(wait, current); + mtd_raw_dev_data_t *rawdevice = mtd->priv; + if(rawdevice->readonly) + return; + DEBUG(2, "blkmtd: sync: called\n"); stuff_inq: @@ -784,36 +884,144 @@ } spin_unlock(&mbd_writeq_lock); - DEBUG(2, "blkmtdL sync: finished\n"); + DEBUG(2, "blkmtd: sync: finished\n"); } + +#ifdef BLKMTD_PROC_DEBUG +/* procfs stuff */ +static int blkmtd_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int clean = 0, dirty = 0, locked = 0; + struct list_head *temp; + int i, len, pages = 0, cnt; + MOD_INC_USE_COUNT; + spin_lock(&mbd_writeq_lock); + cnt = write_queue_cnt; + i = write_queue_tail; + while(cnt) { + if(!write_queue[i].iserase) + pages += write_queue[i].pagecnt; + i++; + i %= write_queue_sz; + cnt--; + } + + /* Count the size of the page lists */ + list_for_each(temp, &mtd_rawdevice->as.clean_pages) { + clean++; + } + list_for_each(temp, &mtd_rawdevice->as.dirty_pages) { + dirty++; + } + list_for_each(temp, &mtd_rawdevice->as.locked_pages) { + locked++; + } + + len = sprintf(page, "Write queue head: %d\nWrite queue tail: %d\n" + "Write queue count: %d\nPages in queue: %d (%dK)\n" + "Clean Pages: %d\nDirty Pages: %d\nLocked Pages: %d\n" + "nrpages: %ld\n", + write_queue_head, write_queue_tail, write_queue_cnt, + pages, pages << (PAGE_SHIFT-10), clean, dirty, locked, + mtd_rawdevice->as.nrpages); + if(len <= count) + *eof = 1; + spin_unlock(&mbd_writeq_lock); + MOD_DEC_USE_COUNT; + return len; +} +#endif + + /* Cleanup and exit - sync the device and kill of the kernel thread */ static void __exit cleanup_blkmtd(void) { - if (mtd_info) { - mtd_raw_dev_data_t *rawdevice = mtd_info->priv; - // sync the device - if (rawdevice) { - blkmtd_sync(mtd_info); +#ifdef BLKMTD_PROC_DEBUG + if(blkmtd_proc) { + remove_proc_entry("blkmtd_debug", NULL); + } +#endif + + if (mtd_rawdevice) { + /* sync the device */ + if (!mtd_rawdevice->readonly) { + blkmtd_sync(&mtd_rawdevice->mtd_info); write_task_finish = 1; wake_up_interruptible(&thr_wq); down(&thread_sem); - if(rawdevice->binding != NULL) - blkdev_put(rawdevice->binding, BDEV_RAW); - filp_close(rawdevice->file, NULL); - kfree(mtd_info->priv); } - if(mtd_info->eraseregions) - kfree(mtd_info->eraseregions); - del_mtd_device(mtd_info); - kfree(mtd_info); - mtd_info = NULL; + del_mtd_device(&mtd_rawdevice->mtd_info); + if(mtd_rawdevice->binding != NULL) + blkdev_put(mtd_rawdevice->binding, BDEV_RAW); + + if(mtd_rawdevice->mtd_info.eraseregions) + kfree(mtd_rawdevice->mtd_info.eraseregions); + if(mtd_rawdevice->mtd_info.name) + kfree(mtd_rawdevice->mtd_info.name); + + kfree(mtd_rawdevice); + } + if(write_queue) + kfree(write_queue); + + if(erase_page) { + UnlockPage(erase_page); + __free_pages(erase_page, 0); } printk("blkmtd: unloaded for %s\n", device); } extern struct module __this_module; +#ifndef MODULE + +/* Handle kernel boot params */ + + +static int __init param_blkmtd_device(char *str) +{ + device = str; + return 1; +} + + +static int __init param_blkmtd_erasesz(char *str) +{ + erasesz = simple_strtol(str, NULL, 0); + return 1; +} + + +static int __init param_blkmtd_ro(char *str) +{ + ro = simple_strtol(str, NULL, 0); + return 1; +} + + +static int __init param_blkmtd_bs(char *str) +{ + bs = simple_strtol(str, NULL, 0); + return 1; +} + + +static int __init param_blkmtd_count(char *str) +{ + count = simple_strtol(str, NULL, 0); + return 1; +} + +__setup("blkmtd_device=", param_blkmtd_device); +__setup("blkmtd_erasesz=", param_blkmtd_erasesz); +__setup("blkmtd_ro=", param_blkmtd_ro); +__setup("blkmtd_bs=", param_blkmtd_bs); +__setup("blkmtd_count=", param_blkmtd_count); + +#endif + + /* for a given size and initial erase size, calculate the number and size of each erase region */ static int __init calc_erase_regions(struct mtd_erase_region_info *info, size_t erase_size, size_t total_size) @@ -842,12 +1050,16 @@ } +extern kdev_t name_to_kdev_t(char *line) __init; + /* Startup */ static int __init init_blkmtd(void) { +#ifdef MODULE struct file *file = NULL; struct inode *inode; - mtd_raw_dev_data_t *rawdevice = NULL; +#endif + int maj, min; int i, blocksize, blocksize_bits; loff_t size = 0; @@ -856,15 +1068,12 @@ kdev_t rdev; int err; int mode; - int totalsize = 0, total_sectors = 0; int regions; - mtd_info = NULL; - - // Check args + /* Check args */ if(device == 0) { printk("blkmtd: error, missing `device' name\n"); - return 1; + return -EINVAL; } if(ro) @@ -873,12 +1082,25 @@ if(erasesz) erase_size = erasesz; - DEBUG(1, "blkmtd: got device = `%s' erase size = %dK readonly = %s\n", device, erase_size, readonly ? "yes" : "no"); - // Get a handle on the device + if(wqs) { + if(wqs < 16) + wqs = 16; + if(wqs > 4*WRITE_QUEUE_SZ) + wqs = 4*WRITE_QUEUE_SZ; + write_queue_sz = wqs; + } + + DEBUG(1, "blkmtd: device = `%s' erase size = %dK readonly = %s queue size = %d\n", + device, erase_size, readonly ? "yes" : "no", write_queue_sz); + /* Get a handle on the device */ mode = (readonly) ? O_RDONLY : O_RDWR; + +#ifdef MODULE + file = filp_open(device, mode, 0); if(IS_ERR(file)) { - DEBUG(2, "blkmtd: open_namei returned %ld\n", PTR_ERR(file)); + printk("blkmtd: error, cant open device %s\n", device); + DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file)); return 1; } @@ -891,11 +1113,19 @@ return 1; } rdev = inode->i_rdev; - //filp_close(file, NULL); - DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n", - MAJOR(rdev), MINOR(rdev)); - maj = MAJOR(rdev); - min = MINOR(rdev); + filp_close(file, NULL); +#else + rdev = name_to_kdev_t(device); +#endif + + maj = major(rdev); + min = minor(rdev); + DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n", maj, min); + + if(kdev_none(rdev)) { + printk("blkmtd: bad block device: `%s'\n", device); + return 1; + } if(maj == MTD_BLOCK_MAJOR) { printk("blkmtd: attempting to use an MTD device as a block device\n"); @@ -905,14 +1135,7 @@ DEBUG(1, "blkmtd: devname = %s\n", bdevname(rdev)); blocksize = BLOCK_SIZE; - if(bs) { - blocksize = bs; - } else { - if (blksize_size[maj] && blksize_size[maj][min]) { - DEBUG(2, "blkmtd: blksize_size = %d\n", blksize_size[maj][min]); - blocksize = blksize_size[maj][min]; - } - } + blocksize = bs ? bs : block_size(rdev); i = blocksize; blocksize_bits = 0; while(i != 1) { @@ -927,116 +1150,159 @@ size = ((loff_t) blk_size[maj][min] << BLOCK_SIZE_BITS) >> blocksize_bits; } } - total_sectors = size; size *= blocksize; - totalsize = size; DEBUG(1, "blkmtd: size = %ld\n", (long int)size); if(size == 0) { printk("blkmtd: cant determine size\n"); return 1; } - rawdevice = (mtd_raw_dev_data_t *)kmalloc(sizeof(mtd_raw_dev_data_t), GFP_KERNEL); - if(rawdevice == NULL) { + + mtd_rawdevice = (mtd_raw_dev_data_t *)kmalloc(sizeof(mtd_raw_dev_data_t), GFP_KERNEL); + if(mtd_rawdevice == NULL) { err = -ENOMEM; goto init_err; } - memset(rawdevice, 0, sizeof(mtd_raw_dev_data_t)); - // get the block device - rawdevice->binding = bdget(kdev_t_to_nr(MKDEV(maj, min))); - err = blkdev_get(rawdevice->binding, mode, 0, BDEV_RAW); + memset(mtd_rawdevice, 0, sizeof(mtd_raw_dev_data_t)); + /* get the block device */ + mtd_rawdevice->binding = bdget(kdev_t_to_nr(mk_kdev(maj, min))); + err = blkdev_get(mtd_rawdevice->binding, mode, 0, BDEV_RAW); if (err) { goto init_err; } - rawdevice->totalsize = totalsize; - rawdevice->total_sectors = total_sectors; - rawdevice->sector_size = blocksize; - rawdevice->sector_bits = blocksize_bits; - rawdevice->readonly = readonly; - - DEBUG(2, "sector_size = %d, sector_bits = %d\n", rawdevice->sector_size, rawdevice->sector_bits); - - mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL); - if (mtd_info == NULL) { - err = -ENOMEM; + mtd_rawdevice->totalsize = size; + mtd_rawdevice->sector_size = blocksize; + mtd_rawdevice->sector_bits = blocksize_bits; + mtd_rawdevice->readonly = readonly; + + /* See if device ends on page boundary */ + if(size % PAGE_SIZE) { + mtd_rawdevice->partial_last_page = size >> PAGE_SHIFT; + mtd_rawdevice->last_page_sectors = (size & (PAGE_SIZE-1)) >> blocksize_bits; + } + + DEBUG(2, "sector_size = %d, sector_bits = %d, partial_last_page = %d last_page_sectors = %d\n", + mtd_rawdevice->sector_size, mtd_rawdevice->sector_bits, + mtd_rawdevice->partial_last_page, mtd_rawdevice->last_page_sectors); + + /* Setup the MTD structure */ + /* make the name contain the block device in */ + mtd_rawdevice->mtd_info.name = kmalloc(9 + strlen(device), GFP_KERNEL); + if(mtd_rawdevice->mtd_info.name == NULL) goto init_err; - } - memset(mtd_info, 0, sizeof(*mtd_info)); - // Setup the MTD structure - mtd_info->name = "blkmtd block device"; + sprintf(mtd_rawdevice->mtd_info.name, "blkmtd: %s", device); if(readonly) { - mtd_info->type = MTD_ROM; - mtd_info->flags = MTD_CAP_ROM; - mtd_info->erasesize = erase_size << 10; + mtd_rawdevice->mtd_info.type = MTD_ROM; + mtd_rawdevice->mtd_info.flags = MTD_CAP_ROM; + mtd_rawdevice->mtd_info.erasesize = erase_size << 10; } else { - mtd_info->type = MTD_RAM; - mtd_info->flags = MTD_CAP_RAM; - mtd_info->erasesize = erase_size << 10; - } - mtd_info->size = size; - mtd_info->erase = blkmtd_erase; - mtd_info->read = blkmtd_read; - mtd_info->write = blkmtd_write; - mtd_info->sync = blkmtd_sync; - mtd_info->point = 0; - mtd_info->unpoint = 0; + mtd_rawdevice->mtd_info.type = MTD_RAM; + mtd_rawdevice->mtd_info.flags = MTD_CAP_RAM; + mtd_rawdevice->mtd_info.erasesize = erase_size << 10; + } + mtd_rawdevice->mtd_info.size = size; + mtd_rawdevice->mtd_info.erase = blkmtd_erase; + mtd_rawdevice->mtd_info.read = blkmtd_read; + mtd_rawdevice->mtd_info.write = blkmtd_write; + mtd_rawdevice->mtd_info.sync = blkmtd_sync; + mtd_rawdevice->mtd_info.point = 0; + mtd_rawdevice->mtd_info.unpoint = 0; - mtd_info->priv = rawdevice; + mtd_rawdevice->mtd_info.priv = mtd_rawdevice; regions = calc_erase_regions(NULL, erase_size << 10, size); DEBUG(1, "blkmtd: init: found %d erase regions\n", regions); - mtd_info->eraseregions = kmalloc(regions * sizeof(struct mtd_erase_region_info), GFP_KERNEL); - if(mtd_info->eraseregions == NULL) { + mtd_rawdevice->mtd_info.eraseregions = kmalloc(regions * sizeof(struct mtd_erase_region_info), GFP_KERNEL); + if(mtd_rawdevice->mtd_info.eraseregions == NULL) { + err = -ENOMEM; + goto init_err; } - mtd_info->numeraseregions = regions; - calc_erase_regions(mtd_info->eraseregions, erase_size << 10, size); + mtd_rawdevice->mtd_info.numeraseregions = regions; + calc_erase_regions(mtd_rawdevice->mtd_info.eraseregions, erase_size << 10, size); /* setup the page cache info */ - INIT_LIST_HEAD(&rawdevice->as.clean_pages); - INIT_LIST_HEAD(&rawdevice->as.dirty_pages); - INIT_LIST_HEAD(&rawdevice->as.locked_pages); - rawdevice->as.nrpages = 0; - rawdevice->as.a_ops = &blkmtd_aops; - rawdevice->as.host = inode; - rawdevice->as.i_mmap = NULL; - rawdevice->as.i_mmap_shared = NULL; - spin_lock_init(&rawdevice->as.i_shared_lock); - rawdevice->as.gfp_mask = GFP_KERNEL; - rawdevice->file = file; - - file->private_data = rawdevice; + + mtd_rawdevice->as.nrpages = 0; + INIT_LIST_HEAD(&mtd_rawdevice->as.clean_pages); + INIT_LIST_HEAD(&mtd_rawdevice->as.dirty_pages); + INIT_LIST_HEAD(&mtd_rawdevice->as.locked_pages); + mtd_rawdevice->as.host = NULL; + spin_lock_init(&(mtd_rawdevice->as.i_shared_lock)); + + mtd_rawdevice->as.a_ops = &blkmtd_aops; + mtd_rawdevice->as.i_mmap = NULL; + mtd_rawdevice->as.i_mmap_shared = NULL; + mtd_rawdevice->as.gfp_mask = GFP_KERNEL; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - mtd_info->module = THIS_MODULE; + mtd_rawdevice->mtd_info.module = THIS_MODULE; #endif - if (add_mtd_device(mtd_info)) { - err = -EIO; - goto init_err; - } - init_waitqueue_head(&thr_wq); - init_waitqueue_head(&mtbd_sync_wq); - DEBUG(3, "blkmtd: init: kernel task @ %p\n", write_queue_task); - DEBUG(2, "blkmtd: init: starting kernel task\n"); - kernel_thread(write_queue_task, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - DEBUG(2, "blkmtd: init: started\n"); - printk("blkmtd loaded: version = %s using %s erase_size = %dK %s\n", VERSION, device, erase_size, (readonly) ? "(read-only)" : ""); - return 0; + if (add_mtd_device(&mtd_rawdevice->mtd_info)) { + err = -EIO; + goto init_err; + } + if(!mtd_rawdevice->readonly) { + /* Allocate the write queue */ + write_queue = kmalloc(write_queue_sz * sizeof(mtdblkdev_write_queue_t), GFP_KERNEL); + if(!write_queue) { + err = -ENOMEM; + goto init_err; + } + /* Set up the erase page */ + erase_page = alloc_pages(GFP_KERNEL, 0); + if(erase_page == NULL) { + err = -ENOMEM; + goto init_err; + } + memset(page_address(erase_page), 0xff, PAGE_SIZE); + lock_page(erase_page); + + init_waitqueue_head(&thr_wq); + init_waitqueue_head(&mtbd_sync_wq); + DEBUG(3, "blkmtd: init: kernel task @ %p\n", write_queue_task); + DEBUG(2, "blkmtd: init: starting kernel task\n"); + kernel_thread(write_queue_task, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + DEBUG(2, "blkmtd: init: started\n"); + printk("blkmtd loaded: version = %s using %s erase_size = %dK %s\n", + VERSION, device, erase_size, (readonly) ? "(read-only)" : ""); + } + +#ifdef BLKMTD_PROC_DEBUG + /* create proc entry */ + DEBUG(2, "Creating /proc/blkmtd_debug\n"); + blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444, + NULL, blkmtd_proc_read, NULL); + if(blkmtd_proc == NULL) { + printk("Cant create /proc/blkmtd_debug\n"); + } else { + blkmtd_proc->owner = THIS_MODULE; + } +#endif + + /* Everything is ok if we got here */ + return 0; + init_err: - if(!rawdevice) { - if(rawdevice->binding) - blkdev_put(rawdevice->binding, BDEV_RAW); - kfree(rawdevice); - rawdevice = NULL; - } - if(mtd_info) { - if(mtd_info->eraseregions) - kfree(mtd_info->eraseregions); - kfree(mtd_info); - mtd_info = NULL; - } - return err; + if(mtd_rawdevice) { + if(mtd_rawdevice->mtd_info.eraseregions) + kfree(mtd_rawdevice->mtd_info.eraseregions); + if(mtd_rawdevice->mtd_info.name) + kfree(mtd_rawdevice->mtd_info.name); + if(mtd_rawdevice->binding) + blkdev_put(mtd_rawdevice->binding, BDEV_RAW); + kfree(mtd_rawdevice); + } + + if(write_queue) { + kfree(write_queue); + write_queue = NULL; + } + + if(erase_page) + __free_pages(erase_page, 0); + return err; } module_init(init_blkmtd); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/mtd/devices/doc1000.c linux-2.5/drivers/mtd/devices/doc1000.c --- linux-2.5.1/drivers/mtd/devices/doc1000.c Thu Oct 4 22:14:59 2001 +++ linux-2.5/drivers/mtd/devices/doc1000.c Sun Dec 30 21:17:30 2001 @@ -20,7 +20,6 @@ #include <linux/ioctl.h> #include <asm/io.h> #include <asm/system.h> -#include <asm/segment.h> #include <stdarg.h> #include <linux/delay.h> #include <linux/init.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/mtd/devices/pmc551.c linux-2.5/drivers/mtd/devices/pmc551.c --- linux-2.5.1/drivers/mtd/devices/pmc551.c Thu Oct 4 22:14:59 2001 +++ linux-2.5/drivers/mtd/devices/pmc551.c Sun Dec 30 21:17:30 2001 @@ -98,7 +98,6 @@ #include <linux/ioctl.h> #include <asm/io.h> #include <asm/system.h> -#include <asm/segment.h> #include <stdarg.h> #include <linux/pci.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/mtd/devices/slram.c linux-2.5/drivers/mtd/devices/slram.c --- linux-2.5.1/drivers/mtd/devices/slram.c Thu Oct 4 22:14:59 2001 +++ linux-2.5/drivers/mtd/devices/slram.c Sun Dec 30 21:17:30 2001 @@ -20,7 +20,6 @@ #include <linux/init.h> #include <asm/io.h> #include <asm/system.h> -#include <asm/segment.h> #include <stdarg.h> #include <linux/mtd/mtd.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/mtd/ftl.c linux-2.5/drivers/mtd/ftl.c --- linux-2.5.1/drivers/mtd/ftl.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/mtd/ftl.c Tue Jan 1 23:42:42 2002 @@ -72,33 +72,12 @@ #include <linux/hdreg.h> #include <stdarg.h> -#if (LINUX_VERSION_CODE >= 0x20100) #include <linux/vmalloc.h> -#endif -#if (LINUX_VERSION_CODE >= 0x20303) #include <linux/blkpg.h> -#endif #include <linux/mtd/ftl.h> -/*====================================================================*/ -/* Stuff which really ought to be in compatmac.h */ - -#if (LINUX_VERSION_CODE < 0x20328) -#define register_disk(dev, drive, minors, ops, size) \ - do { (dev)->part[(drive)*(minors)].nr_sects = size; \ - if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \ - resetup_one_dev(dev, drive); } while (0); -#endif -#if (LINUX_VERSION_CODE < 0x20320) -#define BLK_DEFAULT_QUEUE(n) blk_dev[n].request_fn -#define blk_init_queue(q, req) q = (req) -#define blk_cleanup_queue(q) q = NULL -#define request_arg_t void -#else #define request_arg_t request_queue_t *q -#endif - /*====================================================================*/ @@ -206,10 +185,6 @@ major: FTL_MAJOR, major_name: "ftl", minor_shift: PART_BITS, - max_p: MAX_PART, -#if (LINUX_VERSION_CODE < 0x20328) - max_nr: MAX_DEV*MAX_PART, -#endif part: ftl_hd, sizes: ftl_sizes, }; @@ -224,23 +199,12 @@ static void ftl_erase_callback(struct erase_info *done); -#if LINUX_VERSION_CODE < 0x20326 -static struct file_operations ftl_blk_fops = { - open: ftl_open, - release: ftl_close, - ioctl: ftl_ioctl, - read: block_read, - write: block_write, - fsync: block_fsync -}; -#else static struct block_device_operations ftl_blk_fops = { owner: THIS_MODULE, open: ftl_open, release: ftl_close, ioctl: ftl_ioctl, }; -#endif /*====================================================================== @@ -1177,22 +1141,11 @@ case BLKRRPART: ret = ftl_reread_partitions(minor); break; -#if (LINUX_VERSION_CODE < 0x20303) - case BLKFLSBUF: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if (!capable(CAP_SYS_ADMIN)) return -EACCES; -#endif - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - break; - RO_IOCTLS(inode->i_rdev, arg); -#else case BLKROSET: case BLKROGET: case BLKFLSBUF: ret = blk_ioctl(inode->i_rdev, cmd, arg); break; -#endif default: ret = -EINVAL; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/mtd/nftlcore.c linux-2.5/drivers/mtd/nftlcore.c --- linux-2.5.1/drivers/mtd/nftlcore.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/mtd/nftlcore.c Tue Jan 1 23:42:42 2002 @@ -62,14 +62,9 @@ static struct gendisk nftl_gendisk = { major: MAJOR_NR, major_name: "nftl", - minor_shift: NFTL_PARTN_BITS, /* Bits to shift to get real from partition */ - max_p: (1<<NFTL_PARTN_BITS)-1, /* Number of partitions per real */ -#if LINUX_VERSION_CODE < 0x20328 - max_nr: MAX_NFTLS, /* maximum number of real */ - init: dummy_init, /* init function */ -#endif - part: part_table, /* hd struct */ - sizes: nftl_sizes, /* block sizes */ + minor_shift: NFTL_PARTN_BITS, /* # of partition bits */ + part: part_table, /* hd struct */ + sizes: nftl_sizes, /* block sizes */ }; struct NFTLrecord *NFTLs[MAX_NFTLS]; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/mtd/nftlmount.c linux-2.5/drivers/mtd/nftlmount.c --- linux-2.5.1/drivers/mtd/nftlmount.c Thu Oct 4 22:13:18 2001 +++ linux-2.5/drivers/mtd/nftlmount.c Thu Dec 20 19:14:29 2001 @@ -4,7 +4,7 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: nftlmount.c,v 1.23 2001/09/19 21:42:32 dwmw2 Exp $ + * $Id: nftlmount.c,v 1.25 2001/11/30 16:46:27 dwmw2 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 @@ -39,7 +39,7 @@ #define SECTORSIZE 512 -char nftlmountrev[]="$Revision: 1.23 $"; +char nftlmountrev[]="$Revision: 1.25 $"; /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the * various device information of the NFTL partition and Bad Unit Table. Update @@ -94,11 +94,11 @@ continue; } -#if 1 /* Some people seem to have devices without ECC or erase marks +#if 0 /* Some people seem to have devices without ECC or erase marks on the Media Header blocks. There are enough other sanity checks in here that we can probably do without it. */ - if (le16_to_cpu ((h1.EraseMark | h1.EraseMark1) != ERASE_MARK)) { + if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) { printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n", block * nftl->EraseSize, nftl->mtd->index, le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/3c501.c linux-2.5/drivers/net/3c501.c --- linux-2.5.1/drivers/net/3c501.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/3c501.c Thu Dec 27 16:32:31 2001 @@ -87,8 +87,12 @@ * */ +#define DRV_NAME "3c501" +#define DRV_VERSION "2001/11/17" + + static const char version[] = - "3c501.c: 2000/02/08 Alan Cox (alan@redhat.com).\n"; + DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@redhat.com).\n"; /* * Braindamage remaining: @@ -108,7 +112,9 @@ #include <linux/errno.h> #include <linux/config.h> /* for CONFIG_IP_MULTICAST */ #include <linux/spinlock.h> +#include <linux/ethtool.h> +#include <asm/uaccess.h> #include <asm/bitops.h> #include <asm/io.h> @@ -139,12 +145,14 @@ static int el1_close(struct net_device *dev); static struct net_device_stats *el1_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); #define EL1_IO_EXTENT 16 #ifndef EL_DEBUG #define EL_DEBUG 0 /* use 0 for production, 1 for devel., >2 for debug */ #endif /* Anything above 5 is wordy death! */ +#define debug el_debug static int el_debug = EL_DEBUG; /* @@ -377,6 +385,7 @@ dev->stop = &el1_close; dev->get_stats = &el1_get_stats; dev->set_multicast_list = &set_multicast_list; + dev->do_ioctl = netdev_ioctl; /* * Setup the generic properties @@ -915,6 +924,86 @@ } } +/** + * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls + * @dev: network interface on which out-of-band action is to be performed + * @useraddr: userspace address to which data is to be read and returned + * + * Process the various commands of the SIOCETHTOOL interface. + */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + debug = edata.data; + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} + +/** + * netdev_ioctl: Handle network interface ioctls + * @dev: network interface on which out-of-band action is to be performed + * @rq: user request data + * @cmd: command issued by user + * + * Process the various out-of-band ioctls passed to this driver. + */ + +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + + switch (cmd) { + case SIOCETHTOOL: + rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + break; + + default: + rc = -EOPNOTSUPP; + break; + } + + return rc; +} + #ifdef MODULE static struct net_device dev_3c501 = { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/3c503.c linux-2.5/drivers/net/3c503.c --- linux-2.5.1/drivers/net/3c503.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/3c503.c Thu Dec 27 16:32:31 2001 @@ -29,11 +29,17 @@ Paul Gortmaker : add support for the 2nd 8kB of RAM on 16 bit cards. Paul Gortmaker : multiple card support for module users. rjohnson@analogic.com : Fix up PIO interface for efficient operation. + Jeff Garzik : ethtool support */ +#define DRV_NAME "3c503" +#define DRV_VERSION "1.10a" +#define DRV_RELDATE "11/17/2001" + + static const char version[] = - "3c503.c:v1.10 9/23/93 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; + DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n"; #include <linux/module.h> @@ -45,7 +51,9 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/ethtool.h> +#include <asm/uaccess.h> #include <asm/io.h> #include <asm/system.h> #include <asm/byteorder.h> @@ -74,6 +82,7 @@ int ring_offset); static void el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); /* This routine probes for a memory-mapped 3c503 board by looking for @@ -301,6 +310,7 @@ dev->open = &el2_open; dev->stop = &el2_close; + dev->do_ioctl = &netdev_ioctl; if (dev->mem_start) printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n", @@ -607,6 +617,71 @@ outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL); return; } + +/** + * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls + * @dev: network interface on which out-of-band action is to be performed + * @useraddr: userspace address to which data is to be read and returned + * + * Process the various commands of the SIOCETHTOOL interface. + */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} + +/** + * netdev_ioctl: Handle network interface ioctls + * @dev: network interface on which out-of-band action is to be performed + * @rq: user request data + * @cmd: command issued by user + * + * Process the various out-of-band ioctls passed to this driver. + */ + +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + + switch (cmd) { + case SIOCETHTOOL: + rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + break; + + default: + rc = -EOPNOTSUPP; + break; + } + + return rc; +} + + #ifdef MODULE #define MAX_EL2_CARDS 4 /* Max number of EL2 cards per module */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/3c505.c linux-2.5/drivers/net/3c505.c --- linux-2.5.1/drivers/net/3c505.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/3c505.c Thu Dec 27 16:32:31 2001 @@ -35,8 +35,13 @@ * Philip Blundell <Philip.Blundell@pobox.com> * Multicard/soft configurable dma channel/rev 2 hardware support * by Christopher Collins <ccollins@pcug.org.au> + * Ethtool support (jgarzik), 11/17/2001 */ +#define DRV_NAME "3c505" +#define DRV_VERSION "1.10a" + + /* Theory of operation: * * The 3c505 is quite an intelligent board. All communication with it is done @@ -103,6 +108,9 @@ #include <linux/slab.h> #include <linux/ioport.h> #include <linux/spinlock.h> +#include <linux/ethtool.h> + +#include <asm/uaccess.h> #include <asm/bitops.h> #include <asm/io.h> #include <asm/dma.h> @@ -148,10 +156,11 @@ *********************************************************/ #ifdef ELP_DEBUG -static const int elp_debug = ELP_DEBUG; +static int elp_debug = ELP_DEBUG; #else -static const int elp_debug; +static int elp_debug; #endif +#define debug elp_debug /* * 0 = no messages (well, some) @@ -1260,6 +1269,87 @@ } } +/** + * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls + * @dev: network interface on which out-of-band action is to be performed + * @useraddr: userspace address to which data is to be read and returned + * + * Process the various commands of the SIOCETHTOOL interface. + */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + debug = edata.data; + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} + +/** + * netdev_ioctl: Handle network interface ioctls + * @dev: network interface on which out-of-band action is to be performed + * @rq: user request data + * @cmd: command issued by user + * + * Process the various out-of-band ioctls passed to this driver. + */ + +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + + switch (cmd) { + case SIOCETHTOOL: + rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + break; + + default: + rc = -EOPNOTSUPP; + break; + } + + return rc; +} + + /****************************************************** * * initialise Etherlink Plus board @@ -1280,6 +1370,7 @@ dev->tx_timeout = elp_timeout; /* local */ dev->watchdog_timeo = 10*HZ; dev->set_multicast_list = elp_set_mc_list; /* local */ + dev->do_ioctl = netdev_ioctl; /* local */ /* Setup the generic properties */ ether_setup(dev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/3c507.c linux-2.5/drivers/net/3c507.c --- linux-2.5.1/drivers/net/3c507.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/net/3c507.c Thu Dec 27 16:32:31 2001 @@ -25,8 +25,12 @@ The statistics need to be updated correctly. */ +#define DRV_NAME "3c507" +#define DRV_VERSION "1.10a" +#define DRV_RELDATE "11/17/2001" + static const char version[] = - "3c507.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; + DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n"; #include <linux/module.h> @@ -52,6 +56,9 @@ #include <linux/in.h> #include <linux/string.h> #include <linux/spinlock.h> +#include <linux/ethtool.h> + +#include <asm/uaccess.h> #include <asm/system.h> #include <asm/bitops.h> #include <asm/io.h> @@ -70,6 +77,8 @@ #define NET_DEBUG 1 #endif static unsigned int net_debug = NET_DEBUG; +#define debug net_debug + /* A zero-terminated list of common I/O addresses to be probed. */ static unsigned int netcard_portlist[] __initdata = @@ -296,6 +305,7 @@ static void hardware_send_packet(struct net_device *dev, void *buf, short length); static void init_82586_mem(struct net_device *dev); +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); /* Check for a network adaptor of this type, and return '0' iff one exists. @@ -427,6 +437,7 @@ dev->get_stats = el16_get_stats; dev->tx_timeout = el16_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + dev->do_ioctl = netdev_ioctl; ether_setup(dev); /* Generic ethernet behaviour */ @@ -864,6 +875,88 @@ lp->rx_head = rx_head; lp->rx_tail = rx_tail; } + +/** + * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls + * @dev: network interface on which out-of-band action is to be performed + * @useraddr: userspace address to which data is to be read and returned + * + * Process the various commands of the SIOCETHTOOL interface. + */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + debug = edata.data; + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} + +/** + * netdev_ioctl: Handle network interface ioctls + * @dev: network interface on which out-of-band action is to be performed + * @rq: user request data + * @cmd: command issued by user + * + * Process the various out-of-band ioctls passed to this driver. + */ + +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + + switch (cmd) { + case SIOCETHTOOL: + rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + break; + + default: + rc = -EOPNOTSUPP; + break; + } + + return rc; +} + + #ifdef MODULE static struct net_device dev_3c507; static int io = 0x300; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/3c509.c linux-2.5/drivers/net/3c509.c --- linux-2.5.1/drivers/net/3c509.c Sun Nov 25 17:43:42 2001 +++ linux-2.5/drivers/net/3c509.c Thu Dec 27 16:32:31 2001 @@ -43,8 +43,14 @@ v1.18 12Mar2001 Andrew Morton <andrewm@uow.edu.au> - Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz) - Reviewed against 1.18 from scyld.com + v1.18 17Nov2001 Jeff Garzik <jgarzik@mandrakesoft.com> + - ethtool support */ +#define DRV_NAME "3c509" +#define DRV_VERSION "1.18a" +#define DRV_RELDATE "17Nov2001" + /* A few values that may be tweaked. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -70,12 +76,14 @@ #include <linux/skbuff.h> #include <linux/delay.h> /* for udelay() */ #include <linux/spinlock.h> +#include <linux/ethtool.h> +#include <asm/uaccess.h> #include <asm/bitops.h> #include <asm/io.h> #include <asm/irq.h> -static char versionA[] __initdata = "3c509.c:1.18 12Mar2001 becker@scyld.com\n"; +static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE "becker@scyld.com\n"; static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n"; #ifdef EL3_DEBUG @@ -84,6 +92,7 @@ static int el3_debug = 2; #endif + /* To minimize the size of the driver source I only define operating constants if they are used several times. You'll need the manual anyway if you want to understand driver details. */ @@ -158,6 +167,7 @@ static int el3_close(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void el3_tx_timeout (struct net_device *dev); +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); #ifdef CONFIG_MCA struct el3_mca_adapters_struct { @@ -513,6 +523,7 @@ dev->set_multicast_list = &set_multicast_list; dev->tx_timeout = el3_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + dev->do_ioctl = netdev_ioctl; /* Fill in the generic fields of the device structure. */ ether_setup(dev); @@ -1003,6 +1014,85 @@ return 0; } +/** + * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls + * @dev: network interface on which out-of-band action is to be performed + * @useraddr: userspace address to which data is to be read and returned + * + * Process the various commands of the SIOCETHTOOL interface. + */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = el3_debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + el3_debug = edata.data; + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} + +/** + * netdev_ioctl: Handle network interface ioctls + * @dev: network interface on which out-of-band action is to be performed + * @rq: user request data + * @cmd: command issued by user + * + * Process the various out-of-band ioctls passed to this driver. + */ + +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + + switch (cmd) { + case SIOCETHTOOL: + rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + break; + + default: + rc = -EOPNOTSUPP; + break; + } + + return rc; +} + #ifdef MODULE /* Parameters that may be passed into the module. */ static int debug = -1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/3c515.c linux-2.5/drivers/net/3c515.c --- linux-2.5.1/drivers/net/3c515.c Sun Nov 25 17:43:42 2001 +++ linux-2.5/drivers/net/3c515.c Thu Dec 27 16:32:31 2001 @@ -16,9 +16,17 @@ 2/2/00- Added support for kernel-level ISAPnP by Stephen Frost <sfrost@snowman.net> and Alessandro Zummo Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox. + + 11/17/2001 - Added ethtool support (jgarzik) + */ -static char *version = "3c515.c:v0.99-sn 2000/02/12 becker@cesdis.gsfc.nasa.gov and others\n"; +#define DRV_NAME "3c515" +#define DRV_VERSION "0.99t" +#define DRV_RELDATE "17-Nov-2001" + +static char *version = +DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " becker@scyld.com and others\n"; #define CORKSCREW 1 @@ -63,6 +71,9 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/timer.h> +#include <linux/ethtool.h> + +#include <asm/uaccess.h> #include <asm/bitops.h> #include <asm/io.h> #include <asm/dma.h> @@ -393,6 +404,7 @@ static void update_stats(int addr, struct net_device *dev); static struct net_device_stats *corkscrew_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); /* @@ -721,6 +733,7 @@ dev->stop = &corkscrew_close; dev->get_stats = &corkscrew_get_stats; dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = netdev_ioctl; return 0; } @@ -1591,6 +1604,87 @@ outw(new_mode, ioaddr + EL3_CMD); } + +/** + * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls + * @dev: network interface on which out-of-band action is to be performed + * @useraddr: userspace address to which data is to be read and returned + * + * Process the various commands of the SIOCETHTOOL interface. + */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = corkscrew_debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + corkscrew_debug = edata.data; + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} + +/** + * netdev_ioctl: Handle network interface ioctls + * @dev: network interface on which out-of-band action is to be performed + * @rq: user request data + * @cmd: command issued by user + * + * Process the various out-of-band ioctls passed to this driver. + */ + +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + + switch (cmd) { + case SIOCETHTOOL: + rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + break; + + default: + rc = -EOPNOTSUPP; + break; + } + + return rc; +} + #ifdef MODULE void cleanup_module(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/3c523.c linux-2.5/drivers/net/3c523.c --- linux-2.5.1/drivers/net/3c523.c Wed Jun 20 18:10:53 2001 +++ linux-2.5/drivers/net/3c523.c Thu Dec 27 16:32:31 2001 @@ -81,10 +81,15 @@ added option to disable multicast as is causes problems Ganesh Sittampalam <ganesh.sittampalam@magdalen.oxford.ac.uk> Stuart Adamson <stuart.adamson@compsoc.net> + Nov 2001 + added support for ethtool (jgarzik) $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $ */ +#define DRV_NAME "3c523" +#define DRV_VERSION "17-Nov-2001" + #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -95,6 +100,9 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/mca.h> +#include <linux/ethtool.h> + +#include <asm/uaccess.h> #include <asm/processor.h> #include <asm/bitops.h> #include <asm/io.h> @@ -182,6 +190,7 @@ #ifdef ELMC_MULTICAST static void set_multicast_list(struct net_device *dev); #endif +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); /* helper-functions */ static int init586(struct net_device *dev); @@ -563,7 +572,8 @@ #else dev->set_multicast_list = NULL; #endif - + dev->do_ioctl = netdev_ioctl; + ether_setup(dev); /* note that we haven't actually requested the IRQ from the kernel. @@ -1214,6 +1224,69 @@ } #endif +/** + * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls + * @dev: network interface on which out-of-band action is to be performed + * @useraddr: userspace address to which data is to be read and returned + * + * Process the various commands of the SIOCETHTOOL interface. + */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "MCA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} + +/** + * netdev_ioctl: Handle network interface ioctls + * @dev: network interface on which out-of-band action is to be performed + * @rq: user request data + * @cmd: command issued by user + * + * Process the various out-of-band ioctls passed to this driver. + */ + +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + + switch (cmd) { + case SIOCETHTOOL: + rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + break; + + default: + rc = -EOPNOTSUPP; + break; + } + + return rc; +} + /*************************************************************************/ #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/3c527.c linux-2.5/drivers/net/3c527.c --- linux-2.5.1/drivers/net/3c527.c Thu Apr 12 19:15:25 2001 +++ linux-2.5/drivers/net/3c527.c Thu Dec 27 16:32:31 2001 @@ -16,8 +16,12 @@ * */ +#define DRV_NAME "3c527" +#define DRV_VERSION "0.6a" +#define DRV_RELDATE "2001/11/17" + static const char *version = - "3c527.c:v0.6 2001/03/03 Richard Proctor (rnp@netlink.co.nz)\n"; +DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Proctor (rnp@netlink.co.nz)\n"; /** * DOC: Traps for the unwary @@ -90,6 +94,9 @@ #include <linux/in.h> #include <linux/slab.h> #include <linux/string.h> +#include <linux/ethtool.h> + +#include <asm/uaccess.h> #include <asm/system.h> #include <asm/bitops.h> #include <asm/io.h> @@ -108,7 +115,7 @@ * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels */ -static const char* cardname = "3c527"; +static const char* cardname = DRV_NAME; /* use 0 for production, 1 for verification, >2 for debug */ #ifndef NET_DEBUG @@ -213,6 +220,7 @@ static struct net_device_stats *mc32_get_stats(struct net_device *dev); static void mc32_set_multicast_list(struct net_device *dev); static void mc32_reset_multicast_list(struct net_device *dev); +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); /** * mc32_probe - Search for supported boards @@ -502,7 +510,7 @@ dev->set_multicast_list = mc32_set_multicast_list; dev->tx_timeout = mc32_timeout; dev->watchdog_timeo = HZ*5; /* Board does all the work */ - + dev->do_ioctl = netdev_ioctl; lp->xceiver_state = HALTED; @@ -1644,6 +1652,86 @@ do_mc32_set_multicast_list(dev,1); } +/** + * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls + * @dev: network interface on which out-of-band action is to be performed + * @useraddr: userspace address to which data is to be read and returned + * + * Process the various commands of the SIOCETHTOOL interface. + */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "MCA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = mc32_debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + mc32_debug = edata.data; + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} + +/** + * netdev_ioctl: Handle network interface ioctls + * @dev: network interface on which out-of-band action is to be performed + * @rq: user request data + * @cmd: command issued by user + * + * Process the various out-of-band ioctls passed to this driver. + */ + +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + + switch (cmd) { + case SIOCETHTOOL: + rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + break; + + default: + rc = -EOPNOTSUPP; + break; + } + + return rc; +} + #ifdef MODULE static struct net_device this_device; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/3c59x.c linux-2.5/drivers/net/3c59x.c --- linux-2.5.1/drivers/net/3c59x.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/net/3c59x.c Thu Dec 13 16:32:36 2001 @@ -2919,7 +2919,7 @@ static struct pci_driver vortex_driver = { name: "3c59x", probe: vortex_init_one, - remove: vortex_remove_one, + remove: __devexit_p(vortex_remove_one), id_table: vortex_pci_tbl, #ifdef CONFIG_PM suspend: vortex_suspend, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/8139cp.c linux-2.5/drivers/net/8139cp.c --- linux-2.5.1/drivers/net/8139cp.c Mon Nov 19 23:19:42 2001 +++ linux-2.5/drivers/net/8139cp.c Thu Dec 13 16:32:36 2001 @@ -1313,7 +1313,7 @@ name: DRV_NAME, id_table: cp_pci_tbl, probe: cp_init_one, - remove: cp_remove_one, + remove: __devexit_p(cp_remove_one), }; static int __init cp_init (void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/8139too.c linux-2.5/drivers/net/8139too.c --- linux-2.5.1/drivers/net/8139too.c Sat Nov 24 19:26:37 2001 +++ linux-2.5/drivers/net/8139too.c Thu Dec 13 16:32:36 2001 @@ -1636,23 +1636,24 @@ struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned int entry; + unsigned int len = skb->len; /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; - if (likely(skb->len < TX_BUF_SIZE)) { + if (likely(len < TX_BUF_SIZE)) { skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); dev_kfree_skb(skb); } else { dev_kfree_skb(skb); tp->stats.tx_dropped++; return 0; - } + } /* Note: the chip doesn't have auto-pad! */ spin_lock_irq(&tp->lock); RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), - tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + tp->tx_flag | max(len, (unsigned int)ETH_ZLEN)); dev->trans_start = jiffies; @@ -1663,8 +1664,8 @@ netif_stop_queue (dev); spin_unlock_irq(&tp->lock); - DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", - dev->name, skb->data, skb->len, entry); + DPRINTK ("%s: Queued Tx packet size %u to slot %d.\n", + dev->name, len, entry); return 0; } @@ -2493,7 +2494,7 @@ name: DRV_NAME, id_table: rtl8139_pci_tbl, probe: rtl8139_init_one, - remove: rtl8139_remove_one, + remove: __devexit_p(rtl8139_remove_one), #ifdef CONFIG_PM suspend: rtl8139_suspend, resume: rtl8139_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/Config.in linux-2.5/drivers/net/Config.in --- linux-2.5.1/drivers/net/Config.in Mon Dec 10 19:17:40 2001 +++ linux-2.5/drivers/net/Config.in Thu Dec 27 16:32:31 2001 @@ -10,9 +10,7 @@ tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER tristate 'Universal TUN/TAP device driver support' CONFIG_TUN if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_NETLINK" = "y" ]; then - tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP - fi + tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP fi if [ "$CONFIG_ISAPNP" = "y" -o "$CONFIG_ISAPNP" = "m" ]; then @@ -36,11 +34,15 @@ if [ "$CONFIG_PPC" = "y" ]; then dep_tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE $CONFIG_ALL_PPC if [ "$CONFIG_MACE" != "n" ]; then - bool ' Use AAUI port instead of TP by default' CONFIG_MACE_AAUI_PORT + bool ' Use AAUI port instead of TP by default' CONFIG_MACE_AAUI_PORT fi dep_tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC $CONFIG_ALL_PPC dep_tristate ' GMAC (G4/iBook ethernet) support' CONFIG_GMAC $CONFIG_ALL_PPC - tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET + if [ "$CONFIG_4xx" = "y" ]; then + if [ "$CONFIG_STB03xxx" = "y" -o "$CONFIG_403GCX" = "y" ]; then + tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET + fi + fi fi if [ "$CONFIG_ZORRO" = "y" ]; then tristate ' Ariadne support' CONFIG_ARIADNE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/acenic.c linux-2.5/drivers/net/acenic.c --- linux-2.5.1/drivers/net/acenic.c Mon Nov 19 23:19:42 2001 +++ linux-2.5/drivers/net/acenic.c Sat Jan 12 12:32:41 2002 @@ -208,6 +208,8 @@ (((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO) #define pci_dma_supported(dev, mask) \ (((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0) +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) #elif (LINUX_VERSION_CODE < 0x02040d) @@ -231,6 +233,8 @@ } #define pci_unmap_page(cookie, dma_addr, size, dir) \ pci_unmap_single(cookie, dma_addr, size, dir) +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) #endif @@ -839,9 +843,11 @@ struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; if (skb) { + struct ring_info *ringp; dma_addr_t mapping; - mapping = ap->skb->rx_std_skbuff[i].mapping; + ringp = &ap->skb->rx_std_skbuff[i]; + mapping = PCI_UNMAP_ADDR(ringp, mapping); pci_unmap_page(ap->pdev, mapping, ACE_STD_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); @@ -856,9 +862,11 @@ struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb; if (skb) { + struct ring_info *ringp; dma_addr_t mapping; - mapping = ap->skb->rx_mini_skbuff[i].mapping; + ringp = &ap->skb->rx_mini_skbuff[i]; + mapping = PCI_UNMAP_ADDR(ringp,mapping); pci_unmap_page(ap->pdev, mapping, ACE_MINI_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); @@ -872,9 +880,11 @@ for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb; if (skb) { + struct ring_info *ringp; dma_addr_t mapping; - mapping = ap->skb->rx_jumbo_skbuff[i].mapping; + ringp = &ap->skb->rx_jumbo_skbuff[i]; + mapping = PCI_UNMAP_ADDR(ringp, mapping); pci_unmap_page(ap->pdev, mapping, ACE_JUMBO_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); @@ -1518,7 +1528,7 @@ ace_set_rxtx_parms(dev, 0); if (board_idx == BOARD_IDX_OVERFLOW) { - printk(KERN_WARNING "%s: more then %i NICs detected, " + printk(KERN_WARNING "%s: more than %i NICs detected, " "ignoring module parameters!\n", dev->name, ACE_MAX_MOD_PARMS); } else if (board_idx >= 0) { @@ -1832,7 +1842,8 @@ ACE_STD_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_std_skbuff[idx].skb = skb; - ap->skb->rx_std_skbuff[idx].mapping = mapping; + PCI_UNMAP_ADDR_SET(&ap->skb->rx_std_skbuff[idx], + mapping, mapping); rd = &ap->rx_std_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -1897,7 +1908,8 @@ ACE_MINI_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_mini_skbuff[idx].skb = skb; - ap->skb->rx_mini_skbuff[idx].mapping = mapping; + PCI_UNMAP_ADDR_SET(&ap->skb->rx_mini_skbuff[idx], + mapping, mapping); rd = &ap->rx_mini_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -1957,7 +1969,8 @@ ACE_JUMBO_BUFSIZE - (2 + 16), PCI_DMA_FROMDEVICE); ap->skb->rx_jumbo_skbuff[idx].skb = skb; - ap->skb->rx_jumbo_skbuff[idx].mapping = mapping; + PCI_UNMAP_ADDR_SET(&ap->skb->rx_jumbo_skbuff[idx], + mapping, mapping); rd = &ap->rx_jumbo_ring[idx]; set_aceaddr(&rd->addr, mapping); @@ -2163,7 +2176,9 @@ skb = rip->skb; rip->skb = NULL; - pci_unmap_page(ap->pdev, rip->mapping, mapsize, + pci_unmap_page(ap->pdev, + PCI_UNMAP_ADDR(rip, mapping), + mapsize, PCI_DMA_FROMDEVICE); skb_put(skb, retdesc->size); @@ -2229,12 +2244,13 @@ info = ap->skb->tx_skbuff + idx; skb = info->skb; - mapping = info->mapping; + mapping = PCI_UNMAP_ADDR(info, mapping); if (mapping) { - pci_unmap_page(ap->pdev, mapping, info->maplen, + pci_unmap_page(ap->pdev, mapping, + PCI_UNMAP_LEN(info, maplen), PCI_DMA_TODEVICE); - info->mapping = 0; + PCI_UNMAP_ADDR_SET(info, mapping, 0); } if (skb) { @@ -2518,13 +2534,14 @@ info = ap->skb->tx_skbuff + i; skb = info->skb; - mapping = info->mapping; + mapping = PCI_UNMAP_ADDR(info, mapping); if (mapping) { memset(ap->tx_ring + i, 0, sizeof(struct tx_desc)); - pci_unmap_page(ap->pdev, mapping, info->maplen, + pci_unmap_page(ap->pdev, mapping, + PCI_UNMAP_LEN(info, maplen), PCI_DMA_TODEVICE); - info->mapping = 0; + PCI_UNMAP_ADDR_SET(info, mapping, 0); } if (skb) { dev_kfree_skb(skb); @@ -2545,7 +2562,6 @@ return 0; } - static inline dma_addr_t ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb, struct sk_buff *tail, u32 idx) @@ -2559,8 +2575,8 @@ info = ap->skb->tx_skbuff + idx; info->skb = tail; - info->mapping = mapping; - info->maplen = skb->len; + PCI_UNMAP_ADDR_SET(info, mapping, mapping); + PCI_UNMAP_LEN_SET(info, maplen, skb->len); return mapping; } @@ -2661,8 +2677,8 @@ } else { info->skb = NULL; } - info->mapping = mapping; - info->maplen = frag->size; + PCI_UNMAP_ADDR_SET(info, mapping, mapping); + PCI_UNMAP_LEN_SET(info, maplen, frag->size); ace_load_tx_bd(desc, mapping, flagsize); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/acenic.h linux-2.5/drivers/net/acenic.h --- linux-2.5.1/drivers/net/acenic.h Mon Nov 19 23:19:42 2001 +++ linux-2.5/drivers/net/acenic.h Thu Dec 27 16:32:31 2001 @@ -585,7 +585,7 @@ struct ring_info { struct sk_buff *skb; - dma_addr_t mapping; + DECLARE_PCI_UNMAP_ADDR(mapping) }; @@ -596,8 +596,8 @@ */ struct tx_ring_info { struct sk_buff *skb; - dma_addr_t mapping; - int maplen; + DECLARE_PCI_UNMAP_ADDR(mapping) + DECLARE_PCI_UNMAP_LEN(maplen) }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/aironet4500_core.c linux-2.5/drivers/net/aironet4500_core.c --- linux-2.5.1/drivers/net/aironet4500_core.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/aironet4500_core.c Mon Jan 7 21:33:57 2002 @@ -2836,7 +2836,7 @@ return 0; final: printk(KERN_ERR "aironet init failed \n"); - return NODEV; + return -ENODEV; }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/arcnet/com20020-pci.c linux-2.5/drivers/net/arcnet/com20020-pci.c --- linux-2.5.1/drivers/net/arcnet/com20020-pci.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/net/arcnet/com20020-pci.c Thu Dec 13 16:32:36 2001 @@ -160,7 +160,7 @@ name: "com20020", id_table: com20020pci_id_table, probe: com20020pci_probe, - remove: com20020pci_remove + remove: __devexit_p(com20020pci_remove), }; static int __init com20020pci_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/arcnet/com90io.c linux-2.5/drivers/net/arcnet/com90io.c --- linux-2.5.1/drivers/net/arcnet/com90io.c Sun Nov 4 17:31:58 2001 +++ linux-2.5/drivers/net/arcnet/com90io.c Mon Jan 14 22:39:45 2002 @@ -241,7 +241,10 @@ return -ENODEV; } /* Reserve the I/O region - guaranteed to work by check_region */ - request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)"); + if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)")) { + free_irq(dev->irq, dev); + return -EBUSY; + } /* Initialize the rest of the device structure. */ dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/bmac.c linux-2.5/drivers/net/bmac.c --- linux-2.5.1/drivers/net/bmac.c Wed Nov 14 23:16:31 2001 +++ linux-2.5/drivers/net/bmac.c Thu Dec 27 16:32:31 2001 @@ -22,7 +22,8 @@ #include <asm/io.h> #include <asm/page.h> #include <asm/pgtable.h> -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #ifdef CONFIG_PMAC_PBOOK #include <linux/adb.h> #include <linux/pmu.h> @@ -155,7 +156,7 @@ static void bmac_start_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 void bmac_enable_and_reset_chip(struct net_device *dev); static int bmac_set_address(struct net_device *dev, void *addr); static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs); static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs); @@ -229,21 +230,18 @@ } static void -bmac_reset_chip(struct net_device *dev) +bmac_enable_and_reset_chip(struct net_device *dev) { struct bmac_data *bp = (struct bmac_data *) dev->priv; volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_regs *td = bp->tx_dma; - dbdma_reset(rd); - dbdma_reset(td); + if (rd) + dbdma_reset(rd); + if (td) + dbdma_reset(td); - feature_set(bp->node, FEATURE_BMac_IO_enable); - udelay(10000); - feature_set(bp->node, FEATURE_BMac_reset); - udelay(10000); - feature_clear(bp->node, FEATURE_BMac_reset); - udelay(10000); + pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 1); } #define MIFDELAY udelay(10) @@ -522,10 +520,7 @@ } } } - feature_set(bp->node, FEATURE_BMac_reset); - mdelay(10); - feature_clear(bp->node, FEATURE_BMac_IO_enable); - mdelay(10); + pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); break; case PBOOK_WAKE: /* see if this is enough */ @@ -1267,7 +1262,7 @@ unsigned char *data; save_flags(flags); cli(); - bmac_reset_chip(dev); + bmac_enable_and_reset_chip(dev); bmac_init_tx_ring(bp); bmac_init_rx_ring(bp); bmac_init_chip(dev); @@ -1350,14 +1345,30 @@ bmac->full_name); return; } + bp = (struct bmac_data *) dev->priv; SET_MODULE_OWNER(dev); + bp->node = bmac; + if (!request_OF_resource(bmac, 0, " (bmac)")) { + printk(KERN_ERR "BMAC: can't request IO resource !\n"); + goto err_out; + } + if (!request_OF_resource(bmac, 1, " (bmac tx dma)")) { + printk(KERN_ERR "BMAC: can't request TX DMA resource !\n"); + goto err_out; + } + + if (!request_OF_resource(bmac, 2, " (bmac rx dma)")) { + printk(KERN_ERR "BMAC: can't request RX DMA resource !\n"); + goto err_out; + } dev->base_addr = (unsigned long) ioremap(bmac->addrs[0].address, bmac->addrs[0].size); if (!dev->base_addr) goto err_out; dev->irq = bmac->intrs[0].line; + bmac_enable_and_reset_chip(dev); bmwrite(dev, INTDISABLE, DisableAll); printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": "")); @@ -1369,6 +1380,10 @@ XXDEBUG((", base_addr=%#0lx", dev->base_addr)); printk("\n"); + /* Enable chip without interrupts for now */ + bmac_enable_and_reset_chip(dev); + bmwrite(dev, INTDISABLE, DisableAll); + dev->open = bmac_open; dev->stop = bmac_close; dev->hard_start_xmit = bmac_output; @@ -1380,7 +1395,6 @@ if (bmac_verify_checksum(dev) != 0) goto err_out_iounmap; - bp = (struct bmac_data *) dev->priv; bp->is_bmac_plus = is_bmac_plus; bp->tx_dma = (volatile struct dbdma_regs *) ioremap(bmac->addrs[1].address, bmac->addrs[1].size); @@ -1399,7 +1413,6 @@ bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1); skb_queue_head_init(bp->queue); - bp->node = bmac; memset((char *) bp->tx_cmds, 0, (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd)); /* init_timer(&bp->tx_timeout); */ @@ -1421,6 +1434,12 @@ goto err_out_irq1; } + /* Mask chip interrupts and disable chip, will be + * re-enabled on open() + */ + disable_irq(dev->irq); + pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); + bp->next_bmac = bmac_devs; bmac_devs = dev; return; @@ -1436,6 +1455,12 @@ err_out_iounmap: iounmap((void *)dev->base_addr); err_out: + if (bp->node) { + release_OF_resource(bp->node, 0); + release_OF_resource(bp->node, 1); + release_OF_resource(bp->node, 2); + pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); + } unregister_netdev(dev); kfree(dev); } @@ -1447,6 +1472,7 @@ /* reset the chip */ bp->opened = 1; bmac_reset_and_enable(dev); + enable_irq(dev->irq); dev->flags |= IFF_RUNNING; return 0; } @@ -1459,6 +1485,7 @@ unsigned short config; int i; + bp->sleeping = 1; dev->flags &= ~(IFF_UP | IFF_RUNNING); /* disable rx and tx */ @@ -1492,6 +1519,8 @@ XXDEBUG(("bmac: all bufs freed\n")); bp->opened = 0; + disable_irq(dev->irq); + pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); return 0; } @@ -1561,7 +1590,7 @@ bmwrite(dev, TXCFG, (config & ~TxMACEnable)); out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD)); printk(KERN_ERR "bmac: transmit timeout - resetting\n"); - bmac_reset_chip(dev); + bmac_enable_and_reset_chip(dev); /* restart rx dma */ cp = bus_to_virt(ld_le32(&rd->cmdptr)); @@ -1683,11 +1712,15 @@ bp = (struct bmac_data *) dev->priv; bmac_devs = bp->next_bmac; + unregister_netdev(dev); + + release_OF_resource(bp->node, 0); + release_OF_resource(bp->node, 1); + release_OF_resource(bp->node, 2); free_irq(dev->irq, dev); free_irq(bp->tx_dma_intr, dev); free_irq(bp->rx_dma_intr, dev); - unregister_netdev(dev); kfree(dev); } while (bmac_devs != NULL); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/bonding.c linux-2.5/drivers/net/bonding.c --- linux-2.5.1/drivers/net/bonding.c Tue Nov 13 17:19:41 2001 +++ linux-2.5/drivers/net/bonding.c Thu Dec 13 16:32:36 2001 @@ -185,7 +185,6 @@ #include <linux/if_bonding.h> #include <linux/smp.h> -#include <limits.h> #include <linux/if_ether.h> #include <linux/if_arp.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/de2104x.c linux-2.5/drivers/net/de2104x.c --- linux-2.5.1/drivers/net/de2104x.c Mon Dec 10 19:17:40 2001 +++ linux-2.5/drivers/net/de2104x.c Thu Jan 3 23:04:39 2002 @@ -28,8 +28,8 @@ */ #define DRV_NAME "de2104x" -#define DRV_VERSION "0.5.1" -#define DRV_RELDATE "Nov 20, 2001" +#define DRV_VERSION "0.5.4" +#define DRV_RELDATE "Jan 1, 2002" #include <linux/config.h> #include <linux/module.h> @@ -45,6 +45,7 @@ #include <linux/rtnetlink.h> #include <asm/io.h> #include <asm/uaccess.h> +#include <asm/unaligned.h> /* These identify the driver base version and may not be removed. */ static char version[] __initdata = @@ -99,6 +100,7 @@ #define DE_DUMMY_SKB ((struct sk_buff *) 2) #define DE_SETUP_FRAME_WORDS 96 #define DE_EEPROM_WORDS 256 +#define DE_EEPROM_SIZE (DE_EEPROM_WORDS * sizeof(u16)) #define DE_MAX_MEDIA 5 #define DE_MEDIA_TP_AUTO 0 @@ -109,6 +111,8 @@ #define DE_MEDIA_INVALID DE_MAX_MEDIA #define DE_MEDIA_FIRST 0 #define DE_MEDIA_LAST (DE_MAX_MEDIA - 1) +#define DE_AUI_BNC (SUPPORTED_AUI | SUPPORTED_BNC) + #define DE_TIMER_LINK (60 * HZ) #define DE_TIMER_NO_LINK (5 * HZ) @@ -117,7 +121,9 @@ #define DE_REGS_VER 1 /* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (6*HZ) +#define TX_TIMEOUT (6*HZ) + +#define DE_UNALIGNED_16(a) (u16)(get_unaligned((u16 *)(a))) /* This is a mysterious value that can be written to CSR11 in the 21040 (only) to support a pre-NWay full-duplex signaling mechanism using short frames. @@ -254,7 +260,6 @@ u16 default_media; u8 n_blocks; u8 unused; - struct de_srom_media_block media[0]; } __attribute__((packed)); struct de_desc { @@ -307,6 +312,7 @@ struct media_info media[DE_MAX_MEDIA]; struct timer_list media_timer; + u8 *ee_data; unsigned board_idx; unsigned de21040 : 1; unsigned media_lock : 1; @@ -319,6 +325,7 @@ static void de_media_interrupt (struct de_private *de, u32 status); static void de21040_media_timer (unsigned long data); static void de21041_media_timer (unsigned long data); +static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media); static struct pci_device_id de_pci_tbl[] __initdata = { @@ -918,7 +925,6 @@ dw32(MacStatus, dr32(MacStatus)); - synchronize_irq(); udelay(10); de->rx_tail = 0; @@ -968,15 +974,29 @@ else de->macmode &= ~FullDuplex; - if (netif_msg_link(de)) - printk(KERN_INFO "%s: set link %s, mode %x, sia %x,%x,%x,%x\n" - KERN_INFO " set mode %x, set sia %x,%x,%x\n", + if (netif_msg_link(de)) { + printk(KERN_INFO "%s: set link %s\n" + KERN_INFO "%s: mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n" + KERN_INFO "%s: set mode 0x%x, set sia 0x%x,0x%x,0x%x\n", de->dev->name, media_name[media], - dr32(MacMode), dr32(SIAStatus), dr32(CSR13), - dr32(CSR14), dr32(CSR15), de->macmode, - de->media[media].csr13, - de->media[media].csr14, - de->media[media].csr15); + de->dev->name, dr32(MacMode), dr32(SIAStatus), + dr32(CSR13), dr32(CSR14), dr32(CSR15), + de->dev->name, de->macmode, de->media[media].csr13, + de->media[media].csr14, de->media[media].csr15); + } +} + +static void de_next_media (struct de_private *de, u32 *media, + unsigned int n_media) +{ + unsigned int i; + + for (i = 0; i < n_media; i++) { + if (de_ok_to_advertise(de, media[i])) { + de->media_type = media[i]; + return; + } + } } static void de21040_media_timer (unsigned long data) @@ -985,6 +1005,7 @@ struct net_device *dev = de->dev; u32 status = dr32(SIAStatus); unsigned int carrier; + unsigned long flags; carrier = (status & NetCxnErr) ? 0 : 1; @@ -1009,12 +1030,17 @@ if (de->media_lock) return; - if (de->media_type == DE_MEDIA_AUI) - de->media_type = DE_MEDIA_TP; - else - de->media_type = DE_MEDIA_AUI; + if (de->media_type == DE_MEDIA_AUI) { + u32 next_state = DE_MEDIA_TP; + de_next_media(de, &next_state, 1); + } else { + u32 next_state = DE_MEDIA_AUI; + de_next_media(de, &next_state, 1); + } + spin_lock_irqsave(&de->lock, flags); de_stop_rxtx(de); + spin_unlock_irqrestore(&de->lock, flags); de_set_media(de); de_start_rxtx(de); @@ -1061,8 +1087,9 @@ { struct de_private *de = (struct de_private *) data; struct net_device *dev = de->dev; - u32 status = dr32(SIAStatus), new_media; + u32 status = dr32(SIAStatus); unsigned int carrier; + unsigned long flags; carrier = (status & NetCxnErr) ? 0 : 1; @@ -1093,27 +1120,55 @@ /* if activity detected, use that as hint for new media type */ if (status & NonselPortActive) { - if (de->media_type == DE_MEDIA_AUI) - de->media_type = DE_MEDIA_TP; - else + unsigned int have_media = 1; + + /* if AUI/BNC selected, then activity is on TP port */ + if (de->media_type == DE_MEDIA_AUI || + de->media_type == DE_MEDIA_BNC) { + if (de_ok_to_advertise(de, DE_MEDIA_TP_AUTO)) + de->media_type = DE_MEDIA_TP_AUTO; + else + have_media = 0; + } + + /* TP selected. If there is only TP and BNC, then it's BNC */ + else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_BNC) && + de_ok_to_advertise(de, DE_MEDIA_BNC)) + de->media_type = DE_MEDIA_BNC; + + /* TP selected. If there is only TP and AUI, then it's AUI */ + else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_AUI) && + de_ok_to_advertise(de, DE_MEDIA_AUI)) de->media_type = DE_MEDIA_AUI; - goto set_media; - } - /* move to next advertised media */ - new_media = de->media_type; - do { - if (new_media == DE_MEDIA_LAST) - new_media = DE_MEDIA_FIRST; + /* otherwise, ignore the hint */ else - new_media++; - } while ((!de_ok_to_advertise(de, new_media)) && - (new_media != de->media_type)); + have_media = 0; - de->media_type = new_media; + if (have_media) + goto set_media; + } + + /* + * Absent or ambiguous activity hint, move to next advertised + * media state. If de->media_type is left unchanged, this + * simply resets the PHY and reloads the current media settings. + */ + if (de->media_type == DE_MEDIA_AUI) { + u32 next_states[] = { DE_MEDIA_BNC, DE_MEDIA_TP_AUTO }; + de_next_media(de, next_states, ARRAY_SIZE(next_states)); + } else if (de->media_type == DE_MEDIA_BNC) { + u32 next_states[] = { DE_MEDIA_TP_AUTO, DE_MEDIA_AUI }; + de_next_media(de, next_states, ARRAY_SIZE(next_states)); + } else { + u32 next_states[] = { DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO }; + de_next_media(de, next_states, ARRAY_SIZE(next_states)); + } set_media: + spin_lock_irqsave(&de->lock, flags); de_stop_rxtx(de); + spin_unlock_irqrestore(&de->lock, flags); de_set_media(de); de_start_rxtx(de); @@ -1145,20 +1200,21 @@ static int de_reset_mac (struct de_private *de) { - unsigned tmp; - u32 status; + u32 status, tmp; /* * Reset MAC. Copied from de4x5.c. */ - dr32 (BusMode); + tmp = dr32 (BusMode); + if (tmp == 0xffffffff) + return -ENODEV; mdelay (1); - dw32 (BusMode, de_bus_mode | CmdReset); + dw32 (BusMode, tmp | CmdReset); mdelay (1); - dw32 (BusMode, de_bus_mode); + dw32 (BusMode, tmp); mdelay (1); for (tmp = 0; tmp < 5; tmp++) { @@ -1309,12 +1365,20 @@ } for (i = 0; i < DE_TX_RING_SIZE; i++) { - if (de->tx_skb[i].skb) { - struct sk_buff *skb = de->tx_skb[i].skb; - pci_unmap_single(de->pdev, de->tx_skb[i].mapping, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb(skb); - de->net_stats.tx_dropped++; + struct sk_buff *skb = de->tx_skb[i].skb; + if ((skb) && (skb != DE_DUMMY_SKB)) { + if (skb != DE_SETUP_SKB) { + dev_kfree_skb(skb); + de->net_stats.tx_dropped++; + pci_unmap_single(de->pdev, + de->tx_skb[i].mapping, + skb->len, PCI_DMA_TODEVICE); + } else { + pci_unmap_single(de->pdev, + de->tx_skb[i].mapping, + sizeof(de->setup_frame), + PCI_DMA_TODEVICE); + } } } @@ -1334,6 +1398,7 @@ { struct de_private *de = dev->priv; int rc; + unsigned long flags; if (netif_msg_ifup(de)) printk(KERN_DEBUG "%s: enabling interface\n", dev->name); @@ -1362,11 +1427,15 @@ } netif_start_queue(dev); + mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK); return 0; err_out_hw: + spin_lock_irqsave(&de->lock, flags); de_stop_hw(de); + spin_unlock_irqrestore(&de->lock, flags); + err_out_free: de_free_rings(de); return rc; @@ -1375,15 +1444,21 @@ static int de_close (struct net_device *dev) { struct de_private *de = dev->priv; + unsigned long flags; if (netif_msg_ifdown(de)) printk(KERN_DEBUG "%s: disabling interface\n", dev->name); - netif_stop_queue(dev); - netif_carrier_off(dev); del_timer_sync(&de->media_timer); + + spin_lock_irqsave(&de->lock, flags); de_stop_hw(de); + netif_stop_queue(dev); + netif_carrier_off(dev); + spin_unlock_irqrestore(&de->lock, flags); + free_irq(dev->irq, dev); + de_free_rings(de); de_adapter_sleep(de); pci_disable_device(de->pdev); @@ -1558,6 +1633,7 @@ strcpy (info.driver, DRV_NAME); strcpy (info.version, DRV_VERSION); strcpy (info.bus_info, de->pdev->slot_name); + info.eedump_len = DE_EEPROM_SIZE; info.regdump_len = DE_REGS_SIZE; if (copy_to_user (useraddr, &info, sizeof (info))) return -EFAULT; @@ -1658,6 +1734,23 @@ return 0; } + /* get SROM dump */ + case ETHTOOL_GEEPROM: { + struct ethtool_eeprom eeprom; + + if (!de->ee_data) + break; + if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) + return -EFAULT; + if ((eeprom.offset != 0) || (eeprom.magic != 0) || + (eeprom.len != DE_EEPROM_SIZE)) + return -EINVAL; + + useraddr += offsetof(struct ethtool_regs, data); + if (copy_to_user(useraddr, de->ee_data, DE_EEPROM_SIZE)) + return -EFAULT; + } + default: break; } @@ -1703,7 +1796,31 @@ } } -/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ +static void __init de21040_get_media_info(struct de_private *de) +{ + unsigned int i; + + de->media_type = DE_MEDIA_TP; + de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full | + SUPPORTED_10baseT_Half | SUPPORTED_AUI; + de->media_advertise = de->media_supported; + + for (i = 0; i < DE_MAX_MEDIA; i++) { + switch (i) { + case DE_MEDIA_AUI: + case DE_MEDIA_TP: + case DE_MEDIA_TP_FD: + de->media[i].type = i; + de->media[i].csr13 = t21040_csr13[i]; + de->media[i].csr14 = t21040_csr14[i]; + de->media[i].csr15 = t21040_csr15[i]; + break; + default: + de->media[i].type = DE_MEDIA_INVALID; + break; + } + } +} /* Note: this routine returns extra data bits for size detection. */ static unsigned __init tulip_read_eeprom(void *regs, int location, int addr_len) @@ -1741,15 +1858,16 @@ return retval; } -static void __init tulip_get_srom_info (struct de_private *de) +static void __init de21041_get_srom_info (struct de_private *de) { unsigned i, sa_offset = 0, ofs; - u8 ee_data[DE_EEPROM_WORDS * sizeof(u16)]; + u8 ee_data[DE_EEPROM_SIZE + 6] = {}; unsigned ee_addr_size = tulip_read_eeprom(de->regs, 0xff, 8) & 0x40000 ? 8 : 6; struct de_srom_info_leaf *il; + void *bufp; /* download entire eeprom */ - for (i = 0; i < sizeof(ee_data)/2; i++) + for (i = 0; i < DE_EEPROM_WORDS; i++) ((u16 *)ee_data)[i] = le16_to_cpu(tulip_read_eeprom(de->regs, i, ee_addr_size)); @@ -1780,13 +1898,18 @@ goto bad_srom; /* get default media type */ - switch (il->default_media) { + switch (DE_UNALIGNED_16(&il->default_media)) { case 0x0001: de->media_type = DE_MEDIA_BNC; break; case 0x0002: de->media_type = DE_MEDIA_AUI; break; case 0x0204: de->media_type = DE_MEDIA_TP_FD; break; default: de->media_type = DE_MEDIA_TP_AUTO; break; } + if (netif_msg_probe(de)) + printk(KERN_INFO "de%d: SROM leaf offset %u, default media %s\n", + de->board_idx, ofs, + media_name[de->media_type]); + /* init SIA register values to defaults */ for (i = 0; i < DE_MAX_MEDIA; i++) { de->media[i].type = DE_MEDIA_INVALID; @@ -1798,8 +1921,9 @@ /* parse media blocks to see what medias are supported, * and if any custom CSR values are provided */ + bufp = ((void *)il) + sizeof(*il); for (i = 0; i < il->n_blocks; i++) { - struct de_srom_media_block *ib = &il[i].media[0]; + struct de_srom_media_block *ib = bufp; unsigned idx; /* index based on media type in media block */ @@ -1828,16 +1952,37 @@ goto bad_srom; } + de->media[idx].type = idx; + + if (netif_msg_probe(de)) + printk(KERN_INFO "de%d: media block #%u: %s", + de->board_idx, i, + media_name[de->media[idx].type]); + + bufp += sizeof (ib->opts); + if (ib->opts & MediaCustomCSRs) { - de->media[idx].csr13 = ib->csr13; - de->media[idx].csr14 = ib->csr14; - de->media[idx].csr15 = ib->csr15; - } + de->media[idx].csr13 = DE_UNALIGNED_16(&ib->csr13); + de->media[idx].csr14 = DE_UNALIGNED_16(&ib->csr14); + de->media[idx].csr15 = DE_UNALIGNED_16(&ib->csr15); + bufp += sizeof(ib->csr13) + sizeof(ib->csr14) + + sizeof(ib->csr15); + + if (netif_msg_probe(de)) + printk(" (%x,%x,%x)\n", + de->media[idx].csr13, + de->media[idx].csr14, + de->media[idx].csr15); + + } else if (netif_msg_probe(de)) + printk("\n"); - de->media[idx].type = idx; - de->media_advertise |= de->media_supported; + if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3])) + break; } + de->media_advertise = de->media_supported; + fill_defaults: /* fill in defaults, for cases where custom CSRs not used */ for (i = 0; i < DE_MAX_MEDIA; i++) { @@ -1849,12 +1994,9 @@ de->media[i].csr15 = t21041_csr15[i]; } - if (netif_msg_link(de)) - printk(KERN_INFO "de%d: SROM-listed ports: %s%s%s\n", - de->board_idx, - de->media_supported & SUPPORTED_TP ? "TP " : "", - de->media_supported & SUPPORTED_BNC ? "BNC " : "", - de->media_supported & SUPPORTED_AUI ? "AUI" : ""); + de->ee_data = kmalloc(DE_EEPROM_SIZE, GFP_KERNEL); + if (de->ee_data) + memcpy(de->ee_data, &ee_data[0], DE_EEPROM_SIZE); return; @@ -1970,35 +2112,21 @@ de_adapter_wake(de); /* make sure hardware is not running */ - de_stop_hw(de); + rc = de_reset_mac(de); + if (rc) { + printk(KERN_ERR PFX "Cannot reset MAC, pci dev %s\n", + pdev->slot_name); + goto err_out_iomap; + } - /* get MAC address, and some register values related to media types */ + /* get MAC address, initialize default media type and + * get list of supported media + */ if (de->de21040) { - unsigned i; - de21040_get_mac_address(de); - - de->media_type = DE_MEDIA_TP; - de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full | - SUPPORTED_10baseT_Half | SUPPORTED_AUI; - de->media_advertise = de->media_supported; - for (i = 0; i < DE_MAX_MEDIA; i++) { - switch (i) { - case DE_MEDIA_AUI: - case DE_MEDIA_TP: - case DE_MEDIA_TP_FD: - de->media[i].type = i; - de->media[i].csr13 = t21040_csr13[i]; - de->media[i].csr14 = t21040_csr14[i]; - de->media[i].csr15 = t21040_csr15[i]; - break; - default: - de->media[i].type = DE_MEDIA_INVALID; - break; - } - } + de21040_get_media_info(de); } else { - tulip_get_srom_info(de); + de21041_get_srom_info(de); } /* register new network interface with kernel */ @@ -2029,6 +2157,8 @@ return 0; err_out_iomap: + if (de->ee_data) + kfree(de->ee_data); iounmap(regs); err_out_res: pci_release_regions(pdev); @@ -2047,6 +2177,8 @@ if (!dev) BUG(); unregister_netdev(dev); + if (de->ee_data) + kfree(de->ee_data); iounmap(de->regs); pci_release_regions(pdev); pci_disable_device(pdev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/de4x5.c linux-2.5/drivers/net/de4x5.c --- linux-2.5.1/drivers/net/de4x5.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/de4x5.c Tue Jan 8 01:17:10 2002 @@ -3652,7 +3652,7 @@ tmp = virt_to_bus(p->data); i = ((tmp + ALIGN) & ~ALIGN) - tmp; skb_reserve(p, i); - lp->rx_ring[index].buf = tmp + i; + lp->rx_ring[index].buf = cpu_to_le32(tmp + i); ret = lp->rx_skb[index]; lp->rx_skb[index] = p; @@ -5623,7 +5623,7 @@ if (!capable(CAP_NET_ADMIN)) return -EPERM; omr = inl(DE4X5_OMR); omr &= ~OMR_PR; - outb(omr, DE4X5_OMR); + outl(omr, DE4X5_OMR); dev->flags &= ~IFF_PROMISC; break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/defxx.c linux-2.5/drivers/net/defxx.c --- linux-2.5.1/drivers/net/defxx.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/defxx.c Wed Jan 2 17:23:52 2002 @@ -500,7 +500,7 @@ static int __init dfx_eisa_init(void) { - int rc = -NODEV; + int rc = -ENODEV; int i; /* used in for loops */ u16 port; /* temporary I/O (port) address */ u32 slot_id; /* EISA hardware (slot) ID read from adapter */ @@ -3360,7 +3360,7 @@ static struct pci_driver dfx_driver = { name: "defxx", probe: dfx_init_one, - remove: dfx_remove_one, + remove: __devexit_p(dfx_remove_one), id_table: dfx_pci_tbl, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/dl2k.c linux-2.5/drivers/net/dl2k.c --- linux-2.5.1/drivers/net/dl2k.c Mon Nov 19 23:19:42 2001 +++ linux-2.5/drivers/net/dl2k.c Thu Dec 27 16:32:31 2001 @@ -15,18 +15,22 @@ 0.01 2001/05/03 Created DL2000-based linux driver 0.02 2001/05/21 Added VLAN and hardware checksum support. 1.00 2001/06/26 Added jumbo frame support. - 1.01 2001/08/21 Added two parameters, int_count and int_timeout. + 1.01 2001/08/21 Added two parameters, rx_coalesce and rx_timeout. 1.02 2001/10/08 Supported fiber media. Added flow control parameters. - 1.03 2001/10/12 Changed the default media to 1000mbps_fd for the - fiber devices. - 1.04 2001/11/08 Fixed a bug which Tx stop when a very busy case. + 1.03 2001/10/12 Changed the default media to 1000mbps_fd for + the fiber devices. + 1.04 2001/11/08 Fixed Tx stopped when tx very busy. + 1.05 2001/11/22 Fixed Tx stopped when unidirectional tx busy. + 1.06 2001/12/13 Fixed disconnect bug at 10Mbps mode. + Fixed tx_full flag incorrect. + Added tx_coalesce paramter. */ #include "dl2k.h" static char version[] __devinitdata = - KERN_INFO "D-Link DL2000-based linux driver v1.04 2001/11/08\n"; + KERN_INFO "D-Link DL2000-based linux driver v1.06 2001/12/13\n"; #define MAX_UNITS 8 static int mtu[MAX_UNITS]; @@ -36,11 +40,13 @@ static int tx_flow[MAX_UNITS]; static int rx_flow[MAX_UNITS]; static int copy_thresh; -static int int_count; /* Rx frame count each interrupt */ -static int int_timeout; /* Rx DMA wait time in 64ns increments */ +static int rx_coalesce = 5; /* Rx frame count each interrupt */ +static int rx_timeout = 750; /* Rx DMA wait time in 64ns increments */ +static int tx_coalesce = 8; /* HW xmit count each TxComplete */ MODULE_AUTHOR ("Edward Peng"); MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter"); +MODULE_LICENSE("GPL"); MODULE_PARM (mtu, "1-" __MODULE_STRING (MAX_UNITS) "i"); MODULE_PARM (media, "1-" __MODULE_STRING (MAX_UNITS) "s"); MODULE_PARM (vlan, "1-" __MODULE_STRING (MAX_UNITS) "i"); @@ -48,13 +54,15 @@ MODULE_PARM (tx_flow, "1-" __MODULE_STRING (MAX_UNITS) "i"); MODULE_PARM (rx_flow, "1-" __MODULE_STRING (MAX_UNITS) "i"); MODULE_PARM (copy_thresh, "i"); -MODULE_PARM (int_count, "i"); -MODULE_PARM (int_timeout, "i"); +MODULE_PARM (rx_coalesce, "i"); +MODULE_PARM (rx_timeout, "i"); +MODULE_PARM (tx_coalesce, "i"); /* Enable the default interrupts */ +#define DEFAULT_INTR (RxDMAComplete | HostError | IntRequested | TxComplete| \ + UpdateStats | LinkEvent) #define EnableInt() \ -writew(RxDMAComplete | HostError | IntRequested | TxComplete| \ - UpdateStats | LinkEvent, ioaddr + IntEnable) +writew(DEFAULT_INTR, ioaddr + IntEnable) static int max_intrloop = 50; static int multicast_filter_limit = 0x40; @@ -163,11 +171,11 @@ np->speed = 10; np->full_duplex = 0; } else if (strcmp (media[card_idx], "1000mbps_fd") == 0 || - strcmp (media[card_idx], "5") == 0) { + strcmp (media[card_idx], "6") == 0) { np->speed=1000; np->full_duplex=1; } else if (strcmp (media[card_idx], "1000mbps_hd") == 0 || - strcmp (media[card_idx], "6") == 0) { + strcmp (media[card_idx], "5") == 0) { np->speed = 1000; np->full_duplex = 0; } else { @@ -176,7 +184,7 @@ } if (jumbo[card_idx] != 0) { np->jumbo = 1; - dev->mtu = 9000; + dev->mtu = MAX_JUMBO; } else { np->jumbo = 0; if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE) @@ -184,14 +192,15 @@ } np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ? vlan[card_idx] : 0; - if (int_count != 0 && int_timeout != 0) { - np->int_count = int_count; - np->int_timeout = int_timeout; + if (rx_coalesce != 0 && rx_timeout != 0) { + np->rx_coalesce = rx_coalesce; + np->rx_timeout = rx_timeout; np->coalesce = 1; } np->tx_flow = (tx_flow[card_idx]) ? 1 : 0; np->rx_flow = (rx_flow[card_idx]) ? 1 : 0; - + if (tx_coalesce < 1) + tx_coalesce = 1; } dev->open = &rio_open; dev->hard_start_xmit = &start_xmit; @@ -202,8 +211,8 @@ dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->change_mtu = &change_mtu; -#ifdef TX_HW_CHECKSUM - dev->features = NETIF_F_SG | NETIF_F_HW_CSUM; +#if 0 + dev->features = NETIF_F_IP_CSUM; #endif pci_set_drvdata (pdev, dev); @@ -389,13 +398,12 @@ i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; - /* DebugCtrl bit 4, 5, 9 must set */ writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl); /* Jumbo frame */ if (np->jumbo != 0) - writew (9014, ioaddr + MaxFrameSize); + writew (MAX_JUMBO+14, ioaddr + MaxFrameSize); alloc_list (dev); @@ -405,7 +413,7 @@ set_multicast (dev); if (np->coalesce) { - writel (np->int_count | np->int_timeout << 16, + writel (np->rx_coalesce | np->rx_timeout << 16, ioaddr + RxDMAIntCtrl); } /* Set RIO to poll every N*320nsec. */ @@ -442,13 +450,31 @@ struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; - printk (KERN_WARNING "%s: Transmit timed out, TxStatus %4.4x.\n", + printk (KERN_INFO "%s: Tx timed out (%4.4x), is buffer full?\n", dev->name, readl (ioaddr + TxStatus)); + /* Free used tx skbuffs */ + for (; np->cur_tx - np->old_tx > 0; np->old_tx++) { + int entry = np->old_tx % TX_RING_SIZE; + struct sk_buff *skb; + + if (!(np->tx_ring[entry].status & TFDDone)) + break; + skb = np->tx_skbuff[entry]; + pci_unmap_single (np->pdev, + np->tx_ring[entry].fraginfo, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq (skb); + np->tx_skbuff[entry] = 0; + } dev->if_port = 0; dev->trans_start = jiffies; np->stats.tx_errors++; - if (!np->tx_full) + /* If the ring is no longer full, clear tx_full and + call netif_wake_queue() */ + if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) { + np->tx_full = 0; netif_wake_queue (dev); + } } /* allocate and initialize Tx and Rx descriptors */ @@ -466,16 +492,19 @@ /* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */ for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = 0; - np->tx_ring[i].status = 0; + np->tx_ring[i].status = cpu_to_le64 (TFDDone); + np->tx_ring[i].next_desc = cpu_to_le64 (np->tx_ring_dma + + ((i+1)%TX_RING_SIZE) * + sizeof (struct + netdev_desc)); } /* Initialize Rx descriptors */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma + - ((i + - 1) % RX_RING_SIZE) * - sizeof (struct - netdev_desc)); + ((i + 1) % RX_RING_SIZE) * + sizeof (struct + netdev_desc)); np->rx_ring[i].status = 0; np->rx_ring[i].fraginfo = 0; np->rx_skbuff[i] = 0; @@ -523,13 +552,12 @@ entry = np->cur_tx % TX_RING_SIZE; np->tx_skbuff[entry] = skb; txdesc = &np->tx_ring[entry]; - txdesc->next_desc = 0; /* Set TFDDone to avoid TxDMA gather this descriptor */ txdesc->status = cpu_to_le64 (TFDDone); txdesc->status |= cpu_to_le64 (entry | WordAlignDisable | (1 << FragCountShift)); -#ifdef TX_HW_CHECKSUM +#if 0 if (skb->ip_summed == CHECKSUM_HW) { txdesc->status |= cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable | @@ -545,21 +573,13 @@ /* Send one packet each time at 10Mbps mode */ /* Tx coalescing loop do not exceed 8 */ - if (entry % 0x08 == 0 || np->speed == 10) + if (entry % tx_coalesce == 0 || np->speed == 10) txdesc->status |= cpu_to_le64 (TxIndicate); txdesc->fraginfo = cpu_to_le64 (pci_map_single (np->pdev, skb->data, skb->len, PCI_DMA_TODEVICE)); txdesc->fraginfo |= cpu_to_le64 (skb->len) << 48; - /* Chain the last descriptor's pointer to this one */ - if (np->last_tx) - np->last_tx->next_desc = cpu_to_le64 (np->tx_ring_dma + - entry * - sizeof (struct - netdev_desc)); - np->last_tx = txdesc; - /* Clear TFDDone, then TxDMA start to send this descriptor */ txdesc->status &= ~cpu_to_le64 (TFDDone); @@ -571,8 +591,10 @@ if (np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1 && np->speed != 10) { /* do nothing */ } else { + spin_lock_irqsave(&np->lock, flags); np->tx_full = 1; netif_stop_queue (dev); + spin_unlock_irqrestore (&np->lock, flags); } /* The first TFDListPtr */ @@ -581,15 +603,15 @@ dev->base_addr + TFDListPtr0); writel (0, dev->base_addr + TFDListPtr1); } - - spin_lock_irqsave (&np->lock, flags); + if (np->old_tx > TX_RING_SIZE) { + spin_lock_irqsave (&np->lock, flags); tx_shift = TX_RING_SIZE; np->old_tx -= tx_shift; np->cur_tx -= tx_shift; + spin_unlock_irqrestore (&np->lock, flags); } - spin_unlock_irqrestore (&np->lock, flags); - + /* NETDEV WATCHDOG timer */ dev->trans_start = jiffies; return 0; @@ -606,33 +628,24 @@ ioaddr = dev->base_addr; np = dev->priv; - spin_lock (&np->lock); + spin_lock(&np->lock); while (1) { - int_status = readw (ioaddr + IntStatus) & - (HostError | TxComplete | IntRequested | - UpdateStats | LinkEvent | RxDMAComplete); - writew (int_status & (HostError | TxComplete | RxComplete | - IntRequested | UpdateStats | LinkEvent | - TxDMAComplete | RxDMAComplete | RFDListEnd - | RxDMAPriority), ioaddr + IntStatus); + int_status = readw (ioaddr + IntStatus); + writew (int_status, ioaddr + IntStatus); + int_status &= DEFAULT_INTR; if (int_status == 0) break; /* Processing received packets */ if (int_status & RxDMAComplete) receive_packet (dev); /* TxComplete interrupt */ - if (int_status & TxComplete || np->tx_full) { - int tx_status = readl (ioaddr + TxStatus); + if ((int_status & TxComplete) || np->tx_full) { + int tx_status; + tx_status = readl (ioaddr + TxStatus); if (tx_status & 0x01) tx_error (dev, tx_status); - /* Send one packet each time at 10Mbps mode */ - if (np->speed == 10) { - np->tx_full = 0; - netif_wake_queue (dev); - } - /* Free used tx skbuffs */ - for (; np->cur_tx - np->old_tx > 0; np->old_tx++) { + for (;np->cur_tx - np->old_tx > 0; np->old_tx++) { int entry = np->old_tx % TX_RING_SIZE; struct sk_buff *skb; @@ -649,9 +662,12 @@ /* If the ring is no longer full, clear tx_full and call netif_wake_queue() */ if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) { - np->tx_full = 0; - netif_wake_queue (dev); + if (np->speed != 10 || int_status & TxComplete) { + np->tx_full = 0; + netif_wake_queue (dev); + } } + /* Handle uncommon events */ if (int_status & (IntRequested | HostError | LinkEvent | UpdateStats)) @@ -666,7 +682,7 @@ break; } } - spin_unlock (&np->lock); + spin_unlock(&np->lock); } static void @@ -742,7 +758,7 @@ np->stats.collisions++; #endif - /* Restart the Tx. */ + /* Restart the Tx */ writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl); } @@ -808,7 +824,7 @@ skb_put (skb, pkt_len); } skb->protocol = eth_type_trans (skb, dev); -#ifdef RX_HW_CHECKSUM +#if 0 /* Checksum done by hw, but csum value unavailable. */ if (!(frame_status & (TCPError | UDPError | IPError))) { skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -899,7 +915,7 @@ /* PCI Error, a catastronphic error related to the bus interface occurs, set GlobalReset and HostReset to reset. */ if (int_status & HostError) { - printk (KERN_ERR "%s: PCI Error! IntStatus %4.4x.\n", + printk (KERN_ERR "%s: HostError! IntStatus %4.4x.\n", dev->name, int_status); writew (GlobalReset | HostReset, ioaddr + ASICCtrl + 2); mdelay (500); @@ -914,8 +930,8 @@ u16 temp1; u16 temp2; int i; - /* All statistics registers need to acknowledge, - else overflow could cause some problem */ + /* All statistics registers need to be acknowledged, + else statistic overflow could cause problems */ np->stats.rx_packets += readl (ioaddr + FramesRcvOk); np->stats.tx_packets += readl (ioaddr + FramesXmtOk); np->stats.rx_bytes += readl (ioaddr + OctetRcvOk); @@ -961,7 +977,7 @@ change_mtu (struct net_device *dev, int new_mtu) { struct netdev_private *np = dev->priv; - int max = (np->jumbo) ? 9000 : 1536; + int max = (np->jumbo) ? MAX_JUMBO : 1536; if ((new_mtu < 68) || (new_mtu > max)) { return -EINVAL; @@ -1671,7 +1687,7 @@ name:"dl2k", id_table:rio_pci_tbl, probe:rio_probe1, - remove:rio_remove1, + remove:__devexit_p(rio_remove1), }; static int __init @@ -1693,8 +1709,9 @@ Compile command: -gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2x.c +gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2k.c Read Documentation/networking/dl2k.txt for details. */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/dl2k.h linux-2.5/drivers/net/dl2k.h --- linux-2.5.1/drivers/net/dl2k.h Mon Nov 19 23:19:42 2001 +++ linux-2.5/drivers/net/dl2k.h Mon Jan 7 21:37:26 2002 @@ -33,7 +33,7 @@ #include <linux/spinlock.h> #include <linux/time.h> #define TX_RING_SIZE 128 -#define TX_QUEUE_LEN 96 /* Limit ring entries actually used. */ +#define TX_QUEUE_LEN 120 /* Limit ring entries actually used. */ #define RX_RING_SIZE 128 #define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct netdev_desc) #define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct netdev_desc) @@ -649,13 +649,13 @@ struct pci_dev *pdev; spinlock_t lock; struct net_device_stats stats; - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - unsigned int speed; /* Operating speed */ - unsigned int vlan; /* VLAN Id */ - unsigned int chip_id; /* PCI table chip id */ - unsigned int int_count; /* Maximum frames each RxDMAComplete intr */ - unsigned int int_timeout; /* Wait time between RxDMAComplete intr */ - unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int speed; /* Operating speed */ + unsigned int vlan; /* VLAN Id */ + unsigned int chip_id; /* PCI table chip id */ + unsigned int rx_coalesce; /* Maximum frames each RxDMAComplete intr */ + unsigned int rx_timeout; /* Wait time between RxDMAComplete intr */ + unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int an_enable:2; /* Auto-Negotiated Enable */ unsigned int jumbo:1; /* Jumbo frame enable */ @@ -697,6 +697,7 @@ MODULE_DEVICE_TABLE (pci, rio_pci_tbl); #define TX_TIMEOUT (4*HZ) #define PACKET_SIZE 1536 +#define MAX_JUMBO 8000 #define RIO_IO_SIZE 340 #ifdef RIO_DEBUG #define DEBUG_TFD_DUMP(x) debug_tfd_dump(x) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/eepro100.c linux-2.5/drivers/net/eepro100.c --- linux-2.5.1/drivers/net/eepro100.c Mon Nov 12 17:47:18 2001 +++ linux-2.5/drivers/net/eepro100.c Thu Jan 10 13:32:21 2002 @@ -168,6 +168,9 @@ #ifndef PCI_DEVICE_ID_INTEL_ID1030 #define PCI_DEVICE_ID_INTEL_ID1030 0x1030 #endif +#ifndef PCI_DEVICE_ID_INTEL_ID1038 +#define PCI_DEVICE_ID_INTEL_ID1038 0x1038 +#endif static int speedo_debug = 1; @@ -2267,12 +2270,32 @@ PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CAM, + PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1038, + PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_7, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1032, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1033, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1034, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1038, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1227, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1228, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x5200, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x5201, + PCI_ANY_ID, PCI_ANY_ID, }, { 0,} }; MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl); @@ -2281,7 +2304,7 @@ name: "eepro100", id_table: eepro100_pci_tbl, probe: eepro100_init_one, - remove: eepro100_remove_one, + remove: __devexit_p(eepro100_remove_one), #ifdef CONFIG_PM suspend: eepro100_suspend, resume: eepro100_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/epic100.c linux-2.5/drivers/net/epic100.c --- linux-2.5.1/drivers/net/epic100.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/epic100.c Thu Dec 13 16:32:36 2001 @@ -1507,7 +1507,7 @@ name: DRV_NAME, id_table: epic_pci_tbl, probe: epic_init_one, - remove: epic_remove_one, + remove: __devexit_p(epic_remove_one), #ifdef CONFIG_PM suspend: epic_suspend, resume: epic_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/fc/iph5526.c linux-2.5/drivers/net/fc/iph5526.c --- linux-2.5.1/drivers/net/fc/iph5526.c Wed Nov 28 18:22:27 2001 +++ linux-2.5/drivers/net/fc/iph5526.c Thu Dec 27 22:10:28 2001 @@ -4534,14 +4534,14 @@ { int i = 0; - driver_template.module = &__this_module; - scsi_register_module(MODULE_SCSI_HA, &driver_template); + driver_template.module = THIS_MODULE; + scsi_register_host(&driver_template); if (driver_template.present) scsi_registered = TRUE; else { printk("iph5526: SCSI registeration failed!!!\n"); scsi_registered = FALSE; - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + scsi_unregister_host(&driver_template); } while(fc[i] != NULL) { @@ -4590,7 +4590,7 @@ i++; } if (scsi_registered == TRUE) - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + scsi_unregister_host(&driver_template); } #endif /* MODULE */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/fealnx.c linux-2.5/drivers/net/fealnx.c --- linux-2.5.1/drivers/net/fealnx.c Mon Nov 19 23:19:42 2001 +++ linux-2.5/drivers/net/fealnx.c Thu Dec 13 16:32:36 2001 @@ -1858,7 +1858,7 @@ name: "fealnx", id_table: fealnx_pci_tbl, probe: fealnx_init_one, - remove: fealnx_remove_one, + remove: __devexit_p(fealnx_remove_one), }; static int __init fealnx_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/gmac.c linux-2.5/drivers/net/gmac.c --- linux-2.5.1/drivers/net/gmac.c Wed Oct 17 04:56:29 2001 +++ linux-2.5/drivers/net/gmac.c Thu Dec 27 16:32:31 2001 @@ -36,7 +36,8 @@ #include <asm/prom.h> #include <asm/io.h> #include <asm/pgtable.h> -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #include <asm/keylargo.h> #include <asm/pci-bridge.h> #ifdef CONFIG_PMAC_PBOOK @@ -296,6 +297,7 @@ } } +#ifdef CONFIG_PMAC_PBOOK /* Power management: stop PHY chip for suspend mode * * TODO: This will have to be modified is WOL is to be supported. @@ -441,6 +443,7 @@ GM_OUT(GM_RX_CONF, 0); } } +#endif static int mii_do_reset_phy(struct gmac *gm, int phy_addr) @@ -585,8 +588,8 @@ gm->phy_type = PHY_UNKNOWN; /* Hard reset the PHY */ - feature_gmac_phy_reset(gm->of_node); - + pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gm->of_node, 0, 0); + /* Find the PHY */ for(i=0; i<=31; i++) { mii_control = mii_read(gm, i, MII_CR); @@ -683,7 +686,7 @@ gmac_set_power(struct gmac *gm, int power_up) { if (power_up) { - feature_set_gmac_power(gm->of_node, 1); + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gm->of_node, 0, 1); if (gm->pci_devfn != 0xff) { u16 cmd; @@ -708,7 +711,7 @@ PCI_CACHE_LINE_SIZE, 8); } } else { - feature_set_gmac_power(gm->of_node, 0); + pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gm->of_node, 0, 0); } } @@ -1617,6 +1620,11 @@ SET_MODULE_OWNER(dev); gm = dev->priv; + gm->of_node = gmac; + if (!request_OF_resource(gmac, 0, " (gmac)")) { + printk(KERN_ERR "GMAC: can't request IO resource !\n"); + goto out_unreg; + } dev->base_addr = gmac->addrs[0].address; gm->regs = (volatile unsigned int *) ioremap(gmac->addrs[0].address, 0x10000); @@ -1626,7 +1634,6 @@ } dev->irq = gmac->intrs[0].line; gm->dev = dev; - gm->of_node = gmac; spin_lock_init(&gm->lock); @@ -1667,6 +1674,8 @@ out_unreg: unregister_netdev(dev); + if (gm->of_node) + release_OF_resource(gm->of_node, 0); kfree(dev); out_rxdesc: free_page(rx_descpage); @@ -1677,6 +1686,7 @@ MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt"); MODULE_DESCRIPTION("PowerMac GMAC driver."); MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; static void __exit gmac_cleanup_module(void) { @@ -1694,6 +1704,7 @@ iounmap((void *) gm->regs); free_page(gm->tx_desc_page); free_page(gm->rx_desc_page); + release_OF_resource(gm->of_node, 0); gmacs = gm->next_gmac; kfree(dev); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/hamradio/6pack.c linux-2.5/drivers/net/hamradio/6pack.c --- linux-2.5.1/drivers/net/hamradio/6pack.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/hamradio/6pack.c Mon Jan 14 22:39:45 2002 @@ -700,7 +700,6 @@ /* Initialize 6pack control device -- register 6pack line discipline */ static char msg_banner[] __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION " (dynamic channels, max=%d)\n"; -static char msg_invparm[] __initdata = KERN_ERR "6pack: sixpack_maxdev parameter too large.\n"; static char msg_nomem[] __initdata = KERN_ERR "6pack: can't allocate sixpack_ctrls[] array! No 6pack available.\n"; static char msg_regfail[] __initdata = KERN_ERR "6pack: can't register line discipline (err = %d)\n"; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/hamradio/bpqether.c linux-2.5/drivers/net/hamradio/bpqether.c --- linux-2.5.1/drivers/net/hamradio/bpqether.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/hamradio/bpqether.c Sun Dec 30 21:17:30 2001 @@ -69,7 +69,6 @@ #include <linux/if_arp.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/hamradio/dmascc.c linux-2.5/drivers/net/hamradio/dmascc.c --- linux-2.5.1/drivers/net/hamradio/dmascc.c Wed Apr 18 21:40:06 2001 +++ linux-2.5/drivers/net/hamradio/dmascc.c Sun Dec 30 21:17:30 2001 @@ -43,7 +43,6 @@ #include <asm/dma.h> #include <asm/io.h> #include <asm/irq.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <net/ax25.h> #include "z8530.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/hamradio/mkiss.c linux-2.5/drivers/net/hamradio/mkiss.c --- linux-2.5.1/drivers/net/hamradio/mkiss.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/hamradio/mkiss.c Sun Dec 30 21:17:30 2001 @@ -27,7 +27,6 @@ #include <linux/config.h> #include <linux/module.h> #include <asm/system.h> -#include <asm/segment.h> #include <asm/bitops.h> #include <asm/uaccess.h> #include <linux/string.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/ioc3-eth.c linux-2.5/drivers/net/ioc3-eth.c --- linux-2.5.1/drivers/net/ioc3-eth.c Wed Oct 17 04:56:29 2001 +++ linux-2.5/drivers/net/ioc3-eth.c Thu Dec 13 16:32:36 2001 @@ -1515,7 +1515,7 @@ name: "ioc3-eth", id_table: ioc3_pci_tbl, probe: ioc3_probe, - remove: ioc3_remove_one, + remove: __devexit_p(ioc3_remove_one), }; static int __init ioc3_init_module(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/irda/ali-ircc.c linux-2.5/drivers/net/irda/ali-ircc.c --- linux-2.5.1/drivers/net/irda/ali-ircc.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/irda/ali-ircc.c Mon Jan 14 22:39:45 2002 @@ -291,15 +291,13 @@ self->io.fifo_size = 16; /* SIR: 16, FIR: 32 Benjamin 2000/11/1 */ /* Reserve the ioports that we need */ - ret = check_region(self->io.fir_base, self->io.fir_ext); - if (ret < 0) { + if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) { WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", self->io.fir_base); dev_self[i] = NULL; kfree(self); return -ENODEV; } - request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/irda/irda-usb.c linux-2.5/drivers/net/irda/irda-usb.c --- linux-2.5.1/drivers/net/irda/irda-usb.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/net/irda/irda-usb.c Tue Jan 1 23:42:42 2002 @@ -112,9 +112,9 @@ 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 speed_bulk_callback(purb_t purb); -static void write_bulk_callback(purb_t purb); -static void irda_usb_receive(purb_t purb); +static void speed_bulk_callback(struct urb *urb); +static void write_bulk_callback(struct urb *urb); +static void irda_usb_receive(struct urb *urb); 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); @@ -248,15 +248,15 @@ { unsigned long flags; __u8 *frame; - purb_t purb; + struct urb *urb; int ret; IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n", self->new_speed, self->new_xbofs); /* Grab the speed URB */ - purb = &self->speed_urb; - if (purb->status != 0) { + urb = &self->speed_urb; + if (urb->status != 0) { WARNING(__FUNCTION__ "(), URB still in use!\n"); return; } @@ -270,15 +270,15 @@ irda_usb_build_header(self, frame, 1); /* Submit the 0 length IrDA frame to trigger new speed settings */ - FILL_BULK_URB(purb, self->usbdev, + FILL_BULK_URB(urb, self->usbdev, usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), frame, IRDA_USB_SPEED_MTU, speed_bulk_callback, self); - purb->transfer_buffer_length = USB_IRDA_HEADER; - purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK; - purb->timeout = MSECS_TO_JIFFIES(100); + urb->transfer_buffer_length = USB_IRDA_HEADER; + urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK; + urb->timeout = MSECS_TO_JIFFIES(100); - if ((ret = usb_submit_urb(purb))) { + if ((ret = usb_submit_urb(urb))) { WARNING(__FUNCTION__ "(), failed Speed URB\n"); } spin_unlock_irqrestore(&self->lock, flags); @@ -288,9 +288,9 @@ /* * Note : this function will be called with both speed_urb and empty_urb... */ -static void speed_bulk_callback(purb_t purb) +static void speed_bulk_callback(struct urb *urb) { - struct irda_usb_cb *self = purb->context; + struct irda_usb_cb *self = urb->context; IRDA_DEBUG(2, __FUNCTION__ "()\n"); @@ -301,9 +301,9 @@ } /* Check for timeout and other USB nasties */ - if (purb->status != 0) { + if (urb->status != 0) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", urb->status, urb->transfer_flags); /* Don't do anything here, that might confuse the USB layer. * Instead, we will wait for irda_usb_net_timeout(), the @@ -314,10 +314,10 @@ } /* urb is now available */ - purb->status = 0; + urb->status = 0; /* If it was the speed URB, allow the stack to send more packets */ - if(purb == &self->speed_urb) { + if(urb == &self->speed_urb) { netif_wake_queue(self->netdev); } } @@ -329,7 +329,7 @@ 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; + struct urb *urb = &self->tx_urb; unsigned long flags; s32 speed; s16 xbofs; @@ -372,7 +372,7 @@ } } - if (purb->status != 0) { + if (urb->status != 0) { WARNING(__FUNCTION__ "(), URB still in use!\n"); dev_kfree_skb(skb); return 0; @@ -392,22 +392,22 @@ /* FIXME: Make macro out of this one */ ((struct irda_skb_cb *)skb->cb)->context = self; - FILL_BULK_URB(purb, self->usbdev, + FILL_BULK_URB(urb, 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; + urb->transfer_buffer_length = skb->len; /* Note : unlink *must* be Asynchronous because of the code in * irda_usb_net_timeout() -> call in irq - Jean II */ - purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK; + urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK; /* This flag (USB_ZERO_PACKET) indicates that what we send is not * a continuous stream of data but separate packets. * In this case, the USB layer will insert an empty USB frame (TD) * after each of our packets that is exact multiple of the frame size. * This is how the dongle will detect the end of packet - Jean II */ - purb->transfer_flags |= USB_ZERO_PACKET; + urb->transfer_flags |= USB_ZERO_PACKET; /* Timeout need to be shorter than NET watchdog timer */ - purb->timeout = MSECS_TO_JIFFIES(200); + urb->timeout = MSECS_TO_JIFFIES(200); /* Generate min turn time. FIXME: can we do better than this? */ /* Trying to a turnaround time at this level is trying to measure @@ -451,7 +451,7 @@ } /* Ask USB to send the packet */ - if ((res = usb_submit_urb(purb))) { + if ((res = usb_submit_urb(urb))) { WARNING(__FUNCTION__ "(), failed Tx URB\n"); self->stats.tx_errors++; /* Let USB recover : We will catch that in the watchdog */ @@ -472,9 +472,9 @@ /* * Note : this function will be called only for tx_urb... */ -static void write_bulk_callback(purb_t purb) +static void write_bulk_callback(struct urb *urb) { - struct sk_buff *skb = purb->context; + struct sk_buff *skb = urb->context; struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context; IRDA_DEBUG(2, __FUNCTION__ "()\n"); @@ -487,12 +487,12 @@ /* Free up the skb */ dev_kfree_skb_any(skb); - purb->context = NULL; + urb->context = NULL; /* Check for timeout and other USB nasties */ - if (purb->status != 0) { + if (urb->status != 0) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", urb->status, urb->transfer_flags); /* Don't do anything here, that might confuse the USB layer, * and we could go in recursion and blow the kernel stack... @@ -504,7 +504,7 @@ } /* urb is now available */ - purb->status = 0; + urb->status = 0; /* If the network is closed, stop everything */ if ((!self->netopen) || (!self->present)) { @@ -534,7 +534,7 @@ static void irda_usb_net_timeout(struct net_device *netdev) { struct irda_usb_cb *self = netdev->priv; - purb_t purb; + struct urb *urb; int done = 0; /* If we have made any progress */ IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n"); @@ -546,13 +546,13 @@ } /* Check speed URB */ - purb = &(self->speed_urb); - if (purb->status != 0) { - IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); + urb = &(self->speed_urb); + if (urb->status != 0) { + IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags); - switch (purb->status) { + switch (urb->status) { case -EINPROGRESS: - usb_unlink_urb(purb); + usb_unlink_urb(urb); /* Note : above will *NOT* call netif_wake_queue() * in completion handler, we will come back here. * Jean II */ @@ -563,7 +563,7 @@ case -ETIMEDOUT: /* -110 */ case -ENOENT: /* -2 (urb unlinked by us) */ default: /* ??? - Play safe */ - purb->status = 0; + urb->status = 0; netif_wake_queue(self->netdev); done = 1; break; @@ -571,11 +571,11 @@ } /* Check Tx URB */ - purb = &(self->tx_urb); - if (purb->status != 0) { - struct sk_buff *skb = purb->context; + urb = &(self->tx_urb); + if (urb->status != 0) { + struct sk_buff *skb = urb->context; - IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); + IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags); /* Increase error count */ self->stats.tx_errors++; @@ -589,11 +589,11 @@ irda_usb_change_speed_xbofs(self); #endif /* IU_BUG_KICK_TIMEOUT */ - switch (purb->status) { + switch (urb->status) { case -EINPROGRESS: - usb_unlink_urb(purb); + usb_unlink_urb(urb); /* Note : above will *NOT* call netif_wake_queue() - * in completion handler, because purb->status will + * in completion handler, because urb->status will * be -ENOENT. We will fix that at the next watchdog, * leaving more time to USB to recover... * Also, we are in interrupt, so we need to have @@ -608,9 +608,9 @@ default: /* ??? - Play safe */ if(skb != NULL) { dev_kfree_skb_any(skb); - purb->context = NULL; + urb->context = NULL; } - purb->status = 0; + urb->status = 0; netif_wake_queue(self->netdev); done = 1; break; @@ -685,7 +685,7 @@ * * Jean II */ -static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb) +static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *urb) { struct irda_skb_cb *cb; int ret; @@ -693,8 +693,8 @@ IRDA_DEBUG(2, __FUNCTION__ "()\n"); /* Check that we have an urb */ - if (!purb) { - WARNING(__FUNCTION__ "(), Bug : purb == NULL\n"); + if (!urb) { + WARNING(__FUNCTION__ "(), Bug : urb == NULL\n"); return; } @@ -720,17 +720,17 @@ cb->context = self; /* Reinitialize URB */ - FILL_BULK_URB(purb, self->usbdev, + FILL_BULK_URB(urb, self->usbdev, usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), skb->data, skb->truesize, irda_usb_receive, skb); - purb->transfer_flags = USB_QUEUE_BULK; + urb->transfer_flags = USB_QUEUE_BULK; /* Note : unlink *must* be synchronous because of the code in * irda_usb_net_close() -> free the skb - Jean II */ - purb->status = 0; - purb->next = NULL; /* Don't auto resubmit URBs */ + urb->status = 0; + urb->next = NULL; /* Don't auto resubmit URBs */ - ret = usb_submit_urb(purb); + ret = usb_submit_urb(urb); if (ret) { /* If this ever happen, we are in deep s***. * Basically, the Rx path will stop... */ @@ -740,19 +740,19 @@ /*------------------------------------------------------------------*/ /* - * Function irda_usb_receive(purb) + * Function irda_usb_receive(urb) * * Called by the USB subsystem when a frame has been received * */ -static void irda_usb_receive(purb_t purb) +static void irda_usb_receive(struct urb *urb) { - struct sk_buff *skb = (struct sk_buff *) purb->context; + struct sk_buff *skb = (struct sk_buff *) urb->context; struct irda_usb_cb *self; struct irda_skb_cb *cb; struct sk_buff *new; - IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", purb->actual_length); + IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", urb->actual_length); /* Find ourselves */ cb = (struct irda_skb_cb *) skb->cb; @@ -768,27 +768,27 @@ } /* Check the status */ - if (purb->status != 0) { - switch (purb->status) { + if (urb->status != 0) { + switch (urb->status) { case -EILSEQ: self->stats.rx_errors++; self->stats.rx_crc_errors++; break; case -ECONNRESET: /* -104 */ - IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", urb->transfer_flags); /* 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: - IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", urb->status, urb->transfer_flags); break; } goto done; } /* Check for empty frames */ - if (purb->actual_length <= USB_IRDA_HEADER) { + if (urb->actual_length <= USB_IRDA_HEADER) { WARNING(__FUNCTION__ "(), empty frame!\n"); goto done; } @@ -801,7 +801,7 @@ get_fast_time(&self->stamp); /* Fix skb, and remove USB-IrDA header */ - skb_put(skb, purb->actual_length); + skb_put(skb, urb->actual_length); skb_pull(skb, USB_IRDA_HEADER); /* Don't waste a lot of memory on small IrDA frames */ @@ -834,7 +834,7 @@ netif_rx(new); done: - /* Note : at this point, the URB we've just received (purb) + /* Note : at this point, the URB we've just received (urb) * is still referenced by the USB layer. For example, if we * have received a -ECONNRESET, uhci_cleanup_unlink() will * continue to process it (in fact, cleaning it up). @@ -848,8 +848,8 @@ /* Submit the idle URB to replace the URB we've just received */ irda_usb_submit(self, skb, self->idle_rx_urb); /* Recycle Rx URB : Now, the idle URB is the present one */ - self->idle_rx_urb = purb; - purb->context = NULL; + self->idle_rx_urb = urb; + urb->context = NULL; } /*------------------------------------------------------------------*/ @@ -992,14 +992,14 @@ /* 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; + struct urb *urb = &(self->rx_urb[i]); + struct sk_buff *skb = (struct sk_buff *) urb->context; /* Cancel the receive command */ - usb_unlink_urb(purb); + usb_unlink_urb(urb); /* The skb is ours, free it */ if(skb) { dev_kfree_skb(skb); - purb->context = NULL; + urb->context = NULL; } } /* Cancel Tx and speed URB */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/irda/irport.c linux-2.5/drivers/net/irda/irport.c --- linux-2.5.1/drivers/net/irda/irport.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/irda/irport.c Thu Jan 10 13:32:21 2002 @@ -140,7 +140,7 @@ { struct net_device *dev; struct irport_cb *self; - int ret; + void *ret; int err; IRDA_DEBUG(0, __FUNCTION__ "()\n"); @@ -169,13 +169,12 @@ self->io.fifo_size = 16; /* Lock the port that we need */ - ret = check_region(self->io.sir_base, self->io.sir_ext); - if (ret < 0) { + ret = request_region(self->io.sir_base, self->io.sir_ext, driver_name); + if (!ret) { IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", self->io.sir_base); return NULL; } - request_region(self->io.sir_base, self->io.sir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/irda/irtty.c linux-2.5/drivers/net/irda/irtty.c --- linux-2.5.1/drivers/net/irda/irtty.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/irda/irtty.c Wed Jan 2 17:23:52 2002 @@ -32,7 +32,6 @@ #include <linux/if_arp.h> #include <linux/rtnetlink.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <net/irda/irda.h> @@ -173,7 +172,7 @@ /* Give self a name */ sprintf(name, "%s%d", tty->driver.name, - MINOR(tty->device) - tty->driver.minor_start + + minor(tty->device) - tty->driver.minor_start + tty->driver.name_base); hashbin_insert(irtty, (irda_queue_t *) self, (int) self, NULL); @@ -911,7 +910,7 @@ /* Give self a hardware name */ sprintf(hwname, "%s%d", tty->driver.name, - MINOR(tty->device) - tty->driver.minor_start + + minor(tty->device) - tty->driver.minor_start + tty->driver.name_base); /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/irda/nsc-ircc.c linux-2.5/drivers/net/irda/nsc-ircc.c --- linux-2.5.1/drivers/net/irda/nsc-ircc.c Fri Oct 5 01:41:09 2001 +++ linux-2.5/drivers/net/irda/nsc-ircc.c Thu Jan 10 13:32:21 2002 @@ -246,7 +246,7 @@ struct net_device *dev; struct nsc_ircc_cb *self; struct pm_dev *pmdev; - int ret; + void *ret; int err; IRDA_DEBUG(2, __FUNCTION__ "()\n"); @@ -282,15 +282,14 @@ self->io.fifo_size = 32; /* Reserve the ioports that we need */ - ret = check_region(self->io.fir_base, self->io.fir_ext); - if (ret < 0) { + ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name); + if (!ret) { WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", self->io.fir_base); dev_self[i] = NULL; kfree(self); return -ENODEV; } - request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/irda/w83977af_ir.c linux-2.5/drivers/net/irda/w83977af_ir.c --- linux-2.5.1/drivers/net/irda/w83977af_ir.c Sun Sep 30 19:26:06 2001 +++ linux-2.5/drivers/net/irda/w83977af_ir.c Thu Jan 10 13:32:21 2002 @@ -160,7 +160,7 @@ { struct net_device *dev; struct w83977af_ir *self; - int ret; + void *ret; int err; IRDA_DEBUG(0, __FUNCTION__ "()\n"); @@ -190,14 +190,13 @@ self->io.fifo_size = 32; /* Lock the port that we need */ - ret = check_region(self->io.fir_base, self->io.fir_ext); - if (ret < 0) { + ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name); + if (!ret) { IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", self->io.fir_base); /* w83977af_cleanup( self); */ return -ENODEV; } - request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/jazzsonic.c linux-2.5/drivers/net/jazzsonic.c --- linux-2.5.1/drivers/net/jazzsonic.c Sun Sep 9 17:43:01 2001 +++ linux-2.5/drivers/net/jazzsonic.c Sun Dec 30 21:17:30 2001 @@ -29,7 +29,6 @@ #include <asm/system.h> #include <asm/bitops.h> #include <asm/pgtable.h> -#include <asm/segment.h> #include <asm/io.h> #include <asm/dma.h> #include <asm/jazz.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/mace.c linux-2.5/drivers/net/mace.c --- linux-2.5.1/drivers/net/mace.c Wed Oct 17 04:56:29 2001 +++ linux-2.5/drivers/net/mace.c Thu Jan 10 22:41:07 2002 @@ -24,18 +24,18 @@ static struct net_device *mace_devs; static int port_aaui = -1; -MODULE_PARM(port_aaui, "i"); -MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)"); +#define N_RX_RING 8 +#define N_TX_RING 6 +#define MAX_TX_ACTIVE 1 +#define NCMDS_TX 1 /* dma commands per element in tx ring */ +#define RX_BUFLEN (ETH_FRAME_LEN + 8) +#define TX_TIMEOUT HZ /* 1 second */ -#define N_RX_RING 8 -#define N_TX_RING 6 -#define MAX_TX_ACTIVE 1 -#define NCMDS_TX 1 /* dma commands per element in tx ring */ -#define RX_BUFLEN (ETH_FRAME_LEN + 8) -#define TX_TIMEOUT HZ /* 1 second */ +/* Chip rev needs workaround on HW & multicast addr change */ +#define BROKEN_ADDRCHG_REV 0x0941 /* Bits in transmit DMA status */ -#define TX_DMA_ERR 0x80 +#define TX_DMA_ERR 0x80 struct mace_data { volatile struct mace *mace; @@ -59,6 +59,8 @@ struct timer_list tx_timeout; int timeout_active; int port_aaui; + int chipid; + struct device_node* of_node; struct net_device *next_mace; }; @@ -152,9 +154,25 @@ SET_MODULE_OWNER(dev); mp = dev->priv; + mp->of_node = mace; + + if (!request_OF_resource(mace, 0, " (mace)")) { + printk(KERN_ERR "MACE: can't request IO resource !\n"); + goto err_out; + } + if (!request_OF_resource(mace, 1, " (mace tx dma)")) { + printk(KERN_ERR "MACE: can't request TX DMA resource !\n"); + goto err_out; + } + + if (!request_OF_resource(mace, 2, " (mace tx dma)")) { + printk(KERN_ERR "MACE: can't request RX DMA resource !\n"); + goto err_out; + } + dev->base_addr = mace->addrs[0].address; mp->mace = (volatile struct mace *) - ioremap(mace->addrs[0].address, 0x1000); + ioremap(mace->addrs[0].address, 0x1000); dev->irq = mace->intrs[0].line; printk(KERN_INFO "%s: MACE at", dev->name); @@ -163,8 +181,10 @@ dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j]; printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); } - printk(", chip revision %d.%d\n", - in_8(&mp->mace->chipid_hi), in_8(&mp->mace->chipid_lo)); + mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) | + in_8(&mp->mace->chipid_lo); + printk(", chip revision %d.%d\n", mp->chipid >> 8, mp->chipid & 0xff); + mp = (struct mace_data *) dev->priv; mp->maccc = ENXMT | ENRCV; @@ -221,6 +241,16 @@ mp->next_mace = mace_devs; mace_devs = dev; + return; + +err_out: + unregister_netdev(dev); + if (mp->of_node) { + release_OF_resource(mp->of_node, 0); + release_OF_resource(mp->of_node, 1); + release_OF_resource(mp->of_node, 2); + } + kfree(dev); } static void dbdma_reset(volatile struct dbdma_regs *dma) @@ -273,14 +303,19 @@ __mace_set_address(dev, dev->dev_addr); /* clear the multicast filter */ - out_8(&mb->iac, ADDRCHG | LOGADDR); - while ((in_8(&mb->iac) & ADDRCHG) != 0) - ; - for (i = 0; i < 8; ++i) { - out_8(&mb->ladrf, 0); + if (mp->chipid == BROKEN_ADDRCHG_REV) + out_8(&mb->iac, LOGADDR); + else { + out_8(&mb->iac, ADDRCHG | LOGADDR); + while ((in_8(&mb->iac) & ADDRCHG) != 0) + ; } + for (i = 0; i < 8; ++i) + out_8(&mb->ladrf, 0); + /* done changing address */ - out_8(&mb->iac, 0); + if (mp->chipid != BROKEN_ADDRCHG_REV) + out_8(&mb->iac, 0); if (mp->port_aaui) out_8(&mb->plscc, PORTSEL_AUI + ENPLSIO); @@ -290,16 +325,23 @@ static void __mace_set_address(struct net_device *dev, void *addr) { - volatile struct mace *mb = ((struct mace_data *) dev->priv)->mace; + struct mace_data *mp = (struct mace_data *) dev->priv; + volatile struct mace *mb = mp->mace; unsigned char *p = addr; int i; /* load up the hardware address */ - out_8(&mb->iac, ADDRCHG | PHYADDR); - while ((in_8(&mb->iac) & ADDRCHG) != 0) - ; + if (mp->chipid == BROKEN_ADDRCHG_REV) + out_8(&mb->iac, PHYADDR); + else { + out_8(&mb->iac, ADDRCHG | PHYADDR); + while ((in_8(&mb->iac) & ADDRCHG) != 0) + ; + } for (i = 0; i < 6; ++i) out_8(&mb->padr, dev->dev_addr[i] = p[i]); + if (mp->chipid != BROKEN_ADDRCHG_REV) + out_8(&mb->iac, 0); } static int mace_set_address(struct net_device *dev, void *addr) @@ -312,7 +354,6 @@ __mace_set_address(dev, addr); - out_8(&mb->iac, 0); /* note: setting ADDRCHG clears ENRCV */ out_8(&mb->maccc, mp->maccc); @@ -557,12 +598,17 @@ printk("\n"); #endif - out_8(&mb->iac, ADDRCHG | LOGADDR); - while ((in_8(&mb->iac) & ADDRCHG) != 0) - ; - for (i = 0; i < 8; ++i) { - out_8(&mb->ladrf, multicast_filter[i]); + if (mp->chipid == BROKEN_ADDRCHG_REV) + out_8(&mb->iac, LOGADDR); + else { + out_8(&mb->iac, ADDRCHG | LOGADDR); + while ((in_8(&mb->iac) & ADDRCHG) != 0) + ; } + for (i = 0; i < 8; ++i) + out_8(&mb->ladrf, multicast_filter[i]); + if (mp->chipid != BROKEN_ADDRCHG_REV) + out_8(&mb->iac, 0); } /* reset maccc */ out_8(&mb->maccc, mp->maccc); @@ -913,7 +959,10 @@ MODULE_AUTHOR("Paul Mackerras"); MODULE_DESCRIPTION("PowerMac MACE driver."); +MODULE_PARM(port_aaui, "i"); +MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)"); MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; static void __exit mace_cleanup (void) { @@ -921,19 +970,23 @@ struct mace_data *mp; while ((dev = mace_devs) != 0) { - mp = (struct mace_data *) mace_devs->priv; - mace_devs = mp->next_mace; + mp = (struct mace_data *) mace_devs->priv; + mace_devs = mp->next_mace; - free_irq(dev->irq, dev); - free_irq(mp->tx_dma_intr, dev); - free_irq(mp->rx_dma_intr, dev); + unregister_netdev(dev); + free_irq(dev->irq, dev); + free_irq(mp->tx_dma_intr, dev); + free_irq(mp->rx_dma_intr, dev); + + release_OF_resource(mp->of_node, 0); + release_OF_resource(mp->of_node, 1); + release_OF_resource(mp->of_node, 2); - unregister_netdev(dev); - kfree(dev); + kfree(dev); } if (dummy_buf != NULL) { - kfree(dummy_buf); - dummy_buf = NULL; + kfree(dummy_buf); + dummy_buf = NULL; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/macsonic.c linux-2.5/drivers/net/macsonic.c --- linux-2.5.1/drivers/net/macsonic.c Wed Oct 17 04:56:29 2001 +++ linux-2.5/drivers/net/macsonic.c Sun Dec 30 21:17:30 2001 @@ -40,7 +40,6 @@ #include <asm/system.h> #include <asm/bitops.h> #include <asm/pgtable.h> -#include <asm/segment.h> #include <asm/io.h> #include <asm/hwtest.h> #include <asm/dma.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/natsemi.c linux-2.5/drivers/net/natsemi.c --- linux-2.5.1/drivers/net/natsemi.c Mon Nov 19 23:19:42 2001 +++ linux-2.5/drivers/net/natsemi.c Mon Jan 14 23:44:46 2002 @@ -100,7 +100,15 @@ * ETHTOOL_* further support (Tim Hockin) version 1.0.13: - * ETHTOOL_[GS]EEPROM support (Tim Hockin) + * ETHTOOL_GEEPROM support (Tim Hockin) + + version 1.0.14: + * Cleanup some messages and autoneg in ethtool (Tim Hockin) + * OOM error handling. + * reinit_ring() instead of {drain,init}_ring(). + * Rx status FIFO overrun bug fixed: + The nic sets that bit instead of IntrRxDone, + just call netdev_rx and hang is gone. TODO: * big endian support with CFG:BEM instead of cpu_to_le32 @@ -108,9 +116,40 @@ * flow control */ +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/timer.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/init.h> +#include <linux/spinlock.h> +#include <linux/ethtool.h> +#include <linux/delay.h> +#include <linux/rtnetlink.h> +#include <linux/mii.h> +#include <asm/processor.h> /* Processor type for cache alignment. */ +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + #define DRV_NAME "natsemi" -#define DRV_VERSION "1.07+LK1.0.13" -#define DRV_RELDATE "Oct 19, 2001" +#define DRV_VERSION "1.07+LK1.0.14" +#define DRV_RELDATE "Nov 27, 2001" /* Updated to recommendations in pci-skeleton v2.03. */ @@ -129,7 +168,12 @@ /* The user-configurable values. These may be modified when a driver module is loaded.*/ -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +#define NATSEMI_DEF_MSG (NETIF_MSG_DRV | \ + NETIF_MSG_LINK | \ + NETIF_MSG_WOL | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) +static int debug = NATSEMI_DEF_MSG; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -161,7 +205,7 @@ There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */ -#define RX_RING_SIZE 64 +#define RX_RING_SIZE 32 /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -180,37 +224,6 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ -#if !defined(__OPTIMIZE__) -#warning You must compile this file with the correct options! -#warning See the last lines of the source file. -#error You must compile this driver with "-O". -#endif - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/timer.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/init.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/delay.h> -#include <linux/rtnetlink.h> -#include <linux/mii.h> -#include <asm/processor.h> /* Processor type for cache alignment. */ -#include <asm/bitops.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/uaccess.h> - /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = KERN_INFO DRV_NAME ".c:v1.07 1/9/2001 Written by Donald Becker <becker@scyld.com>\n" @@ -229,7 +242,7 @@ MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(max_interrupt_work, "DP8381x maximum events handled per interrupt"); MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); -MODULE_PARM_DESC(debug, "DP8381x debug level (0-5)"); +MODULE_PARM_DESC(debug, "DP8381x debug bitmask"); MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex"); MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)"); @@ -414,6 +427,7 @@ enum ChipConfig_bits { CfgPhyDis = 0x200, CfgPhyRst = 0x400, + CfgExtPhy = 0x1000, CfgAnegEnable = 0x2000, CfgAneg100 = 0x4000, CfgAnegFull = 0x8000, @@ -612,6 +626,7 @@ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int oom; /* These values are keep track of the transceiver/media in use. */ unsigned int full_duplex; /* Rx filter. */ @@ -627,6 +642,7 @@ u16 advertising; /* NWay media advertisement */ unsigned int iosize; spinlock_t lock; + u32 msg_enable; }; static int eeprom_read(long ioaddr, int location); @@ -640,9 +656,12 @@ static void netdev_timer(unsigned long data); static void tx_timeout(struct net_device *dev); static int alloc_ring(struct net_device *dev); +static void refill_rx(struct net_device *dev); static void init_ring(struct net_device *dev); +static void drain_tx(struct net_device *dev); static void drain_ring(struct net_device *dev); static void free_ring(struct net_device *dev); +static void reinit_ring(struct net_device *dev); static void init_registers(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); @@ -746,6 +765,7 @@ pci_set_drvdata(pdev, dev); np->iosize = iosize; spin_lock_init(&np->lock); + np->msg_enable = debug; /* Reset the chip to erase previous misconfiguration. */ natsemi_reload_eeprom(dev); @@ -760,7 +780,8 @@ if (option & 0x200) np->full_duplex = 1; if (option & 15) - printk(KERN_INFO "%s: ignoring user supplied media type %d", + printk(KERN_INFO + "%s: ignoring user supplied media type %d", dev->name, option & 15); } if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) @@ -789,14 +810,17 @@ } netif_carrier_off(dev); - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, natsemi_pci_info[chip_idx].name, ioaddr); - for (i = 0; i < ETH_ALEN-1; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + if (netif_msg_drv(np)) { + printk(KERN_INFO "%s: %s at %#08lx, ", + dev->name, natsemi_pci_info[chip_idx].name, ioaddr); + for (i = 0; i < ETH_ALEN-1; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x, IRQ %d.\n", dev->dev_addr[i], irq); + } np->advertising = mdio_read(dev, 1, MII_ADVERTISE); - if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) { + if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000 + && netif_msg_probe(np)) { u32 chip_config = readl(ioaddr + ChipConfig); printk(KERN_INFO "%s: Transceiver default autonegotiation %s " "10%s %s duplex.\n", @@ -805,12 +829,18 @@ chip_config & CfgAneg100 ? "0" : "", chip_config & CfgAnegFull ? "full" : "half"); } - printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", - dev->name, mdio_read(dev, 1, MII_BMSR), - np->advertising); + if (netif_msg_probe(np)) + printk(KERN_INFO + "%s: Transceiver status %#04x advertising %#04x.\n", + dev->name, mdio_read(dev, 1, MII_BMSR), + np->advertising); /* save the silicon revision for later querying */ np->srr = readl(ioaddr + SiliconRev); + if (netif_msg_hw(np)) + printk(KERN_INFO "%s: silicon revision %#04x.\n", + dev->name, np->srr); + return 0; } @@ -907,6 +937,7 @@ u32 rfcr; u16 pmatch[3]; u16 sopass[3]; + struct netdev_private *np = dev->priv; /* * Resetting the chip causes some registers to be lost. @@ -940,10 +971,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: reset did not complete in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: reset completed in %d usec.\n", dev->name, i*5); } @@ -972,6 +1003,7 @@ static void natsemi_reload_eeprom(struct net_device *dev) { + struct netdev_private *np = dev->priv; int i; writel(EepromReload, dev->base_addr + PCIBusCfg); @@ -980,10 +1012,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: EEPROM did not reload in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: EEPROM reloaded in %d usec.\n", dev->name, i*5); } @@ -992,6 +1024,7 @@ static void natsemi_stop_rxtx(struct net_device *dev) { long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; int i; writel(RxOff | TxOff, ioaddr + ChipCmd); @@ -1000,10 +1033,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n", dev->name, i*5); } @@ -1021,7 +1054,7 @@ i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); if (i) return i; - if (debug > 1) + if (netif_msg_ifup(np)) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", dev->name, dev->irq); i = alloc_ring(dev); @@ -1036,8 +1069,8 @@ netif_start_queue(dev); - if (debug > 2) - printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n", + if (netif_msg_ifup(np)) + printk(KERN_DEBUG "%s: Done netdev_open(), status: %#08x.\n", dev->name, (int)readl(ioaddr + ChipCmd)); /* Set the timer to check for link beat. */ @@ -1057,19 +1090,18 @@ int duplex; int chipcfg = readl(ioaddr + ChipConfig); - if(!(chipcfg & CfgLink)) { + if (!(chipcfg & CfgLink)) { if (netif_carrier_ok(dev)) { - if (debug) - printk(KERN_INFO "%s: no link. Disabling watchdog.\n", + if (netif_msg_link(np)) + printk(KERN_NOTICE "%s: link down.\n", dev->name); netif_carrier_off(dev); } return; } if (!netif_carrier_ok(dev)) { - if (debug) - printk(KERN_INFO "%s: link is back. Enabling watchdog.\n", - dev->name); + if (netif_msg_link(np)) + printk(KERN_NOTICE "%s: link up.\n", dev->name); netif_carrier_on(dev); } @@ -1077,10 +1109,11 @@ /* if duplex is set then bit 28 must be set, too */ if (duplex ^ !!(np->rx_config & RxAcceptTx)) { - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link" - " capability.\n", dev->name, - duplex ? "full" : "half"); + if (netif_msg_link(np)) + printk(KERN_INFO + "%s: Setting %s-duplex based on negotiated " + "link capability.\n", dev->name, + duplex ? "full" : "half"); if (duplex) { np->rx_config |= RxAcceptTx; np->tx_config |= TxCarrierIgn | TxHeartIgn; @@ -1099,17 +1132,12 @@ long ioaddr = dev->base_addr; int i; - /* save the silicon revision for later */ - if (debug > 4) - printk(KERN_DEBUG "%s: found silicon revision %xh.\n", - dev->name, np->srr); - for (i=0;i<NATSEMI_HW_TIMEOUT;i++) { if (readl(dev->base_addr + ChipConfig) & CfgAnegDone) break; udelay(10); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_link(np)) { printk(KERN_INFO "%s: autonegotiation did not complete in %d usec.\n", dev->name, i*10); @@ -1174,8 +1202,8 @@ * nothing will be written to memory. */ np->SavedClkRun = readl(ioaddr + ClkRun); writel(np->SavedClkRun & ~PMEEnable, ioaddr + ClkRun); - if (np->SavedClkRun & PMEStatus) { - printk(KERN_NOTICE "%s: Wake-up event %8.8x\n", + if (np->SavedClkRun & PMEStatus && netif_msg_wol(np)) { + printk(KERN_NOTICE "%s: Wake-up event %#08x\n", dev->name, readl(ioaddr + WOLCmd)); } @@ -1191,11 +1219,15 @@ } /* - * The frequency on this has been increased because of a nasty little problem. + * netdev_timer: + * Purpose: + * 1) check for link changes. Usually they are handled by the MII interrupt + * 2) check for sudden death of the NIC: * It seems that a reference set for this chip went out with incorrect info, * and there exist boards that aren't quite right. An unexpected voltage drop * can cause the PHY to get itself in a weird state (basically reset..). * NOTE: this only seems to affect revC chips. + * 3) check of death of the RX path due to OOM. */ static void netdev_timer(unsigned long data) { @@ -1205,7 +1237,7 @@ long ioaddr = dev->base_addr; u16 dspcfg; - if (debug > 3) { + if (netif_msg_timer(np)) { /* DO NOT read the IntrStatus register, * a read clears any pending interrupts. */ @@ -1213,17 +1245,23 @@ dev->name); } + spin_lock_irq(&np->lock); + /* check for a nasty random phy-reset - use dspcfg as a flag */ writew(1, ioaddr+PGSEL); dspcfg = readw(ioaddr+DSPCFG); writew(0, ioaddr+PGSEL); if (dspcfg != DSPCFG_VAL) { if (!netif_queue_stopped(dev)) { - printk(KERN_INFO - "%s: possible phy reset: re-initializing\n", - dev->name); + spin_unlock_irq(&np->lock); + if (netif_msg_hw(np)) + printk(KERN_NOTICE + "%s: possible phy reset: re-initializing\n", + dev->name); disable_irq(dev->irq); spin_lock_irq(&np->lock); + natsemi_reset(dev); + reinit_ring(dev); init_registers(dev); spin_unlock_irq(&np->lock); enable_irq(dev->irq); @@ -1233,9 +1271,19 @@ } } else { /* init_registers() calls check_link() for the above case */ - spin_lock_irq(&np->lock); check_link(dev); - spin_unlock_irq(&np->lock); + } + spin_unlock_irq(&np->lock); + if (np->oom) { + disable_irq(dev->irq); + np->oom = 0; + refill_rx(dev); + enable_irq(dev->irq); + if (!np->oom) { + writel(RxOn, dev->base_addr + ChipCmd); + } else { + next_tick = 1; + } } mod_timer(&np->timer, jiffies + next_tick); } @@ -1244,18 +1292,18 @@ { struct netdev_private *np = dev->priv; - if (debug > 2) { + if (netif_msg_pktdata(np)) { int i; printk(KERN_DEBUG " Tx ring at %p:\n", np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) { - printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n", i, np->tx_ring[i].next_desc, np->tx_ring[i].cmd_status, np->tx_ring[i].addr); } printk(KERN_DEBUG " Rx ring %p:\n", np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) { - printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n", i, np->rx_ring[i].next_desc, np->rx_ring[i].cmd_status, np->rx_ring[i].addr); @@ -1271,14 +1319,15 @@ disable_irq(dev->irq); spin_lock_irq(&np->lock); if (netif_device_present(dev)) { - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", - dev->name, readl(ioaddr + IntrStatus)); + if (netif_msg_tx_err(np)) + printk(KERN_WARNING + "%s: Transmit timed out, status %#08x," + " resetting...\n", + dev->name, readl(ioaddr + IntrStatus)); dump_ring(dev); natsemi_reset(dev); - drain_ring(dev); - init_ring(dev); + reinit_ring(dev); init_registers(dev); } else { printk(KERN_WARNING @@ -1305,15 +1354,53 @@ return 0; } +static void refill_rx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + int entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_dma[entry] = pci_map_single(np->pci_dev, + skb->data, skb->len, PCI_DMA_FROMDEVICE); + np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); + } + np->rx_ring[entry].cmd_status = + cpu_to_le32(np->rx_buf_sz); + } + if (np->cur_rx - np->dirty_tx == RX_RING_SIZE) { + if (debug > 2) + printk(KERN_INFO "%s: going OOM.\n", dev->name); + np->oom = 1; + } +} + /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void init_ring(struct net_device *dev) { struct netdev_private *np = dev->priv; int i; - np->cur_rx = np->cur_tx = 0; - np->dirty_rx = np->dirty_tx = 0; + /* 1) TX ring */ + np->dirty_tx = np->cur_tx = 0; + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = NULL; + np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma + +sizeof(struct netdev_desc) + *((i+1)%TX_RING_SIZE+RX_RING_SIZE)); + np->tx_ring[i].cmd_status = 0; + } + /* 2) RX ring */ + np->dirty_rx = 0; + np->cur_rx = RX_RING_SIZE; np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); np->rx_head_desc = &np->rx_ring[0]; @@ -1328,29 +1415,25 @@ np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn); np->rx_skbuff[i] = NULL; } + refill_rx(dev); + dump_ring(dev); +} - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_dma[i] = pci_map_single(np->pci_dev, - skb->data, skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[i].addr = cpu_to_le32(np->rx_dma[i]); - np->rx_ring[i].cmd_status = cpu_to_le32(np->rx_buf_sz); - } - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); +static void drain_tx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + int i; for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_skbuff[i]) { + pci_unmap_single(np->pci_dev, + np->rx_dma[i], + np->rx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(np->tx_skbuff[i]); + } np->tx_skbuff[i] = NULL; - np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma - +sizeof(struct netdev_desc) - *((i+1)%TX_RING_SIZE+RX_RING_SIZE)); - np->tx_ring[i].cmd_status = 0; } - dump_ring(dev); } static void drain_ring(struct net_device *dev) @@ -1371,16 +1454,29 @@ } np->rx_skbuff[i] = NULL; } - for (i = 0; i < TX_RING_SIZE; i++) { - if (np->tx_skbuff[i]) { - pci_unmap_single(np->pci_dev, - np->rx_dma[i], - np->rx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb(np->tx_skbuff[i]); - } - np->tx_skbuff[i] = NULL; - } + drain_tx(dev); +} + +static void reinit_ring(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + int i; + + /* drain TX ring */ + drain_tx(dev); + np->dirty_tx = np->cur_tx = 0; + for (i=0;i<TX_RING_SIZE;i++) + np->tx_ring[i].cmd_status = 0; + + /* RX Ring */ + np->dirty_rx = 0; + np->cur_rx = RX_RING_SIZE; + np->rx_head_desc = &np->rx_ring[0]; + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) + np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn); + + refill_rx(dev); } static void free_ring(struct net_device *dev) @@ -1431,7 +1527,7 @@ dev->trans_start = jiffies; - if (debug > 4) { + if (netif_msg_tx_queued(np)) { printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } @@ -1445,13 +1541,14 @@ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) { - if (debug > 4) + if (netif_msg_tx_err(np)) printk(KERN_DEBUG "%s: tx frame #%d is busy.\n", dev->name, np->dirty_tx); break; } - if (debug > 4) - printk(KERN_DEBUG "%s: tx frame #%d finished with status %8.8xh.\n", + if (netif_msg_tx_done(np)) + printk(KERN_DEBUG + "%s: tx frame #%d finished, status %#08x.\n", dev->name, np->dirty_tx, le32_to_cpu(np->tx_ring[entry].cmd_status)); if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescPktOK)) { @@ -1488,27 +1585,24 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = dev_instance; - struct netdev_private *np; - long ioaddr; + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; int boguscnt = max_interrupt_work; - ioaddr = dev->base_addr; - np = dev->priv; - if (!netif_device_present(dev)) return; do { /* Reading automatically acknowledges all int sources. */ u32 intr_status = readl(ioaddr + IntrStatus); - if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + if (netif_msg_intr(np)) + printk(KERN_DEBUG "%s: Interrupt, status %#08x.\n", dev->name, intr_status); if (intr_status == 0) break; - if (intr_status & (IntrRxDone | IntrRxIntr)) + if (intr_status & (IntrRxDone | IntrRxIntr | RxStatusFIFOOver)) netdev_rx(dev); if (intr_status & (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr) ) { @@ -1523,13 +1617,13 @@ if (--boguscnt < 0) { printk(KERN_WARNING "%s: Too much work at interrupt, " - "status=0x%4.4x.\n", + "status=%#08x.\n", dev->name, intr_status); break; } } while (1); - if (debug > 4) + if (netif_msg_intr(np)) printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name); } @@ -1545,22 +1639,28 @@ /* If the driver owns the next entry it's a new packet. Send it up. */ while (desc_status < 0) { /* e.g. & DescOwn */ - if (debug > 4) - printk(KERN_DEBUG " In netdev_rx() entry %d status was %8.8x.\n", - entry, desc_status); + if (netif_msg_rx_status(np)) + printk(KERN_DEBUG + " netdev_rx() entry %d status was %#08x.\n", + entry, desc_status); if (--boguscnt < 0) break; - if ((desc_status & (DescMore|DescPktOK|DescRxLong)) != DescPktOK) { + if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){ if (desc_status & DescMore) { - printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " - "multiple buffers, entry %#x status %x.\n", - dev->name, np->cur_rx, desc_status); + if (netif_msg_rx_err(np)) + printk(KERN_WARNING + "%s: Oversized(?) Ethernet " + "frame spanned multiple " + "buffers, entry %#08x " + "status %#08x.\n", dev->name, + np->cur_rx, desc_status); np->stats.rx_length_errors++; } else { /* There was a error. */ - if (debug > 2) - printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", - desc_status); + if (netif_msg_rx_err(np)) + printk(KERN_DEBUG + " netdev_rx() Rx error was " + "%#08x.\n", desc_status); np->stats.rx_errors++; if (desc_status & (DescRxAbort|DescRxOver)) np->stats.rx_over_errors++; @@ -1575,8 +1675,8 @@ struct sk_buff *skb; /* Omit CRC size. */ int pkt_len = (desc_status & DescSizeMask) - 4; - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ + /* Check if the packet is long enough to accept + * without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; @@ -1610,26 +1710,14 @@ desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); } - /* Refill the Rx ring buffers. */ - for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { - struct sk_buff *skb; - entry = np->dirty_rx % RX_RING_SIZE; - if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[entry] = skb; - if (skb == NULL) - break; /* Better luck next round. */ - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_dma[entry] = pci_map_single(np->pci_dev, - skb->data, skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); - } - np->rx_ring[entry].cmd_status = - cpu_to_le32(np->rx_buf_sz); - } + refill_rx(dev); /* Restart Rx engine if stopped. */ - writel(RxOn, dev->base_addr + ChipCmd); + if (np->oom) + mod_timer(&np->timer, jiffies + 1); + else + writel(RxOn, dev->base_addr + ChipCmd); + } static void netdev_error(struct net_device *dev, int intr_status) @@ -1639,11 +1727,16 @@ spin_lock(&np->lock); if (intr_status & LinkChange) { - printk(KERN_NOTICE - "%s: Link changed: Autonegotiation advertising" - " %4.4x partner %4.4x.\n", dev->name, - (int)mdio_read(dev, 1, MII_ADVERTISE), - (int)mdio_read(dev, 1, MII_LPA)); + u16 adv = mdio_read(dev, 1, MII_ADVERTISE); + u16 lpa = mdio_read(dev, 1, MII_LPA); + if (mdio_read(dev, 1, MII_BMCR) & BMCR_ANENABLE + && netif_msg_link(np)) { + printk(KERN_INFO + "%s: Autonegotiation advertising" + " %#04x partner %#04x.\n", dev->name, + adv, lpa); + } + /* read MII int status to clear the flag */ readw(ioaddr + MIntrStatus); check_link(dev); @@ -1654,18 +1747,19 @@ if (intr_status & IntrTxUnderrun) { if ((np->tx_config & TxDrthMask) < 62) np->tx_config += 2; - if (debug > 2) - printk(KERN_NOTICE "%s: increasing Tx theshold, new tx cfg %8.8xh.\n", - dev->name, np->tx_config); + if (netif_msg_tx_err(np)) + printk(KERN_NOTICE + "%s: increased Tx theshold, txcfg %#08x.\n", + dev->name, np->tx_config); writel(np->tx_config, ioaddr + TxConfig); } - if (intr_status & WOLPkt) { + if (intr_status & WOLPkt && netif_msg_wol(np)) { int wol_status = readl(ioaddr + WOLCmd); - printk(KERN_NOTICE "%s: Link wake-up event %8.8x\n", + printk(KERN_NOTICE "%s: Link wake-up event %#08x\n", dev->name, wol_status); } if (intr_status & RxStatusFIFOOver) { - if (debug >= 2) { + if (netif_msg_rx_err(np) && netif_msg_intr(np)) { printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", dev->name); } @@ -1673,10 +1767,8 @@ } /* Hmmmmm, it's not clear how to recover from PCI faults. */ if (intr_status & IntrPCIErr) { - if (debug) { - printk(KERN_NOTICE "%s: PCI error %08x\n", dev->name, - intr_status & IntrPCIErr); - } + printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name, + intr_status & IntrPCIErr); np->stats.tx_fifo_errors++; np->stats.rx_fifo_errors++; } @@ -1775,7 +1867,8 @@ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ - printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", + dev->name); rx_mode = RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys; } else if ((dev->mc_count > multicast_filter_limit) @@ -1910,7 +2003,7 @@ /* get message-level */ case ETHTOOL_GMSGLVL: { struct ethtool_value edata = {ETHTOOL_GMSGLVL}; - edata.data = debug; + edata.data = np->msg_enable; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; @@ -1920,7 +2013,7 @@ struct ethtool_value edata; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; - debug = edata.data; + np->msg_enable = edata.data; return 0; } /* restart autonegotiation */ @@ -2108,18 +2201,22 @@ ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_TP); + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); - /* only supports twisted-pair */ - ecmd->port = PORT_TP; + /* only supports twisted-pair or MII */ + tmp = readl(dev->base_addr + ChipConfig); + if (tmp & CfgExtPhy) + ecmd->port = PORT_MII; + else + ecmd->port = PORT_TP; /* only supports internal transceiver */ ecmd->transceiver = XCVR_INTERNAL; - /* this isn't fully supported at higher layers */ + /* not sure what this is for */ ecmd->phy_address = readw(dev->base_addr + PhyCtrl) & PhyAddrMask; - ecmd->advertising = ADVERTISED_TP; + ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; tmp = mdio_read(dev, 1, MII_ADVERTISE); if (tmp & ADVERTISE_10HALF) ecmd->advertising |= ADVERTISED_10baseT_Half; @@ -2130,20 +2227,21 @@ if (tmp & ADVERTISE_100FULL) ecmd->advertising |= ADVERTISED_100baseT_Full; - tmp = readl(dev->base_addr + ChipConfig); - if (tmp & CfgAnegEnable) { + tmp = mdio_read(dev, 1, MII_BMCR); + if (tmp & BMCR_ANENABLE) { ecmd->advertising |= ADVERTISED_Autoneg; ecmd->autoneg = AUTONEG_ENABLE; } else { ecmd->autoneg = AUTONEG_DISABLE; } + tmp = readl(dev->base_addr + ChipConfig); if (tmp & CfgSpeed100) { ecmd->speed = SPEED_100; } else { ecmd->speed = SPEED_10; } - + if (tmp & CfgFullDuplex) { ecmd->duplex = DUPLEX_FULL; } else { @@ -2164,7 +2262,7 @@ return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; - if (ecmd->port != PORT_TP) + if (ecmd->port != PORT_TP && ecmd->port != PORT_MII) return -EINVAL; if (ecmd->transceiver != XCVR_INTERNAL) return -EINVAL; @@ -2174,39 +2272,22 @@ /* WHEW! now lets bang some bits */ + tmp = mdio_read(dev, 1, MII_BMCR); if (ecmd->autoneg == AUTONEG_ENABLE) { - /* advertise only what has been requested */ - tmp = readl(dev->base_addr + ChipConfig); - tmp &= ~(CfgAneg100 | CfgAnegFull); - tmp |= CfgAnegEnable; - if (ecmd->advertising & ADVERTISED_100baseT_Half - || ecmd->advertising & ADVERTISED_100baseT_Full) { - tmp |= CfgAneg100; - } - if (ecmd->advertising & ADVERTISED_10baseT_Full - || ecmd->advertising & ADVERTISED_100baseT_Full) { - tmp |= CfgAnegFull; - } - writel(tmp, dev->base_addr + ChipConfig); - /* turn on autonegotiation, and force a renegotiate */ - tmp = mdio_read(dev, 1, MII_BMCR); - tmp |= (BMCR_ANENABLE | BMCR_ANRESTART); - mdio_write(dev, 1, MII_BMCR, tmp); + /* turn on autonegotiation */ + tmp |= BMCR_ANENABLE; np->advertising = mdio_read(dev, 1, MII_ADVERTISE); } else { /* turn off auto negotiation, set speed and duplexity */ - tmp = mdio_read(dev, 1, MII_BMCR); tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); - if (ecmd->speed == SPEED_100) { + if (ecmd->speed == SPEED_100) tmp |= BMCR_SPEED100; - } - if (ecmd->duplex == DUPLEX_FULL) { + if (ecmd->duplex == DUPLEX_FULL) tmp |= BMCR_FULLDPLX; - } else { + else np->full_duplex = 0; - } - mdio_write(dev, 1, MII_BMCR, tmp); } + mdio_write(dev, 1, MII_BMCR, tmp); return 0; } @@ -2241,7 +2322,7 @@ /* the interrupt status is clear-on-read - see if we missed any */ if (rbuf[4] & rbuf[5]) { printk(KERN_WARNING - "%s: shoot, we dropped an interrupt (0x%x)\n", + "%s: shoot, we dropped an interrupt (%#08x)\n", dev->name, rbuf[4] & rbuf[5]); } @@ -2308,7 +2389,7 @@ long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; - if (debug > 1) + if (netif_msg_wol(np)) printk(KERN_INFO "%s: remaining active for wake-on-lan\n", dev->name); @@ -2331,7 +2412,8 @@ /* enable the WOL interrupt. * Could be used to send a netlink message. */ - writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask); + writel(WOLPkt, ioaddr + IntrMask); + writel(1, ioaddr + IntrEnable); } } @@ -2341,22 +2423,28 @@ struct netdev_private *np = dev->priv; netif_stop_queue(dev); - netif_carrier_off(dev); - if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", - dev->name, (int)readl(ioaddr + ChipCmd)); - printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", - dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); - } + if (netif_msg_ifdown(np)) + printk(KERN_DEBUG + "%s: Shutting down ethercard, status was %#04x.\n", + dev->name, (int)readl(ioaddr + ChipCmd)); + if (netif_msg_pktdata(np)) + printk(KERN_DEBUG + "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, + np->cur_rx, np->dirty_rx); + /* Disable interrupts, and flush posted writes */ + writel(0, ioaddr + IntrEnable); + readl(ioaddr + IntrEnable); + free_irq(dev->irq, dev); del_timer_sync(&np->timer); - - disable_irq(dev->irq); + /* Interrupt disabled, interrupt handler released, + * queue stopped, timer deleted. All async codepaths + * that access the driver are disabled. + */ spin_lock_irq(&np->lock); - /* Disable and clear interrupts */ - writel(0, ioaddr + IntrEnable); readl(ioaddr + IntrMask); readw(ioaddr + MIntrStatus); @@ -2369,17 +2457,6 @@ __get_stats(dev); spin_unlock_irq(&np->lock); - /* race: shared irq and as most nics the DP83815 - * reports _all_ interrupt conditions in IntrStatus, even - * disabled ones. - * packet received after disable_irq, but before stop_rxtx - * --> race. intr_handler would restart the rx process. - * netif_device_{de,a}tach around {enable,free}_irq. - */ - netif_device_detach(dev); - enable_irq(dev->irq); - free_irq(dev->irq, dev); - netif_device_attach(dev); /* clear the carrier last - an interrupt could reenable it otherwise */ netif_carrier_off(dev); @@ -2387,7 +2464,7 @@ drain_ring(dev); free_ring(dev); - { + { u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary; if (wol) { /* restart the NIC in WOL mode. @@ -2518,7 +2595,7 @@ name: DRV_NAME, id_table: natsemi_pci_tbl, probe: natsemi_probe1, - remove: natsemi_remove1, + remove: __devexit_p(natsemi_remove1), #ifdef CONFIG_PM suspend: natsemi_suspend, resume: natsemi_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/ne.c linux-2.5/drivers/net/ne.c --- linux-2.5.1/drivers/net/ne.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/net/ne.c Fri Jan 4 16:40:15 2002 @@ -76,6 +76,9 @@ #endif static struct isapnp_device_id isapnp_clone_list[] __initdata = { + { ISAPNP_CARD_ID('A','X','E',0x2011), + ISAPNP_VENDOR('A','X','E'), ISAPNP_FUNCTION(0x2011), + (long) "NetGear EA201" }, { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216), (long) "NN NE2000" }, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/ne2k-pci.c linux-2.5/drivers/net/ne2k-pci.c --- linux-2.5.1/drivers/net/ne2k-pci.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/net/ne2k-pci.c Thu Dec 13 16:32:36 2001 @@ -642,7 +642,7 @@ static struct pci_driver ne2k_driver = { name: DRV_NAME, probe: ne2k_pci_init_one, - remove: ne2k_pci_remove_one, + remove: __devexit_p(ne2k_pci_remove_one), id_table: ne2k_pci_tbl, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/ni52.c linux-2.5/drivers/net/ni52.c --- linux-2.5.1/drivers/net/ni52.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/net/ni52.c Sat Jan 12 12:32:41 2002 @@ -40,7 +40,7 @@ * The internal sysbus seems to be slow. So we often lose packets because of * overruns while receiving from a fast remote host. * This can slow down TCP connections. Maybe the newer ni5210 cards are better. - * my experience is, that if a machine sends with more then about 500-600K/s + * my experience is, that if a machine sends with more than about 500-600K/s * the fifo/sysbus overflows. * * IMPORTANT NOTE: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/ns83820.c linux-2.5/drivers/net/ns83820.c --- linux-2.5.1/drivers/net/ns83820.c Fri Nov 9 21:45:35 2001 +++ linux-2.5/drivers/net/ns83820.c Thu Dec 13 22:09:29 2001 @@ -1,7 +1,7 @@ -#define VERSION "0.13" -/* ns83820.c by Benjamin LaHaise <bcrl@redhat.com> +#define _VERSION "0.15" +/* ns83820.c by Benjamin LaHaise <bcrl@redhat.com> with contributions. * - * $Revision: 1.34.2.8 $ + * $Revision: 1.34.2.12 $ * * Copyright 2001 Benjamin LaHaise. * Copyright 2001 Red Hat. @@ -45,6 +45,12 @@ * 0.12 - add statistics counters * - add allmulti/promisc support * 20011009 0.13 - hotplug support, other smaller pci api cleanups + * 20011204 0.13a - optical transceiver support added + * by Michael Clark <michael@metaparadigm.com> + * 20011205 0.13b - call register_netdev earlier in initialization + * suppress duplicate link status messages + * 20011117 0.14 - ethtool GDRVINFO, GLINK support from jgarzik + * 20011204 0.15 get ppc (big endian) working * * Driver Overview * =============== @@ -65,6 +71,7 @@ * D-Link DGE-500T * PureData PDP8023Z-TG * SMC SMC9452TX SMC9462TX + * Netgear GA621 * * Special thanks to SMC for providing hardware to test this driver on. * @@ -86,23 +93,25 @@ #include <linux/in.h> /* for IPPROTO_... */ #include <linux/eeprom.h> #include <linux/compiler.h> +#include <linux/ethtool.h> //#include <linux/skbrefill.h> #include <asm/io.h> +#include <asm/uaccess.h> /* Dprintk is used for more interesting debug events */ #undef Dprintk #define Dprintk dprintk #ifdef CONFIG_HIGHMEM64G -#define USE_64BIT_ADDR +#define USE_64BIT_ADDR "+" #elif defined(__ia64__) -#define USE_64BIT_ADDR +#define USE_64BIT_ADDR "+" #endif /* Tell davem to fix the pci dma api. Grrr. */ /* stolen from acenic.c */ -#ifdef CONFIG_HIGHMEM +#if 0 //def CONFIG_HIGHMEM #if defined(CONFIG_X86) #define DMAADDR_OFFSET 0 #if defined(CONFIG_HIGHMEM64G) @@ -138,6 +147,12 @@ } #endif +#if defined(USE_64BIT_ADDR) +#define VERSION _VERSION USE_64BIT_ADDR +#else +#define VERSION _VERSION +#endif + /* tunables */ #define RX_BUF_SIZE 6144 /* 8192 */ #define NR_RX_DESC 256 @@ -213,6 +228,7 @@ #define CFG_DUPSTS 0x10000000 #define CFG_TBI_EN 0x01000000 #define CFG_MODE_1000 0x00400000 +#define CFG_AUTO_1000 0x00200000 #define CFG_PINT_CTL 0x001c0000 #define CFG_PINT_DUPSTS 0x00100000 #define CFG_PINT_LNKSTS 0x00080000 @@ -316,6 +332,36 @@ #define VDR 0xc4 #define CCSR 0xcc +#define TBICR 0xe0 +#define TBISR 0xe4 +#define TANAR 0xe8 +#define TANLPAR 0xec +#define TANER 0xf0 +#define TESR 0xf4 + +#define TBICR_MR_AN_ENABLE 0x00001000 +#define TBICR_MR_RESTART_AN 0x00000200 + +#define TBISR_MR_LINK_STATUS 0x00000020 +#define TBISR_MR_AN_COMPLETE 0x00000004 + +#define TANAR_PS2 0x00000100 +#define TANAR_PS1 0x00000080 +#define TANAR_HALF_DUP 0x00000040 +#define TANAR_FULL_DUP 0x00000020 + +#define GPIOR_GP5_OE 0x00000200 +#define GPIOR_GP4_OE 0x00000100 +#define GPIOR_GP3_OE 0x00000080 +#define GPIOR_GP2_OE 0x00000040 +#define GPIOR_GP1_OE 0x00000020 +#define GPIOR_GP3_OUT 0x00000004 +#define GPIOR_GP1_OUT 0x00000001 + +#define LINK_AUTONEGOTIATE 0x01 +#define LINK_DOWN 0x02 +#define LINK_UP 0x04 + #define __kick_rx(dev) writel(CR_RXE, dev->base + CR) #define kick_rx(dev) do { \ @@ -390,6 +436,7 @@ u32 IMR_cache; struct eeprom ee; + unsigned linkstate; spinlock_t tx_lock; @@ -441,11 +488,11 @@ static inline void build_rx_desc32(struct ns83820 *dev, u32 *desc, u32 link, u32 buf, u32 cmdsts, u32 extsts) { - desc[0] = link; - desc[1] = buf; - desc[3] = extsts; + desc[0] = cpu_to_le32(link); + desc[1] = cpu_to_le32(buf); + desc[3] = cpu_to_le32(extsts); mb(); - desc[2] = cmdsts; + desc[2] = cpu_to_le32(cmdsts); } #define build_rx_desc build_rx_desc32 @@ -486,7 +533,7 @@ build_rx_desc(dev, sg, 0, buf, cmdsts, 0); /* update link of previous rx */ if (next_empty != dev->rx_info.next_rx) - dev->rx_info.descs[((NR_RX_DESC + next_empty - 1) % NR_RX_DESC) * DESC_SIZE] = dev->rx_info.phy_descs + (next_empty * DESC_SIZE * 4); + dev->rx_info.descs[((NR_RX_DESC + next_empty - 1) % NR_RX_DESC) * DESC_SIZE] = cpu_to_le32(dev->rx_info.phy_descs + (next_empty * DESC_SIZE * 4)); return 0; } @@ -545,39 +592,93 @@ static void phy_intr(struct ns83820 *dev) { - static char *speeds[] = { "10", "100", "1000", "1000(?)" }; + static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; u32 cfg, new_cfg; + u32 tbisr, tanar, tanlpar; + int speed, fullduplex, newlinkstate; - new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS); cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; - if (cfg & CFG_SPDSTS1) - new_cfg |= CFG_MODE_1000 | CFG_SB; - else - new_cfg &= ~CFG_MODE_1000 | CFG_SB; + if (dev->CFG_cache & CFG_TBI_EN) { - if ((cfg & CFG_LNKSTS) && ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) { - writel(new_cfg, dev->base + CFG); - dev->CFG_cache = new_cfg; - } + /* we have an optical transceiver */ + tbisr = readl(dev->base + TBISR); + tanar = readl(dev->base + TANAR); + tanlpar = readl(dev->base + TANLPAR); + dprintk("phy_intr: tbisr=%08x, tanar=%08x, tanlpar=%08x\n", + tbisr, tanar, tanlpar); + + if ( (fullduplex = (tanlpar & TANAR_FULL_DUP) + && (tanar & TANAR_FULL_DUP)) ) { + + /* both of us are full duplex */ + writel(readl(dev->base + TXCFG) + | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP, + dev->base + TXCFG); + writel(readl(dev->base + RXCFG) | RXCFG_RX_FD, + dev->base + RXCFG); + /* Light up full duplex LED */ + writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT, + dev->base + GPIOR); + + } else if(((tanlpar & TANAR_HALF_DUP) + && (tanar & TANAR_HALF_DUP)) + || ((tanlpar & TANAR_FULL_DUP) + && (tanar & TANAR_HALF_DUP)) + || ((tanlpar & TANAR_HALF_DUP) + && (tanar & TANAR_FULL_DUP))) { + + /* one or both of us are half duplex */ + writel((readl(dev->base + TXCFG) + & ~(TXCFG_CSI | TXCFG_HBI)) | TXCFG_ATP, + dev->base + TXCFG); + writel(readl(dev->base + RXCFG) & ~RXCFG_RX_FD, + dev->base + RXCFG); + /* Turn off full duplex LED */ + writel(readl(dev->base + GPIOR) & ~GPIOR_GP1_OUT, + dev->base + GPIOR); + } - dev->CFG_cache &= ~CFG_SPDSTS; - dev->CFG_cache |= cfg & CFG_SPDSTS; + speed = 4; /* 1000F */ - if (cfg & CFG_LNKSTS) { - netif_start_queue(&dev->net_dev); - netif_wake_queue(&dev->net_dev); } else { - netif_stop_queue(&dev->net_dev); + /* we have a copper transceiver */ + new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS); + + if (cfg & CFG_SPDSTS1) + new_cfg |= CFG_MODE_1000 | CFG_SB; + else + new_cfg &= ~CFG_MODE_1000 | CFG_SB; + + if ((cfg & CFG_LNKSTS) && ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) { + writel(new_cfg, dev->base + CFG); + dev->CFG_cache = new_cfg; + } + + dev->CFG_cache &= ~CFG_SPDSTS; + dev->CFG_cache |= cfg & CFG_SPDSTS; + + speed = ((cfg / CFG_SPDSTS0) & 3); + fullduplex = (cfg & CFG_DUPSTS); } - if (cfg & CFG_LNKSTS) + newlinkstate = (cfg & CFG_LNKSTS) ? LINK_UP : LINK_DOWN; + + if (newlinkstate & LINK_UP + && dev->linkstate != newlinkstate) { + netif_start_queue(&dev->net_dev); + netif_wake_queue(&dev->net_dev); printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n", dev->net_dev.name, - speeds[((cfg / CFG_SPDSTS0) & 3)], - (cfg & CFG_DUPSTS) ? "full" : "half"); - else + speeds[speed], + fullduplex ? "full" : "half"); + } else if (newlinkstate & LINK_DOWN + && dev->linkstate != newlinkstate) { + netif_stop_queue(&dev->net_dev); printk(KERN_INFO "%s: link now down.\n", dev->net_dev.name); + } + + dev->linkstate = newlinkstate; } static int ns83820_setup_rx(struct ns83820 *dev) @@ -698,15 +799,15 @@ dprintk("walking descs\n"); next_rx = info->next_rx; desc = info->descs + (DESC_SIZE * next_rx); - while ((CMDSTS_OWN & (cmdsts = desc[CMDSTS])) && + while ((CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) && (cmdsts != CMDSTS_OWN)) { struct sk_buff *skb; - u32 extsts = desc[EXTSTS]; - dmaaddr_high_t bufptr = *(hw_addr_t *)(desc + BUFPTR); + u32 extsts = le32_to_cpu(desc[EXTSTS]); + dmaaddr_high_t bufptr = le32_to_cpu(desc[BUFPTR]); dprintk("cmdsts: %08x\n", cmdsts); - dprintk("link: %08x\n", desc[LINK]); - dprintk("extsts: %08x\n", desc[EXTSTS]); + dprintk("link: %08x\n", cpu_to_le32(desc[LINK])); + dprintk("extsts: %08x\n", extsts); skb = info->skbs[next_rx]; info->skbs[next_rx] = NULL; @@ -718,14 +819,14 @@ pci_unmap_single(dev->pci_dev, bufptr, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); if (CMDSTS_OK & cmdsts) { -#ifndef __i386__ +#if 0 //ndef __i386__ struct sk_buff *tmp; #endif int len = cmdsts & 0xffff; if (!skb) BUG(); skb_put(skb, len); -#ifndef __i386__ /* I hate the network stack sometimes */ +#if 0 //ndef __i386__ /* I hate the network stack sometimes */ tmp = __dev_alloc_skb(RX_BUF_SIZE+16, GFP_ATOMIC); if (!tmp) goto done; @@ -788,9 +889,9 @@ desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n", - tx_done_idx, dev->tx_free_idx, desc[CMDSTS]); + tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[CMDSTS])); while ((tx_done_idx != dev->tx_free_idx) && - !(CMDSTS_OWN & (cmdsts = desc[CMDSTS])) ) { + !(CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) ) { struct sk_buff *skb; if (cmdsts & CMDSTS_ERR) @@ -801,13 +902,13 @@ dev->stats.tx_bytes += cmdsts & 0xffff; dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n", - tx_done_idx, dev->tx_free_idx, desc[CMDSTS]); + tx_done_idx, dev->tx_free_idx, cmdsts); skb = dev->tx_skbs[tx_done_idx]; dev->tx_skbs[tx_done_idx] = NULL; dprintk("done(%p)\n", skb); if (skb) { pci_unmap_single(dev->pci_dev, - *(hw_addr_t *)(desc + BUFPTR), + le32_to_cpu(desc[BUFPTR]), skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(skb); @@ -815,7 +916,7 @@ tx_done_idx = (tx_done_idx + 1) % NR_TX_DESC; dev->tx_done_idx = tx_done_idx; - desc[CMDSTS] = 0; + desc[CMDSTS] = cpu_to_le32(0); barrier(); desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); } @@ -936,17 +1037,17 @@ } #endif - dprintk("frag[%3u]: %4u @ 0x%x%08Lx\n", free_idx, len, + dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len, (unsigned long long)buf); free_idx = (free_idx + 1) % NR_TX_DESC; - desc[LINK] = dev->tx_phy_descs + (free_idx * DESC_SIZE * 4); - *(hw_addr_t *)(desc + BUFPTR) = buf; - desc[EXTSTS] = extsts; + desc[LINK] = cpu_to_le32(dev->tx_phy_descs + (free_idx * DESC_SIZE * 4)); + desc[BUFPTR] = cpu_to_le32(buf); + desc[EXTSTS] = cpu_to_le32(extsts); cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0); cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN; cmdsts |= len; - desc[CMDSTS] = cmdsts; + desc[CMDSTS] = cpu_to_le32(cmdsts); if (residue) { buf += len; @@ -957,7 +1058,8 @@ if (!nr_frags) break; - buf = pci_map_single_high(dev->pci_dev, frag->page, 0, + buf = pci_map_single_high(dev->pci_dev, frag->page, + frag->page_offset, frag->size, PCI_DMA_TODEVICE); dprintk("frag: buf=%08Lx page=%08lx\n", (long long)buf, (long)(frag->page - mem_map)); @@ -967,7 +1069,7 @@ } dprintk("done pkt\n"); dev->tx_skbs[free_idx] = skb; - first_desc[CMDSTS] |= CMDSTS_OWN; + first_desc[CMDSTS] |= cpu_to_le32(CMDSTS_OWN); dev->tx_free_idx = free_idx; kick_tx(dev); @@ -1007,6 +1109,59 @@ return &dev->stats; } +static int ns83820_ethtool_ioctl (struct ns83820 *dev, void *useraddr) +{ + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy(info.driver, "ns83820"); + strcpy(info.version, VERSION); + strcpy(info.bus_info, dev->pci_dev->slot_name); + if (copy_to_user(useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = { ETHTOOL_GLINK }; + u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; + + if (cfg & CFG_LNKSTS) + edata.data = 1; + else + edata.data = 0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} + +static int ns83820_ioctl(struct net_device *_dev, struct ifreq *rq, int cmd) +{ + struct ns83820 *dev = _dev->priv; + + switch(cmd) { + case SIOCETHTOOL: + return ns83820_ethtool_ioctl(dev, (void *) rq->ifr_data); + + default: + return -EOPNOTSUPP; + } +} + static void ns83820_irq(int foo, void *data, struct pt_regs *regs) { struct ns83820 *dev = data; @@ -1048,10 +1203,14 @@ Dprintk("BAD\n"); } - if (ISR_RXSOVR & isr) - Dprintk("overrun\n"); - if (ISR_RXORN & isr) - Dprintk("overrun\n"); + if (unlikely(ISR_RXSOVR & isr)) { + Dprintk("overrun: rxsovr\n"); + dev->stats.rx_over_errors ++; + } + if (unlikely(ISR_RXORN & isr)) { + Dprintk("overrun: rxorn\n"); + dev->stats.rx_over_errors ++; + } if ((ISR_RXRCMP & isr) && dev->rx_info.up) writel(CR_RXE, dev->base + CR); @@ -1150,9 +1309,10 @@ memset(dev->tx_descs, 0, 4 * NR_TX_DESC * DESC_SIZE); for (i=0; i<NR_TX_DESC; i++) { - *(hw_addr_t *)(dev->tx_descs + (i * DESC_SIZE) + LINK) - = dev->tx_phy_descs - + ((i+1) % NR_TX_DESC) * DESC_SIZE * 4; + dev->tx_descs[(i * DESC_SIZE) + LINK] + = cpu_to_le32( + dev->tx_phy_descs + + ((i+1) % NR_TX_DESC) * DESC_SIZE * 4); } dev->tx_idx = 0; @@ -1190,6 +1350,9 @@ #if 0 /* I've left this in as an example of how to use eeprom.h */ data = eeprom_readw(&dev->ee, 0xa + 2 - i); #else + /* Read from the perfect match memory: this is loaded by + * the chip from the EEPROM via the EELOAD self test. + */ writel(i*2, dev->base + RFCR); data = readl(dev->base + RFDR); #endif @@ -1287,6 +1450,8 @@ goto out_unmap; } + if(register_netdev(&dev->net_dev)) goto out_unmap; + dev->net_dev.open = ns83820_open; dev->net_dev.stop = ns83820_stop; dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit; @@ -1294,6 +1459,7 @@ dev->net_dev.get_stats = ns83820_get_stats; dev->net_dev.change_mtu = ns83820_change_mtu; dev->net_dev.set_multicast_list = ns83820_set_multicast; + dev->net_dev.do_ioctl = ns83820_ioctl; //FIXME: dev->net_dev.tx_timeout = ns83820_tx_timeout; pci_set_drvdata(pci_dev, dev); @@ -1318,12 +1484,15 @@ dev->CFG_cache = readl(dev->base + CFG); if ((dev->CFG_cache & CFG_PCI64_DET)) { - printk("%s: enabling 64 bit PCI.\n", dev->net_dev.name); + printk("%s: enabling 64 bit PCI addressing.\n", + dev->net_dev.name); dev->CFG_cache |= CFG_T64ADDR | CFG_DATA64_EN; - } else { - printk("%s: disabling 64 bit PCI.\n", dev->net_dev.name); +#if defined(USE_64BIT_ADDR) + dev->net_dev.features |= NETIF_F_HIGHDMA; +#endif + } else dev->CFG_cache &= ~(CFG_T64ADDR | CFG_DATA64_EN); - } + dev->CFG_cache &= (CFG_TBI_EN | CFG_MRM_DIS | CFG_MWI_DIS | CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 | CFG_M64ADDR); @@ -1333,15 +1502,28 @@ dev->CFG_cache |= CFG_POW; #ifdef USE_64BIT_ADDR dev->CFG_cache |= CFG_M64ADDR; - printk("using 64 bit addressing\n"); #endif -#ifdef __LITTLE_ENDIAN + /* Big endian mode does not seem to do what the docs suggest */ dev->CFG_cache &= ~CFG_BEM; -#elif defined(__BIG_ENDIAN) - dev->CFG_cache |= CFG_BEM; -#else -#error This driver only works for big or little endian!!! -#endif + + /* setup optical transceiver if we have one */ + if (dev->CFG_cache & CFG_TBI_EN) { + printk("%s: enabling optical transceiver\n", dev->net_dev.name); + writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR); + + /* setup auto negotiation feature advertisement */ + writel(readl(dev->base + TANAR) + | TANAR_HALF_DUP | TANAR_FULL_DUP, + dev->base + TANAR); + + /* start auto negotiation */ + writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN, + dev->base + TBICR); + writel(TBICR_MR_AN_ENABLE, dev->base + TBICR); + dev->linkstate = LINK_AUTONEGOTIATE; + + dev->CFG_cache |= CFG_MODE_1000; + } writel(dev->CFG_cache, dev->base + CFG); dprintk("CFG: %08x\n", dev->CFG_cache); @@ -1397,15 +1579,15 @@ dev->net_dev.features |= NETIF_F_HIGHDMA; #endif - register_netdev(&dev->net_dev); - - printk(KERN_INFO "%s: ns83820.c v" VERSION ": DP83820 %02x:%02x:%02x:%02x:%02x:%02x pciaddr=0x%08lx irq=%d rev 0x%x\n", + printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n", dev->net_dev.name, + (unsigned)readl(dev->base + SRR) >> 8, + (unsigned)readl(dev->base + SRR) & 0xff, dev->net_dev.dev_addr[0], dev->net_dev.dev_addr[1], dev->net_dev.dev_addr[2], dev->net_dev.dev_addr[3], dev->net_dev.dev_addr[4], dev->net_dev.dev_addr[5], addr, pci_dev->irq, - (unsigned)readl(dev->base + SRR) + (dev->net_dev.features & NETIF_F_HIGHDMA) ? "sg" : "h,sg" ); return 0; @@ -1455,7 +1637,7 @@ name: "ns83820", id_table: ns83820_pci_tbl, probe: ns83820_init_one, - remove: ns83820_remove_one, + remove: __devexit_p(ns83820_remove_one), #if 0 /* FIXME: implement */ suspend: , resume: , diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pci-skeleton.c linux-2.5/drivers/net/pci-skeleton.c --- linux-2.5.1/drivers/net/pci-skeleton.c Wed Oct 17 04:56:29 2001 +++ linux-2.5/drivers/net/pci-skeleton.c Thu Dec 13 16:32:36 2001 @@ -834,7 +834,7 @@ printk (KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); - mdio_write (dev, tp->phys[0], 4, 0x141); + mdio_write (dev, tp->phys[0], MII_ADVERTISE, ADVERTISE_FULL); tp->duplex_lock = 1; } @@ -1235,20 +1235,20 @@ struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int next_tick = 60 * HZ; - int mii_reg5; + int mii_lpa; - mii_reg5 = mdio_read (dev, tp->phys[0], 5); + mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA); - if (!tp->duplex_lock && mii_reg5 != 0xffff) { - int duplex = (mii_reg5 & 0x0100) - || (mii_reg5 & 0x01C0) == 0x0040; + if (!tp->duplex_lock && mii_lpa != 0xffff) { + int duplex = (mii_lpa & LPA_100FULL) + || (mii_lpa & 0x01C0) == 0x0040; if (tp->full_duplex != duplex) { tp->full_duplex = duplex; printk (KERN_INFO "%s: Setting %s-duplex based on MII #%d link" " partner ability of %4.4x.\n", dev->name, tp->full_duplex ? "full" : "half", - tp->phys[0], mii_reg5); + tp->phys[0], mii_lpa); NETDRV_W8 (Cfg9346, Cfg9346_Unlock); NETDRV_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); NETDRV_W8 (Cfg9346, Cfg9346_Lock); @@ -1980,7 +1980,7 @@ name: MODNAME, id_table: netdrv_pci_tbl, probe: netdrv_init_one, - remove: netdrv_remove_one, + remove: __devexit_p(netdrv_remove_one), #ifdef CONFIG_PM suspend: netdrv_suspend, resume: netdrv_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/3c589_cs.c linux-2.5/drivers/net/pcmcia/3c589_cs.c --- linux-2.5.1/drivers/net/pcmcia/3c589_cs.c Tue Nov 13 17:02:30 2001 +++ linux-2.5/drivers/net/pcmcia/3c589_cs.c Thu Dec 27 16:32:31 2001 @@ -17,6 +17,9 @@ ======================================================================*/ +#define DRV_NAME "3c589_cs" +#define DRV_VERSION "1.162" + #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> @@ -28,6 +31,9 @@ #include <linux/interrupt.h> #include <linux/in.h> #include <linux/delay.h> +#include <linux/ethtool.h> + +#include <asm/uaccess.h> #include <asm/io.h> #include <asm/system.h> #include <asm/bitops.h> @@ -134,7 +140,7 @@ INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"3c589_cs.c 1.162 2001/10/13 00:08:50 (David Hinds)"; +DRV_NAME ".c " DRV_VERSION " 2001/10/13 00:08:50 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -159,6 +165,7 @@ static int el3_close(struct net_device *dev); static void el3_tx_timeout(struct net_device *dev); static void set_multicast_list(struct net_device *dev); +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static dev_info_t dev_info = "3c589_cs"; @@ -249,7 +256,8 @@ dev->tx_timeout = el3_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; #endif - + dev->do_ioctl = netdev_ioctl; + /* Register with Card Services */ link->next = dev_list; dev_list = link; @@ -638,6 +646,71 @@ ioaddr + EL3_CMD); outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull | AdapterFailure, ioaddr + EL3_CMD); +} + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + +#ifdef PCMCIA_DEBUG + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = pc_debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + pc_debug = edata.data; + return 0; + } +#endif + + default: + break; + } + + return -EOPNOTSUPP; +} + +static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc; + + switch (cmd) { + case SIOCETHTOOL: + rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + break; + + default: + rc = -EOPNOTSUPP; + break; + } + + return rc; } static int el3_config(struct net_device *dev, struct ifmap *map) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/Config.in linux-2.5/drivers/net/pcmcia/Config.in --- linux-2.5.1/drivers/net/pcmcia/Config.in Mon Nov 12 17:35:43 2001 +++ linux-2.5/drivers/net/pcmcia/Config.in Thu Dec 13 16:32:36 2001 @@ -11,10 +11,10 @@ dep_tristate ' 3Com 3c574 PCMCIA support' CONFIG_PCMCIA_3C574 $CONFIG_PCMCIA dep_tristate ' Fujitsu FMV-J18x PCMCIA support' CONFIG_PCMCIA_FMVJ18X $CONFIG_PCMCIA dep_tristate ' NE2000 compatible PCMCIA support' CONFIG_PCMCIA_PCNET $CONFIG_PCMCIA + dep_tristate ' Asix AX88190 PCMCIA support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA dep_tristate ' New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA - dep_tristate ' broken NS8390-cards support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA if [ "$CONFIG_IBMTR" != "y" ]; then dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/aironet4500_cs.c linux-2.5/drivers/net/pcmcia/aironet4500_cs.c --- linux-2.5.1/drivers/net/pcmcia/aironet4500_cs.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/net/pcmcia/aironet4500_cs.c Thu Dec 27 16:32:31 2001 @@ -10,8 +10,11 @@ * */ +#define DRV_NAME "aironet4500_cs" +#define DRV_VERSION "0.1" + static const char *awc_version = -"aironet4500_cs.c v0.1 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n"; +DRV_NAME ".c v" DRV_VERSION " 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n"; #include <linux/module.h> @@ -24,6 +27,9 @@ #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/in.h> +#include <linux/ethtool.h> + +#include <asm/uaccess.h> #include <asm/io.h> #include <asm/system.h> #include <asm/bitops.h> @@ -159,6 +165,66 @@ return ret; } +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + +#ifdef PCMCIA_DEBUG + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = pc_debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + pc_debug = edata.data; + return 0; + } +#endif + + default: + break; + } + + return -EOPNOTSUPP; +} + +static int awc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + + default: + return -EOPNOTSUPP; + } + return 0; +} + /* awc_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered @@ -230,7 +296,8 @@ // dev->set_config = &awc_config_misiganes,aga mitte awc_config; dev->get_stats = &awc_get_stats; // dev->set_multicast_list = &awc_set_multicast_list; - + dev->do_ioctl = &awc_ioctl; + strcpy(dev->name, ((struct awc_private *)dev->priv)->node.dev_name); ether_setup(dev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/axnet_cs.c linux-2.5/drivers/net/pcmcia/axnet_cs.c --- linux-2.5.1/drivers/net/pcmcia/axnet_cs.c Mon Nov 12 17:35:43 2001 +++ linux-2.5/drivers/net/pcmcia/axnet_cs.c Thu Dec 13 16:32:36 2001 @@ -11,7 +11,7 @@ Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net - axnet_cs.c 1.11 2001/06/12 12:42:40 + axnet_cs.c 1.24 2001/11/18 02:46:51 The network driver code is based on Donald Becker's NE2000 code: @@ -20,7 +20,7 @@ Director, National Security Agency. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov + Donald Becker may be reached at becker@scyld.com ======================================================================*/ @@ -33,12 +33,13 @@ #include <linux/string.h> #include <linux/timer.h> #include <linux/delay.h> +#include <linux/spinlock.h> #include <asm/io.h> #include <asm/system.h> #include <asm/byteorder.h> #include <linux/netdevice.h> -#include "ax8390.h" +#include "../8390.h" #include <pcmcia/version.h> #include <pcmcia/cs_types.h> @@ -51,7 +52,6 @@ #define AXNET_CMD 0x00 #define AXNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */ #define AXNET_RESET 0x1f /* Issue a read to reset, a write to clear. */ -#define AXNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */ #define AXNET_MII_EEP 0x14 /* Offset of MII access port */ #define AXNET_START_PG 0x40 /* First page of TX buffer */ @@ -59,26 +59,13 @@ #define AXNET_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */ -#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 = -"axnet_cs.c 1.11 2001/06/12 12:42:40 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - -#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb); -#define skb_tx_check(dev, skb) -#define add_rx_bytes(stats, n) (stats)->rx_bytes += n; -#define add_tx_bytes(stats, n) (stats)->tx_bytes += n; -#define netif_mark_up(dev) do { } while (0) -#define netif_mark_down(dev) do { } while (0) - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); +MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver"); +MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") @@ -87,9 +74,14 @@ static int irq_list[4] = { -1 }; MODULE_PARM(irq_list, "1-4i"); -/* Ugh! Let the user hardwire the hardware address for queer cards */ -static int hw_addr[6] = { 0, /* ... */ }; -MODULE_PARM(hw_addr, "6i"); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"axnet_cs.c 1.24 2001/11/18 02:46:51 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -120,6 +112,11 @@ static dev_info_t dev_info = "axnet_cs"; static dev_link_t *dev_list; +static int axdev_init(struct net_device *dev); +static void AX88190_init(struct net_device *dev, int startp); +static int ax_open(struct net_device *dev); +static void ax_interrupt(int irq, void *dev_id, struct pt_regs *regs); + /*====================================================================*/ typedef struct axnet_dev_t { @@ -210,7 +207,7 @@ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - ethdev_init(dev); + axdev_init(dev); dev->init = &axnet_init; dev->open = &axnet_open; dev->stop = &axnet_close; @@ -302,7 +299,7 @@ {0x00, EN0_RCNTHI}, {0x00, EN0_IMR}, /* Mask completion irq. */ {0xFF, EN0_ISR}, - {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_RXOFF|0x40, EN0_RXCR}, /* 0x60 Set to monitor */ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ {0x10, EN0_RCNTLO}, {0x00, EN0_RCNTHI}, @@ -331,30 +328,6 @@ /*====================================================================== - This should be totally unnecessary... but when we can't figure - out the hardware address any other way, we'll let the user hard - wire it when the module is initialized. - -======================================================================*/ - -static int get_hwired(dev_link_t *link) -{ - struct net_device *dev = link->priv; - int i; - - for (i = 0; i < 6; i++) - if (hw_addr[i] != 0) break; - if (i == 6) - return 0; - - for (i = 0; i < 6; i++) - dev->dev_addr[i] = hw_addr[i]; - - return 1; -} /* get_hwired */ - -/*====================================================================== - axnet_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. @@ -419,7 +392,8 @@ CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; + /* don't trust the CIS on this; Linksys got it wrong */ + link->conf.Present = 0x63; /* Configure card */ link->state |= DEV_CONFIG; @@ -440,7 +414,7 @@ if ((cfg->index == 0) || (cfg->io.nwin == 0)) goto next_entry; - link->conf.ConfigIndex = cfg->index; + link->conf.ConfigIndex = 0x05; /* For multifunction cards, by convention, we configure the network function with window 0, and serial with window 1 */ if (io->nwin > 1) { @@ -480,9 +454,9 @@ goto failed; } - if (!get_prom(link) && !get_hwired(link)) { - printk(KERN_NOTICE "axnet_cs: unable to read hardware net" - " address for io base %#3lx\n", dev->base_addr); + if (!get_prom(link)) { + printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n"); + printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n"); unregister_netdev(dev); goto failed; } @@ -542,7 +516,7 @@ if (link->open) { DEBUG(1, "axnet_cs: release postponed, '%s' still open\n", - info->node.dev_name); + ((axnet_dev_t *)(link->priv))->node.dev_name); link->state |= DEV_STALE_CONFIG; return; } @@ -602,7 +576,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { axnet_reset_8390(&info->dev); - NS8390_init(&info->dev, 1); + AX88190_init(&info->dev, 1); netif_device_attach(&info->dev); } } @@ -692,7 +666,7 @@ info->watchdog.expires = jiffies + HZ; add_timer(&info->watchdog); - return ei_open(dev); + return ax_open(dev); } /* axnet_open */ /*====================================================================*/ @@ -708,7 +682,6 @@ link->open--; netif_stop_queue(dev); - netif_mark_down(dev); del_timer(&info->watchdog); if (link->state & DEV_STALE_CONFIG) mod_timer(&link->release, jiffies + HZ/20); @@ -755,7 +728,7 @@ { axnet_dev_t *info = dev_id; info->stale = 0; - ei_interrupt(irq, dev_id, regs); + ax_interrupt(irq, dev_id, regs); } static void ei_watchdog(u_long arg) @@ -807,7 +780,7 @@ else printk(KERN_INFO "%s: link partner did not autonegotiate\n", dev->name); - NS8390_init(dev, 1); + AX88190_init(dev, 1); } info->link_status = link; } @@ -944,10 +917,11 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + This is the chip-specific code for many 8390-based ethernet adaptors. This is not a complete driver, it must be combined with board-specific code such as ne.c, wd.c, 3c503.c, etc. @@ -957,7 +931,6 @@ a simple innocent change. Please contact me or Donald if you think you have found something that needs changing. -- PG - Changelog: Paul Gortmaker : remove set_bit lock, other cleanups. @@ -981,8 +954,8 @@ */ -static const char *version = - "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; +static const char *version_8390 = + "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@scyld.com)\n"; #include <asm/uaccess.h> #include <asm/bitops.h> @@ -1062,25 +1035,23 @@ * them. */ - - /** - * ei_open - Open/initialize the board. + * ax_open - Open/initialize the board. * @dev: network device to initialize * * This routine goes all-out, setting everything * up anew at each open, even though many of these registers should only * need to be set once at boot. */ -static int ei_open(struct net_device *dev) +static int ax_open(struct net_device *dev) { unsigned long flags; struct ei_device *ei_local = (struct ei_device *) dev->priv; - /* This can't happen unless somebody forgot to call ethdev_init(). */ + /* This can't happen unless somebody forgot to call axdev_init(). */ if (ei_local == NULL) { - printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name); + printk(KERN_EMERG "%s: ax_open passed a non-existent device!\n", dev->name); return -ENXIO; } @@ -1099,10 +1070,9 @@ */ spin_lock_irqsave(&ei_local->page_lock, flags); - NS8390_init(dev, 1); + AX88190_init(dev, 1); /* Set the flag before we drop the lock, That way the IRQ arrives after its set and we get no silly warnings */ - netif_mark_up(dev); netif_start_queue(dev); spin_unlock_irqrestore(&ei_local->page_lock, flags); ei_local->irqlock = 0; @@ -1110,27 +1080,6 @@ } /** - * ei_close - shut down network device - * @dev: network device to close - * - * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done. - */ -static int ei_close(struct net_device *dev) -{ - unsigned long flags; - - /* - * Hold the page lock during close - */ - - spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags); - NS8390_init(dev, 0); - spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags); - netif_stop_queue(dev); - return 0; -} - -/** * ei_tx_timeout - handle transmit time out condition * @dev: network device which has apparently fallen asleep * @@ -1169,7 +1118,7 @@ /* Try to restart the card. Perhaps the user has fixed something. */ ei_reset_8390(dev); - NS8390_init(dev, 1); + AX88190_init(dev, 1); spin_unlock(&ei_local->page_lock); enable_irq(dev->irq); @@ -1192,7 +1141,6 @@ unsigned long flags; netif_stop_queue(dev); - skb_tx_check(dev, skb); length = skb->len; @@ -1205,7 +1153,6 @@ outb_p(0x00, e8390_base + EN0_IMR); spin_unlock_irqrestore(&ei_local->page_lock, flags); - /* * Slow phase with lock held. */ @@ -1218,8 +1165,6 @@ send_length = ETH_ZLEN < length ? length : ETH_ZLEN; -#ifdef EI_PINGPONG - /* * We have two Tx slots available for use. Find the first free * slot, and then perform some sanity checks. With two Tx bufs, @@ -1288,22 +1233,6 @@ else netif_start_queue(dev); -#else /* EI_PINGPONG */ - - /* - * Only one Tx buffer in use. You need two Tx bufs to come close to - * back-to-back transmits. Expect a 20 -> 25% performance hit on - * reasonable hardware if you only use one Tx buffer. - */ - - ei_block_output(dev, length, skb->data, ei_local->tx_start_page); - ei_local->txing = 1; - NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); - dev->trans_start = jiffies; - netif_stop_queue(dev); - -#endif /* EI_PINGPONG */ - /* Turn 8390 interrupts back on. */ ei_local->irqlock = 0; outb_p(ENISR_ALL, e8390_base + EN0_IMR); @@ -1311,14 +1240,14 @@ spin_unlock(&ei_local->page_lock); enable_irq(dev->irq); - DEV_KFREE_SKB (skb); - add_tx_bytes(&ei_local->stat, send_length); + dev_kfree_skb (skb); + ei_local->stat.tx_bytes += send_length; return 0; } /** - * ei_interrupt - handle the interrupts from an 8390 + * ax_interrupt - handle the interrupts from an 8390 * @irq: interrupt number * @dev_id: a pointer to the net_device * @regs: unused @@ -1330,7 +1259,7 @@ * needed. */ -static void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static void ax_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; long e8390_base; @@ -1497,8 +1426,6 @@ struct ei_device *ei_local = (struct ei_device *) dev->priv; int status = inb(e8390_base + EN0_TSR); -#ifdef EI_PINGPONG - /* * There are two Tx buffers, see which one finished, and trigger * the send of another one if it exists. @@ -1541,13 +1468,6 @@ // else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n", // dev->name, ei_local->lasttx); -#else /* EI_PINGPONG */ - /* - * Single Tx buffer: mark it free so another packet can be loaded. - */ - ei_local->txing = 0; -#endif - /* Minimize Tx latency: update the statistics after we restart TXing. */ if (status & ENTSR_COL) ei_local->stat.collisions++; @@ -1655,7 +1575,7 @@ netif_rx(skb); dev->last_rx = jiffies; ei_local->stat.rx_packets++; - add_rx_bytes(&ei_local->stat, pkt_len); + ei_local->stat.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) ei_local->stat.multicast++; } @@ -1801,11 +1721,11 @@ long e8390_base = dev->base_addr; if(dev->flags&IFF_PROMISC) - outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR); + outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR); else if(dev->flags&IFF_ALLMULTI || dev->mc_list) - outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR); + outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR); else - outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); + outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); } /* @@ -1813,28 +1733,30 @@ * be parallel to just about everything else. Its also fairly quick and * not called too often. Must protect against both bh and irq users */ - + +#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock) + static void set_multicast_list(struct net_device *dev) { unsigned long flags; - spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags); + spin_lock_irqsave(&dev_lock(dev), flags); do_set_multicast_list(dev); - spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags); + spin_unlock_irqrestore(&dev_lock(dev), flags); } /** - * ethdev_init - init rest of 8390 device struct + * axdev_init - init rest of 8390 device struct * @dev: network device structure to init * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ -static int ethdev_init(struct net_device *dev) +static int axdev_init(struct net_device *dev) { if (ei_debug > 1) - printk(version); + printk(version_8390); if (dev->priv == NULL) { @@ -1857,20 +1779,18 @@ return 0; } - - /* This page of functions should be 8390 generic */ /* Follow National Semi's recommendations for initializing the "NIC". */ /** - * NS8390_init - initialize 8390 hardware + * AX88190_init - initialize 8390 hardware * @dev: network device to initialize * @startp: boolean. non-zero value to initiate chip processing * * Must be called with lock held. */ -static void NS8390_init(struct net_device *dev, int startp) +static void AX88190_init(struct net_device *dev, int startp) { axnet_dev_t *info = (axnet_dev_t *)dev; long e8390_base = dev->base_addr; @@ -1887,7 +1807,7 @@ outb_p(0x00, e8390_base + EN0_RCNTLO); outb_p(0x00, e8390_base + EN0_RCNTHI); /* Set to monitor and loopback mode -- this is vital!. */ - outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */ + outb_p(E8390_RXOFF|0x40, e8390_base + EN0_RXCR); /* 0x60 */ outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */ /* Set the transmit page and receive ring. */ outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR); @@ -1931,7 +1851,7 @@ outb_p(E8390_TXCONFIG | info->duplex_flag, e8390_base + EN0_TXCR); /* xmit on. */ /* 3c503 TechMan says rxconfig only after the NIC is started. */ - outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */ + outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); /* rx on, */ do_set_multicast_list(dev); /* (re)load the mcast table */ } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/fmvj18x_cs.c linux-2.5/drivers/net/pcmcia/fmvj18x_cs.c --- linux-2.5.1/drivers/net/pcmcia/fmvj18x_cs.c Tue Nov 13 17:02:30 2001 +++ linux-2.5/drivers/net/pcmcia/fmvj18x_cs.c Thu Dec 27 16:32:31 2001 @@ -28,6 +28,9 @@ ======================================================================*/ +#define DRV_NAME "fmvj18x_cs" +#define DRV_VERSION "2.6" + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -39,6 +42,9 @@ #include <linux/interrupt.h> #include <linux/in.h> #include <linux/delay.h> +#include <linux/ethtool.h> + +#include <asm/uaccess.h> #include <asm/io.h> #include <asm/system.h> @@ -73,7 +79,7 @@ #ifdef PCMCIA_DEBUG INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = "fmvj18x_cs.c 2.6 2001/09/17"; +static char *version = DRV_NAME ".c " DRV_VERSION " 2001/09/17"; #else #define DEBUG(n, args...) #endif @@ -103,6 +109,7 @@ static struct net_device_stats *fjn_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static void fjn_tx_timeout(struct net_device *dev); +static int fjn_ioctl(struct net_device *, struct ifreq *, int); static dev_info_t dev_info = "fmvj18x_cs"; static dev_link_t *dev_list; @@ -315,6 +322,7 @@ dev->tx_timeout = fjn_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; #endif + dev->do_ioctl = fjn_ioctl; /* Register with Card Services */ link->next = dev_list; @@ -1102,6 +1110,65 @@ /*====================================================================*/ +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + +#ifdef PCMCIA_DEBUG + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = pc_debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + pc_debug = edata.data; + return 0; + } +#endif + + default: + break; + } + + return -EOPNOTSUPP; +} + +static int fjn_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + + default: + return -EOPNOTSUPP; + } +} + static int fjn_config(struct net_device *dev, struct ifmap *map){ return 0; } @@ -1247,3 +1314,4 @@ } restore_flags(flags); } +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/netwave_cs.c linux-2.5/drivers/net/pcmcia/netwave_cs.c --- linux-2.5.1/drivers/net/pcmcia/netwave_cs.c Fri Oct 12 21:21:18 2001 +++ linux-2.5/drivers/net/pcmcia/netwave_cs.c Thu Dec 27 16:32:31 2001 @@ -37,6 +37,9 @@ /* To have statistics (just packets sent) define this */ #undef NETWAVE_STATS +#define DRV_NAME "netwave_cs" +#define DRV_VERSION "0.3.0" + #include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -51,6 +54,9 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/timer.h> +#include <linux/ethtool.h> + +#include <asm/uaccess.h> #include <asm/system.h> #include <asm/bitops.h> #include <asm/io.h> @@ -163,7 +169,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n"; +DRV_NAME ".c " DRV_VERSION " Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n"; #else #define DEBUG(n, args...) #endif @@ -200,6 +206,8 @@ MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); +MODULE_LICENSE("GPL"); + /*====================================================================*/ /* PCMCIA (Card Services) related functions */ @@ -595,6 +603,53 @@ } } /* netwave_flush_stale_links */ +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + +#ifdef PCMCIA_DEBUG + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = pc_debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + pc_debug = edata.data; + return 0; + } +#endif + + default: + break; + } + + return -EOPNOTSUPP; +} /* * Function netwave_ioctl (dev, rq, cmd) * @@ -617,6 +672,9 @@ DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); + if (cmd == SIOCETHTOOL) + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + /* Disable interrupts & save flags */ save_flags(flags); cli(); @@ -1597,4 +1655,3 @@ writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1); writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); } -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/nmclan_cs.c linux-2.5/drivers/net/pcmcia/nmclan_cs.c --- linux-2.5.1/drivers/net/pcmcia/nmclan_cs.c Tue Nov 13 17:02:30 2001 +++ linux-2.5/drivers/net/pcmcia/nmclan_cs.c Thu Dec 27 16:32:31 2001 @@ -106,6 +106,10 @@ ---------------------------------------------------------------------------- */ +#define DRV_NAME "nmclan_cs" +#define DRV_VERSION "0.16" + + /* ---------------------------------------------------------------------------- Conditional Compilation Options ---------------------------------------------------------------------------- */ @@ -130,6 +134,9 @@ #include <linux/interrupt.h> #include <linux/in.h> #include <linux/delay.h> +#include <linux/ethtool.h> + +#include <asm/uaccess.h> #include <asm/io.h> #include <asm/system.h> #include <asm/bitops.h> @@ -375,7 +382,7 @@ static char rcsid[] = "nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao"; static char *version = -"nmclan_cs 0.16 (Roger C. Pao)"; +DRV_NAME " " DRV_VERSION " (Roger C. Pao)"; #endif static dev_info_t dev_info="nmclan_cs"; @@ -1001,6 +1008,66 @@ return 0; } /* mace_close */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + +#ifdef PCMCIA_DEBUG + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = pc_debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + pc_debug = edata.data; + return 0; + } +#endif + + default: + break; + } + + return -EOPNOTSUPP; +} + +static int smc91c92_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + + default: + return -EOPNOTSUPP; + } + return 0; +} /* ---------------------------------------------------------------------------- mace_start_xmit diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/ray_cs.c linux-2.5/drivers/net/pcmcia/ray_cs.c --- linux-2.5.1/drivers/net/pcmcia/ray_cs.c Fri Oct 12 21:21:18 2001 +++ linux-2.5/drivers/net/pcmcia/ray_cs.c Thu Jan 10 13:32:21 2002 @@ -999,7 +999,9 @@ /*===========================================================================*/ int ray_dev_init(struct net_device *dev) { +#ifdef RAY_IMMEDIATE_INIT int i; +#endif /* RAY_IMMEDIATE_INIT */ ray_dev_t *local = dev->priv; dev_link_t *link = local->finder; @@ -1008,6 +1010,7 @@ DEBUG(2,"ray_dev_init - device not present\n"); return -1; } +#ifdef RAY_IMMEDIATE_INIT /* Download startup parameters */ if ( (i = dl_startup_params(dev)) < 0) { @@ -1015,7 +1018,14 @@ "returns 0x%x\n",i); return -1; } - +#else /* RAY_IMMEDIATE_INIT */ + /* Postpone the card init so that we can still configure the card, + * for example using the Wireless Extensions. The init will happen + * in ray_open() - Jean II */ + DEBUG(1,"ray_dev_init: postponing card init to ray_open() ; Status = %d\n", + local->card_status); +#endif /* RAY_IMMEDIATE_INIT */ + /* copy mac and broadcast addresses to linux device */ memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); memset(dev->broadcast, 0xff, ETH_ALEN); @@ -1245,6 +1255,22 @@ wrq->u.freq.e = 0; break; + /* Set frequency/channel */ + case SIOCSIWFREQ: + /* Reject if card is already initialised */ + if(local->card_status != CARD_AWAITING_PARAM) + { + err = -EBUSY; + break; + } + + /* Setting by channel number */ + if ((wrq->u.freq.m > USA_HOP_MOD) || (wrq->u.freq.e > 0)) + err = -EOPNOTSUPP; + else + local->sparm.b5.a_hop_pattern = wrq->u.freq.m; + break; + /* Get current network name (ESSID) */ case SIOCGIWESSID: if (wrq->u.data.pointer) @@ -1262,6 +1288,46 @@ } break; + /* Set desired network name (ESSID) */ + case SIOCSIWESSID: + /* Reject if card is already initialised */ + if(local->card_status != CARD_AWAITING_PARAM) + { + err = -EBUSY; + break; + } + + if (wrq->u.data.pointer) + { + char card_essid[IW_ESSID_MAX_SIZE + 1]; + + /* Check if we asked for `any' */ + if(wrq->u.data.flags == 0) + { + /* Corey : can you do that ? */ + err = -EOPNOTSUPP; + } + else + { + /* Check the size of the string */ + if(wrq->u.data.length > + IW_ESSID_MAX_SIZE + 1) + { + err = -E2BIG; + break; + } + copy_from_user(card_essid, + wrq->u.data.pointer, + wrq->u.data.length); + card_essid[IW_ESSID_MAX_SIZE] = '\0'; + + /* Set the ESSID in the card */ + memcpy(local->sparm.b5.a_current_ess_id, card_essid, + IW_ESSID_MAX_SIZE); + } + } + break; + /* Get current Access Point (BSSID in our case) */ case SIOCGIWAP: memcpy(wrq->u.ap_addr.sa_data, local->bss_id, ETH_ALEN); @@ -1304,6 +1370,34 @@ wrq->u.rts.fixed = 1; break; + /* Set the desired RTS threshold */ + case SIOCSIWRTS: + { + int rthr = wrq->u.rts.value; + + /* Reject if card is already initialised */ + if(local->card_status != CARD_AWAITING_PARAM) + { + err = -EBUSY; + break; + } + + /* if(wrq->u.rts.fixed == 0) we should complain */ +#if WIRELESS_EXT > 8 + if(wrq->u.rts.disabled) + rthr = 32767; + else +#endif /* WIRELESS_EXT > 8 */ + if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */ + { + err = -EINVAL; + break; + } + local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF; + local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF; + } + break; + /* Get the current fragmentation threshold */ case SIOCGIWFRAG: wrq->u.frag.value = (local->sparm.b5.a_frag_threshold[0] << 8) @@ -1313,6 +1407,35 @@ #endif /* WIRELESS_EXT > 8 */ wrq->u.frag.fixed = 1; break; + + /* Set the desired fragmentation threshold */ + case SIOCSIWFRAG: + { + int fthr = wrq->u.frag.value; + + /* Reject if card is already initialised */ + if(local->card_status != CARD_AWAITING_PARAM) + { + err = -EBUSY; + break; + } + + /* if(wrq->u.frag.fixed == 0) should complain */ +#if WIRELESS_EXT > 8 + if(wrq->u.frag.disabled) + fthr = 32767; + else +#endif /* WIRELESS_EXT > 8 */ + if((fthr < 256) || (fthr > 2347)) /* To check out ! */ + { + err = -EINVAL; + break; + } + local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF; + local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF; + } + break; + #endif /* WIRELESS_EXT > 7 */ #if WIRELESS_EXT > 8 @@ -1323,6 +1446,33 @@ else wrq->u.mode = IW_MODE_ADHOC; break; + + /* Set the current mode of operation */ + case SIOCSIWMODE: + { + char card_mode = 1; + + /* Reject if card is already initialised */ + if(local->card_status != CARD_AWAITING_PARAM) + { + err = -EBUSY; + break; + } + + switch (wrq->u.mode) + { + case IW_MODE_ADHOC: + card_mode = 0; + // Fall through + case IW_MODE_INFRA: + local->sparm.b5.a_network_type = card_mode; + break; + default: + err = -EINVAL; + } + } + break; + #endif /* WIRELESS_EXT > 8 */ #if WIRELESS_EXT > 7 /* ------------------ IWSPY SUPPORT ------------------ */ @@ -1549,6 +1699,21 @@ if (link->open == 0) local->num_multi = 0; link->open++; + /* If the card is not started, time to start it ! - Jean II */ + if(local->card_status == CARD_AWAITING_PARAM) { + int i; + + DEBUG(1,"ray_open: doing init now !\n"); + + /* Download startup parameters */ + if ( (i = dl_startup_params(dev)) < 0) + { + printk(KERN_INFO "ray_dev_init dl_startup_params failed - " + "returns 0x%x\n",i); + return -1; + } + } + if (sniffer) netif_stop_queue(dev); else netif_start_queue(dev); @@ -1571,6 +1736,11 @@ netif_stop_queue(dev); if (link->state & DEV_STALE_CONFIG) mod_timer(&link->release, jiffies + HZ/20); + + /* In here, we should stop the hardware (stop card from beeing active) + * and set local->card_status to CARD_AWAITING_PARAM, so that while the + * card is closed we can chage its configuration. + * Probably also need a COR reset to get sane state - Jean II */ MOD_DEC_USE_COUNT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/wavelan.h linux-2.5/drivers/net/pcmcia/wavelan.h --- linux-2.5.1/drivers/net/pcmcia/wavelan.h Fri Mar 2 19:02:15 2001 +++ linux-2.5/drivers/net/pcmcia/wavelan.h Sun Jan 13 22:18:32 2002 @@ -88,6 +88,7 @@ */ const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; + /*************************** PC INTERFACE ****************************/ /* WaveLAN host interface definitions */ @@ -316,6 +317,7 @@ /* Calculate offset of a field in the above structure */ #define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) + /* * Modem Management Controller (MMC) read structure. */ @@ -372,6 +374,7 @@ /* Calculate offset of a field in the above structure */ #define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) + /* Make the two above structures one */ typedef union mm_t diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/wavelan_cs.c linux-2.5/drivers/net/pcmcia/wavelan_cs.c --- linux-2.5.1/drivers/net/pcmcia/wavelan_cs.c Fri Nov 9 23:22:54 2001 +++ linux-2.5/drivers/net/pcmcia/wavelan_cs.c Sun Jan 13 22:18:32 2002 @@ -22,7 +22,7 @@ #ifdef WAVELAN_ROAMING * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu) * based on patch by Joe Finney from Lancaster University. -#endif :-) +#endif * * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor. @@ -37,12 +37,6 @@ * Apr 2 '98 made changes to bring the i82593 control/int handling in line * with offical specs... * - * Changes: - * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000 - * - reorganize kmallocs in wavelan_attach, checking all for failure - * and releasing the previous allocations if one fails - * - * **************************************************************************** * Copyright 1995 * Anthony D. Joseph @@ -72,6 +66,34 @@ /*------------------------------------------------------------------*/ /* + * Wrapper for disabling interrupts. + * (note : inline, so optimised away) + */ +static inline void +wv_splhi(net_local * lp, + unsigned long * pflags) +{ + spin_lock_irqsave(&lp->spinlock, *pflags); + /* Note : above does the cli(); itself */ +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for re-enabling interrupts. + */ +static inline void +wv_splx(net_local * lp, + unsigned long * pflags) +{ + spin_unlock_irqrestore(&lp->spinlock, *pflags); + + /* Note : enabling interrupts on the hardware is done in wv_ru_start() + * via : outb(OP1_INT_ENABLE, LCCR(base)); + */ +} + +/*------------------------------------------------------------------*/ +/* * Wrapper for reporting error to cardservices */ static void cs_error(client_handle_t handle, int func, int ret) @@ -103,7 +125,7 @@ /******************* MODEM MANAGEMENT SUBROUTINES *******************/ /* - * Usefull subroutines to manage the modem of the wavelan + * Useful subroutines to manage the modem of the wavelan */ /*------------------------------------------------------------------*/ @@ -138,7 +160,7 @@ { hacr_write(base, hacr); /* delay might only be needed sometimes */ - mdelay(1L); + mdelay(1); } /* hacr_write_slow */ /*------------------------------------------------------------------*/ @@ -529,7 +551,7 @@ lp->curr_point=NULL; /* No default WavePoint */ lp->cell_search=0; - lp->cell_timer.data=(int)lp; /* Start cell expiry timer */ + lp->cell_timer.data=(long)lp; /* Start cell expiry timer */ lp->cell_timer.function=wl_cell_expiry; lp->cell_timer.expires=jiffies+CELL_TIMEOUT; add_timer(&lp->cell_timer); @@ -569,18 +591,18 @@ #endif /* Disable interrupts & save flags */ - spin_lock_irqsave (&lp->lock, flags); + wv_splhi(lp, &flags); m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); - /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore (&lp->lock, flags); - if(mode==NWID_PROMISC) lp->cell_search=1; else - lp->cell_search=0; + lp->cell_search=0; + + /* ReEnable interrupts & restore flags */ + wv_splx(lp, &flags); } /* Find a record in the WavePoint table matching a given NWID */ @@ -737,7 +759,7 @@ ioaddr_t base = lp->dev->base_addr; mm_t m; unsigned long flags; - + if(wavepoint==lp->curr_point) /* Sanity check... */ { wv_nwid_filter(!NWID_PROMISC,lp); @@ -749,16 +771,16 @@ #endif /* Disable interrupts & save flags */ - spin_lock_irqsave(&lp->lock, flags); - + wv_splhi(lp, &flags); + m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore (&lp->lock, flags); - + wv_splx(lp, &flags); + wv_nwid_filter(!NWID_PROMISC,lp); lp->curr_point=wavepoint; } @@ -775,6 +797,11 @@ wavepoint_history *wavepoint=NULL; /* WavePoint table entry */ net_local *lp=(net_local *)dev->priv; /* Device info */ +#if 0 + /* Some people don't need this, some other may need it */ + nwid=nwid^ntohs(beacon->domain_id); +#endif + #if WAVELAN_ROAMING_DEBUG > 1 printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name); printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual); @@ -832,7 +859,9 @@ /*------------------------------------------------------------------*/ /* * Routine to synchronously send a command to the i82593 chip. - * Should be called with interrupts enabled. + * Should be called with interrupts disabled. + * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(), + * wv_82593_config() & wv_diag()) */ static int wv_82593_cmd(device * dev, @@ -841,74 +870,98 @@ int result) { ioaddr_t base = dev->base_addr; - net_local * lp = (net_local *)dev->priv; int status; + int wait_completed; long spin; - u_long flags; /* Spin until the chip finishes executing its current command (if any) */ + spin = 1000; do { - spin_lock_irqsave (&lp->lock, flags); + /* Time calibration of the loop */ + udelay(10); + + /* Read the interrupt register */ outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - spin_unlock_irqrestore (&lp->lock, flags); } - while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE); + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); - /* We are waiting for command completion */ - wv_wait_completed = TRUE; + /* If the interrupt hasn't be posted */ + if(spin <= 0) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n", + str, status); +#endif + return(FALSE); + } /* Issue the command to the controller */ outb(cmd, LCCR(base)); - /* If we don't have to check the result of the command */ + /* If we don't have to check the result of the command + * Note : this mean that the irq handler will deal with that */ if(result == SR0_NO_RESULT) - { - wv_wait_completed = FALSE; - return(TRUE); - } + return(TRUE); - /* Busy wait while the LAN controller executes the command. - * Note : wv_wait_completed should be volatile */ - spin = 0; - while(wv_wait_completed && (spin++ < 1000)) - udelay(10); + /* We are waiting for command completion */ + wait_completed = TRUE; - /* If the interrupt handler hasn't be called */ - if(wv_wait_completed) + /* Busy wait while the LAN controller executes the command. */ + spin = 1000; + do { - outb(OP0_NOP, LCCR(base)); + /* Time calibration of the loop */ + udelay(10); + + /* Read the interrupt register */ + outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); status = inb(LCSR(base)); - if(status & SR0_INTERRUPT) + + /* Check if there was an interrupt posted */ + if((status & SR0_INTERRUPT)) { - /* There was an interrupt : call the interrupt handler */ -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n"); -#endif + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); - wavelan_interrupt(dev->irq, (void *) dev, - (struct pt_regs *) NULL); + /* Check if interrupt is a command completion */ + if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) && + ((status & SR0_BOTH_RX_TX) != 0x0) && + !(status & SR0_RECEPTION)) + { + /* Signal command completion */ + wait_completed = FALSE; + } + else + { + /* Note : Rx interrupts will be handled later, because we can + * handle multiple Rx packets at once */ +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO "wv_82593_cmd: not our interrupt\n"); +#endif + } } - else - { - wv_wait_completed = 0; /* XXX */ + } + while(wait_completed && (spin-- > 0)); + + /* If the interrupt hasn't be posted */ + if(wait_completed) + { #ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n", - str, status); + printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n", + str, status); #endif - /* We probably should reset the controller here */ - return(FALSE); - } + return(FALSE); } - /* Check the return code provided by the interrupt handler against + /* Check the return code returned by the card (see above) against * the expected return code provided by the caller */ - if((lp->status & SR0_EVENT_MASK) != result) + if((status & SR0_EVENT_MASK) != result) { #ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n", - str, lp->status); + printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n", + str, status); #endif return(FALSE); } @@ -924,14 +977,16 @@ static inline int wv_diag(device * dev) { + int ret = FALSE; + if(wv_82593_cmd(dev, "wv_diag(): diagnose", OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED)) - return(TRUE); + ret = TRUE; #ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n"); #endif - return(FALSE); + return(ret); } /* wv_diag */ /*------------------------------------------------------------------*/ @@ -951,15 +1006,6 @@ int chunk_len; char * buf_ptr = buf; -#ifdef OLDIES - /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem - * quite safe to remove this... */ - - /* If buf is NULL, just increment the ring buffer pointer */ - if(buf == NULL) - return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE); -#endif - /* Get all the buffer */ while(len > 0) { @@ -990,70 +1036,32 @@ * wavelan_interrupt is not an option...), so you may experience * some delay sometime... */ -static inline void wv_82593_reconfig (device * dev) +static inline void +wv_82593_reconfig(device * dev) { - net_local *lp = (net_local *) dev->priv; - dev_link_t *link = ((net_local *) dev->priv)->link; + net_local * lp = (net_local *)dev->priv; + dev_link_t * link = ((net_local *) dev->priv)->link; + unsigned long flags; + + /* Arm the flag, will be cleard in wv_82593_config() */ + lp->reconfig_82593 = TRUE; - /* Check if we can do it now ! */ - if (!(link->open)) { - lp->reconfig_82593 = TRUE; + /* Check if we can do it now ! */ + if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) + { + wv_splhi(lp, &flags); /* Disable interrupts */ + wv_82593_config(dev); + wv_splx(lp, &flags); /* Re-enable interrupts */ + } + else + { #ifdef DEBUG_IOCTL_INFO - printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n", - dev->name, link->open); + printk(KERN_DEBUG + "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n", + dev->name, dev->state, link->open); #endif - } else { - netif_stop_queue (dev); - - lp->reconfig_82593 = FALSE; - wv_82593_config (dev); - netif_wake_queue (dev); - } -} - -#ifdef OLDIES -/*------------------------------------------------------------------*/ -/* - * Dumps the current i82593 receive buffer to the console. - */ -static void wavelan_dump(device *dev) -{ - ioaddr_t base = dev->base_addr; - int i, c; - - /* disable receiver so we can use channel 1 */ - outb(OP0_RCV_DISABLE, LCCR(base)); - - /* reset receive DMA pointer */ - hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET); - hacr_write(base, HACR_DEFAULT); - - /* dump into receive buffer */ - wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE); - - /* set read pointer to start of receive buffer */ - outb(0, PIORL(base)); - outb(0, PIORH(base)); - - printk(KERN_DEBUG "wavelan_cs: dump:\n"); - printk(KERN_DEBUG " 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); - for(i = 0; i < 73; i++){ - if((i % 16) == 0) { - printk("\n0x%02x:", i); - if (!i) { - printk(" "); - continue; - } } - c = inb(PIOP(base)); - printk("%02x ", c); - } - printk("\n"); - - /* enable the receiver again */ - wv_ru_start(dev); } -#endif /********************* DEBUG & INFO SUBROUTINES *********************/ /* @@ -1171,6 +1179,8 @@ return; } + wv_splhi(lp, &flags); + /* Read the mmc */ mmc_out(base, mmwoff(0, mmw_freeze), 1); mmc_read(base, 0, (u_char *)&m, sizeof(m)); @@ -1181,6 +1191,8 @@ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; #endif /* WIRELESS_EXT */ + wv_splx(lp, &flags); + printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); #ifdef DEBUG_SHOW_UNUSED printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", @@ -1265,6 +1277,7 @@ wv_dev_show(device * dev) { printk(KERN_DEBUG "dev:"); + printk(" state=%lX,", dev->state); printk(" trans_start=%ld,", dev->trans_start); printk(" flags=0x%x,", dev->flags); printk("\n"); @@ -1404,7 +1417,7 @@ printk("2430.5"); break; default: - printk("unknown"); + printk("???"); } } @@ -1719,7 +1732,7 @@ memcmp(dac, dac_verify, 2 * 2)) { #ifdef DEBUG_IOCTL_ERROR - printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n"); + printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n"); #endif return -EOPNOTSUPP; } @@ -1892,7 +1905,7 @@ #endif /* Disable interrupts & save flags */ - spin_lock_irqsave (&lp->lock, flags); + wv_splhi(lp, &flags); /* Look what is the request */ switch(cmd) @@ -1968,7 +1981,7 @@ case SIOCGIWFREQ: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody XXX - especially old cards...) */ + * (does it work for everybody ??? - especially old cards...) */ if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { @@ -2239,15 +2252,17 @@ { struct iw_range range; - /* Set the length (very important for backward compatibility) */ - wrq->u.data.length = sizeof(struct iw_range); + /* 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 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 */ +#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 = 1.4 * 1000 * 1000; /* don't argue on this ! */ @@ -2517,7 +2532,7 @@ } /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore (&lp->lock, flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); @@ -2543,11 +2558,8 @@ printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); #endif - if (lp == NULL) /* XXX will this ever occur? */ - return NULL; - /* Disable interrupts & save flags */ - spin_lock_irqsave (&lp->lock, flags); + wv_splhi(lp, &flags); wstats = &lp->wstats; @@ -2573,7 +2585,7 @@ wstats->discard.misc = 0L; /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore (&lp->lock, flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); @@ -2692,12 +2704,6 @@ skb->protocol = eth_type_trans(skb, dev); #ifdef DEBUG_RX_INFO - /* Another glitch : Due to the way the GET_PACKET macro is written, - * we are not sure to have the same thing in skb->data. On the other - * hand, skb->mac.raw is not defined everywhere... - * For versions between 1.2.13 and those where skb->mac.raw appear, - * I don't have a clue... - */ wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); #endif /* DEBUG_RX_INFO */ @@ -2731,9 +2737,7 @@ wl_roam_gather(dev, skb->data, stats); #endif /* WAVELAN_ROAMING */ - /* Spying stuff */ #ifdef WIRELESS_SPY - /* Same as above */ wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); #endif /* WIRELESS_SPY */ #ifdef HISTOGRAM @@ -2766,6 +2770,7 @@ * called to do the actual transfer of the card's data including the * ethernet header into a packet consisting of an sk_buff chain. * (called by wavelan_interrupt()) + * Note : the spinlock is already grabbed for us and irq are disabled. */ static inline void wv_packet_rcv(device * dev) @@ -2916,7 +2921,7 @@ printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); #endif - spin_lock_irqsave (&lp->lock, flags); + wv_splhi(lp, &flags); /* Check if we need some padding */ if(clen < ETH_ZLEN) @@ -2946,15 +2951,7 @@ /* Keep stats up to date */ lp->stats.tx_bytes += length; - /* If watchdog not already active, activate it... */ - if (!timer_pending(&lp->watchdog)) - { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - - spin_unlock_irqrestore (&lp->lock, flags); + wv_splx(lp, &flags); #ifdef DEBUG_TX_INFO wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); @@ -2963,56 +2960,57 @@ #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); #endif - - netif_start_queue (dev); } /*------------------------------------------------------------------*/ /* * This routine is called when we want to send a packet (NET3 callback) - * In this routine, we check if the hardware is ready to accept + * In this routine, we check if the harware is ready to accept * the packet. We also prevent reentrance. Then, we call the function * to send the packet... */ -static int wavelan_packet_xmit (struct sk_buff *skb, - device * dev) +static int +wavelan_packet_xmit(struct sk_buff * skb, + device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local * lp = (net_local *)dev->priv; + unsigned long flags; #ifdef DEBUG_TX_TRACE - printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, - (unsigned) skb); + printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, + (unsigned) skb); #endif - /* - * For ethernet, fill in the header. - */ + /* + * Block a timer-based transmit from overlapping a previous transmit. + * In other words, prevent reentering this routine. + */ + netif_stop_queue(dev); - netif_stop_queue (dev); + /* If somebody has asked to reconfigure the controller, + * we can do it now */ + if(lp->reconfig_82593) + { + wv_splhi(lp, &flags); /* Disable interrupts */ + wv_82593_config(dev); + wv_splx(lp, &flags); /* Re-enable interrupts */ + /* Note : the configure procedure was totally synchronous, + * so the Tx buffer is now free */ + } - /* - * Block a timer-based transmit from overlapping a previous transmit. - * In other words, prevent reentering this routine. - */ - if (1) { - /* If somebody has asked to reconfigure the controller, we can do it now */ - if (lp->reconfig_82593) { - lp->reconfig_82593 = FALSE; - wv_82593_config (dev); - } #ifdef DEBUG_TX_ERROR - if (skb->next) - printk (KERN_INFO "skb has next\n"); + if (skb->next) + printk(KERN_INFO "skb has next\n"); #endif - wv_packet_write (dev, skb->data, skb->len); - } - dev_kfree_skb (skb); + wv_packet_write(dev, skb->data, skb->len); + + dev_kfree_skb(skb); #ifdef DEBUG_TX_TRACE - printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); #endif - return (0); + return(0); } /********************** HARDWARE CONFIGURATION **********************/ @@ -3165,7 +3163,7 @@ */ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody XXX - especially old cards...) */ + * (does it work for everybody ??? - especially old cards...) */ /* Note : WFREQSEL verify that it is able to read from EEprom * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID * is 0xA (Xilinx version) or 0xB (Ariadne version). @@ -3223,7 +3221,7 @@ wv_ru_stop(device * dev) { ioaddr_t base = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local * lp = (net_local *) dev->priv; unsigned long flags; int status; int spin; @@ -3232,35 +3230,35 @@ printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); #endif + wv_splhi(lp, &flags); + /* First, send the LAN controller a stop receive command */ wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", OP0_STOP_RCV, SR0_NO_RESULT); /* Then, spin until the receive unit goes idle */ - spin = 0; + spin = 300; do { udelay(10); - spin_lock_irqsave (&lp->lock, flags); outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - spin_unlock_irqrestore (&lp->lock, flags); } - while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300)); + while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0)); /* Now, spin until the chip finishes executing its current command */ do { udelay(10); - spin_lock_irqsave (&lp->lock, flags); outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - spin_unlock_irqrestore (&lp->lock, flags); } - while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300)); + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); + + wv_splx(lp, &flags); /* If there was a problem */ - if(spin > 300) + if(spin <= 0) { #ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n", @@ -3287,6 +3285,7 @@ { ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; + unsigned long flags; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); @@ -3300,6 +3299,8 @@ if(!wv_ru_stop(dev)) return FALSE; + wv_splhi(lp, &flags); + /* Now we know that no command is being executed. */ /* Set the receive frame pointer and stop pointer */ @@ -3309,8 +3310,17 @@ /* Reset ring management. This sets the receive frame pointer to 1 */ outb(OP1_RESET_RING_MNGMT, LCCR(base)); +#if 0 + /* XXX the i82593 manual page 6-4 seems to indicate that the stop register + should be set as below */ + /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/ +#elif 0 + /* but I set it 0 instead */ + lp->stop = 0; +#else /* but I set it to 3 bytes per packet less than 8K */ lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; +#endif outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); outb(OP1_INT_ENABLE, LCCR(base)); outb(OP1_SWIT_TO_PORT_0, LCCR(base)); @@ -3326,17 +3336,15 @@ #ifdef DEBUG_I82593_SHOW { int status; - unsigned long flags; - int i = 0; + int opri; + int spin = 10000; /* spin until the chip starts receiving */ do { - spin_lock_irqsave (&lp->lock, flags); outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - spin_unlock_irqrestore (&lp->lock, flags); - if(i++ > 10000) + if(spin-- <= 0) break; } while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) && @@ -3345,6 +3353,9 @@ (status & SR3_RCV_STATE_MASK), i); } #endif + + wv_splx(lp, &flags); + #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); #endif @@ -3363,6 +3374,7 @@ ioaddr_t base = dev->base_addr; net_local * lp = (net_local *) dev->priv; struct i82593_conf_block cfblk; + int ret = TRUE; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name); @@ -3457,7 +3469,7 @@ hacr_write(base, HACR_DEFAULT); if(!wv_82593_cmd(dev, "wv_82593_config(): configure", OP0_CONFIGURE, SR0_CONFIGURE_DONE)) - return(FALSE); + ret = FALSE; /* Initialize adapter's ethernet MAC address */ outb(TX_BASE & 0xff, PIORL(base)); @@ -3471,7 +3483,7 @@ hacr_write(base, HACR_DEFAULT); if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup", OP0_IA_SETUP, SR0_IA_SETUP_DONE)) - return(FALSE); + ret = FALSE; #ifdef WAVELAN_ROAMING /* If roaming is enabled, join the "Beacon Request" multicast group... */ @@ -3508,14 +3520,17 @@ hacr_write(base, HACR_DEFAULT); if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", OP0_MC_SETUP, SR0_MC_SETUP_DONE)) - return(FALSE); + ret = FALSE; lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ } + /* Job done, clear the flag */ + lp->reconfig_82593 = FALSE; + #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name); #endif - return(TRUE); + return(ret); } /*------------------------------------------------------------------*/ @@ -3594,6 +3609,8 @@ { net_local * lp = (net_local *) dev->priv; ioaddr_t base = dev->base_addr; + unsigned long flags; + int ret = FALSE; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name); @@ -3612,50 +3629,78 @@ if(wv_pcmcia_reset(dev) == FALSE) return FALSE; - /* Power UP the module + reset the modem + reset host adapter - * (in fact, reset DMA channels) */ - hacr_write_slow(base, HACR_RESET); - hacr_write(base, HACR_DEFAULT); + /* Disable interrupts */ + wv_splhi(lp, &flags); - /* Check if the module has been powered up... */ - if(hasr_read(base) & HASR_NO_CLK) + /* Disguised goto ;-) */ + do { + /* Power UP the module + reset the modem + reset host adapter + * (in fact, reset DMA channels) */ + hacr_write_slow(base, HACR_RESET); + hacr_write(base, HACR_DEFAULT); + + /* Check if the module has been powered up... */ + if(hasr_read(base) & HASR_NO_CLK) + { #ifdef DEBUG_CONFIG_ERRORS - printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", - dev->name); + printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", + dev->name); #endif - return FALSE; - } + break; + } - /* initialize the modem */ - if(wv_mmc_init(dev) == FALSE) - return FALSE; + /* initialize the modem */ + if(wv_mmc_init(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n", + dev->name); +#endif + break; + } - /* reset the LAN controller (i82593) */ - outb(OP0_RESET, LCCR(base)); - mdelay(1); /* A bit crude ! */ - - /* Initialize the LAN controller */ - if((wv_82593_config(dev) == FALSE) || - (wv_diag(dev) == FALSE)) - { + /* reset the LAN controller (i82593) */ + outb(OP0_RESET, LCCR(base)); + mdelay(1); /* A bit crude ! */ + + /* Initialize the LAN controller */ + if(wv_82593_config(dev) == FALSE) + { #ifdef DEBUG_CONFIG_ERRORS - printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name); + printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", + dev->name); #endif - return FALSE; - } + break; + } - /* - * insert code for loopback test here - */ + /* Diagnostic */ + if(wv_diag(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n", + dev->name); +#endif + break; + } - /* The device is now configured */ - lp->configured = 1; + /* + * insert code for loopback test here + */ + + /* The device is now configured */ + lp->configured = 1; + ret = TRUE; + } + while(0); + + /* Re-enable interrupts */ + wv_splx(lp, &flags); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); #endif - return TRUE; + return(ret); } /*------------------------------------------------------------------*/ @@ -3675,10 +3720,6 @@ printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name); #endif - /* If watchdog was activated, kill it ! */ - if (timer_pending(&lp->watchdog)) - del_timer(&lp->watchdog); - lp->nresets++; lp->configured = 0; @@ -3786,13 +3827,13 @@ } /* - * Allocate a 4K memory window. Note that the dev_link_t + * Allocate a small memory window. Note that the dev_link_t * structure provides space for one window handle -- if your * device needs several windows, you'll need to keep track of * the handles in your private data structure, link->priv. */ req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - req.Base = 0; req.Size = 0x1000; + req.Base = req.Size = 0; req.AccessSpeed = mem_speed; link->win = (window_handle_t)link->handle; i = CardServices(RequestWindow, &link->win, &req); @@ -3803,7 +3844,7 @@ } dev->rmem_start = dev->mem_start = - (u_long)ioremap(req.Base, 0x1000); + (u_long)ioremap(req.Base, req.Size); dev->rmem_end = dev->mem_end = dev->mem_start + req.Size; mem.CardOffset = 0; mem.Page = 0; @@ -3817,7 +3858,7 @@ /* Feed device with this info... */ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - netif_start_queue (dev); + netif_start_queue(dev); #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n", @@ -3843,7 +3884,7 @@ return FALSE; } - /* XXX Could you explain me this, Dave ? */ + strcpy(((net_local *) dev->priv)->node.dev_name, dev->name); link->dev = &((net_local *) dev->priv)->node; #ifdef DEBUG_CONFIG_TRACE @@ -3887,7 +3928,7 @@ CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); - link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG); + link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); @@ -3896,7 +3937,7 @@ /*------------------------------------------------------------------*/ /* - * Sometimes, netwave_detach can't be performed following a call from + * Sometimes, wavelan_detach can't be performed following a call from * cardmgr (device still open, pcmcia_release not done) and the device * is put in a STALE_LINK state and remains in memory. * @@ -3970,7 +4011,19 @@ lp = (net_local *) dev->priv; base = dev->base_addr; - spin_lock (&lp->lock); +#ifdef DEBUG_INTERRUPT_INFO + /* Check state of our spinlock (it should be cleared) */ + if(spin_is_locked(&lp->spinlock)) + printk(KERN_DEBUG + "%s: wavelan_interrupt(): spinlock is already locked !!!\n", + dev->name); +#endif + + /* Prevent reentrancy. We need to do that because we may have + * multiple interrupt handler running concurently. + * It is safe because wv_splhi() disable interrupts before aquiring + * the spinlock. */ + spin_lock(&lp->spinlock); /* Treat all pending interrupts */ while(1) @@ -4015,8 +4068,6 @@ break; } - lp->status = status0; /* Save current status (for commands) */ - /* ----------------- RECEIVING PACKET ----------------- */ /* * When the wavelan signal the reception of a new packet, @@ -4054,22 +4105,6 @@ * Most likely : transmission done */ - /* If we are already waiting elsewhere for the command to complete */ - if(wv_wait_completed) - { -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n", - dev->name); -#endif - - /* Signal command completion */ - wv_wait_completed = 0; - - /* Acknowledge the interrupt */ - outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); - continue; - } - /* If a transmission has been done */ if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE || @@ -4081,10 +4116,6 @@ dev->name); #endif - /* If watchdog was activated, kill it ! */ - if(timer_pending(&lp->watchdog)) - del_timer(&lp->watchdog); - /* Get transmission status */ tx_status = inb(LCSR(base)); tx_status |= (inb(LCSR(base)) << 8); @@ -4174,7 +4205,7 @@ lp->stats.collisions += (tx_status & TX_NCOL_MASK); lp->stats.tx_packets++; - netif_wake_queue (dev); + netif_wake_queue(dev); outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ } else /* if interrupt = transmit done or retransmit done */ @@ -4185,9 +4216,9 @@ #endif outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ } - } + } /* while(1) */ - spin_unlock_irq (&lp->lock); + spin_unlock(&lp->spinlock); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); @@ -4196,30 +4227,23 @@ /*------------------------------------------------------------------*/ /* - * Watchdog : when we start a transmission, we set a timer in the - * kernel. If the transmission complete, this timer is disabled. If - * it expire, it try to unlock the hardware. + * Watchdog: when we start a transmission, a timer is set for us in the + * kernel. If the transmission completes, this timer is disabled. If + * the timer expires, we are called and we try to unlock the hardware. * - * Note : this watchdog doesn't work on the same principle as the - * watchdog in the ISA driver. I make it this way because the overhead - * of add_timer() and del_timer() is nothing and that it avoid calling - * the watchdog, saving some CPU... If you want to apply the same - * watchdog to the ISA driver, you should be a bit carefull, because - * of the many transmit buffers... - * This watchdog is also move clever, it try to abort the current - * command before reseting everything... + * Note : This watchdog is move clever than the one in the ISA driver, + * because it try to abort the current command before reseting + * everything... + * On the other hand, it's a bit simpler, because we don't have to + * deal with the multiple Tx buffers... */ static void -wavelan_watchdog(u_long a) +wavelan_watchdog(device * dev) { - device * dev; - net_local * lp; - ioaddr_t base; - int spin; - - dev = (device *) a; - base = dev->base_addr; - lp = (net_local *) dev->priv; + net_local * lp = (net_local *) dev->priv; + ioaddr_t base = dev->base_addr; + unsigned long flags; + int aborted = FALSE; #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); @@ -4230,21 +4254,21 @@ dev->name); #endif - /* We are waiting for command completion */ - wv_wait_completed = TRUE; + wv_splhi(lp, &flags); /* Ask to abort the current command */ outb(OP0_ABORT, LCCR(base)); - /* Busy wait while the LAN controller executes the command. - * Note : wv_wait_completed should be volatile */ - spin = 0; - while(wv_wait_completed && (spin++ < 250)) - udelay(10); - - /* If the interrupt handler hasn't be called or invalid status */ - if((wv_wait_completed) || - ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED)) + /* Wait for the end of the command (a bit hackish) */ + if(wv_82593_cmd(dev, "wavelan_watchdog(): abort", + OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED)) + aborted = TRUE; + + /* Release spinlock here so that wv_hw_reset() can grab it */ + wv_splx(lp, &flags); + + /* Check if we were successful in aborting it */ + if(!aborted) { /* It seem that it wasn't enough */ #ifdef DEBUG_INTERRUPT_ERROR @@ -4269,7 +4293,7 @@ #endif /* We are no more waiting for something... */ - netif_start_queue (dev); + netif_wake_queue(dev); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); @@ -4322,7 +4346,7 @@ return FALSE; if(!wv_ru_start(dev)) wv_hw_reset(dev); /* If problem : reset */ - netif_start_queue (dev); + netif_start_queue(dev); /* Mark the device as used */ link->open++; @@ -4348,7 +4372,6 @@ wavelan_close(device * dev) { dev_link_t * link = ((net_local *) dev->priv)->link; - net_local * lp = (net_local *)dev->priv; ioaddr_t base = dev->base_addr; #ifdef DEBUG_CALLBACK_TRACE @@ -4356,8 +4379,6 @@ (unsigned int) dev); #endif - netif_stop_queue (dev); - /* If the device isn't open, then nothing to do */ if(!link->open) { @@ -4373,17 +4394,13 @@ wv_roam_cleanup(dev); #endif /* WAVELAN_ROAMING */ - /* If watchdog was activated, kill it ! */ - if(timer_pending(&lp->watchdog)) - del_timer(&lp->watchdog); - link->open--; MOD_DEC_USE_COUNT; /* If the card is still present */ - if (netif_device_present(dev)) + if(netif_running(dev)) { - netif_stop_queue (dev); + netif_stop_queue(dev); /* Stop receiving new messages and wait end of transmission */ wv_ru_stop(dev); @@ -4404,21 +4421,6 @@ /*------------------------------------------------------------------*/ /* - * We never need to do anything when a wavelan device is "initialized" - * by the net software, because we only register already-found cards. - */ -static int -wavelan_init(device * dev) -{ -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "<>wavelan_init()\n"); -#endif - - return(0); -} - -/*------------------------------------------------------------------*/ -/* * wavelan_attach() creates an "instance" of the driver, allocating * local data structures for one device (one interface). The device * is registered with Card Services. @@ -4445,24 +4447,8 @@ /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - if (!link) - return NULL; - - /* Allocate the generic data structure */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!dev) - goto fail_alloc_dev; - - /* Allocate the wavelan-specific data structure. */ - lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); - if (!lp) - goto fail_alloc_dev_priv; - - memset(lp, 0, sizeof(net_local)); + if (!link) return NULL; memset(link, 0, sizeof(struct dev_link_t)); - memset(dev, 0, sizeof(struct net_device)); - - dev->priv = lp; /* Unused for the Wavelan */ link->release.function = &wv_pcmcia_release; @@ -4492,18 +4478,35 @@ link->next = dev_list; dev_list = link; + /* Allocate the generic data structure */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (!dev) { + kfree(link); + return NULL; + } + memset(dev, 0x00, sizeof(struct net_device)); link->priv = link->irq.Instance = dev; + /* Allocate the wavelan-specific data structure. */ + dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); + if (!lp) { + kfree(link); + kfree(dev); + return NULL; + } + memset(lp, 0x00, sizeof(net_local)); + /* Init specific data */ - wv_wait_completed = 0; - lp->status = FALSE; lp->configured = 0; lp->reconfig_82593 = FALSE; lp->nresets = 0; + /* Multicast stuff */ + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = 0; - /* Set the watchdog timer */ - lp->watchdog.function = wavelan_watchdog; - lp->watchdog.data = (unsigned long) dev; + /* Init spinlock */ + spin_lock_init(&lp->spinlock); /* back links */ lp->link = link; @@ -4513,7 +4516,6 @@ ether_setup(dev); /* wavelan NET3 callbacks */ - dev->init = &wavelan_init; dev->open = &wavelan_open; dev->stop = &wavelan_close; dev->hard_start_xmit = &wavelan_packet_xmit; @@ -4523,14 +4525,16 @@ dev->set_mac_address = &wavelan_set_mac_address; #endif /* SET_MAC_ADDRESS */ + /* Set the watchdog timer */ + dev->tx_timeout = &wavelan_watchdog; + dev->watchdog_timeo = WATCHDOG_JIFFIES; + #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ dev->do_ioctl = wavelan_ioctl; /* wireless extensions */ dev->get_wireless_stats = wavelan_get_wireless_stats; #endif /* Other specific data */ - strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name); - netif_start_queue (dev); dev->mtu = WAVELAN_MTU; /* Register with Card Services */ @@ -4562,12 +4566,6 @@ #endif return link; - -fail_alloc_dev_priv: - kfree(dev); -fail_alloc_dev: - kfree(link); - return NULL; } /*------------------------------------------------------------------*/ @@ -4698,7 +4696,7 @@ if(link->state & DEV_CONFIG) { /* Accept no more transmissions */ - netif_device_detach(dev); + netif_device_detach(dev); /* Release the card */ wv_pcmcia_release((u_long) link); @@ -4720,7 +4718,7 @@ * obliged to close nicely the wavelan here. David, could you * close the device before suspending them ? And, by the way, * could you, on resume, add a "route add -net ..." after the - * ifconfig up XXX Thanks... */ + * ifconfig up ??? Thanks... */ /* Stop receiving new messages and wait end of transmission */ wv_ru_stop(dev); @@ -4735,8 +4733,7 @@ if(link->state & DEV_CONFIG) { if(link->open) - netif_device_detach(dev); - + netif_device_detach(dev); CardServices(ReleaseConfiguration, link->handle); } break; @@ -4748,7 +4745,7 @@ if(link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); - if(link->open) /* If RESET -> True, If RESUME -> False XXX */ + if(link->open) /* If RESET -> True, If RESUME -> False ??? */ { wv_hw_reset(dev); netif_device_attach(dev); @@ -4838,4 +4835,3 @@ module_init(init_wavelan_cs); module_exit(exit_wavelan_cs); -MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/wavelan_cs.h linux-2.5/drivers/net/pcmcia/wavelan_cs.h --- linux-2.5.1/drivers/net/pcmcia/wavelan_cs.h Fri Oct 12 21:21:18 2001 +++ linux-2.5/drivers/net/pcmcia/wavelan_cs.h Sun Jan 13 22:18:32 2002 @@ -34,6 +34,25 @@ * I try to maintain a web page with the Wireless LAN Howto at : * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html * + * SMP + * --- + * We now are SMP compliant (I eventually fixed the remaining bugs). + * The driver has been tested on a dual P6-150 and survived my usual + * set of torture tests. + * Anyway, I spent enough time chasing interrupt re-entrancy during + * errors or reconfigure, and I designed the locked/unlocked sections + * of the driver with great care, and with the recent addition of + * the spinlock (thanks to the new API), we should be quite close to + * the truth. + * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), + * but better safe than sorry (especially at 2 Mb/s ;-). + * + * I have also looked into disabling only our interrupt on the card + * (via HACR) instead of all interrupts in the processor (via cli), + * so that other driver are not impacted, and it look like it's + * possible, but it's very tricky to do right (full of races). As + * the gain would be mostly for SMP systems, it can wait... + * * Debugging and options * --------------------- * You will find below a set of '#define" allowing a very fine control @@ -122,7 +141,7 @@ * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work. * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start * correctly 2.00 cards (2.4 GHz with frequency selection). - * David Hinds <dhinds@pcmcia.sourceforge.org> integrated the whole in his + * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his * Pcmcia package (+ bug corrections). * * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some @@ -158,8 +177,8 @@ * * This software was originally developed under Linux 1.2.3 * (Slackware 2.0 distribution). - * And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with - * HP OmniBook 4000 & 5500. + * And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+) + * with an HP OmniBook 4000 and then a 5500. * * It is based on other device drivers and information either written * or supplied by: @@ -174,7 +193,7 @@ * Matthew Geier (matthew@cs.su.oz.au), * Remo di Giovanni (remo@cs.su.oz.au), * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), - * David Hinds <dhinds@pcmcia.sourceforge.org>, + * David Hinds <dahinds@users.sourceforge.net>, * Jan Hoogendoorn (c/o marteijn@lucent.com), * Bruce Janson <bruce@cs.usyd.edu.au>, * Anthony D. Joseph <adj@lcs.mit.edu>, @@ -349,6 +368,32 @@ * - Fix check for root permission (break instead of exit) * - New nwid & encoding setting (Wireless Extension 9) * + * Changes made for release in 3.1.12 : + * ---------------------------------- + * - reworked wv_82593_cmd to avoid using the IRQ handler and doing + * ugly things with interrupts. + * - Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog + * - Update to new network API (softnet - 2.3.43) : + * o replace dev->tbusy (David + me) + * o replace dev->tstart (David + me) + * o remove dev->interrupt (David) + * o add SMP locking via spinlock in splxx (me) + * o add spinlock in interrupt handler (me) + * o use kernel watchdog instead of ours (me) + * o verify that all the changes make sense and work (me) + * - Re-sync kernel/pcmcia versions (not much actually) + * - A few other cleanups (David & me)... + * + * Changes made for release in 3.1.22 : + * ---------------------------------- + * - Check that SMP works, remove annoying log message + * + * Changes made for release in 3.1.24 : + * ---------------------------------- + * - Fix unfrequent card lockup when watchdog was reseting the hardware : + * o control first busy loop in wv_82593_cmd() + * o Extend spinlock protection in wv_hw_config() + * * Wishes & dreams: * ---------------- * - Cleanup and integrate the roaming code @@ -368,6 +413,7 @@ #include <linux/string.h> #include <linux/timer.h> #include <linux/interrupt.h> +#include <linux/spinlock.h> #include <linux/in.h> #include <linux/delay.h> #include <asm/uaccess.h> @@ -384,7 +430,7 @@ #ifdef CONFIG_NET_PCMCIA_RADIO #include <linux/wireless.h> /* Wireless extensions */ -#endif /* CONFIG_NET_PCMCIA_RADIO */ +#endif /* Pcmcia headers that we need */ #include <pcmcia/cs_types.h> @@ -437,7 +483,7 @@ #undef DEBUG_RX_INFO /* Header of the transmitted packet */ #undef DEBUG_RX_FAIL /* Normal failure conditions */ #define DEBUG_RX_ERROR /* Unexpected conditions */ -#undef DEBUG_PACKET_DUMP /* Dump packet on the screen */ +#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen */ #undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ #undef DEBUG_IOCTL_INFO /* Various debug info */ #define DEBUG_IOCTL_ERROR /* What's going wrong */ @@ -452,7 +498,7 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n"; +static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n"; #endif /* Watchdog temporisation */ @@ -557,9 +603,9 @@ */ struct net_local { - spinlock_t lock; dev_node_t node; /* ???? What is this stuff ???? */ device * dev; /* Reverse link... */ + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ dev_link_t * link; /* pcmcia structure */ en_stats stats; /* Ethernet interface statistics */ int nresets; /* Number of hw resets */ @@ -568,9 +614,7 @@ u_char promiscuous; /* Promiscuous mode */ u_char allmulticast; /* All Multicast mode */ int mc_count; /* Number of multicast addresses */ - timer_list watchdog; /* To avoid blocking state */ - u_char status; /* Current i82593 status */ int stop; /* Current i82593 Stop Hit Register */ int rfp; /* Last DMA machine receive pointer */ int overrunning; /* Receiver overrun flag */ @@ -617,8 +661,14 @@ #endif /* WAVELAN_ROAMING */ /* ----------------------- MISC SUBROUTINES ------------------------ */ +static inline void + wv_splhi(net_local *, /* Disable interrupts */ + unsigned long *); /* flags */ +static inline void + wv_splx(net_local *, /* ReEnable interrupts */ + unsigned long *); /* flags */ static void - cs_error(client_handle_t, /* Report error to cardmgr */ + cs_error(client_handle_t, /* Report error to cardmgr */ int, int); /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ @@ -722,16 +772,15 @@ wv_flush_stale_links(void); /* "detach" all possible devices */ /* ---------------------- INTERRUPT HANDLING ---------------------- */ static void -wavelan_interrupt(int, /* Interrupt handler */ - void *, - struct pt_regs *); + wavelan_interrupt(int, /* Interrupt handler */ + void *, + struct pt_regs *); static void - wavelan_watchdog(u_long); /* Transmission watchdog */ + wavelan_watchdog(device *); /* Transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int wavelan_open(device *), /* Open the device */ - wavelan_close(device *), /* Close the device */ - wavelan_init(device *); /* Do nothing */ + wavelan_close(device *); /* Close the device */ static dev_link_t * wavelan_attach(void); /* Create a new device */ static void @@ -744,11 +793,7 @@ /**************************** VARIABLES ****************************/ static dev_info_t dev_info = "wavelan_cs"; -static dev_link_t *dev_list; /* Linked list of devices */ - -/* WARNING : the following variable MUST be volatile - * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ -static volatile int wv_wait_completed; +static dev_link_t *dev_list = NULL; /* Linked list of devices */ /* * Parameters that can be set with 'insmod' @@ -761,7 +806,7 @@ static int irq_list[4] = { -1 }; /* Shared memory speed, in ns */ -static int mem_speed; +static int mem_speed = 0; /* New module interface */ MODULE_PARM(irq_mask, "i"); @@ -770,9 +815,11 @@ #ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ /* Enable roaming mode ? No ! Please keep this to 0 */ -static int do_roaming; +static int do_roaming = 0; MODULE_PARM(do_roaming, "i"); #endif /* WAVELAN_ROAMING */ + +MODULE_LICENSE("GPL"); #endif /* WAVELAN_CS_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/xircom_cb.c linux-2.5/drivers/net/pcmcia/xircom_cb.c --- linux-2.5.1/drivers/net/pcmcia/xircom_cb.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/net/pcmcia/xircom_cb.c Thu Dec 13 16:32:36 2001 @@ -170,7 +170,7 @@ name: "xircom_cb", id_table: xircom_pci_table, probe: xircom_probe, - remove: xircom_remove, + remove: __devexit_p(xircom_remove), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcmcia/xircom_tulip_cb.c linux-2.5/drivers/net/pcmcia/xircom_tulip_cb.c --- linux-2.5.1/drivers/net/pcmcia/xircom_tulip_cb.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/net/pcmcia/xircom_tulip_cb.c Thu Dec 13 16:32:36 2001 @@ -1748,7 +1748,7 @@ name: DRV_NAME, id_table: xircom_pci_table, probe: xircom_init_one, - remove: xircom_remove_one, + remove: __devexit_p(xircom_remove_one), #ifdef CONFIG_PM suspend: xircom_suspend, resume: xircom_resume diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/pcnet32.c linux-2.5/drivers/net/pcnet32.c --- linux-2.5.1/drivers/net/pcnet32.c Sun Nov 11 18:09:33 2001 +++ linux-2.5/drivers/net/pcnet32.c Thu Dec 27 16:32:31 2001 @@ -648,6 +648,13 @@ #if defined(__i386__) printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name); memcpy(dev->dev_addr, promaddr, 6); +#elif defined(__powerpc__) + if (!is_valid_ether_addr(dev->dev_addr) + && is_valid_ether_addr(promaddr)) { + printk("\n" KERN_WARNING "%s: using PROM address:", + dev->name); + memcpy(dev->dev_addr, promaddr, 6); + } #endif } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/rclanmtl.c linux-2.5/drivers/net/rclanmtl.c --- linux-2.5.1/drivers/net/rclanmtl.c Mon Jul 2 21:03:04 2001 +++ linux-2.5/drivers/net/rclanmtl.c Mon Jan 14 22:39:45 2002 @@ -299,21 +299,21 @@ { int result; PPAB pPab; - U32 pciBaseAddr = dev->base_addr; PDPA pDpa = dev->priv; + U32 pciBaseAddr = dev->base_addr; PU8 p_msgbuf = pDpa->PLanApiPA; PU8 p_phymsgbuf = (PU8) virt_to_bus ((void *) p_msgbuf); dprintk - ("InitI2O: Adapter:0x%04ux ATU:0x%08ulx msgbuf:0x%08ulx phymsgbuf:0x%08ulx\n" - "TransmitCallbackFunction:0x%08ulx ReceiveCallbackFunction:0x%08ulx\n", + ("InitI2O: Adapter:0x%x ATU:0x%x msgbuf:0x%x phymsgbuf:0x%x\n" + "TransmitCallbackFunction:0x%x ReceiveCallbackFunction:0x%x\n", pDpa->id, pciBaseAddr, (u32) p_msgbuf, (u32) p_phymsgbuf, (u32) TransmitCallbackFunction, (u32) ReceiveCallbackFunction); /* Check if this interface already initialized - if so, shut it down */ if (pDpa->pPab != NULL) { - printk (KERN_WARNING - "(rcpci45 driver:) pDpa->pPab [%d] != NULL\n", + dprintk (KERN_WARNING + "pDpa->pPab [%d] != NULL\n", pDpa->id); /* RCResetLANCard(pDpa->id, 0, (PU32)NULL, (PFNCALLBACK)NULL); */ pDpa->pPab = NULL; @@ -324,8 +324,8 @@ pPab = kmalloc (sizeof (*pPab), GFP_KERNEL); if (!pPab) { - printk (KERN_ERR - "(rcpci45 driver:) RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n"); + dprintk (KERN_ERR + "RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n"); result = RC_RTN_MALLOC_ERROR; goto err_out; } @@ -354,8 +354,7 @@ goto err_out_dealloc; if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) { - printk (KERN_INFO - "(rcpci45 driver:) pPab->IOPState == op: resetting adapter\n"); + dprintk (KERN_INFO "pPab->IOPState == op: resetting adapter\n"); RCResetLANCard (dev, 0, (PU32) NULL, (PFNCALLBACK) NULL); } @@ -445,7 +444,7 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock); @@ -502,7 +501,7 @@ dprintk ("RCPostRecvBuffers(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock); @@ -570,13 +569,13 @@ dev); } else if (I2O_LAN_RECEIVE_POST == p8Msg[7]) { /* Receive Packet Reply Msg */ dprintk - ("I2O_RECV_REPLY pPab:0x%08ulx p8Msg:0x%08ulx p32:0x%08ulx\n", + ("I2O_RECV_REPLY pPab:0x%x p8Msg:0x%x p32:0x%x\n", (u32) pPab, (u32) p8Msg, (u32) p32); - dprintk ("msg: 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + dprintk ("msg: 0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], p32[2], p32[3]); - dprintk (" 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + dprintk (" 0x%x:0x%x:0x%x:0x%x\n", p32[4], p32[5], p32[6], p32[7]); - dprintk (" 0x%08ulx:0X%08ulx:0x%08ulx:0x%08ulx\n", + dprintk (" 0x%x:0X%x:0x%x:0x%x\n", p32[8], p32[9], p32[10], p32[11]); /* status, count, buckets remaining, packetParmBlock, adapter */ (*pPab->pRecvCallbackFunc) (p8Msg[19], p8Msg[12], @@ -623,8 +622,8 @@ dev); break; default: - printk (KERN_WARNING - "(rcpci45 driver:) Unknown private I2O msg received: 0x%x\n", + dprintk (KERN_WARNING + "Unknown private I2O msg received: 0x%x\n", p32[5]); break; } @@ -658,14 +657,13 @@ PFNWAITCALLBACK WaitCallback) { U32 msgOffset; - volatile U32 timeout; volatile PU32 pMsg; volatile PU32 p32, pReturnAddr; P_NICSTAT pStats; int i; PPAB pPab = ((PDPA) dev->priv)->pPab; -/*dprintk("Get82558Stats() StatsReturnAddr:0x%08ulx\n", StatsReturnAddr); */ +/*dprintk("Get82558Stats() StatsReturnAddr:0x%x\n", StatsReturnAddr); */ if (pPab == NULL) return RC_RTN_ADPTR_NOT_REGISTERED; @@ -677,10 +675,10 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); -/*dprintk("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ +/*dprintk("Get82558Stats - pMsg = 0x%x, InQ msgOffset = 0x%x\n", pMsg, msgOffset);*/ /*dprintk("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -690,30 +688,22 @@ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_STATS; pMsg[5] = pPab->outMsgBlockPhyAddr; - p32 = (PU32) pPab->outMsgBlockPhyAddr; +// p32 = (PU32) pPab->outMsgBlockPhyAddr; + p32 = (PU32)pPab->pLinOutMsgBlock; pStats = (P_NICSTAT) pPab->pLinOutMsgBlock; pStats->dump_status = 0xFFFFFFFF; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; - timeout = 100000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (pStats->dump_status != 0xFFFFFFFF) - break; - - if (!timeout--) { - dprintk - ("RCGet82558Stats() Timeout waiting for NIC statistics\n"); + i = 0; + while (pStats->dump_status == 0xFFFFFFFF) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for NIC statistics\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(50); } - pReturnAddr = (PU32) StatsReturnAddr; /* copy Nic stats to user's structure */ @@ -732,13 +722,13 @@ RCGetLinkStatus (struct net_device * dev, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback) { + int i; U32 msgOffset; - volatile U32 timeout; volatile PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA) dev->priv)->pPab; - dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%08ulx\n", + dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%x\n", (u32) ReturnAddr); if (pPab == NULL) @@ -751,9 +741,9 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); -/*dprintk("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ +/*dprintk("Get82558LinkStatus - pMsg = 0x%x, InQ msgOffset = 0x%x\n", pMsg, msgOffset);*/ /*dprintk("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -769,20 +759,13 @@ /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; - timeout = 100000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (*p32 != 0xFFFFFFFF) - break; - - if (!timeout--) { + i = 0; + while (*p32 == 0xFFFFFFFF) { + if (i++ > 0xff) { dprintk ("Timeout waiting for link status\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(50); } *ReturnAddr = *p32; /* 1 = up 0 = down */ @@ -802,8 +785,7 @@ RC_RETURN RCGetMAC (struct net_device * dev, PFNWAITCALLBACK WaitCallback) { - unsigned timeout; - U32 off; + U32 off, i; PU8 mac = dev->dev_addr; PU32 p; U32 temp[2]; @@ -839,17 +821,13 @@ (uint) p_atu, (uint) off, (uint) p); /* wait for the rcpci45 board to update the info */ - timeout = 1000000; + i = 0; while (0 == p_atu->EtherMacLow) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (!timeout--) { - printk ("rc_getmac: Timeout\n"); + if (i++ > 0xff) { + dprintk ("rc_getmac: Timeout\n"); return RC_RTN_MSG_REPLY_TIMEOUT; - } + } + udelay(50); } /* read the mac address */ @@ -1001,16 +979,16 @@ RCGetPromiscuousMode (struct net_device * dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; PU32 pMsg; volatile PU32 p32; + U32 msgOffset, i; PPAB pPab = ((PDPA) dev->priv)->pPab; msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + dprintk (KERN_WARNING + "RCGetLinkSpeed(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } @@ -1034,23 +1012,15 @@ pPab->p_atu->InQueue = msgOffset; - /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; + i = 0; - if (!timeout--) { - dprintk - ("Timeout waiting for promiscuous mode from adapter\n"); - dprintk ("0x%8x\n", p32[0]); + /* wait for response */ + while (p32[0] == 0xff) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for promiscuous mode\n"); return RC_RTN_NO_LINK_SPEED; } + udelay(50); } /* get mode */ @@ -1115,7 +1085,7 @@ RCGetBroadcastMode (struct net_device * dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; + U32 msgOffset; PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA) dev->priv)->pPab; @@ -1123,8 +1093,8 @@ msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + dprintk (KERN_WARNING + "RCGetLinkSpeed(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } @@ -1149,23 +1119,10 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - printk (KERN_WARNING - "(rcpci45 driver:) Timeout waiting for promiscuous mode from adapter\n"); - printk (KERN_WARNING "(rcpci45 driver:) 0x%8x\n", - p32[0]); - return RC_RTN_NO_LINK_SPEED; - } + if (p32[0] == 0xff) { + dprintk (KERN_WARNING + "Timeout waiting for promiscuous mode\n"); + return RC_RTN_NO_LINK_SPEED; } /* get mode */ @@ -1192,7 +1149,7 @@ RCGetLinkSpeed (struct net_device * dev, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; volatile PU32 p32; U8 IOPLinkSpeed; @@ -1201,8 +1158,8 @@ msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + dprintk (KERN_WARNING + "RCGetLinkSpeed(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } @@ -1227,26 +1184,16 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - dprintk ("Timeout waiting for link speed from IOP\n"); - dprintk ("0x%8x\n", p32[0]); + i = 0; + while (p32[0] == 0xff) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for link speed\n"); return RC_RTN_NO_LINK_SPEED; } + udelay(50); } - /* get Link speed */ IOPLinkSpeed = (U8) ((volatile PU8) p32)[0] & 0x0f; - *pLinkSpeedCode = IOPLinkSpeed; return RC_RTN_NO_ERROR; @@ -1304,7 +1251,7 @@ RCGetFirmwareVer (struct net_device * dev, PU8 pFirmString, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA) dev->priv)->pPab; @@ -1336,22 +1283,14 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - dprintk ("Timeout waiting for link speed from IOP\n"); + i = 0; + while (p32[0] == 0xff) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for link speed\n"); return RC_RTN_NO_FIRM_VER; } + udelay(50); } - strcpy (pFirmString, (PU8) p32); return RC_RTN_NO_ERROR; } @@ -1403,9 +1342,9 @@ or until timer goes off */ while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) { RCProcI2OMsgQ (dev); - udelay (1000); /* please don't hog the bus!!! */ + mdelay (1); timeout++; - if (timeout > 10000) { + if (timeout > 200) { break; } } @@ -1427,7 +1366,7 @@ RC_RETURN RCResetIOP (struct net_device * dev) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; PPAB pPab = ((PDPA) dev->priv)->pPab; volatile PU32 p32; @@ -1452,7 +1391,7 @@ pMsg[7] = 0; pMsg[8] = 1; /* return 1 byte */ - /* virual pointer to return buffer - clear first two dwords */ + /* virtual pointer to return buffer - clear first two dwords */ p32 = (volatile PU32) pPab->pLinOutMsgBlock; p32[0] = 0; p32[1] = 0; @@ -1462,17 +1401,13 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] || p32[1]) - break; - - if (!timeout--) { + i = 0; + while (!p32[0] && !p32[1]) { + if (i++ > 0xff) { dprintk ("RCResetIOP timeout\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(100); } return RC_RTN_NO_ERROR; } @@ -1525,11 +1460,11 @@ or until timer goes off */ while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) { RCProcI2OMsgQ (dev); - udelay (1000); /* please don't hog the bus!!! */ + mdelay (1); timeout++; - if (timeout > 10000) { - printk (KERN_WARNING - "(rcpci45 driver:) RCShutdownLANCard(): timeout\n"); + if (timeout > 200) { + dprintk (KERN_WARNING + "RCShutdownLANCard(): timeout\n"); break; } } @@ -1594,14 +1529,13 @@ RCGetRavlinIPandMask (struct net_device * dev, PU32 pIpAddr, PU32 pNetMask, PFNWAITCALLBACK WaitCallback) { - unsigned timeout; - U32 off; + U32 off, i; PU32 pMsg, p32; PPAB pPab = ((PDPA) dev->priv)->pPab; PATU p_atu; dprintk - ("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", + ("RCGetRavlinIPandMask: pIpAddr is 0x%x, *IpAddr is 0x%x\n", (u32) pIpAddr, *pIpAddr); if (pPab == NULL) @@ -1619,7 +1553,7 @@ pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); dprintk - ("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", + ("RCGetRavlinIPandMask: p_atu 0x%x, off 0x%x, p32 0x%x\n", (u32) p_atu, off, (u32) p32); /* setup private message */ pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1631,25 +1565,21 @@ p_atu->InQueue = off; /* send it to the I2O device */ dprintk - ("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", + ("RCGetRavlinIPandMask: p_atu 0x%x, off 0x%x, p32 0x%x\n", (u32) p_atu, off, (u32) p32); /* wait for the rcpci45 board to update the info */ - timeout = 100000; + i = 0; while (0xffffffff == *p32) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (!timeout--) { + if (i++ > 0xff) { dprintk ("RCGetRavlinIPandMask: Timeout\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(50); } dprintk - ("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%08ulx, p32[1] (IPmask) 0x%08ulx\n", + ("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%x, p32[1] (IPmask) 0x%x\n", p32[0], p32[1]); /* send IP and mask to user's space */ @@ -1657,7 +1587,7 @@ *pNetMask = p32[1]; dprintk - ("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", + ("RCGetRavlinIPandMask: pIpAddr is 0x%x, *IpAddr is 0x%x\n", (u32) pIpAddr, *pIpAddr); return RC_RTN_NO_ERROR; @@ -1682,7 +1612,7 @@ static int SendI2OOutboundQInitMsg (PPAB pPab) { - U32 msgOffset, timeout, phyOutQFrames, i; + U32 msgOffset, phyOutQFrames, i; volatile PU32 pMsg; volatile PU32 p32; @@ -1693,11 +1623,11 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); dprintk - ("SendI2OOutboundQInitMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", + ("SendI2OOutboundQInitMsg - pMsg = 0x%x, InQ msgOffset = 0x%x\n", (u32) pMsg, msgOffset); pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6; @@ -1711,7 +1641,7 @@ /* phys address to return status - area right after PAB */ pMsg[7] = pPab->outMsgBlockPhyAddr; - /* virual pointer to return buffer - clear first two dwords */ + /* virtual pointer to return buffer - clear first two dwords */ p32 = (PU32) pPab->pLinOutMsgBlock; p32[0] = 0; @@ -1719,34 +1649,19 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 100000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0]) - break; - - if (!timeout--) { - dprintk - ("Timeout wait for InitOutQ InPrgress status from IOP\n"); + i = 0; + while (!p32[0]) { + if (i++ > 0xff) { + printk("rc: InitOutQ timeout\n"); return RC_RTN_NO_I2O_STATUS; } + udelay(50); } - - timeout = 100000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE) - break; - - if (!timeout--) { - dprintk - ("Timeout wait for InitOutQ Complete status from IOP\n"); - return RC_RTN_NO_I2O_STATUS; - } + if (p32[0] != I2O_EXEC_OUTBOUND_INIT_COMPLETE) { + printk("rc: exec outbound init failed (%x)\n", + p32[0]); + return RC_RTN_NO_I2O_STATUS; } - /* load PCI outbound free Q with MF physical addresses */ phyOutQFrames = pPab->outMsgBlockPhyAddr; @@ -1768,7 +1683,7 @@ static int GetI2OStatus (PPAB pPab) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; volatile PU32 p32; @@ -1779,7 +1694,7 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1793,51 +1708,41 @@ pMsg[7] = 0; pMsg[8] = 88; /* return 88 bytes */ - /* virual pointer to return buffer - clear first two dwords */ + /* virtual pointer to return buffer - clear first two dwords */ p32 = (volatile PU32) pPab->pLinOutMsgBlock; p32[0] = 0; p32[1] = 0; dprintk - ("GetI2OStatus - pMsg:0x%08ulx, msgOffset:0x%08ulx, [1]:0x%08ulx, [6]:0x%08ulx\n", + ("GetI2OStatus - pMsg:0x%x, msgOffset:0x%x, [1]:0x%x, [6]:0x%x\n", (u32) pMsg, msgOffset, pMsg[1], pMsg[6]); /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; - dprintk ("Return status to p32 = 0x%08ulx\n", (u32) p32); + dprintk ("Return status to p32 = 0x%x\n", (u32) p32); /* wait for response */ - timeout = 1000000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] && p32[1]) - break; - - if (!timeout--) { + i = 0; + while (!p32[0] || !p32[1]) { + if (i++ > 0xff) { dprintk ("Timeout waiting for status from IOP\n"); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[0], p32[1], p32[2], p32[3]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[4], p32[5], p32[6], p32[7]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[8], p32[9], p32[10], p32[11]); return RC_RTN_NO_I2O_STATUS; } + udelay(50); } - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], + dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], p32[2], p32[3]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], + dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[4], p32[5], p32[6], p32[7]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9], + dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[8], p32[9], p32[10], p32[11]); /* get IOP state */ pPab->IOPState = ((volatile PU8) p32)[10]; pPab->InboundMFrameSize = ((volatile PU16) p32)[6]; - dprintk ("IOP state 0x%02x InFrameSize = 0x%04x\n", + dprintk ("IOP state 0x%x InFrameSize = 0x%x\n", pPab->IOPState, pPab->InboundMFrameSize); return RC_RTN_NO_ERROR; } @@ -1862,11 +1767,11 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); dprintk - ("SendEnableSysMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", + ("SendEnableSysMsg - pMsg = 0x%x, InQ msgOffset = 0x%x\n", (u32) pMsg, msgOffset); pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1885,7 +1790,7 @@ ** ========================================================================= ** FillI2OMsgFromTCB() ** -** inputs pMsgU32 - virual pointer (mapped to physical) of message frame +** inputs pMsgU32 - virtual pointer (mapped to physical) of message frame ** pXmitCntrlBlock - pointer to caller buffer control block. ** ** fills in LAN SGL after Transaction Control Word or Bucket Count. @@ -1908,9 +1813,9 @@ nmbrDwords = 0; dprintk ("FillI2OMsgSGLFromTCBX\n"); - dprintk ("TCB 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + dprintk ("TCB 0x%x:0x%x:0x%x:0x%x:0x%x\n", pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]); - dprintk ("pTCB 0x%08ulx, pMsg 0x%08ulx\n", (u32) pTCB, (u32) pMsg); + dprintk ("pTCB 0x%x, pMsg 0x%x\n", (u32) pTCB, (u32) pMsg); nmbrBuffers = *pTCB++; @@ -1987,11 +1892,11 @@ p32 = (PU32) p8Msg; dprintk - ("VXD: ProcessOutboundI2OMsg - pPab 0x%08ulx, phyAdr 0x%08ulx, linAdr 0x%08ulx\n", + ("VXD: ProcessOutboundI2OMsg - pPab 0x%x, phyAdr 0x%x, linAdr 0x%x\n", (u32) pPab, phyAddrMsg, (u32) p8Msg); - dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], + dprintk ("msg :0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], p32[2], p32[3]); - dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], + dprintk ("msg :0x%x:0x%x:0x%x:0x%x\n", p32[4], p32[5], p32[6], p32[7]); if (p32[4] >> 24 != I2O_REPLY_STATUS_SUCCESS) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/rclanmtl.h linux-2.5/drivers/net/rclanmtl.h --- linux-2.5.1/drivers/net/rclanmtl.h Mon Jul 2 21:03:04 2001 +++ linux-2.5/drivers/net/rclanmtl.h Mon Jan 14 22:39:45 2002 @@ -54,10 +54,10 @@ #include <asm/io.h> /* Debug stuff. Define for debug output */ -#define RCDEBUG +#undef RCDEBUG #ifdef RCDEBUG -#define dprintk(args...) printk(KERN_DEBUG "(rcpci45 driver:) " args) +#define dprintk(args...) printk("rc: " args) #else #define dprintk(args...) { } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/rcpci45.c linux-2.5/drivers/net/rcpci45.c --- linux-2.5.1/drivers/net/rcpci45.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/net/rcpci45.c Mon Jan 14 22:39:45 2002 @@ -29,6 +29,9 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** +** Pete Popov, Oct 2001: Fixed a few bugs to make the driver functional +** again. Note that this card is not supported or manufactured by +** RedCreek anymore. ** ** Rasmus Andersen, December 2000: Converted to new PCI API and general ** cleanup. @@ -62,7 +65,7 @@ #include <asm/uaccess.h> static char version[] __initdata = - "RedCreek Communications PCI linux driver version 2.03\n"; + "RedCreek Communications PCI linux driver version 2.20\n"; #define RC_LINUX_MODULE #include "rclanmtl.h" @@ -87,6 +90,14 @@ /* RedCreek's OSM default LAN receive Initiator */ #define DEFAULT_RECV_INIT_CONTEXT 0xA17 +/* minimum msg buffer size needed by the card + * Note that the size of this buffer is hard code in the + * ipsec card's firmware. Thus, the size MUST be a minimum + * of 16K. Otherwise the card will end up using memory + * that does not belong to it. + */ +#define MSG_BUF_SIZE 16384 + static U32 DriverControlWord; static void rc_timer (unsigned long); @@ -120,39 +131,25 @@ PDPA pDpa = dev->priv; if (!dev) { - printk (KERN_ERR - "(rcpci45 driver:) remove non-existent device\n"); + printk (KERN_ERR "%s: remove non-existent device\n", + dev->name); return; } - dprintk ("remove_one: IOP reset: 0x%x\n", RCResetIOP (dev)); - - /* RAA Inspired by starfire.c and yellowfin.c we keep these - * here. */ + RCResetIOP (dev); unregister_netdev (dev); free_irq (dev->irq, dev); iounmap ((void *) dev->base_addr); pci_release_regions (pdev); - kfree (pDpa->PLanApiPA); - kfree (pDpa->pPab); - kfree (pDpa); + if (pDpa->msgbuf) + kfree (pDpa->msgbuf); + if (pDpa->pPab) + kfree (pDpa->pPab); kfree (dev); pci_set_drvdata (pdev, NULL); } static int -RCinit (struct net_device *dev) -{ - dev->open = &RCopen; - dev->hard_start_xmit = &RC_xmit_packet; - dev->stop = &RCclose; - dev->get_stats = &RCget_stats; - dev->do_ioctl = &RCioctl; - dev->set_config = &RCconfig; - return 0; -} - -static int rcpci45_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned long *vaddr; @@ -166,17 +163,17 @@ /* * Allocate and fill new device structure. - * We need enough for struct net_device plus DPA plus the LAN API private - * area, which requires a minimum of 16KB. The top of the allocated - * area will be assigned to struct net_device; the next chunk will be - * assigned to DPA; and finally, the rest will be assigned to the - * the LAN API layer. + * We need enough for struct net_device plus DPA plus the LAN + * API private area, which requires a minimum of 16KB. The top + * of the allocated area will be assigned to struct net_device; + * the next chunk will be assigned to DPA; and finally, the rest + * will be assigned to the the LAN API layer. */ dev = init_etherdev (NULL, sizeof (*pDpa)); if (!dev) { printk (KERN_ERR - "(rcpci45 driver:) unable to allocate in init_etherdev\n"); + "(rcpci45 driver:) init_etherdev alloc failed\n"); error = -ENOMEM; goto err_out; } @@ -184,13 +181,14 @@ error = pci_enable_device (pdev); if (error) { printk (KERN_ERR - "(rcpci45 driver:) %d: unable to enable pci device, aborting\n", + "(rcpci45 driver:) %d: pci enable device error\n", card_idx); goto err_out; } error = -ENOMEM; pci_start = pci_resource_start (pdev, 0); pci_len = pci_resource_len (pdev, 0); + printk("pci_start %x pci_len %x\n", pci_start, pci_len); pci_set_drvdata (pdev, dev); @@ -200,29 +198,30 @@ if (!pci_start || !(pci_resource_flags (pdev, 0) & IORESOURCE_MEM)) { printk (KERN_ERR - "(rcpci45 driver:) No PCI memory resources! Aborting.\n"); + "(rcpci45 driver:) No PCI mem resources! Aborting\n"); error = -EBUSY; goto err_out_free_dev; } /* - * Save the starting address of the LAN API private area. We'll - * pass that to RCInitI2OMsgLayer(). + * pDpa->msgbuf is where the card will dma the I2O + * messages. Thus, we need contiguous physical pages of + * memory. */ - /* RAA FIXME: This size should be a #define somewhere after I - * clear up some questions: What flags are neeeded in the alloc below - * and what needs to be done before the memarea is long word aligned? - * (Look in old code for an approach.) (Also note that the 16K below - * is substantially less than the 32K allocated before (even though - * some of the spacce was used for data structures.) */ - pDpa->msgbuf = kmalloc (16384, GFP_KERNEL); + pDpa->msgbuf = kmalloc (MSG_BUF_SIZE, GFP_DMA|GFP_ATOMIC|GFP_KERNEL); if (!pDpa->msgbuf) { - printk (KERN_ERR "(rcpci45 driver:) Could not allocate %d byte memory for the private msgbuf!\n", 16384); /* RAA FIXME not hardcoded! */ + printk (KERN_ERR "(rcpci45 driver:) \ + Could not allocate %d byte memory for the \ + private msgbuf!\n", MSG_BUF_SIZE); goto err_out_free_dev; } - pDpa->PLanApiPA = (void *) (((long) pDpa->msgbuf + 0xff) & ~0xff); - dprintk ("pDpa->PLanApiPA = 0x%x\n", (uint) pDpa->PLanApiPA); + /* + * Save the starting address of the LAN API private area. We'll + * pass that to RCInitI2OMsgLayer(). + * + */ + pDpa->PLanApiPA = (void *) (((long) pDpa->msgbuf + 0xff) & ~0xff); /* The adapter is accessible through memory-access read/write, not * I/O read/write. Thus, we need to map it to some virtual address @@ -235,17 +234,20 @@ vaddr = (ulong *) ioremap (pci_start, pci_len); if (!vaddr) { printk (KERN_ERR - "(rcpci45 driver:) Unable to remap address range from %lu to %lu\n", + "(rcpci45 driver:) \ + Unable to remap address range from %lu to %lu\n", pci_start, pci_start + pci_len); goto err_out_free_region; } - dprintk ("rcpci45_init_one: 0x%x, priv = 0x%x, vaddr = 0x%x\n", - (uint) dev, (uint) dev->priv, (uint) vaddr); dev->base_addr = (unsigned long) vaddr; dev->irq = pdev->irq; - - dev->init = &RCinit; + dev->open = &RCopen; + dev->hard_start_xmit = &RC_xmit_packet; + dev->stop = &RCclose; + dev->get_stats = &RCget_stats; + dev->do_ioctl = &RCioctl; + dev->set_config = &RCconfig; return 0; /* success */ @@ -258,7 +260,7 @@ kfree (dev); err_out: card_idx--; - return error; + return -ENODEV; } static struct pci_driver rcpci45_driver = { @@ -272,9 +274,8 @@ rcpci_init_module (void) { int rc = pci_module_init (&rcpci45_driver); - if (!rc) - printk (KERN_INFO "%s", version); + printk (KERN_ERR "%s", version); return rc; } @@ -287,56 +288,56 @@ int requested = 0; int error; - dprintk ("(rcpci45 driver:) RCopen\n"); + MOD_INC_USE_COUNT; + if (pDpa->nexus) { + /* This is not the first time RCopen is called. Thus, + * the interface was previously opened and later closed + * by RCclose(). RCclose() does a Shutdown; to wake up + * the adapter, a reset is mandatory before we can post + * receive buffers. However, if the adapter initiated + * a reboot while the interface was closed -- and interrupts + * were turned off -- we need will need to reinitialize + * the adapter, rather than simply waking it up. + */ + printk (KERN_INFO "Waking up adapter...\n"); + RCResetLANCard (dev, 0, 0, 0); + } else { + pDpa->nexus = 1; + /* + * RCInitI2OMsgLayer is done only once, unless the + * adapter was sent a warm reboot + */ + error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, + (PFNRXCALLBACK) RCrecv_callback, + (PFNCALLBACK) RCreboot_callback); + if (error) { + printk (KERN_ERR "%s: Unable to init msg layer (%x)\n", + dev->name, error); + goto err_out; + } + if ((error = RCGetMAC (dev, NULL))) { + printk (KERN_ERR "%s: Unable to get adapter MAC\n", + dev->name); + goto err_out; + } + } /* Request a shared interrupt line. */ error = request_irq (dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev); if (error) { - printk (KERN_ERR "(rcpci45 driver:) %s: unable to get IRQ %d\n", - dev->name, dev->irq); + printk (KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); goto err_out; } - error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, - (PFNRXCALLBACK) RCrecv_callback, - (PFNCALLBACK) RCreboot_callback); - if (error) { - printk (KERN_ERR - "(rcpci45 driver:) Unable to initialize msg layer\n"); - goto err_out_free_irq; - } - if ((error = RCGetMAC (dev, NULL))) { - printk (KERN_ERR - "(rcpci45 driver:) Unable to get adapter MAC\n"); - goto err_out_free_irq; - } - DriverControlWord |= WARM_REBOOT_CAPABLE; RCReportDriverCapability (dev, DriverControlWord); printk (KERN_INFO "%s: RedCreek Communications IPSEC VPN adapter\n", dev->name); - /* RAA: Old RCopen starts here */ RCEnableI2OInterrupts (dev); - /* RAA Hmm, how does the comment below jibe with the newly imported - * code above? A FIXME!!*/ - if (pDpa->nexus) { - /* This is not the first time RCopen is called. Thus, - * the interface was previously opened and later closed - * by RCclose(). RCclose() does a Shutdown; to wake up - * the adapter, a reset is mandatory before we can post - * receive buffers. However, if the adapter initiated - * a reboot while the interface was closed -- and interrupts - * were turned off -- we need will need to reinitialize - * the adapter, rather than simply waking it up. - */ - dprintk (KERN_INFO "Waking up adapter...\n"); - RCResetLANCard (dev, 0, 0, 0); - } else - pDpa->nexus = 1; - while (post_buffers) { if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG) requested = MAX_NMBR_POST_BUFFERS_PER_MSG; @@ -346,29 +347,30 @@ if (count < requested) { /* - * Check to see if we were able to post any buffers at all. + * Check to see if we were able to post + * any buffers at all. */ if (post_buffers == MAX_NMBR_RCV_BUFFERS) { - printk (KERN_ERR - "(rcpci45 driver:) Error RCopen: not able to allocate any buffers\r\n"); - return (-ENOMEM); + printk (KERN_ERR "%s: \ + unable to allocate any buffers\n", + dev->name); + goto err_out_free_irq; } - printk (KERN_WARNING - "(rcpci45 driver:) Warning RCopen: not able to allocate all requested buffers\r\n"); + printk (KERN_WARNING "%s: \ + unable to allocate all requested buffers\n", dev->name); break; /* we'll try to post more buffers later */ } else post_buffers -= count; } pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers; pDpa->shutdown = 0; /* just in case */ - dprintk ("RCopen: posted %d buffers\n", (uint) pDpa->numOutRcvBuffers); - MOD_INC_USE_COUNT; netif_start_queue (dev); return 0; err_out_free_irq: free_irq (dev->irq, dev); err_out: + MOD_DEC_USE_COUNT; return error; } @@ -384,15 +386,16 @@ netif_stop_queue (dev); if (pDpa->shutdown || pDpa->reboot) { - dprintk ("RC_xmit_packet: tbusy!\n"); + printk ("RC_xmit_packet: tbusy!\n"); return 1; } /* - * The user is free to reuse the TCB after RCI2OSendPacket() returns, since - * the function copies the necessary info into its own private space. Thus, - * our TCB can be a local structure. The skb, on the other hand, will be - * freed up in our interrupt handler. + * The user is free to reuse the TCB after RCI2OSendPacket() + * returns, since the function copies the necessary info into its + * own private space. Thus, our TCB can be a local structure. + * The skb, on the other hand, will be freed up in our interrupt + * handler. */ ptcb->bcount = 1; @@ -406,11 +409,9 @@ ptcb->b.size = skb->len; ptcb->b.addr = virt_to_bus ((void *) skb->data); - dprintk ("RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n", - (uint) skb, (uint) pDpa, (uint) pDpa->id, (uint) ptcb); if ((status = RCI2OSendPacket (dev, (U32) NULL, (PRCTCB) ptcb)) != RC_RTN_NO_ERROR) { - dprintk ("RC send error 0x%x\n", (uint) status); + printk ("%s: send error 0x%x\n", dev->name, (uint) status); return 1; } else { dev->trans_start = jiffies; @@ -440,23 +441,20 @@ PDPA pDpa = dev->priv; if (!pDpa) { - printk (KERN_ERR - "(rcpci45 driver:) Fatal error: xmit callback, !pDpa\n"); + printk (KERN_ERR "%s: Fatal Error in xmit callback, !pDpa\n", + dev->name); return; } -/* dprintk("xmit_callback: Status = 0x%x\n", (uint)Status); */ if (Status != I2O_REPLY_STATUS_SUCCESS) - dprintk ("xmit_callback: Status = 0x%x\n", (uint) Status); + printk (KERN_INFO "%s: xmit_callback: Status = 0x%x\n", + dev->name, (uint) Status); if (pDpa->shutdown || pDpa->reboot) - dprintk ("xmit callback: shutdown||reboot\n"); - - dprintk ("xmit_callback: PcktCount = %d, BC = 0x%x\n", - (uint) PcktCount, (uint) BufferContext); + printk (KERN_INFO "%s: xmit callback: shutdown||reboot\n", + dev->name); while (PcktCount--) { skb = (struct sk_buff *) (BufferContext[0]); - dprintk ("skb = 0x%x\n", (uint) skb); BufferContext++; dev_kfree_skb_irq (skb); } @@ -468,19 +466,18 @@ { PDPA pDpa = dev->priv; - dprintk ("RCreset_callback Status 0x%x\n", (uint) Status); + printk ("RCreset_callback Status 0x%x\n", (uint) Status); /* * Check to see why we were called. */ if (pDpa->shutdown) { - printk (KERN_INFO - "(rcpci45 driver:) Shutting down interface\n"); + printk (KERN_INFO "%s: shutting down interface\n", + dev->name); pDpa->shutdown = 0; pDpa->reboot = 0; - MOD_DEC_USE_COUNT; } else if (pDpa->reboot) { - printk (KERN_INFO - "(rcpci45 driver:) reboot, shutdown adapter\n"); + printk (KERN_INFO "%s: reboot, shutdown adapter\n", + dev->name); /* * We don't set any of the flags in RCShutdownLANCard() * and we don't pass a callback routine to it. @@ -489,7 +486,7 @@ */ RCDisableI2OInterrupts (dev); RCShutdownLANCard (dev, 0, 0, 0); - printk (KERN_INFO "(rcpci45 driver:) scheduling timer...\n"); + printk (KERN_INFO "%s: scheduling timer...\n", dev->name); init_timer (&pDpa->timer); pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 4 sec. */ pDpa->timer.data = (unsigned long) dev; @@ -503,12 +500,12 @@ { PDPA pDpa = dev->priv; - dprintk ("RCreboot: rcv buffers outstanding = %d\n", - (uint) pDpa->numOutRcvBuffers); + printk (KERN_INFO "%s: reboot: rcv buffers outstanding = %d\n", + dev->name, (uint) pDpa->numOutRcvBuffers); if (pDpa->shutdown) { - printk (KERN_INFO - "(rcpci45 driver:) skipping reboot sequence -- shutdown already initiated\n"); + printk (KERN_INFO "%s: skip reboot, shutdown initiated\n", + dev->name); return; } pDpa->reboot = 1; @@ -560,12 +557,9 @@ ptcb->bcount = 1; - dprintk ("RCrecv_callback: 0x%x, 0x%x, 0x%x\n", - (uint) PktCount, (uint) BucketsRemain, (uint) PacketDescBlock); - if ((pDpa->shutdown || pDpa->reboot) && !Status) - dprintk ("shutdown||reboot && !Status: PktCount = %d\n", - PktCount); + printk (KERN_INFO "%s: shutdown||reboot && !Status (%d)\n", + dev->name, PktCount); if ((Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown) { /* @@ -574,76 +568,38 @@ */ if (!pDpa->shutdown && !pDpa->reboot) - printk (KERN_INFO - "(rcpci45 driver:) RCrecv error: status = 0x%x\n", - (uint) Status); + printk (KERN_INFO "%s: recv error status = 0x%x\n", + dev->name, (uint) Status); else - dprintk ("Returning %d buffers, status = 0x%x\n", - PktCount, (uint) Status); + printk (KERN_DEBUG "%s: Returning %d buffs stat 0x%x\n", + dev->name, PktCount, (uint) Status); /* - * TO DO: check the nature of the failure and put the adapter in - * failed mode if it's a hard failure. Send a reset to the adapter - * and free all outstanding memory. + * TO DO: check the nature of the failure and put the + * adapter in failed mode if it's a hard failure. + * Send a reset to the adapter and free all outstanding memory. */ - if (Status == I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER) - dprintk ("RCrecv status ABORT NO DATA TRANSFER\n"); - - /* check for reset status: I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */ if (PacketDescBlock) { while (PktCount--) { skb = (struct sk_buff *) PacketDescBlock[0]; - dprintk ("free skb 0x%p\n", skb); dev_kfree_skb (skb); pDpa->numOutRcvBuffers--; - PacketDescBlock += BD_SIZE; /* point to next context field */ + /* point to next context field */ + PacketDescBlock += BD_SIZE; } } return; } else { while (PktCount--) { skb = (struct sk_buff *) PacketDescBlock[0]; - if (pDpa->shutdown) - dprintk ("shutdown: skb=0x%x\n", (uint) skb); - - dprintk ("skb = 0x%x: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", - (uint) skb, (uint) skb->data[0], - (uint) skb->data[1], (uint) skb->data[2], - (uint) skb->data[3], (uint) skb->data[4], - (uint) skb->data[5]); - -#ifdef PROMISCUOUS_BY_DEFAULT /* early 2.x firmware */ - if ((memcmp (dev->dev_addr, skb->data, 6)) && - (!broadcast_packet (skb->data))) { - /* - * Re-post the buffer to the adapter. Since the adapter usually - * return 1 to 2 receive buffers at a time, it's not too inefficient - * post one buffer at a time but ... may be that should be - * optimized at some point. - */ - ptcb->b.context = (U32) skb; - ptcb->b.scount = 1; - ptcb->b.size = MAX_ETHER_SIZE; - ptcb->b.addr = virt_to_bus ((void *) skb->data); - - if (RCPostRecvBuffers (dev, (PRCTCB) ptcb) != - RC_RTN_NO_ERROR) { - printk (KERN_WARNING - "(rcpci45 driver:) RCrecv_callback: post buffer failed!\n"); - dev_kfree_skb (skb); - } else - pDpa->numOutRcvBuffers++; - } else -#endif /* PROMISCUOUS_BY_DEFAULT */ - { - len = PacketDescBlock[2]; - skb->dev = dev; - skb_put (skb, len); /* adjust length and tail */ - skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); /* send the packet to the kernel */ - dev->last_rx = jiffies; - } - pDpa->numOutRcvBuffers--; - PacketDescBlock += BD_SIZE; /* point to next context field */ + len = PacketDescBlock[2]; + skb->dev = dev; + skb_put (skb, len); /* adjust length and tail */ + skb->protocol = eth_type_trans (skb, dev); + netif_rx (skb); /* send the packet to the kernel */ + dev->last_rx = jiffies; + pDpa->numOutRcvBuffers--; + /* point to next context field */ + PacketDescBlock += BD_SIZE; } } @@ -680,11 +636,8 @@ pDpa = dev->priv; if (pDpa->shutdown) - dprintk ("shutdown: service irq\n"); - - dprintk ("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n", - (uint) pDpa, (uint) dev, (uint) pDpa->id); - dprintk ("dev = 0x%x\n", (uint) dev); + printk (KERN_DEBUG "%s: shutdown, service irq\n", + dev->name); RCProcI2OMsgQ (dev); } @@ -715,62 +668,60 @@ RCReportDriverCapability (dev, DriverControlWord); RCEnableI2OInterrupts (dev); - if (dev->flags & IFF_UP) { - while (post_buffers) { - if (post_buffers > - MAX_NMBR_POST_BUFFERS_PER_MSG) - requested = - MAX_NMBR_POST_BUFFERS_PER_MSG; - else - requested = post_buffers; - count = - RC_allocate_and_post_buffers (dev, - requested); - post_buffers -= count; - if (count < requested) - break; - } - pDpa->numOutRcvBuffers = - MAX_NMBR_RCV_BUFFERS - post_buffers; - dprintk ("rc: posted %d buffers \r\n", - (uint) pDpa->numOutRcvBuffers); + + if (!(dev->flags & IFF_UP)) { + retry = 0; + return; + } + while (post_buffers) { + if (post_buffers > + MAX_NMBR_POST_BUFFERS_PER_MSG) + requested = + MAX_NMBR_POST_BUFFERS_PER_MSG; + else + requested = post_buffers; + count = + RC_allocate_and_post_buffers (dev, + requested); + post_buffers -= count; + if (count < requested) + break; } - dprintk ("Initialization done.\n"); + pDpa->numOutRcvBuffers = + MAX_NMBR_RCV_BUFFERS - post_buffers; + printk ("Initialization done.\n"); netif_wake_queue (dev); retry = 0; return; case RC_RTN_FREE_Q_EMPTY: retry++; - printk (KERN_WARNING - "(rcpci45 driver:) inbound free q empty\n"); + printk (KERN_WARNING "%s inbound free q empty\n", + dev->name); break; default: retry++; - printk (KERN_WARNING - "(rcpci45 driver:) bad status after reboot: %d\n", - init_status); + printk (KERN_WARNING "%s bad stat after reboot: %d\n", + dev->name, init_status); break; } if (retry > REBOOT_REINIT_RETRY_LIMIT) { - printk (KERN_WARNING - "(rcpci45 driver:) unable to reinitialize adapter after reboot\n"); - printk (KERN_WARNING - "(rcpci45 driver:) decrementing driver and closing interface\n"); + printk (KERN_WARNING "%s unable to reinitialize adapter after reboot\n", dev->name); + printk (KERN_WARNING "%s decrementing driver and closing interface\n", dev->name); RCDisableI2OInterrupts (dev); dev->flags &= ~IFF_UP; MOD_DEC_USE_COUNT; } else { - printk (KERN_INFO - "(rcpci45 driver:) rescheduling timer...\n"); + printk (KERN_INFO "%s: rescheduling timer...\n", + dev->name); init_timer (&pDpa->timer); - pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 3 sec. */ + pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); pDpa->timer.data = (unsigned long) dev; - pDpa->timer.function = &rc_timer; /* timer handler */ + pDpa->timer.function = &rc_timer; add_timer (&pDpa->timer); } } else - printk (KERN_WARNING "(rcpci45 driver:) timer??\n"); + printk (KERN_WARNING "%s: unexpected timer irq\n", dev->name); } static int @@ -778,19 +729,16 @@ { PDPA pDpa = dev->priv; + printk("RCclose\n"); netif_stop_queue (dev); - dprintk ("RCclose\r\n"); - if (pDpa->reboot) { - printk (KERN_INFO - "(rcpci45 driver:) skipping reset -- adapter already in reboot mode\n"); + printk (KERN_INFO "%s skipping reset -- adapter already in reboot mode\n", dev->name); dev->flags &= ~IFF_UP; pDpa->shutdown = 1; + MOD_DEC_USE_COUNT; return 0; } - dprintk ("receive buffers outstanding: %d\n", - (uint) pDpa->numOutRcvBuffers); pDpa->shutdown = 1; @@ -806,6 +754,7 @@ (PFNCALLBACK) RCreset_callback); dev->flags &= ~IFF_UP; + MOD_DEC_USE_COUNT; return 0; } @@ -817,56 +766,42 @@ PDPA pDpa = dev->priv; if (!pDpa) { - dprintk ("RCget_stats: !pDpa\n"); return 0; } else if (!(dev->flags & IFF_UP)) { - dprintk ("RCget_stats: device down\n"); return 0; } memset (&RCstats, 0, sizeof (RCLINKSTATS)); if ((RCGetLinkStatistics (dev, &RCstats, (void *) 0)) == RC_RTN_NO_ERROR) { - dprintk ("TX_good 0x%x\n", (uint) RCstats.TX_good); - dprintk ("TX_maxcol 0x%x\n", (uint) RCstats.TX_maxcol); - dprintk ("TX_latecol 0x%x\n", (uint) RCstats.TX_latecol); - dprintk ("TX_urun 0x%x\n", (uint) RCstats.TX_urun); - dprintk ("TX_crs 0x%x\n", (uint) RCstats.TX_crs); - dprintk ("TX_def 0x%x\n", (uint) RCstats.TX_def); - dprintk ("TX_singlecol 0x%x\n", (uint) RCstats.TX_singlecol); - dprintk ("TX_multcol 0x%x\n", (uint) RCstats.TX_multcol); - dprintk ("TX_totcol 0x%x\n", (uint) RCstats.TX_totcol); - - dprintk ("Rcv_good 0x%x\n", (uint) RCstats.Rcv_good); - dprintk ("Rcv_CRCerr 0x%x\n", (uint) RCstats.Rcv_CRCerr); - dprintk ("Rcv_alignerr 0x%x\n", (uint) RCstats.Rcv_alignerr); - dprintk ("Rcv_reserr 0x%x\n", (uint) RCstats.Rcv_reserr); - dprintk ("Rcv_orun 0x%x\n", (uint) RCstats.Rcv_orun); - dprintk ("Rcv_cdt 0x%x\n", (uint) RCstats.Rcv_cdt); - dprintk ("Rcv_runt 0x%x\n", (uint) RCstats.Rcv_runt); - - pDpa->stats.rx_packets = RCstats.Rcv_good; /* total packets received */ - pDpa->stats.tx_packets = RCstats.TX_good; /* total packets transmitted */ - pDpa->stats.rx_errors = RCstats.Rcv_CRCerr + RCstats.Rcv_alignerr + RCstats.Rcv_reserr + RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt; /* bad packets received */ + /* total packets received */ + pDpa->stats.rx_packets = RCstats.Rcv_good + /* total packets transmitted */; + pDpa->stats.tx_packets = RCstats.TX_good; + + pDpa->stats.rx_errors = RCstats.Rcv_CRCerr + + RCstats.Rcv_alignerr + RCstats.Rcv_reserr + + RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt; - pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs + RCstats.TX_def + RCstats.TX_totcol; /* packet transmit problems */ + pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs + + RCstats.TX_def + RCstats.TX_totcol; /* * This needs improvement. */ - pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ - pDpa->stats.tx_dropped = 0; /* no space available in linux */ - pDpa->stats.multicast = 0; /* multicast packets received */ + pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ + pDpa->stats.tx_dropped = 0; /* no space available in linux */ + pDpa->stats.multicast = 0; /* multicast packets received */ pDpa->stats.collisions = RCstats.TX_totcol; /* detailed rx_errors: */ pDpa->stats.rx_length_errors = 0; - pDpa->stats.rx_over_errors = RCstats.Rcv_orun; /* receiver ring buff overflow */ - pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; /* recved pkt with crc error */ - pDpa->stats.rx_frame_errors = 0; /* recv'd frame alignment error */ - pDpa->stats.rx_fifo_errors = 0; /* recv'r fifo overrun */ - pDpa->stats.rx_missed_errors = 0; /* receiver missed packet */ + pDpa->stats.rx_over_errors = RCstats.Rcv_orun; + pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; + pDpa->stats.rx_frame_errors = 0; + pDpa->stats.rx_fifo_errors = 0; + pDpa->stats.rx_missed_errors = 0; /* detailed tx_errors */ pDpa->stats.tx_aborted_errors = 0; @@ -886,8 +821,6 @@ RCuser_struct RCuser; PDPA pDpa = dev->priv; - dprintk ("RCioctl: cmd = 0x%x\n", cmd); - if (!capable (CAP_NET_ADMIN)) return -EPERM; @@ -911,16 +844,12 @@ switch (RCuser.cmd) { case RCUC_GETFWVER: - printk (KERN_INFO - "(rcpci45 driver:) RC GETFWVER\n"); RCUD_GETFWVER = &RCuser.RCUS_GETFWVER; RCGetFirmwareVer (dev, (PU8) & RCUD_GETFWVER-> FirmString, NULL); break; case RCUC_GETINFO: - printk (KERN_INFO - "(rcpci45 driver:) RC GETINFO\n"); RCUD_GETINFO = &RCuser.RCUS_GETINFO; RCUD_GETINFO->mem_start = dev->base_addr; RCUD_GETINFO->mem_end = @@ -929,8 +858,6 @@ RCUD_GETINFO->irq = dev->irq; break; case RCUC_GETIPANDMASK: - printk (KERN_INFO - "(rcpci45 driver:) RC GETIPANDMASK\n"); RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK; RCGetRavlinIPandMask (dev, (PU32) & @@ -940,8 +867,6 @@ NetMask, NULL); break; case RCUC_GETLINKSTATISTICS: - printk (KERN_INFO - "(rcpci45 driver:) RC GETLINKSTATISTICS\n"); RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS; RCGetLinkStatistics (dev, @@ -950,75 +875,39 @@ StatsReturn, NULL); break; case RCUC_GETLINKSTATUS: - printk (KERN_INFO - "(rcpci45 driver:) RC GETLINKSTATUS\n"); RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS; RCGetLinkStatus (dev, (PU32) & RCUD_GETLINKSTATUS-> ReturnStatus, NULL); break; case RCUC_GETMAC: - printk (KERN_INFO - "(rcpci45 driver:) RC GETMAC\n"); RCUD_GETMAC = &RCuser.RCUS_GETMAC; RCGetMAC (dev, NULL); + memcpy(RCUD_GETMAC, dev->dev_addr, 8); break; case RCUC_GETPROM: - printk (KERN_INFO - "(rcpci45 driver:) RC GETPROM\n"); RCUD_GETPROM = &RCuser.RCUS_GETPROM; RCGetPromiscuousMode (dev, (PU32) & RCUD_GETPROM-> PromMode, NULL); break; case RCUC_GETBROADCAST: - printk (KERN_INFO - "(rcpci45 driver:) RC GETBROADCAST\n"); RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST; RCGetBroadcastMode (dev, (PU32) & RCUD_GETBROADCAST-> BroadcastMode, NULL); break; case RCUC_GETSPEED: - printk (KERN_INFO - "(rcpci45 driver:) RC GETSPEED\n"); if (!(dev->flags & IFF_UP)) { - printk (KERN_ERR - "(rcpci45 driver:) RCioctl, GETSPEED error: interface down\n"); return -ENODATA; } RCUD_GETSPEED = &RCuser.RCUS_GETSPEED; RCGetLinkSpeed (dev, (PU32) & RCUD_GETSPEED-> LinkSpeedCode, NULL); - printk (KERN_INFO - "(rcpci45 driver:) RC speed = 0x%u\n", - RCUD_GETSPEED->LinkSpeedCode); break; case RCUC_SETIPANDMASK: - printk (KERN_INFO - "(rcpci45 driver:) RC SETIPANDMASK\n"); RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK; - printk (KERN_INFO - "(rcpci45 driver:) RC New IP Addr = %d.%d.%d.%d, ", - (U8) ((RCUD_SETIPANDMASK-> - IpAddr) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - IpAddr >> 8) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - IpAddr >> 16) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - IpAddr >> 24) & 0xff)); - printk (KERN_INFO - "(rcpci45 driver:) RC New Mask = %d.%d.%d.%d\n", - (U8) ((RCUD_SETIPANDMASK-> - NetMask) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - NetMask >> 8) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - NetMask >> 16) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - NetMask >> 24) & 0xff)); RCSetRavlinIPandMask (dev, (U32) RCUD_SETIPANDMASK-> IpAddr, @@ -1026,61 +915,33 @@ NetMask); break; case RCUC_SETMAC: - printk (KERN_INFO - "(rcpci45 driver:) RC SETMAC\n"); - RCUD_SETMAC = &RCuser.RCUS_SETMAC; - printk (KERN_INFO - "(rcpci45 driver:) RC New MAC addr = %02X:%02X:%02X:%02X:%02X:%02X\n", - (U8) (RCUD_SETMAC->mac[0]), - (U8) (RCUD_SETMAC->mac[1]), - (U8) (RCUD_SETMAC->mac[2]), - (U8) (RCUD_SETMAC->mac[3]), - (U8) (RCUD_SETMAC->mac[4]), - (U8) (RCUD_SETMAC->mac[5])); RCSetMAC (dev, (PU8) & RCUD_SETMAC->mac); break; case RCUC_SETSPEED: - printk (KERN_INFO - "(rcpci45 driver:) RC SETSPEED\n"); RCUD_SETSPEED = &RCuser.RCUS_SETSPEED; RCSetLinkSpeed (dev, (U16) RCUD_SETSPEED-> LinkSpeedCode); - printk (KERN_INFO - "(rcpci45 driver:) RC New speed = 0x%x\n", - RCUD_SETSPEED->LinkSpeedCode); break; case RCUC_SETPROM: - printk (KERN_INFO - "(rcpci45 driver:) RC SETPROM\n"); RCUD_SETPROM = &RCuser.RCUS_SETPROM; RCSetPromiscuousMode (dev, (U16) RCUD_SETPROM-> PromMode); - printk (KERN_INFO - "(rcpci45 driver:) RC New prom mode = 0x%x\n", - RCUD_SETPROM->PromMode); break; case RCUC_SETBROADCAST: - printk (KERN_INFO - "(rcpci45 driver:) RC SETBROADCAST\n"); RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST; RCSetBroadcastMode (dev, (U16) RCUD_SETBROADCAST-> BroadcastMode); - printk (KERN_INFO - "(rcpci45 driver:) RC New broadcast mode = 0x%x\n", - RCUD_SETBROADCAST->BroadcastMode); break; default: - printk (KERN_INFO - "(rcpci45 driver:) RC command default\n"); RCUD_DEFAULT = &RCuser.RCUS_DEFAULT; RCUD_DEFAULT->rc = 0x11223344; break; } - if (copy_to_user - (rq->ifr_data, &RCuser, sizeof (RCuser))) + if (copy_to_user (rq->ifr_data, &RCuser, + sizeof (RCuser))) return -EFAULT; break; } /* RCU_COMMAND */ @@ -1098,15 +959,14 @@ /* * To be completed ... */ - dprintk ("RCconfig\n"); return 0; if (dev->flags & IFF_UP) /* can't act on a running interface */ return -EBUSY; /* Don't allow changing the I/O address */ if (map->base_addr != dev->base_addr) { - printk (KERN_WARNING - "(rcpci45 driver:) Change I/O address not implemented\n"); + printk (KERN_WARNING "%s Change I/O address not implemented\n", + dev->name); return -EOPNOTSUPP; } return 0; @@ -1135,44 +995,36 @@ if (!numBuffers) return 0; else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) { - dprintk ("Too many buffers requested!\n"); - dprintk ("attempting to allocate only 32 buffers\n"); + printk (KERN_ERR "%s: Too many buffers requested!\n", + dev->name); numBuffers = 32; } p = (PU32) kmalloc (sizeof (U32) + numBuffers * sizeof (singleB), - GFP_KERNEL); - - dprintk ("TCB = 0x%x\n", (uint) p); + GFP_DMA|GFP_ATOMIC|GFP_KERNEL); if (!p) { - printk (KERN_WARNING - "(rcpci45 driver:) RCopen: unable to allocate TCB\n"); + printk (KERN_WARNING "%s unable to allocate TCB\n", + dev->name); return 0; } p[0] = 0; /* Buffer Count */ - pB = (psingleB) ((U32) p + sizeof (U32)); /* point to the first buffer */ - - dprintk ("p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint) p[0], (uint) p, - (uint) pB); - dprintk ("pB = 0x%x\n", (uint) pB); + pB = (psingleB) ((U32) p + sizeof (U32));/* point to the first buffer */ for (i = 0; i < numBuffers; i++) { skb = dev_alloc_skb (MAX_ETHER_SIZE + 2); if (!skb) { - dprintk - ("Doh! RCopen: unable to allocate enough skbs!\n"); - if (*p != 0) { /* did we allocate any buffers at all? */ - dprintk ("will post only %d buffers \n", - (uint) (*p)); + printk (KERN_WARNING + "%s: unable to allocate enough skbs!\n", + dev->name); + if (*p != 0) { /* did we allocate any buffers */ break; } else { kfree (p); /* Free the TCB */ return 0; } } - dprintk ("post 0x%x\n", (uint) skb); skb_reserve (skb, 2); /* Align IP on 16 byte boundaries */ pB->context = (U32) skb; pB->scount = 1; /* segment count */ @@ -1183,18 +1035,16 @@ } if ((status = RCPostRecvBuffers (dev, (PRCTCB) p)) != RC_RTN_NO_ERROR) { - printk (KERN_WARNING - "(rcpci45 driver:) Post buffer failed with error code 0x%x!\n", - status); - pB = (psingleB) ((U32) p + sizeof (U32)); /* point to the first buffer */ + printk (KERN_WARNING "%s: Post buffer failed, error 0x%x\n", + dev->name, status); + /* point to the first buffer */ + pB = (psingleB) ((U32) p + sizeof (U32)); while (p[0]) { skb = (struct sk_buff *) pB->context; - dprintk ("freeing 0x%x\n", (uint) skb); dev_kfree_skb (skb); p[0]--; pB++; } - dprintk ("freed all buffers, p[0] = %d\n", (uint) p[0]); } res = p[0]; kfree (p); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/sb1000.c linux-2.5/drivers/net/sb1000.c --- linux-2.5.1/drivers/net/sb1000.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/net/sb1000.c Mon Jan 14 22:39:45 2002 @@ -204,7 +204,12 @@ /* * Ok set it up. */ - + if (!request_region(ioaddr[0], 16, dev->name)) + continue; + if (!request_region(ioaddr[1], 16, dev->name)) { + release_region(ioaddr[0], 16); + continue; + } dev->base_addr = ioaddr[0]; /* rmem_end holds the second I/O address - fv */ @@ -262,9 +267,6 @@ /* Lock resources */ - request_region(ioaddr[0], 16, dev->name); - request_region(ioaddr[1], 16, dev->name); - return 0; } } @@ -962,8 +964,6 @@ /* rmem_end holds the second I/O address - fv */ ioaddr[1] = dev->rmem_end; name = dev->name; - request_region(ioaddr[0], SB1000_IO_EXTENT, "sb1000"); - request_region(ioaddr[1], SB1000_IO_EXTENT, "sb1000"); /* initialize sb1000 */ if ((status = sb1000_reset(ioaddr, name))) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/sgiseeq.c linux-2.5/drivers/net/sgiseeq.c --- linux-2.5.1/drivers/net/sgiseeq.c Thu Apr 12 19:15:25 2001 +++ linux-2.5/drivers/net/sgiseeq.c Sun Dec 30 21:17:30 2001 @@ -16,7 +16,6 @@ #include <linux/delay.h> #include <asm/io.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/bitops.h> #include <asm/page.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/shaper.c linux-2.5/drivers/net/shaper.c --- linux-2.5.1/drivers/net/shaper.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/net/shaper.c Thu Dec 13 16:32:36 2001 @@ -737,6 +737,11 @@ static void __exit shaper_exit (void) { + int i; + + for (i = 0; i < shapers; i++) + unregister_netdev(&devs[i]); + kfree(devs); devs = NULL; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/sis900.c linux-2.5/drivers/net/sis900.c --- linux-2.5.1/drivers/net/sis900.c Tue Oct 9 22:13:03 2001 +++ linux-2.5/drivers/net/sis900.c Thu Dec 27 16:32:31 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.08.01 Aug. 25 2001 + Revision: 1.08.02 Nov. 30 2001 Modified from the driver which is originally written by Donald Becker. @@ -18,6 +18,7 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.08.02 Nov. 30 2001 Hui-Fen Hsu workaround for EDB & bug fix for dhcp problem Rev 1.08.01 Aug. 25 2001 Hui-Fen Hsu update for 630ET & workaround for ICS1893 PHY Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix 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 @@ -55,18 +56,23 @@ #include <linux/netdevice.h> #include <linux/init.h> #include <linux/mii.h> - #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/ethtool.h> + #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> #include <asm/io.h> -#include <linux/delay.h> +#include <asm/uaccess.h> /* User space memory access functions */ #include "sis900.h" +#define SIS900_MODULE_NAME "sis900" +#define SIS900_DRV_VERSION "v1.08.02 11/30/2001" + static char version[] __devinitdata = -KERN_INFO "sis900.c: v1.08.01 9/25/2001\n"; +KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n"; static int max_interrupt_work = 40; static int multicast_filter_limit = 128; @@ -870,6 +876,9 @@ netif_start_queue(net_dev); + /* Workaround for EDB */ + sis900_set_mode(ioaddr, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); + /* Enable all known interrupts by setting the interrupt mask. */ outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr); outl(RxENA | inl(ioaddr + cr), ioaddr + cr); @@ -1126,6 +1135,7 @@ 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); + netif_start_queue(net_dev); } sis_priv->timer.expires = jiffies + HZ; @@ -1409,6 +1419,12 @@ unsigned int entry; unsigned long flags; + /* Don't transmit data before the complete of auto-negotiation */ + if(!sis_priv->autong_complete){ + netif_stop_queue(net_dev); + return 1; + } + spin_lock_irqsave(&sis_priv->lock, flags); /* Calculate the next Tx descriptor entry. */ @@ -2092,13 +2108,11 @@ pci_set_drvdata(pci_dev, NULL); } -#define SIS900_MODULE_NAME "sis900" - static struct pci_driver sis900_pci_driver = { name: SIS900_MODULE_NAME, id_table: sis900_pci_tbl, probe: sis900_probe, - remove: sis900_remove, + remove: __devexit_p(sis900_remove), }; static int __init sis900_init_module(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/skfp/h/cmtdef.h linux-2.5/drivers/net/skfp/h/cmtdef.h --- linux-2.5.1/drivers/net/skfp/h/cmtdef.h Fri Feb 18 22:55:53 2000 +++ linux-2.5/drivers/net/skfp/h/cmtdef.h Sat Jan 12 12:32:41 2002 @@ -171,7 +171,7 @@ /* WARNING : * EVENT_PCM* must be last in the above list - * if more then two ports are used, EVENT_PCM .. EVENT_PCMA+NUM_PHYS-1 + * if more than two ports are used, EVENT_PCM .. EVENT_PCMA+NUM_PHYS-1 * are used ! */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/slip.c linux-2.5/drivers/net/slip.c --- linux-2.5.1/drivers/net/slip.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/net/slip.c Tue Jan 8 00:44:24 2002 @@ -739,7 +739,7 @@ break; if (slp->ctrl.leased) { - if (slp->ctrl.line != line) + if (!kdev_same(slp->ctrl.line, line)) continue; if (slp->ctrl.tty) return NULL; @@ -753,7 +753,7 @@ continue; if (current->pid == slp->ctrl.pid) { - if (slp->ctrl.line == line && score < 3) { + if (kdev_same(slp->ctrl.line, line) && score < 3) { sel = i; score = 3; continue; @@ -764,7 +764,7 @@ } continue; } - if (slp->ctrl.line == line && score < 1) { + if (kdev_same(slp->ctrl.line, line) && score < 1) { sel = i; score = 1; continue; @@ -944,7 +944,7 @@ tty->disc_data = 0; sl->tty = NULL; if (!sl->leased) - sl->line = 0; + sl->line = NODEV; /* VSV = very important to remove timers */ #ifdef CONFIG_SLIP_SMART @@ -1393,10 +1393,8 @@ /* First of all: check for active disciplines and hangup them. */ do { - if (busy) { - current->counter = 0; - schedule(); - } + if (busy) + yield(); busy = 0; local_bh_disable(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/starfire.c linux-2.5/drivers/net/starfire.c --- linux-2.5.1/drivers/net/starfire.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/net/starfire.c Thu Dec 27 16:32:31 2001 @@ -93,13 +93,16 @@ - Fixed initialization timing problems - Fixed interrupt mask definitions + LK1.3.5 (jgarzik) + - ethtool NWAY_RST, GLINK, [GS]MSGLVL support + TODO: - implement tx_timeout() properly */ #define DRV_NAME "starfire" -#define DRV_VERSION "1.03+LK1.3.4" -#define DRV_RELDATE "August 14, 2001" +#define DRV_VERSION "1.03+LK1.3.5" +#define DRV_RELDATE "November 17, 2001" #include <linux/version.h> #include <linux/module.h> @@ -1789,6 +1792,47 @@ return 0; } + /* restart autonegotiation */ + case ETHTOOL_NWAY_RST: { + int tmp; + int r = -EINVAL; + /* if autoneg is off, it's an error */ + tmp = mdio_read(dev, np->phys[0], MII_BMCR); + if (tmp & BMCR_ANENABLE) { + tmp |= (BMCR_ANRESTART); + mdio_write(dev, np->phys[0], MII_BMCR, tmp); + r = 0; + } + return r; + } + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS) + edata.data = 1; + else + edata.data = 0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + debug = edata.data; + return 0; + } default: return -EOPNOTSUPP; } @@ -1963,7 +2007,7 @@ static struct pci_driver starfire_driver = { name: DRV_NAME, probe: starfire_init_one, - remove: starfire_remove_one, + remove: __devexit_p(starfire_remove_one), id_table: starfire_pci_tbl, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/strip.c linux-2.5/drivers/net/strip.c --- linux-2.5.1/drivers/net/strip.c Fri Nov 9 22:02:24 2001 +++ linux-2.5/drivers/net/strip.c Sun Dec 30 21:17:30 2001 @@ -87,7 +87,6 @@ #include <linux/init.h> #include <asm/system.h> #include <asm/uaccess.h> -#include <asm/segment.h> #include <asm/bitops.h> /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/sundance.c linux-2.5/drivers/net/sundance.c --- linux-2.5.1/drivers/net/sundance.c Fri Oct 19 15:32:28 2001 +++ linux-2.5/drivers/net/sundance.c Thu Dec 27 16:32:31 2001 @@ -16,11 +16,16 @@ Support and updates available at http://www.scyld.com/network/sundance.html + + + Version 1.01a (jgarzik): + - Replace some MII-related magic numbers with constants + */ #define DRV_NAME "sundance" -#define DRV_VERSION "1.01" -#define DRV_RELDATE "4/09/00" +#define DRV_VERSION "1.01a" +#define DRV_RELDATE "11-Nov-2001" /* The user-configurable values. @@ -442,7 +447,7 @@ int irq; int i; long ioaddr; - u16 mii_reg0; + u16 mii_ctl; void *ring_space; dma_addr_t ring_dma; @@ -581,15 +586,15 @@ } } /* Reset PHY */ - mdio_write (dev, np->phys[0], 0, 0x8000); + mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET); mdelay (300); - mdio_write (dev, np->phys[0], 0, 0x1200); + mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART); /* Force media type */ if (!np->an_enable) { - mii_reg0 = 0; - mii_reg0 |= (np->speed == 100) ? 0x2000 : 0; - mii_reg0 |= (np->full_duplex) ? 0x0100 : 0; - mdio_write (dev, np->phys[0], 0, mii_reg0); + mii_ctl = 0; + mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0; + mii_ctl |= (np->full_duplex) ? BMCR_FULLDPLX : 0; + mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl); printk (KERN_INFO "Override speed=%d, %s duplex\n", np->speed, np->full_duplex ? "Full" : "Half"); @@ -797,12 +802,12 @@ { struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; - int mii_reg5 = mdio_read(dev, np->phys[0], 5); - int negotiated = mii_reg5 & np->advertising; + int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); + int negotiated = mii_lpa & np->advertising; int duplex; /* Force media */ - if (!np->an_enable || mii_reg5 == 0xffff) { + if (!np->an_enable || mii_lpa == 0xffff) { if (np->full_duplex) writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex, ioaddr + MACCtrl0); @@ -1183,7 +1188,7 @@ { long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; - u16 mii_reg0, mii_reg4, mii_reg5; + u16 mii_ctl, mii_advertise, mii_lpa; int speed; if (intr_status & IntrDrvRqst) { @@ -1199,27 +1204,27 @@ } if (intr_status & LinkChange) { if (np->an_enable) { - mii_reg4 = mdio_read (dev, np->phys[0], 4); - mii_reg5= mdio_read (dev, np->phys[0], 5); - mii_reg4 &= mii_reg5; + mii_advertise = mdio_read (dev, np->phys[0], MII_ADVERTISE); + mii_lpa= mdio_read (dev, np->phys[0], MII_LPA); + mii_advertise &= mii_lpa; printk (KERN_INFO "%s: Link changed: ", dev->name); - if (mii_reg4 & 0x0100) + if (mii_advertise & ADVERTISE_100FULL) printk ("100Mbps, full duplex\n"); - else if (mii_reg4 & 0x0080) + else if (mii_advertise & ADVERTISE_100HALF) printk ("100Mbps, half duplex\n"); - else if (mii_reg4 & 0x0040) + else if (mii_advertise & ADVERTISE_10FULL) printk ("10Mbps, full duplex\n"); - else if (mii_reg4 & 0x0020) + else if (mii_advertise & ADVERTISE_10HALF) printk ("10Mbps, half duplex\n"); else printk ("\n"); } else { - mii_reg0 = mdio_read (dev, np->phys[0], 0); - speed = (mii_reg0 & 0x2000) ? 100 : 10; + mii_ctl = mdio_read (dev, np->phys[0], MII_BMCR); + speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; printk (KERN_INFO "%s: Link changed: %dMbps ,", dev->name, speed); - printk ("%s duplex.\n", (mii_reg0 & 0x0100) ? + printk ("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ? "full" : "half"); } check_duplex (dev); @@ -1474,7 +1479,7 @@ name: DRV_NAME, id_table: sundance_pci_tbl, probe: sundance_probe1, - remove: sundance_remove1, + remove: __devexit_p(sundance_remove1), }; static int __init sundance_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/sungem.c linux-2.5/drivers/net/sungem.c --- linux-2.5.1/drivers/net/sungem.c Sun Oct 21 17:36:54 2001 +++ linux-2.5/drivers/net/sungem.c Thu Dec 13 16:32:36 2001 @@ -1,7 +1,15 @@ -/* $Id: sungem.c,v 1.30 2001/10/17 06:55:10 davem Exp $ +/* $Id: sungem.c,v 1.43 2001/12/05 08:40:54 davem Exp $ * sungem.c: Sun GEM ethernet driver. * * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) + * + * Support for Apple GMAC and assorted PHYs by + * Benjamin Herrenscmidt (benh@kernel.crashing.org) + * + * TODO: + * - Get rid of all those nasty mdelay's and replace them + * with schedule_timeout. + * - Implement WOL */ #include <linux/module.h> @@ -23,11 +31,15 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <linux/mii.h> +#include <linux/ethtool.h> #include <asm/system.h> #include <asm/bitops.h> #include <asm/io.h> #include <asm/byteorder.h> +#include <asm/uaccess.h> +#include <asm/irq.h> #ifdef __sparc__ #include <asm/idprom.h> @@ -45,15 +57,33 @@ #include "sungem.h" +#define DRV_NAME "sungem" +#define DRV_VERSION "0.96" +#define DRV_RELDATE "11/17/01" +#define DRV_AUTHOR "David S. Miller (davem@redhat.com)" + static char version[] __devinitdata = - "sungem.c:v0.95 16/Oct/01 David S. Miller (davem@redhat.com)\n"; + DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; -MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); +MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver"); MODULE_LICENSE("GPL"); MODULE_PARM(gem_debug, "i"); MODULE_PARM_DESC(gem_debug, "(ignored)"); +MODULE_PARM(link_mode, "i"); + +static int link_mode; + +static u16 link_modes[] __devinitdata = { + BMCR_ANENABLE, /* 0 : autoneg */ + 0, /* 1 : 10bt half duplex */ + BMCR_SPEED100, /* 2 : 100bt half duplex */ + BMCR_SPD2, /* verify this */ /* 3 : 1000bt half duplex */ + BMCR_FULLDPLX, /* 4 : 10bt full duplex */ + BMCR_SPEED100|BMCR_FULLDPLX, /* 5 : 100bt full duplex */ + BMCR_SPD2|BMCR_FULLDPLX /* 6 : 1000bt full duplex */ +}; #define GEM_MODULE_NAME "gem" #define PFX GEM_MODULE_NAME ": " @@ -73,7 +103,7 @@ * they only support 10/100 speeds. -DaveM * * Apple's GMAC does support gigabit on machines with - * the BCM5400 or 5401 PHYs. -BenH + * the BCM54xx PHYs. -BenH */ { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_GEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, @@ -362,10 +392,6 @@ return 1; } -static void gem_stop(struct gem *, unsigned long); -static void gem_init_rings(struct gem *, int); -static void gem_init_hw(struct gem *); - /* All non-normal interrupt conditions get serviced here. * Returns non-zero if we should just exit the interrupt * handler right now (ie. if we reset the card which invalidates @@ -418,9 +444,9 @@ return 0; do_reset: - gem_stop(gp, gp->regs); - gem_init_rings(gp, 1); - gem_init_hw(gp); + gp->reset_task_pending = 1; + schedule_task(&gp->reset_task); + return 1; } @@ -627,6 +653,10 @@ struct gem *gp = dev->priv; printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + if (!gp->hw_running) { + printk("%s: hrm.. hw not running !\n", dev->name); + return; + } printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x]\n", dev->name, readl(gp->regs + TXDMA_CFG), @@ -640,13 +670,19 @@ spin_lock_irq(&gp->lock); - gem_stop(gp, gp->regs); - gem_init_rings(gp, 1); - gem_init_hw(gp); + gp->reset_task_pending = 1; + schedule_task(&gp->reset_task); spin_unlock_irq(&gp->lock); +} - netif_wake_queue(dev); +static __inline__ int gem_intme(int entry) +{ + /* Algorithm: IRQ every 1/2 of descriptors. */ + if (!(entry & ((TX_RING_SIZE>>1)-1))) + return 1; + + return 0; } static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -690,15 +726,22 @@ ~PAGE_MASK), len, PCI_DMA_TODEVICE); ctrl |= TXDCTRL_SOF | TXDCTRL_EOF | len; + if (gem_intme(entry)) + ctrl |= TXDCTRL_INTME; txd->buffer = cpu_to_le64(mapping); txd->control_word = cpu_to_le64(ctrl); entry = NEXT_TX(entry); } else { struct gem_txd *txd; u32 first_len; + u64 intme; dma_addr_t first_mapping; int frag, first_entry = entry; + intme = 0; + if (gem_intme(entry)) + intme |= TXDCTRL_INTME; + /* We must give this initial chunk to the device last. * Otherwise we could race with the device. */ @@ -727,11 +770,15 @@ txd->buffer = cpu_to_le64(mapping); txd->control_word = cpu_to_le64(this_ctrl | len); + if (gem_intme(entry)) + intme |= TXDCTRL_INTME; + entry = NEXT_TX(entry); } txd = &gp->init_block->txd[first_entry]; txd->buffer = cpu_to_le64(first_mapping); - txd->control_word = cpu_to_le64(ctrl | TXDCTRL_SOF | first_len); + txd->control_word = + cpu_to_le64(ctrl | TXDCTRL_SOF | intme | first_len); } gp->tx_new = entry; @@ -761,18 +808,19 @@ 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); + gp->reset_task_pending = 1; + schedule_task(&gp->reset_task); spin_unlock_irq(&gp->lock); + flush_scheduled_tasks(); + return 0; } #define STOP_TRIES 32 -static void gem_stop(struct gem *gp, unsigned long regs) +static void gem_stop(struct gem *gp) { int limit; u32 val; @@ -781,13 +829,13 @@ writel(0xffffffff, gp->regs + GREG_IMASK); /* Reset the chip */ - writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, regs + GREG_SWRST); + writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, gp->regs + GREG_SWRST); limit = STOP_TRIES; do { udelay(20); - val = readl(regs + GREG_SWRST); + val = readl(gp->regs + GREG_SWRST); if (limit-- <= 0) break; } while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST)); @@ -810,6 +858,9 @@ val = readl(gp->regs + MAC_RXCFG); writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); + (void) readl(gp->regs + MAC_RXCFG); + udelay(100); + writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK); writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); @@ -828,6 +879,88 @@ { 1, 0, 1 }, /* 1000BT */ }; +static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) +{ + u16 ctl; + + /* Setup link parameters */ + if (!ep) + goto start_aneg; + if (ep->autoneg == AUTONEG_ENABLE) { + /* TODO: parse ep->advertising */ + gp->link_advertise |= (ADVERTISE_10HALF | ADVERTISE_10FULL); + gp->link_advertise |= (ADVERTISE_100HALF | ADVERTISE_100FULL); + /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ + gp->link_cntl = BMCR_ANENABLE; + } else { + gp->link_cntl = 0; + if (ep->speed == SPEED_100) + gp->link_cntl |= BMCR_SPEED100; + else if (ep->speed == SPEED_1000 && gp->gigabit_capable) + /* Hrm... check if this is right... */ + gp->link_cntl |= BMCR_SPD2; + if (ep->duplex == DUPLEX_FULL) + gp->link_cntl |= BMCR_FULLDPLX; + } + +start_aneg: + spin_lock_irq(&gp->lock); + if (!gp->hw_running) { + spin_unlock_irq(&gp->lock); + return; + } + + /* Configure PHY & start aneg */ + ctl = phy_read(gp, MII_BMCR); + ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE); + ctl |= gp->link_cntl; + if (ctl & BMCR_ANENABLE) { + ctl |= BMCR_ANRESTART; + gp->lstate = link_aneg; + } else { + gp->lstate = link_force_ok; + } + phy_write(gp, MII_BMCR, ctl); + + gp->timer_ticks = 0; + gp->link_timer.expires = jiffies + ((12 * HZ) / 10); + add_timer(&gp->link_timer); + spin_unlock_irq(&gp->lock); +} + +static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause) +{ + u32 val; + + *fd = 0; + *spd = 10; + *pause = 0; + + if (gp->phy_mod == phymod_bcm5400 || + gp->phy_mod == phymod_bcm5401 || + gp->phy_mod == phymod_bcm5411) { + int link_mode; + + val = phy_read(gp, MII_BCM5400_AUXSTATUS); + link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> + MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT); + *fd = phy_BCM5400_link_table[link_mode][0]; + *spd = phy_BCM5400_link_table[link_mode][2] ? + 1000 : + (phy_BCM5400_link_table[link_mode][1] ? 100 : 10); + val = phy_read(gp, MII_LPA); + if (val & LPA_PAUSE) + *pause = 1; + } else { + val = phy_read(gp, MII_LPA); + + if (val & (LPA_10FULL | LPA_100FULL)) + *fd = 1; + if (val & (LPA_100FULL | LPA_100HALF)) + *spd = 100; + } +} + /* A link-up condition has occurred, initialize and enable the * rest of the chip. */ @@ -842,32 +975,13 @@ if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) { - if (gp->lstate == aneg_wait) { - if (gp->phy_mod == phymod_bcm5400 || - gp->phy_mod == phymod_bcm5401 || - gp->phy_mod == phymod_bcm5411) { - int link_mode; - val = phy_read(gp, PHY_BCM5400_AUXSTATUS); - link_mode = (val & PHY_BCM5400_AUXSTATUS_LINKMODE_MASK) >> - PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT; - full_duplex = phy_BCM5400_link_table[link_mode][0]; - speed = phy_BCM5400_link_table[link_mode][2] ? 1000 - : (phy_BCM5400_link_table[link_mode][1] ? 100 : 10); - val = phy_read(gp, PHY_LPA); - if (val & PHY_LPA_PAUSE) - pause = 1; - } else { - val = phy_read(gp, PHY_LPA); - if (val & (PHY_LPA_10FULL | PHY_LPA_100FULL)) - full_duplex = 1; - if (val & (PHY_LPA_100FULL | PHY_LPA_100HALF)) - speed = 100; - } - } else { - val = phy_read(gp, PHY_CTRL); - if (val & PHY_CTRL_FDPLX) + val = phy_read(gp, MII_BMCR); + if (val & BMCR_ANENABLE) + gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause); + else { + if (val & BMCR_FULLDPLX) full_duplex = 1; - if (val & PHY_CTRL_SPD100) + if (val & BMCR_SPEED100) speed = 100; } } else { @@ -944,56 +1058,142 @@ static int gem_mdio_link_not_up(struct gem *gp) { - if (gp->lstate == aneg_wait) { - u16 val = phy_read(gp, PHY_CTRL); + if (gp->lstate == link_force_ret) { + printk(KERN_INFO "%s: Autoneg failed again, keeping" + " forced mode\n", gp->dev->name); + phy_write(gp, MII_BMCR, gp->link_fcntl); + gp->timer_ticks = 5; + gp->lstate = link_force_ok; + } else if (gp->lstate == link_aneg) { + u16 val = phy_read(gp, MII_BMCR); /* Try forced modes. */ - val &= ~(PHY_CTRL_ANRES | PHY_CTRL_ANENAB); - val &= ~(PHY_CTRL_FDPLX); - val |= PHY_CTRL_SPD100; - phy_write(gp, PHY_CTRL, val); - gp->timer_ticks = 0; - gp->lstate = force_wait; - return 1; + val &= ~(BMCR_ANRESTART | BMCR_ANENABLE); + val &= ~(BMCR_FULLDPLX); + val |= BMCR_SPEED100; + phy_write(gp, MII_BMCR, val); + gp->timer_ticks = 5; + gp->lstate = link_force_try; } else { /* Downgrade from 100 to 10 Mbps if necessary. * If already at 10Mbps, warn user about the * situation every 10 ticks. */ - u16 val = phy_read(gp, PHY_CTRL); - if (val & PHY_CTRL_SPD100) { - val &= ~PHY_CTRL_SPD100; - phy_write(gp, PHY_CTRL, val); - gp->timer_ticks = 0; - return 1; + u16 val = phy_read(gp, MII_BMCR); + if (val & BMCR_SPEED100) { + val &= ~BMCR_SPEED100; + phy_write(gp, MII_BMCR, val); + gp->timer_ticks = 5; } else { - printk(KERN_ERR "%s: Link down, cable problem?\n", - gp->dev->name); - val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB); - phy_write(gp, PHY_CTRL, val); - gp->timer_ticks = 1; - gp->lstate = aneg_wait; return 1; } } + return 0; +} + +static void gem_init_rings(struct gem *, int); +static void gem_init_hw(struct gem *, int); + +static void gem_reset_task(void *data) +{ + struct gem *gp = (struct gem *) data; + + /* The link went down, we reset the ring, but keep + * DMA stopped. Todo: Use this function for reset + * on error as well. + */ + if (gp->hw_running && gp->opened) { + /* Make sure we don't get interrupts or tx packets */ + spin_lock_irq(&gp->lock); + + netif_stop_queue(gp->dev); + + writel(0xffffffff, gp->regs + GREG_IMASK); + + spin_unlock_irq(&gp->lock); + + /* Reset the chip & rings */ + gem_stop(gp); + gem_init_rings(gp, 0); + gem_init_hw(gp, 0); + + netif_wake_queue(gp->dev); + } + gp->reset_task_pending = 0; } static void gem_link_timer(unsigned long data) { struct gem *gp = (struct gem *) data; - int restart_timer = 0; - gp->timer_ticks++; + if (!gp->hw_running) + return; + + /* If the link of task is still pending, we just + * reschedule the link timer + */ + if (gp->reset_task_pending) + goto restart; + + spin_lock_irq(&gp->lock); if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) { - u16 val = phy_read(gp, PHY_STAT); + u16 val = phy_read(gp, MII_BMSR); + int up; - if (val & PHY_STAT_LSTAT) { - gem_set_link_modes(gp); - } else if (gp->timer_ticks < 10) { - restart_timer = 1; + /* When using autoneg, we really wait for ANEGCOMPLETE or we may + * get a "transcient" incorrect link state + */ +#if 0 + { + u16 cntl = phy_read(gp, MII_BMCR); + if (cntl & BMCR_ANENABLE) + up = (val & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS); + else + up = (val & BMSR_LSTATUS) != 0; + } +#else + up = (val & BMSR_LSTATUS) != 0; +#endif + if (up) { + /* Ok, here we got a link. If we had it due to a forced + * fallback, and we were configured for autoneg, we do + * retry a short autoneg pass. If you know your hub is + * broken, use ethtool ;) + */ + if (gp->lstate == link_force_try && (gp->link_cntl & BMCR_ANENABLE)) { + gp->lstate = link_force_ret; + gp->link_fcntl = phy_read(gp, MII_BMCR); + gp->timer_ticks = 5; + printk(KERN_INFO "%s: Got link after fallback, retrying autoneg" + " once...\n", gp->dev->name); + phy_write(gp, MII_BMCR, + gp->link_fcntl | BMCR_ANENABLE | BMCR_ANRESTART); + } else if (gp->lstate != link_up) { + gp->lstate = link_up; + if (gp->opened) + gem_set_link_modes(gp); + } } else { - restart_timer = gem_mdio_link_not_up(gp); + int restart = 0; + + /* If the link was previously up, we restart the + * whole process + */ + if (gp->lstate == link_up) { + gp->lstate = link_down; + printk(KERN_INFO "%s: Link down\n", gp->dev->name); + gp->reset_task_pending = 1; + schedule_task(&gp->reset_task); + restart = 1; + } else if (++gp->timer_ticks > 10) + restart = gem_mdio_link_not_up(gp); + + if (restart) { + spin_unlock_irq(&gp->lock); + gem_begin_auto_negotiation(gp, NULL); + return; + } } } else { u32 val = readl(gp->regs + PCS_MIISTAT); @@ -1001,17 +1201,17 @@ 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 ((val & PCS_MIISTAT_LS) != 0) { + gp->lstate = link_up; + if (gp->opened) + gem_set_link_modes(gp); } } - if (restart_timer) { - gp->link_timer.expires = jiffies + ((12 * HZ) / 10); - add_timer(&gp->link_timer); - } +restart: + gp->link_timer.expires = jiffies + ((12 * HZ) / 10); + add_timer(&gp->link_timer); + spin_unlock_irq(&gp->lock); } static void gem_clean_rings(struct gem *gp) @@ -1108,66 +1308,72 @@ } } -static int -gem_reset_one_mii_phy(struct gem *gp, int phy_addr) +static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr) { u16 val; int limit = 10000; - val = __phy_read(gp, PHY_CTRL, phy_addr); - val &= ~PHY_CTRL_ISO; - val |= PHY_CTRL_RST; - __phy_write(gp, PHY_CTRL, val, phy_addr); + val = __phy_read(gp, MII_BMCR, phy_addr); + val &= ~BMCR_ISOLATE; + val |= BMCR_RESET; + __phy_write(gp, MII_BMCR, val, phy_addr); udelay(100); while (limit--) { - val = __phy_read(gp, PHY_CTRL, phy_addr); - if ((val & PHY_CTRL_RST) == 0) + val = __phy_read(gp, MII_BMCR, phy_addr); + if ((val & BMCR_RESET) == 0) break; udelay(10); } - if ((val & PHY_CTRL_ISO) && limit > 0) - __phy_write(gp, PHY_CTRL, val & ~PHY_CTRL_ISO, phy_addr); + if ((val & BMCR_ISOLATE) && limit > 0) + __phy_write(gp, MII_BMCR, val & ~BMCR_ISOLATE, phy_addr); return (limit <= 0); } -static void -gem_init_bcm5400_phy(struct gem *gp) +static void gem_init_bcm5201_phy(struct gem *gp) +{ + u16 data; + + data = phy_read(gp, MII_BCM5201_MULTIPHY); + data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE; + phy_write(gp, MII_BCM5201_MULTIPHY, data); +} + +static void gem_init_bcm5400_phy(struct gem *gp) { u16 data; /* Configure for gigabit full duplex */ - data = phy_read(gp, PHY_BCM5400_AUXCONTROL); - data |= PHY_BCM5400_AUXCONTROL_PWR10BASET; - phy_write(gp, PHY_BCM5400_AUXCONTROL, data); - - data = phy_read(gp, PHY_BCM5400_GB_CONTROL); - data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP; - phy_write(gp, PHY_BCM5400_GB_CONTROL, data); + data = phy_read(gp, MII_BCM5400_AUXCONTROL); + data |= MII_BCM5400_AUXCONTROL_PWR10BASET; + phy_write(gp, MII_BCM5400_AUXCONTROL, data); + + data = phy_read(gp, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + phy_write(gp, MII_BCM5400_GB_CONTROL, data); mdelay(10); /* Reset and configure cascaded 10/100 PHY */ gem_reset_one_mii_phy(gp, 0x1f); - data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f); - data |= PHY_BCM5201_MULTIPHY_SERIALMODE; - __phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f); + data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f); + data |= MII_BCM5201_MULTIPHY_SERIALMODE; + __phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f); - data = phy_read(gp, PHY_BCM5400_AUXCONTROL); - data &= ~PHY_BCM5400_AUXCONTROL_PWR10BASET; - phy_write(gp, PHY_BCM5400_AUXCONTROL, data); + data = phy_read(gp, MII_BCM5400_AUXCONTROL); + data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET; + phy_write(gp, MII_BCM5400_AUXCONTROL, data); } -static void -gem_init_bcm5401_phy(struct gem *gp) +static void gem_init_bcm5401_phy(struct gem *gp) { u16 data; int rev; - rev = phy_read(gp, PHY_ID1) & 0x000f; + rev = phy_read(gp, MII_PHYSID2) & 0x000f; if (rev == 0 || rev == 3) { /* Some revisions of 5401 appear to need this * initialisation sequence to disable, according @@ -1191,22 +1397,21 @@ } /* Configure for gigabit full duplex */ - data = phy_read(gp, PHY_BCM5400_GB_CONTROL); - data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP; - phy_write(gp, PHY_BCM5400_GB_CONTROL, data); + data = phy_read(gp, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + phy_write(gp, MII_BCM5400_GB_CONTROL, data); mdelay(1); /* Reset and configure cascaded 10/100 PHY */ gem_reset_one_mii_phy(gp, 0x1f); - data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f); - data |= PHY_BCM5201_MULTIPHY_SERIALMODE; - __phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f); + data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f); + data |= MII_BCM5201_MULTIPHY_SERIALMODE; + __phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f); } -static void -gem_init_bcm5411_phy(struct gem *gp) +static void gem_init_bcm5411_phy(struct gem *gp) { u16 data; @@ -1220,20 +1425,30 @@ /* Here, Apple seems to want to reset it, do * it as well */ - phy_write(gp, PHY_CTRL, PHY_CTRL_RST); + phy_write(gp, MII_BMCR, BMCR_RESET); /* Start autoneg */ - phy_write(gp, PHY_CTRL, - (PHY_CTRL_ANENAB | PHY_CTRL_FDPLX | - PHY_CTRL_ANRES | PHY_CTRL_SPD2)); - - data = phy_read(gp, PHY_BCM5400_GB_CONTROL); - data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP; - phy_write(gp, PHY_BCM5400_GB_CONTROL, data); + phy_write(gp, MII_BMCR, + (BMCR_ANENABLE | BMCR_FULLDPLX | + BMCR_ANRESTART | BMCR_SPD2)); + + data = phy_read(gp, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + phy_write(gp, MII_BCM5400_GB_CONTROL, data); } static void gem_init_phy(struct gem *gp) { + u32 mifcfg; + + if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201) + phy_write(gp, MII_BCM5201_INTERRUPT, 0); + + /* Revert MIF CFG setting done on stop_phy */ + mifcfg = readl(gp->regs + MIF_CFG); + mifcfg &= ~MIF_CFG_BBMODE; + writel(mifcfg, gp->regs + MIF_CFG); + #ifdef CONFIG_ALL_PPC if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { int i; @@ -1241,7 +1456,7 @@ pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0); for (i = 0; i < 32; i++) { gp->mii_phy_addr = i; - if (phy_read(gp, PHY_CTRL) != 0xffff) + if (phy_read(gp, MII_BMCR) != 0xffff) break; } if (i == 32) { @@ -1277,54 +1492,68 @@ /* Take PHY out of isloate mode and reset it. */ gem_reset_one_mii_phy(gp, gp->mii_phy_addr); - phy_id = (phy_read(gp, PHY_ID0) << 16 | phy_read(gp, PHY_ID1)) + phy_id = (phy_read(gp, MII_PHYSID1) << 16 | phy_read(gp, MII_PHYSID2)) & 0xfffffff0; printk(KERN_INFO "%s: MII PHY ID: %x ", gp->dev->name, phy_id); switch(phy_id) { - case 0x406210: - gp->phy_mod = phymod_bcm5201; - printk("BCM 5201\n"); - break; - case 0x4061e0: - printk("BCM 5221\n"); - gp->phy_mod = phymod_bcm5221; - break; - case 0x206040: - printk("BCM 5400\n"); - gp->phy_mod = phymod_bcm5400; - gem_init_bcm5400_phy(gp); - break; - case 0x206050: - printk("BCM 5401\n"); - gp->phy_mod = phymod_bcm5401; - gem_init_bcm5401_phy(gp); - break; - case 0x206070: - printk("BCM 5411\n"); - gp->phy_mod = phymod_bcm5411; - gem_init_bcm5411_phy(gp); - break; - default: - printk("Generic\n"); - gp->phy_mod = phymod_generic; + case 0x406210: + gp->phy_mod = phymod_bcm5201; + gem_init_bcm5201_phy(gp); + printk("BCM 5201\n"); + break; + + case 0x4061e0: + printk("BCM 5221\n"); + gp->phy_mod = phymod_bcm5221; + break; + + case 0x206040: + printk("BCM 5400\n"); + gp->phy_mod = phymod_bcm5400; + gem_init_bcm5400_phy(gp); + gp->gigabit_capable = 1; + break; + + case 0x206050: + printk("BCM 5401\n"); + gp->phy_mod = phymod_bcm5401; + gem_init_bcm5401_phy(gp); + gp->gigabit_capable = 1; + break; + + case 0x206070: + printk("BCM 5411\n"); + gp->phy_mod = phymod_bcm5411; + gem_init_bcm5411_phy(gp); + gp->gigabit_capable = 1; + break; + + case 0x18074c0: + printk("Lucent\n"); + gp->phy_mod = phymod_generic; + break; + + case 0x437420: + printk("Enable Semiconductor\n"); + gp->phy_mod = phymod_generic; + break; + + default: + printk("Unknown\n"); + gp->phy_mod = phymod_generic; + break; }; /* Init advertisement and enable autonegotiation. */ - val = phy_read(gp, PHY_CTRL); - val &= ~PHY_CTRL_ANENAB; - phy_write(gp, PHY_CTRL, val); + val = phy_read(gp, MII_BMCR); + val &= ~BMCR_ANENABLE; + phy_write(gp, MII_BMCR, val); udelay(10); - phy_write(gp, PHY_ADV, - phy_read(gp, PHY_ADV) | - (PHY_ADV_10HALF | PHY_ADV_10FULL | - PHY_ADV_100HALF | PHY_ADV_100FULL)); - - val = phy_read(gp, PHY_CTRL); - val |= PHY_CTRL_ANENAB; - phy_write(gp, PHY_CTRL, val); - val |= PHY_CTRL_ANRES; - phy_write(gp, PHY_CTRL, val); + phy_write(gp, MII_ADVERTISE, + phy_read(gp, MII_ADVERTISE) | + (ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_100FULL)); } else { u32 val; int limit; @@ -1379,6 +1608,7 @@ else val |= PCS_SCTRL_LOOP; writel(val, gp->regs + PCS_SCTRL); + gp->gigabit_capable = 1; } } @@ -1392,7 +1622,7 @@ writel(desc_dma >> 32, gp->regs + TXDMA_DBHI); writel(desc_dma & 0xffffffff, gp->regs + TXDMA_DBLOW); - desc_dma += (TX_RING_SIZE * sizeof(struct gem_txd)); + desc_dma += (INIT_BLOCK_TX_RING_SIZE * sizeof(struct gem_txd)); writel(0, gp->regs + TXDMA_KICK); @@ -1410,12 +1640,12 @@ writel(val, gp->regs + RXDMA_PTHRESH); if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) - writel(((6 & RXDMA_BLANK_IPKTS) | - ((4 << 12) & RXDMA_BLANK_ITIME)), + writel(((5 & RXDMA_BLANK_IPKTS) | + ((8 << 12) & RXDMA_BLANK_ITIME)), gp->regs + RXDMA_BLANK); else - writel(((6 & RXDMA_BLANK_IPKTS) | - ((2 << 12) & RXDMA_BLANK_ITIME)), + writel(((5 & RXDMA_BLANK_IPKTS) | + ((4 << 12) & RXDMA_BLANK_ITIME)), gp->regs + RXDMA_BLANK); } @@ -1551,18 +1781,20 @@ writel(0, gp->regs + MAC_MCCFG); writel(0, gp->regs + MAC_XIFCFG); - writel((MAC_TXSTAT_URUN | MAC_TXSTAT_MPE | - MAC_TXSTAT_NCE | MAC_TXSTAT_ECE | - MAC_TXSTAT_LCE | MAC_TXSTAT_FCE | - MAC_TXSTAT_DTE | MAC_TXSTAT_PCE), gp->regs + MAC_TXMASK); - writel((MAC_RXSTAT_OFLW | MAC_RXSTAT_FCE | - MAC_RXSTAT_ACE | MAC_RXSTAT_CCE | - MAC_RXSTAT_LCE | MAC_RXSTAT_VCE), gp->regs + MAC_RXMASK); - writel(0, gp->regs + MAC_MCMASK); + /* Setup MAC interrupts. We want to get all of the interesting + * counter expiration events, but we do not want to hear about + * normal rx/tx as the DMA engine tells us that. + */ + writel(MAC_TXSTAT_XMIT, gp->regs + MAC_TXMASK); + writel(MAC_RXSTAT_RCV, gp->regs + MAC_RXMASK); + + /* Don't enable even the PAUSE interrupts for now, we + * make no use of those events other than to record them. + */ + writel(0xffffffff, gp->regs + MAC_MCMASK); } -static void -gem_init_pause_thresholds(struct gem* gp) +static void gem_init_pause_thresholds(struct gem *gp) { /* Calculate pause thresholds. Setting the OFF threshold to the * full RX fifo size effectively disables PAUSE generation which @@ -1580,11 +1812,7 @@ } { - u32 cfg = readl(gp->regs + GREG_BIFCFG); - - /* XXX Why do I do this? -DaveM XXX */ - cfg |= GREG_BIFCFG_B64DIS; - writel(cfg, gp->regs + GREG_BIFCFG); + u32 cfg; cfg = GREG_CFG_IBURST; cfg |= ((31 << 1) & GREG_CFG_TXDMALIM); @@ -1598,21 +1826,15 @@ struct pci_dev *pdev = gp->pdev; u32 mif_cfg; - /* On Apple's sungem, we can't realy on registers as the chip + /* On Apple's sungem, we can't rely on registers as the chip * was been powered down by the firmware. We do the PHY lookup * when the interface is opened and we configure the driver * with known values. */ if (pdev->vendor == PCI_VENDOR_ID_APPLE) { gp->phy_type = phy_mii_mdio0; - mif_cfg = readl(gp->regs + MIF_CFG); - mif_cfg &= ~MIF_CFG_PSELECT; - writel(mif_cfg, gp->regs + MIF_CFG); - writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE); - writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG); gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64; gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64; - gem_init_pause_thresholds(gp); return 0; } @@ -1651,7 +1873,7 @@ for (i = 0; i < 32; i++) { gp->mii_phy_addr = i; - if (phy_read(gp, PHY_CTRL) != 0xffff) + if (phy_read(gp, MII_BMCR) != 0xffff) break; } if (i == 32) { @@ -1685,12 +1907,10 @@ } } - gem_init_pause_thresholds(gp); - return 0; } -static void gem_init_hw(struct gem *gp) +static void gem_init_hw(struct gem *gp, int restart_link) { /* On Apple's gmac, I initialize the PHY only after * setting up the chip. It appears the gigabit PHYs @@ -1698,18 +1918,28 @@ * the chip is not running, I suspect it might not * be clocked at that point. --BenH */ - if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { - gem_check_invariants(gp); - gp->hw_running = 1; - } - gem_init_phy(gp); + if (restart_link) + gem_init_phy(gp); gem_init_dma(gp); gem_init_mac(gp); + gem_init_pause_thresholds(gp); - gp->timer_ticks = 0; - gp->lstate = aneg_wait; - gp->link_timer.expires = jiffies + ((12 * HZ) / 10); - add_timer(&gp->link_timer); + spin_lock_irq(&gp->lock); + if (restart_link) { + /* Default aneg parameters */ + gp->timer_ticks = 0; + gp->lstate = link_down; + + spin_unlock_irq(&gp->lock); + + /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ + gem_begin_auto_negotiation(gp, NULL); + } else { + if (gp->lstate == link_up) + gem_set_link_modes(gp); + + spin_unlock_irq(&gp->lock); + } } #ifdef CONFIG_ALL_PPC @@ -1717,10 +1947,10 @@ * setup properly. There appear to be no need to restore the * base addresses. */ -static void -gem_apple_powerup(struct gem* gp) +static void gem_apple_powerup(struct gem *gp) { u16 cmd; + u32 mif_cfg; pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1); @@ -1731,31 +1961,162 @@ pci_write_config_word(gp->pdev, PCI_COMMAND, cmd); pci_write_config_byte(gp->pdev, PCI_LATENCY_TIMER, 6); pci_write_config_byte(gp->pdev, PCI_CACHE_LINE_SIZE, 8); + + mdelay(1); + + mif_cfg = readl(gp->regs + MIF_CFG); + mif_cfg &= ~(MIF_CFG_PSELECT|MIF_CFG_POLL|MIF_CFG_BBMODE|MIF_CFG_MDI1); + mif_cfg |= MIF_CFG_MDI0; + writel(mif_cfg, gp->regs + MIF_CFG); + writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE); + writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG); + + mdelay(1); } /* Turn off the chip's clock */ -static void -gem_apple_powerdown(struct gem* gp) +static void gem_apple_powerdown(struct gem *gp) { pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0); } + +#endif /* CONFIG_ALL_PPC */ + +static void gem_stop_phy(struct gem *gp) +{ + u32 mifcfg; + + if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201) + phy_write(gp, MII_BCM5201_INTERRUPT, 0); + + /* Make sure we aren't polling PHY status change. We + * don't currently use that feature though + */ + mifcfg = readl(gp->regs + MIF_CFG); + mifcfg &= ~MIF_CFG_POLL; + writel(mifcfg, gp->regs + MIF_CFG); + + /* Here's a strange hack used by both MacOS 9 and X */ + phy_write(gp, MII_LPA, phy_read(gp, MII_LPA)); + + if (gp->wake_on_lan) { + /* Setup wake-on-lan */ + } else + writel(0, gp->regs + MAC_RXCFG); + writel(0, gp->regs + MAC_TXCFG); + writel(0, gp->regs + MAC_XIFCFG); + writel(0, gp->regs + TXDMA_CFG); + writel(0, gp->regs + RXDMA_CFG); + + if (!gp->wake_on_lan) { + gem_stop(gp); + writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST); + writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST); + if (gp->phy_mod == phymod_bcm5400 || gp->phy_mod == phymod_bcm5401 || + gp->phy_mod == phymod_bcm5411) { +#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ + phy_write(gp, MII_BMCR, BMCR_PDOWN); +#endif + } else if (gp->phy_mod == phymod_bcm5201 || gp->phy_mod == phymod_bcm5221) { +#if 0 /* Commented out in Darwin... someone has those dawn docs ? */ + u16 val = phy_read(gp, MII_BCM5201_AUXMODE2) + phy_write(gp, MII_BCM5201_AUXMODE2, + val & ~MII_BCM5201_AUXMODE2_LOWPOWER); +#endif + phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE); + } + + /* According to Apple, we must set the MDIO pins to this begnign + * state or we may 1) eat more current, 2) damage some PHYs + */ + writel(mifcfg | MIF_CFG_BBMODE, gp->regs + MIF_CFG); + writel(0, gp->regs + MIF_BBCLK); + writel(0, gp->regs + MIF_BBDATA); + writel(0, gp->regs + MIF_BBOENAB); + writel(MAC_XIFCFG_GMII | MAC_XIFCFG_LBCK, gp->regs + MAC_XIFCFG); + (void) readl(gp->regs + MAC_XIFCFG); + } +} + +/* Shut down the chip, must be called with pm_sem held. */ +static void gem_shutdown(struct gem *gp) +{ + /* Make us not-running to avoid timers respawning */ + gp->hw_running = 0; + + /* Stop the link timer */ + del_timer_sync(&gp->link_timer); + + /* Stop the reset task */ + while (gp->reset_task_pending) + schedule(); + + /* Actually stop the chip */ + if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) + gem_stop_phy(gp); + else + gem_stop(gp); + +#ifdef CONFIG_ALL_PPC + /* Power down the chip */ + if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) + gem_apple_powerdown(gp); #endif /* CONFIG_ALL_PPC */ +} + +static void gem_pm_task(void *data) +{ + struct gem *gp = (struct gem *) data; + + /* We assume if we can't lock the pm_sem, then open() was + * called again (or suspend()), and we can safely ignore + * the PM request + */ + if (down_trylock(&gp->pm_sem)) + return; + + /* Driver was re-opened or already shut down */ + if (gp->opened || !gp->hw_running) { + up(&gp->pm_sem); + return; + } + + gem_shutdown(gp); + + up(&gp->pm_sem); +} + +static void gem_pm_timer(unsigned long data) +{ + struct gem *gp = (struct gem *) data; + + schedule_task(&gp->pm_task); +} static int gem_open(struct net_device *dev) { struct gem *gp = dev->priv; - unsigned long regs = gp->regs; + int hw_was_up = gp->hw_running; - del_timer(&gp->link_timer); + down(&gp->pm_sem); + /* Stop the PM timer/task */ + del_timer(&gp->pm_timer); + flush_scheduled_tasks(); + + if (!gp->hw_running) { #ifdef CONFIG_ALL_PPC - /* First, we need to bring up the chip */ - if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) - gem_apple_powerup(gp); + /* First, we need to bring up the chip */ + if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { + gem_apple_powerup(gp); + gem_check_invariants(gp); + } #endif /* CONFIG_ALL_PPC */ + /* Reset the chip */ + gem_stop(gp); - /* Reset the chip */ - gem_stop(gp, regs); + gp->hw_running = 1; + } /* We can now request the interrupt as we know it's masked * on the controller @@ -1763,9 +2124,14 @@ if (request_irq(gp->pdev->irq, gem_interrupt, SA_SHIRQ, dev->name, (void *)dev)) { #ifdef CONFIG_ALL_PPC - if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) + if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE) gem_apple_powerdown(gp); #endif /* CONFIG_ALL_PPC */ + /* Fire the PM timer that will shut us down in about 10 seconds */ + gp->pm_timer.expires = jiffies + 10*HZ; + add_timer(&gp->pm_timer); + up(&gp->pm_sem); + return -EAGAIN; } @@ -1773,7 +2139,11 @@ gem_init_rings(gp, 0); /* Init & setup chip hardware */ - gem_init_hw(gp); + gem_init_hw(gp, !hw_was_up); + + gp->opened = 1; + + up(&gp->pm_sem); return 0; } @@ -1782,17 +2152,110 @@ { struct gem *gp = dev->priv; - del_timer(&gp->link_timer); - gem_stop(gp, gp->regs); + /* Make sure we don't get distracted by suspend/resume */ + down(&gp->pm_sem); + + /* Stop traffic, mark us closed */ + spin_lock_irq(&gp->lock); + + gp->opened = 0; + writel(0xffffffff, gp->regs + GREG_IMASK); + netif_stop_queue(dev); + + spin_unlock_irq(&gp->lock); + + /* Stop chip */ + gem_stop(gp); + + /* Get rid of rings */ gem_clean_rings(gp); - gp->hw_running = 0; + + /* Bye, the pm timer will finish the job */ + free_irq(gp->pdev->irq, (void *) dev); + + /* Fire the PM timer that will shut us down in about 10 seconds */ + gp->pm_timer.expires = jiffies + 10*HZ; + add_timer(&gp->pm_timer); + + up(&gp->pm_sem); + + return 0; +} + +#ifdef CONFIG_PM +static int gem_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct gem *gp = dev->priv; + + /* We hold the PM semaphore during entire driver + * sleep time + */ + down(&gp->pm_sem); + + printk(KERN_INFO "%s: suspending, WakeOnLan %s\n", + dev->name, gp->wake_on_lan ? "enabled" : "disabled"); + + /* If the driver is opened, we stop the DMA */ + if (gp->opened) { + /* Stop traffic, mark us closed */ + netif_device_detach(dev); + + spin_lock_irq(&gp->lock); + + writel(0xffffffff, gp->regs + GREG_IMASK); + + spin_unlock_irq(&gp->lock); + + /* Stop chip */ + gem_stop(gp); + + /* Get rid of ring buffers */ + gem_clean_rings(gp); + + if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) + disable_irq(gp->pdev->irq); + } + + if (gp->hw_running) { + /* Kill PM timer if any */ + del_timer_sync(&gp->pm_timer); + flush_scheduled_tasks(); + + gem_shutdown(gp); + } + + return 0; +} + +static int gem_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct gem *gp = dev->priv; + + printk(KERN_INFO "%s: resuming\n", dev->name); + + if (gp->opened) { #ifdef CONFIG_ALL_PPC - if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) - gem_apple_powerdown(gp); + /* First, we need to bring up the chip */ + if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { + gem_apple_powerup(gp); + gem_check_invariants(gp); + } #endif /* CONFIG_ALL_PPC */ - free_irq(gp->pdev->irq, (void *)dev); + gem_stop(gp); + gp->hw_running = 1; + gem_init_rings(gp, 0); + gem_init_hw(gp, 1); + netif_device_attach(dev); + if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) + enable_irq(gp->pdev->irq); + } + up(&gp->pm_sem); + return 0; } +#endif /* CONFIG_PM */ static struct net_device_stats *gem_get_stats(struct net_device *dev) { @@ -1908,12 +2371,219 @@ writel(hash_table[15], gp->regs + MAC_HASH15); } + /* Hrm... we may walk on the reset task here... */ netif_wake_queue(dev); } +/* Eventually add support for changing the advertisement + * on autoneg. + */ +static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user) +{ + struct gem *gp = dev->priv; + u16 bmcr; + int full_duplex, speed, pause; + struct ethtool_cmd ecmd; + + if (copy_from_user(&ecmd, ep_user, sizeof(ecmd))) + return -EFAULT; + + switch(ecmd.cmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { cmd: ETHTOOL_GDRVINFO }; + + strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN); + strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN); + info.fw_version[0] = '\0'; + strncpy(info.bus_info, gp->pdev->slot_name, ETHTOOL_BUSINFO_LEN); + info.regdump_len = 0; /*SUNGEM_NREGS;*/ + + if (copy_to_user(ep_user, &info, sizeof(info))) + return -EFAULT; + + return 0; + } + + case ETHTOOL_GSET: + ecmd.supported = + (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); + + if (gp->gigabit_capable) + ecmd.supported |= + (SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); + + /* XXX hardcoded stuff for now */ + ecmd.port = PORT_MII; + ecmd.transceiver = XCVR_EXTERNAL; + ecmd.phy_address = 0; /* XXX fixed PHYAD */ + + /* Record PHY settings if HW is on. */ + if (gp->hw_running) { + bmcr = phy_read(gp, MII_BMCR); + gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause); + } else + bmcr = 0; + if (bmcr & BMCR_ANENABLE) { + ecmd.autoneg = AUTONEG_ENABLE; + ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100); + ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; + } else { + ecmd.autoneg = AUTONEG_DISABLE; + ecmd.speed = + (bmcr & BMCR_SPEED100) ? + SPEED_100 : SPEED_10; + ecmd.duplex = + (bmcr & BMCR_FULLDPLX) ? + DUPLEX_FULL : DUPLEX_HALF; + } + if (copy_to_user(ep_user, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + + case ETHTOOL_SSET: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Verify the settings we care about. */ + if (ecmd.autoneg != AUTONEG_ENABLE && + ecmd.autoneg != AUTONEG_DISABLE) + return -EINVAL; + + if (ecmd.autoneg == AUTONEG_DISABLE && + ((ecmd.speed != SPEED_100 && + ecmd.speed != SPEED_10) || + (ecmd.duplex != DUPLEX_HALF && + ecmd.duplex != DUPLEX_FULL))) + return -EINVAL; + + /* Apply settings and restart link process */ + if (gp->hw_running) + del_timer(&gp->link_timer); + gem_begin_auto_negotiation(gp, &ecmd); + return 0; + + case ETHTOOL_NWAY_RST: + if ((gp->link_cntl & BMCR_ANENABLE) == 0) + return -EINVAL; + if (gp->hw_running) + del_timer(&gp->link_timer); + gem_begin_auto_negotiation(gp, NULL); + return 0; + + case ETHTOOL_GWOL: + case ETHTOOL_SWOL: + break; /* todo */ + + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = { cmd: ETHTOOL_GLINK }; + + edata.data = (gp->lstate == link_up); + if (copy_to_user(ep_user, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = { cmd: ETHTOOL_GMSGLVL }; + + edata.data = gem_debug; + if (copy_to_user(ep_user, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + + if (copy_from_user(&edata, ep_user, sizeof(edata))) + return -EFAULT; + gem_debug = edata.data; + return 0; + } + +#if 0 + case ETHTOOL_GREGS: { + struct ethtool_regs regs; + u32 *regbuf; + int r = 0; + + if (copy_from_user(®s, useraddr, sizeof(regs))) + return -EFAULT; + + if (regs.len > SUNGEM_NREGS) { + regs.len = SUNGEM_NREGS; + } + regs.version = 0; + if (copy_to_user(useraddr, ®s, sizeof(regs))) + return -EFAULT; + + if (!gp->hw_running) + return -ENODEV; + useraddr += offsetof(struct ethtool_regs, data); + + /* Use kmalloc to avoid bloating the stack */ + regbuf = kmalloc(4 * SUNGEM_NREGS, GFP_KERNEL); + if (!regbuf) + return -ENOMEM; + spin_lock_irq(&np->lock); + gem_get_regs(gp, regbuf); + spin_unlock_irq(&np->lock); + + if (copy_to_user(useraddr, regbuf, regs.len*sizeof(u32))) + r = -EFAULT; + kfree(regbuf); + return r; + } +#endif + }; + + return -EOPNOTSUPP; +} + static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - return -EINVAL; + struct gem *gp = dev->priv; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; + int rc = -EOPNOTSUPP; + + /* Hold the PM semaphore while doing ioctl's or we may collide + * with open/close and power management and oops. + */ + down(&gp->pm_sem); + + switch (cmd) { + case SIOCETHTOOL: + rc = gem_ethtool_ioctl(dev, ifr->ifr_data); + break; + + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + data->phy_id = gp->mii_phy_addr; + /* Fallthrough... */ + + case SIOCGMIIREG: /* Read MII PHY register. */ + data->val_out = __phy_read(gp, data->reg_num & 0x1f, data->phy_id & 0x1f); + rc = 0; + break; + + case SIOCSMIIREG: /* Write MII PHY register. */ + if (!capable(CAP_NET_ADMIN)) { + rc = -EPERM; + } else { + __phy_write(gp, data->reg_num & 0x1f, data->val_in, data->phy_id & 0x1f); + rc = 0; + } + break; + }; + + up(&gp->pm_sem); + + return rc; } static int __devinit gem_get_device_address(struct gem *gp) @@ -2030,6 +2700,26 @@ gp->dev = dev; spin_lock_init(&gp->lock); + init_MUTEX(&gp->pm_sem); + + init_timer(&gp->link_timer); + gp->link_timer.function = gem_link_timer; + gp->link_timer.data = (unsigned long) gp; + + init_timer(&gp->pm_timer); + gp->pm_timer.function = gem_pm_timer; + gp->pm_timer.data = (unsigned long) gp; + + INIT_TQUEUE(&gp->pm_task, gem_pm_task, gp); + INIT_TQUEUE(&gp->reset_task, gem_reset_task, gp); + + /* Default link parameters */ + if (link_mode >= 0 && link_mode <= 6) + gp->link_cntl = link_modes[link_mode]; + else + gp->link_cntl = BMCR_ANENABLE; + gp->lstate = link_down; + gp->timer_ticks = 0; gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len); if (gp->regs == 0UL) { @@ -2038,9 +2728,26 @@ goto err_out_free_mmio_res; } - /* On Apple's, we might not access the hardware at that point */ + /* On Apple, we power the chip up now in order for check + * invariants to work, but also because the firmware might + * not have properly shut down the PHY. + */ +#ifdef CONFIG_ALL_PPC + if (pdev->vendor == PCI_VENDOR_ID_APPLE) { + gem_apple_powerup(gp); + if (gem_check_invariants(gp)) + goto err_out_iounmap; + gem_stop(gp); + gp->hw_running = 1; + gem_init_phy(gp); + gem_begin_auto_negotiation(gp, NULL); + } +#endif + /* Non Apple hardware, we just reset the chip and check + * for invariants + */ if (pdev->vendor != PCI_VENDOR_ID_APPLE) { - gem_stop(gp, gp->regs); + gem_stop(gp); if (gem_check_invariants(gp)) goto err_out_iounmap; gp->hw_running = 1; @@ -2074,10 +2781,6 @@ i == 5 ? ' ' : ':'); printk("\n"); - init_timer(&gp->link_timer); - gp->link_timer.function = gem_link_timer; - gp->link_timer.data = (unsigned long) gp; - dev->open = gem_open; dev->stop = gem_close; dev->hard_start_xmit = gem_start_xmit; @@ -2095,9 +2798,20 @@ if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; + /* Fire the PM timer that will shut us down in about 10 seconds */ + gp->pm_timer.expires = jiffies + 10*HZ; + add_timer(&gp->pm_timer); + return 0; err_out_iounmap: + down(&gp->pm_sem); + /* Stop the PM timer & task */ + del_timer_sync(&gp->pm_timer); + flush_scheduled_tasks(); + if (gp->hw_running) + gem_shutdown(gp); + up(&gp->pm_sem); iounmap((void *) gp->regs); err_out_free_mmio_res: @@ -2120,6 +2834,14 @@ unregister_netdev(dev); + down(&gp->pm_sem); + /* Stop the PM timer & task */ + del_timer_sync(&gp->pm_timer); + flush_scheduled_tasks(); + if (gp->hw_running) + gem_shutdown(gp); + up(&gp->pm_sem); + pci_free_consistent(pdev, sizeof(struct gem_init_block), gp->init_block, @@ -2127,9 +2849,6 @@ iounmap((void *) gp->regs); release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); -#ifdef CONFIG_ALL_PPC - pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0); -#endif kfree(dev); pci_set_drvdata(pdev, NULL); @@ -2140,7 +2859,11 @@ name: GEM_MODULE_NAME, id_table: gem_pci_tbl, probe: gem_init_one, - remove: gem_remove_one, + remove: __devexit_p(gem_remove_one), +#ifdef CONFIG_PM + suspend: gem_suspend, + resume: gem_resume, +#endif /* CONFIG_PM */ }; static int __init gem_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/sungem.h linux-2.5/drivers/net/sungem.h --- linux-2.5.1/drivers/net/sungem.h Sun Oct 21 17:36:54 2001 +++ linux-2.5/drivers/net/sungem.h Thu Dec 13 16:32:36 2001 @@ -1,4 +1,4 @@ -/* $Id: sungem.h,v 1.8 2001/10/17 05:55:39 davem Exp $ +/* $Id: sungem.h,v 1.10 2001/11/29 03:57:33 davem Exp $ * sungem.h: Definitions for Sun GEM ethernet driver. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -753,64 +753,38 @@ #define PROM_SIZE 0x0fffffUL /* Size of ROM */ #define PROM_END 0x200000UL /* End of ROM */ -/* MII phy registers */ -#define PHY_CTRL 0x00 -#define PHY_STAT 0x01 -#define PHY_ID0 0x02 -#define PHY_ID1 0x03 -#define PHY_ADV 0x04 -#define PHY_LPA 0x05 - -#define PHY_CTRL_SPD2 0x0040 /* Gigabit enable? (bcm5411) */ -#define PHY_CTRL_FDPLX 0x0100 /* Full duplex */ -#define PHY_CTRL_ISO 0x0400 /* Isloate MII from PHY */ -#define PHY_CTRL_ANRES 0x0200 /* Auto-negotiation restart */ -#define PHY_CTRL_ANENAB 0x1000 /* Auto-negotiation enable */ -#define PHY_CTRL_SPD100 0x2000 /* Select 100Mbps */ -#define PHY_CTRL_RST 0x8000 /* Reset PHY */ - -#define PHY_STAT_LSTAT 0x0004 /* Link status */ -#define PHY_STAT_ANEGC 0x0020 /* Auto-negotiation complete */ - -#define PHY_ADV_10HALF 0x0020 -#define PHY_ADV_10FULL 0x0040 -#define PHY_ADV_100HALF 0x0080 -#define PHY_ADV_100FULL 0x0100 - -#define PHY_LPA_10HALF 0x0020 -#define PHY_LPA_10FULL 0x0040 -#define PHY_LPA_100HALF 0x0080 -#define PHY_LPA_100FULL 0x0100 -#define PHY_LPA_PAUSE 0x0400 -#define PHY_LPA_FAULT 0x2000 +/* MII definitions missing from mii.h */ + +#define BMCR_SPD2 0x0040 /* Gigabit enable? (bcm5411) */ +#define LPA_PAUSE 0x0400 /* More PHY registers (specific to Broadcom models) */ /* MII BCM5201 MULTIPHY interrupt register */ -#define PHY_BCM5201_INTERRUPT 0x1A -#define PHY_BCM5201_INTERRUPT_INTENABLE 0x4000 +#define MII_BCM5201_INTERRUPT 0x1A +#define MII_BCM5201_INTERRUPT_INTENABLE 0x4000 -#define PHY_BCM5201_AUXMODE2 0x1B -#define PHY_BCM5201_AUXMODE2_LOWPOWER 0x0008 +#define MII_BCM5201_AUXMODE2 0x1B +#define MII_BCM5201_AUXMODE2_LOWPOWER 0x0008 -#define PHY_BCM5201_MULTIPHY 0x1E +#define MII_BCM5201_MULTIPHY 0x1E /* MII BCM5201 MULTIPHY register bits */ -#define PHY_BCM5201_MULTIPHY_SERIALMODE 0x0002 -#define PHY_BCM5201_MULTIPHY_SUPERISOLATE 0x0008 +#define MII_BCM5201_MULTIPHY_SERIALMODE 0x0002 +#define MII_BCM5201_MULTIPHY_SUPERISOLATE 0x0008 /* MII BCM5400 1000-BASET Control register */ -#define PHY_BCM5400_GB_CONTROL 0x09 -#define PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200 +#define MII_BCM5400_GB_CONTROL 0x09 +#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200 /* MII BCM5400 AUXCONTROL register */ -#define PHY_BCM5400_AUXCONTROL 0x18 -#define PHY_BCM5400_AUXCONTROL_PWR10BASET 0x0004 +#define MII_BCM5400_AUXCONTROL 0x18 +#define MII_BCM5400_AUXCONTROL_PWR10BASET 0x0004 /* MII BCM5400 AUXSTATUS register */ -#define PHY_BCM5400_AUXSTATUS 0x19 -#define PHY_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700 -#define PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8 +#define MII_BCM5400_AUXSTATUS 0x19 +#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700 +#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8 /* When it can, GEM internally caches 4 aligned TX descriptors * at a time, so that it can use full cacheline DMA reads. @@ -936,9 +910,21 @@ #define RX_COPY_THRESHOLD 256 +#if TX_RING_SIZE < 128 +#define INIT_BLOCK_TX_RING_SIZE 128 +#else +#define INIT_BLOCK_TX_RING_SIZE TX_RING_SIZE +#endif + +#if RX_RING_SIZE < 128 +#define INIT_BLOCK_RX_RING_SIZE 128 +#else +#define INIT_BLOCK_RX_RING_SIZE RX_RING_SIZE +#endif + struct gem_init_block { - struct gem_txd txd[TX_RING_SIZE]; - struct gem_rxd rxd[RX_RING_SIZE]; + struct gem_txd txd[INIT_BLOCK_TX_RING_SIZE]; + struct gem_rxd rxd[INIT_BLOCK_RX_RING_SIZE]; }; enum gem_phy_type { @@ -958,9 +944,12 @@ }; enum link_state { - aneg_wait, - force_wait, - aneg_up, + link_down = 0, /* No link, will retry */ + link_aneg, /* Autoneg in progress */ + link_force_try, /* Try Forced link speed */ + link_force_ret, /* Forced mode worked, retrying autoneg */ + link_force_ok, /* Stay in forced mode */ + link_up /* Link is up */ }; struct gem { @@ -973,6 +962,10 @@ * (ie. not power managed) */ int hw_running; + int opened; + struct semaphore pm_sem; + struct tq_struct pm_task; + struct timer_list pm_timer; struct gem_init_block *init_block; @@ -988,14 +981,22 @@ int rx_pause_off; int rx_pause_on; int mii_phy_addr; + int gigabit_capable; + /* Autoneg & PHY control */ + int link_cntl; + int link_advertise; + int link_fcntl; + enum link_state lstate; + struct timer_list link_timer; + int timer_ticks; + int wake_on_lan; + struct tq_struct reset_task; + volatile int reset_task_pending; + /* Diagnostic counters and state. */ u64 pause_entered; u16 pause_last_time_recvd; - - struct timer_list link_timer; - int timer_ticks; - enum link_state lstate; dma_addr_t gblock_dvma; struct pci_dev *pdev; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/tlan.c linux-2.5/drivers/net/tlan.c --- linux-2.5.1/drivers/net/tlan.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/net/tlan.c Thu Dec 13 16:32:36 2001 @@ -430,7 +430,7 @@ name: "tlan", id_table: tlan_pci_tbl, probe: tlan_init_one, - remove: tlan_remove_one, + remove: __devexit_p(tlan_remove_one), }; static int __init tlan_probe(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/tokenring/lanstreamer.c linux-2.5/drivers/net/tokenring/lanstreamer.c --- linux-2.5.1/drivers/net/tokenring/lanstreamer.c Sat Nov 10 23:38:59 2001 +++ linux-2.5/drivers/net/tokenring/lanstreamer.c Thu Dec 13 16:32:36 2001 @@ -1812,7 +1812,7 @@ name: "lanstreamer", id_table: streamer_pci_tbl, probe: streamer_init_one, - remove: streamer_remove_one, + remove: __devexit_p(streamer_remove_one), }; static int __init streamer_init_module(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/tokenring/olympic.c linux-2.5/drivers/net/tokenring/olympic.c --- linux-2.5.1/drivers/net/tokenring/olympic.c Fri Nov 9 21:46:29 2001 +++ linux-2.5/drivers/net/tokenring/olympic.c Thu Dec 13 16:32:36 2001 @@ -1705,7 +1705,7 @@ name: "olympic", id_table: olympic_pci_tbl, probe: olympic_probe, - remove: olympic_remove_one + remove: __devexit_p(olympic_remove_one), }; static int __init olympic_pci_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/tokenring/tmspci.c linux-2.5/drivers/net/tokenring/tmspci.c --- linux-2.5.1/drivers/net/tokenring/tmspci.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/tokenring/tmspci.c Sat Dec 22 00:08:54 2001 @@ -253,7 +253,7 @@ return 0; } -static void __exit tms_pci_rmmod (void) +static void __devexit tms_pci_rmmod (void) { pci_unregister_driver (&tms_pci_driver); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/tulip/tulip_core.c linux-2.5/drivers/net/tulip/tulip_core.c --- linux-2.5.1/drivers/net/tulip/tulip_core.c Tue Dec 11 18:47:49 2001 +++ linux-2.5/drivers/net/tulip/tulip_core.c Thu Dec 13 16:32:36 2001 @@ -1786,7 +1786,7 @@ name: DRV_NAME, id_table: tulip_pci_tbl, probe: tulip_init_one, - remove: tulip_remove_one, + remove: __devexit_p(tulip_remove_one), #ifdef CONFIG_PM suspend: tulip_suspend, resume: tulip_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/via-rhine.c linux-2.5/drivers/net/via-rhine.c --- linux-2.5.1/drivers/net/via-rhine.c Fri Nov 9 21:45:36 2001 +++ linux-2.5/drivers/net/via-rhine.c Wed Dec 19 01:08:32 2001 @@ -161,7 +161,7 @@ KERN_INFO "via-rhine.c:v1.10-LK1.1.12 03/11/2001 Written by Donald Becker\n" KERN_INFO " http://www.scyld.com/network/via-rhine.html\n"; -static char shortname[] __devinitdata = "via-rhine"; +static char shortname[] = "via-rhine"; /* This driver was written to use PCI memory space, however most versions @@ -1667,7 +1667,7 @@ name: "via-rhine", id_table: via_rhine_pci_tbl, probe: via_rhine_init_one, - remove: via_rhine_remove_one, + remove: __devexit_p(via_rhine_remove_one), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/comx-hw-locomx.c linux-2.5/drivers/net/wan/comx-hw-locomx.c --- linux-2.5.1/drivers/net/wan/comx-hw-locomx.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/wan/comx-hw-locomx.c Mon Jan 14 22:39:45 2002 @@ -154,11 +154,9 @@ return -ENODEV; } - if (check_region(dev->base_addr, hw->io_extent)) { + if (!request_region(dev->base_addr, hw->io_extent, dev->name)) { return -EAGAIN; } - - request_region(dev->base_addr, hw->io_extent, dev->name); hw->board.chanA.ctrlio=dev->base_addr + 5; hw->board.chanA.dataio=dev->base_addr + 7; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/comx-hw-mixcom.c linux-2.5/drivers/net/wan/comx-hw-mixcom.c --- linux-2.5.1/drivers/net/wan/comx-hw-mixcom.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/wan/comx-hw-mixcom.c Thu Dec 13 16:32:36 2001 @@ -566,8 +566,6 @@ return 0; -err_restore_flags: - restore_flags(flags); err_release_region: release_region(dev->base_addr, MIXCOM_IO_EXTENT); err_ret: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/cosa.c linux-2.5/drivers/net/wan/cosa.c --- linux-2.5.1/drivers/net/wan/cosa.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/net/wan/cosa.c Wed Jan 2 17:23:52 2002 @@ -940,12 +940,12 @@ unsigned long flags; int n; - if ((n=MINOR(file->f_dentry->d_inode->i_rdev)>>CARD_MINOR_BITS) + if ((n=minor(file->f_dentry->d_inode->i_rdev)>>CARD_MINOR_BITS) >= nr_cards) return -ENODEV; cosa = cosa_cards+n; - if ((n=MINOR(file->f_dentry->d_inode->i_rdev) + if ((n=minor(file->f_dentry->d_inode->i_rdev) & ((1<<CARD_MINOR_BITS)-1)) >= cosa->nchannels) return -ENODEV; chan = cosa->chan + n; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/farsync.c linux-2.5/drivers/net/wan/farsync.c --- linux-2.5.1/drivers/net/wan/farsync.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/net/wan/farsync.c Thu Dec 13 16:32:36 2001 @@ -1810,7 +1810,7 @@ name: FST_NAME, id_table: fst_pci_dev_id, probe: fst_add_one, - remove: fst_remove_one, + remove: __devexit_p(fst_remove_one), suspend: NULL, resume: NULL, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/lapbether.c linux-2.5/drivers/net/wan/lapbether.c --- linux-2.5.1/drivers/net/wan/lapbether.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/wan/lapbether.c Sun Dec 30 21:17:30 2001 @@ -32,7 +32,6 @@ #include <linux/if_arp.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/lmc/lmc_main.c linux-2.5/drivers/net/wan/lmc/lmc_main.c --- linux-2.5.1/drivers/net/wan/lmc/lmc_main.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/wan/lmc/lmc_main.c Sun Dec 30 21:17:30 2001 @@ -50,7 +50,6 @@ #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/delay.h> -#include <asm/segment.h> #include <linux/init.h> #if LINUX_VERSION_CODE < 0x20155 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/lmc/lmc_media.c linux-2.5/drivers/net/wan/lmc/lmc_media.c --- linux-2.5.1/drivers/net/wan/lmc/lmc_media.c Wed Mar 7 03:44:36 2001 +++ linux-2.5/drivers/net/wan/lmc/lmc_media.c Sun Dec 30 21:17:30 2001 @@ -12,7 +12,6 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <asm/segment.h> //#include <asm/smp.h> #if LINUX_VERSION_CODE < 0x20155 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/lmc/lmc_proto.c linux-2.5/drivers/net/wan/lmc/lmc_proto.c --- linux-2.5.1/drivers/net/wan/lmc/lmc_proto.c Wed Mar 7 03:44:36 2001 +++ linux-2.5/drivers/net/wan/lmc/lmc_proto.c Sun Dec 30 21:17:30 2001 @@ -30,7 +30,6 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <asm/segment.h> #include <asm/smp.h> #include <linux/in.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/sdla_chdlc.c linux-2.5/drivers/net/wan/sdla_chdlc.c --- linux-2.5.1/drivers/net/wan/sdla_chdlc.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/wan/sdla_chdlc.c Wed Jan 2 17:23:52 2002 @@ -3933,7 +3933,7 @@ if (!tty->driver_data){ int port; - port = MINOR(tty->device) - tty->driver.minor_start; + port = minor(tty->device) - tty->driver.minor_start; if ((port < 0) || (port >= NR_PORTS)) return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/sdla_fr.c linux-2.5/drivers/net/wan/sdla_fr.c --- linux-2.5.1/drivers/net/wan/sdla_fr.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/wan/sdla_fr.c Mon Jan 7 21:30:55 2002 @@ -163,14 +163,9 @@ #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 <asm/uaccess.h> +#include <linux/inetdevice.h> +#include <linux/netdevice.h> #include <net/route.h> /* Dynamic Route Creation */ #include <linux/etherdevice.h> /* eth_type_trans() used for bridging */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/sdla_ppp.c linux-2.5/drivers/net/wan/sdla_ppp.c --- linux-2.5.1/drivers/net/wan/sdla_ppp.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/wan/sdla_ppp.c Mon Jan 14 22:39:45 2002 @@ -2473,7 +2473,7 @@ #endif default: - printk(KERN_INFO "%s: ERROR: Unsuported PPP Mode Selected\n", + printk(KERN_INFO "%s: ERROR: Unsupported PPP Mode Selected\n", card->devname); printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", card->devname); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wan/sealevel.c linux-2.5/drivers/net/wan/sealevel.c --- linux-2.5.1/drivers/net/wan/sealevel.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/net/wan/sealevel.c Mon Jan 14 22:39:45 2002 @@ -219,12 +219,11 @@ * Get the needed I/O space */ - if(check_region(iobase, 8)) + if(!request_region(iobase, 8, "Sealevel 4021")) { printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); return NULL; } - request_region(iobase, 8, "Sealevel 4021"); b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL); if(!b) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wavelan.c linux-2.5/drivers/net/wavelan.c --- linux-2.5.1/drivers/net/wavelan.c Fri Oct 12 21:21:18 2001 +++ linux-2.5/drivers/net/wavelan.c Thu Jan 10 13:32:21 2002 @@ -4019,7 +4019,8 @@ dev->irq = irq; - request_region(ioaddr, sizeof(ha_t), "wavelan"); + if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) + return -EBUSY; dev->mem_start = 0x0000; dev->mem_end = 0x0000; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/winbond-840.c linux-2.5/drivers/net/winbond-840.c --- linux-2.5.1/drivers/net/winbond-840.c Tue Oct 9 22:13:02 2001 +++ linux-2.5/drivers/net/winbond-840.c Sun Jan 13 23:01:53 2002 @@ -36,6 +36,8 @@ power management. support for big endian descriptors Copyright (C) 2001 Manfred Spraul + * OOM handling + Copyright (C) 2002 Manfred Spraul TODO: * enable pci_power_off @@ -338,39 +340,52 @@ DescIntr=0x80000000, }; -#define PRIV_ALIGN 15 /* Required alignment mask */ #define MII_CNT 1 /* winbond only supports one MII */ struct netdev_private { + /* 1) RX data - accessed only by the hw irq handler, + * by the timer after disable_irq(), + * by the resume & shutdown code, after del_timer_sync() + * and disable_irq(). + */ struct w840_rx_desc *rx_ring; - dma_addr_t rx_addr[RX_RING_SIZE]; - struct w840_tx_desc *tx_ring; - dma_addr_t tx_addr[RX_RING_SIZE]; - dma_addr_t ring_dma_addr; + struct w840_rx_desc *rx_head_desc; + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + int oom; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; - /* The saved address of a sent-in-place packet/buffer, for later free(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; + dma_addr_t rx_addr[RX_RING_SIZE]; + + /* 2) misc members, most for media setup */ + dma_addr_t ring_dma_addr; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ - /* Frequently used values: keep some adjacent for cache effect. */ - spinlock_t lock; int chip_id, drv_flags; struct pci_dev *pci_dev; int csr6; - struct w840_rx_desc *rx_head_desc; - unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - unsigned int cur_tx, dirty_tx; - unsigned int tx_q_bytes; - unsigned int tx_full; /* The Tx queue is full. */ /* These values are keep track of the transceiver/media in use. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; /* MII transceiver section. */ - int mii_cnt; /* MII device addresses. */ - u16 advertising; /* NWay media advertisement */ - unsigned char phys[MII_CNT]; /* MII device addresses, but only the first is used */ + int mii_cnt; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ + unsigned char phys[MII_CNT]; u32 mii; + + /* 3) TX data - accessed under spin_lock_irq(np->lock);. + * Exception: start_tx (protected by dev_xmit_lock) reads + * cur_tx + * The spinlock is part of TX data, since packet TX + * is the only common codepath that needs the lock. + */ + spinlock_t lock; + struct w840_tx_desc *tx_ring; + unsigned int cur_tx, dirty_tx; + /* The saved address of a sent-in-place packet/buffer, for later free(). */ + unsigned int tx_q_bytes; + unsigned int tx_full; /* The Tx queue is full. */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + dma_addr_t tx_addr[TX_RING_SIZE]; }; static int eeprom_read(long ioaddr, int location); @@ -378,6 +393,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int netdev_open(struct net_device *dev); static int update_link(struct net_device *dev); +static void refill_rx(struct net_device *dev); static void netdev_timer(unsigned long data); static void init_rxtx_rings(struct net_device *dev); static void free_rxtx_rings(struct netdev_private *np); @@ -825,11 +841,40 @@ np->full_duplex = 1; } +static void refill_rx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + /* Refill the Rx ring buffers. */ + np->oom = 0; + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + int entry; + entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_addr[entry] = pci_map_single(np->pci_dev, + skb->tail, + skb->len, PCI_DMA_FROMDEVICE); + np->rx_ring[entry].buffer1 = np->rx_addr[entry]; + } + wmb(); + np->rx_ring[entry].status = DescOwn; + } + if (np->cur_rx-np->dirty_rx == RX_RING_SIZE) + np->oom = 1; +} + static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; + long next = 10*HZ; if (debug > 2) printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " @@ -839,8 +884,16 @@ spin_lock_irq(&np->lock); update_csr6(dev, update_link(dev)); spin_unlock_irq(&np->lock); - np->timer.expires = jiffies + 10*HZ; - add_timer(&np->timer); + if (np->oom) { + disable_irq(dev->irq); + refill_rx(dev); + if (np->oom) + next = 1; + else + writel(0, ioaddr + RxStartDemand); + enable_irq(dev->irq); + } + mod_timer(&np->timer, jiffies + next); } static void init_rxtx_rings(struct net_device *dev) @@ -860,22 +913,9 @@ /* Mark the last entry as wrapping the ring. */ np->rx_ring[i-1].length |= DescEndRing; - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail, - skb->len,PCI_DMA_FROMDEVICE); - - np->rx_ring[i].buffer1 = np->rx_addr[i]; - np->rx_ring[i].status = DescOwn; - } - - np->cur_rx = 0; - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + np->cur_rx = RX_RING_SIZE; + np->dirty_rx = 0; + refill_rx(dev); /* Initialize the Tx descriptors */ for (i = 0; i < TX_RING_SIZE; i++) { @@ -1193,8 +1233,9 @@ if (intr_status & (IntrRxDone | RxNoBuf)) netdev_rx(dev); - if (intr_status & RxNoBuf) - writel(0, ioaddr + RxStartDemand); + /* RxNoBuf is an error interrupt, we kick + * RxStartDemand in netdev_error() + */ if (intr_status & (TxIdle | IntrTxDone) && np->cur_tx != np->dirty_tx) { @@ -1326,25 +1367,7 @@ entry = (++np->cur_rx) % RX_RING_SIZE; np->rx_head_desc = &np->rx_ring[entry]; } - - /* Refill the Rx ring buffers. */ - for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { - struct sk_buff *skb; - entry = np->dirty_rx % RX_RING_SIZE; - if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[entry] = skb; - if (skb == NULL) - break; /* Better luck next round. */ - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[entry] = pci_map_single(np->pci_dev, - skb->tail, - skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[entry].buffer1 = np->rx_addr[entry]; - } - wmb(); - np->rx_ring[entry].status = DescOwn; - } + refill_rx(dev); return 0; } @@ -1388,8 +1411,14 @@ if (netif_device_present(dev)) writel(0x1A0F5, ioaddr + IntrEnable); } + /* strictly only needed with RxNoBuf, but + * kicking too often probably doesn't hurt. + */ + if (np->oom) + mod_timer(&np->timer, jiffies+1); + else + writel(0, ioaddr + RxStartDemand); np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; - writel(0, ioaddr + RxStartDemand); spin_unlock(&np->lock); } @@ -1537,6 +1566,7 @@ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); } + del_timer_sync(&np->timer); /* Stop the chip's Tx and Rx processes. */ spin_lock_irq(&np->lock); netif_device_detach(dev); @@ -1555,10 +1585,10 @@ if (debug > 2) { int i; - printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + printk(KERN_DEBUG" Tx ring at %8.8x:\n", (int)np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) - printk(" #%d desc. %4.4x %4.4x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x.\n", i, np->tx_ring[i].length, np->tx_ring[i].status, np->tx_ring[i].buffer1); printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", @@ -1571,8 +1601,6 @@ } #endif /* __i386__ debugging only */ - del_timer_sync(&np->timer); - free_rxtx_rings(np); free_ringdesc(np); @@ -1658,7 +1686,6 @@ return 0; } - static int w840_resume (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); @@ -1682,8 +1709,7 @@ netif_wake_queue(dev); - np->timer.expires = jiffies + 1*HZ; - add_timer(&np->timer); + mod_timer(&np->timer, jiffies + 1*HZ); } else { netif_device_attach(dev); } @@ -1697,7 +1723,7 @@ name: DRV_NAME, id_table: w840_pci_tbl, probe: w840_probe1, - remove: w840_remove1, + remove: __devexit_p(w840_remove1), #ifdef CONFIG_PM suspend: w840_suspend, resume: w840_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/airo.c linux-2.5/drivers/net/wireless/airo.c --- linux-2.5.1/drivers/net/wireless/airo.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/net/wireless/airo.c Sun Dec 30 21:17:30 2001 @@ -19,7 +19,6 @@ #include <linux/config.h> #include <linux/version.h> -#include <asm/segment.h> #include <linux/init.h> #include <linux/kernel.h> @@ -47,7 +46,7 @@ #include <asm/uaccess.h> #ifdef CONFIG_PCI -static struct pci_device_id card_ids[] = __devinitdata { +static struct pci_device_id card_ids[] __devinitdata = { { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, @@ -64,7 +63,7 @@ name: "airo", id_table: card_ids, probe: airo_pci_probe, - remove: airo_pci_remove, + remove: __devexit_p(airo_pci_remove), }; #endif /* CONFIG_PCI */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/airo_cs.c linux-2.5/drivers/net/wireless/airo_cs.c --- linux-2.5.1/drivers/net/wireless/airo_cs.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/net/wireless/airo_cs.c Mon Jan 14 22:39:45 2002 @@ -244,6 +244,11 @@ /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) { + printk(KERN_ERR "airo_cs: no memory for new device\n"); + kfree (link); + return NULL; + } memset(local, 0, sizeof(local_info_t)); link->priv = local; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/airport.c linux-2.5/drivers/net/wireless/airport.c --- linux-2.5.1/drivers/net/wireless/airport.c Wed Oct 17 21:37:01 2001 +++ linux-2.5/drivers/net/wireless/airport.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* airport.c 0.06f +/* airport.c 0.09 * * A driver for "Hermes" chipset based Apple Airport wireless * card. @@ -11,6 +11,8 @@ * 0.06 : fix possible hang on powerup, add sleep support */ +#include <linux/config.h> + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -33,26 +35,27 @@ #include <linux/pmu.h> #include <asm/prom.h> -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #include <asm/irq.h> #include "hermes.h" #include "orinoco.h" -static char version[] __initdata = "airport.c 0.06f (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; +static char version[] __initdata = "airport.c 0.09 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); MODULE_LICENSE("Dual MPL/GPL"); EXPORT_NO_SYMBOLS; -typedef struct dldwd_card { +struct airport { struct device_node* node; int irq_requested; int ndev_registered; int open; /* Common structure (fully included), see orinoco.h */ - struct dldwd_priv priv; -} dldwd_card_t; + struct orinoco_private priv; +}; #ifdef CONFIG_PMAC_PBOOK static int airport_sleep_notify(struct pmu_sleep_notifier *self, int when); @@ -65,8 +68,8 @@ * Function prototypes */ -static dldwd_priv_t* airport_attach(struct device_node *of_node); -static void airport_detach(dldwd_priv_t* priv); +static struct orinoco_private* airport_attach(struct device_node *of_node); +static void airport_detach(struct orinoco_private* priv); static int airport_init(struct net_device *dev); static int airport_open(struct net_device *dev); static int airport_stop(struct net_device *dev); @@ -81,20 +84,15 @@ device numbers are used to derive the corresponding array index. */ -static dldwd_priv_t *airport_dev; +static struct orinoco_private *airport_dev; static int airport_init(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; int rc; - TRACE_ENTER(priv->ndev.name); - MOD_INC_USE_COUNT; - rc = dldwd_init(dev); - if (!rc) - priv->hw_ready = 1; + rc = orinoco_init(dev); MOD_DEC_USE_COUNT; @@ -104,35 +102,33 @@ static int airport_open(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct orinoco_private *priv = dev->priv; + struct airport* card = (struct airport *)priv->card; int rc; - TRACE_ENTER(priv->ndev.name); + netif_device_attach(dev); - rc = dldwd_reset(priv); + rc = orinoco_reset(priv); if (rc) airport_stop(dev); else { card->open = 1; - netif_device_attach(dev); + netif_start_queue(dev); } -// TRACE_EXIT(priv->ndev.name); - return rc; } static int airport_stop(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct orinoco_private *priv = dev->priv; + struct airport* card = (struct airport *)priv->card; TRACE_ENTER(priv->ndev.name); netif_stop_queue(dev); - dldwd_shutdown(priv); + orinoco_shutdown(priv); card->open = 0; TRACE_EXIT(priv->ndev.name); @@ -144,16 +140,14 @@ static int airport_sleep_notify(struct pmu_sleep_notifier *self, int when) { - dldwd_priv_t *priv; - struct net_device *ndev; - dldwd_card_t* card; + struct orinoco_private *priv = airport_dev; + struct hermes *hw = &priv->hw; + struct net_device *dev = &priv->ndev; + struct airport* card = (struct airport *)priv->card; int rc; - if (!airport_dev) + if (! airport_dev) return PBOOK_SLEEP_OK; - priv = airport_dev; - ndev = &priv->ndev; - card = (dldwd_card_t *)priv->card; switch (when) { case PBOOK_SLEEP_REQUEST: @@ -161,41 +155,41 @@ case PBOOK_SLEEP_REJECT: break; case PBOOK_SLEEP_NOW: - printk(KERN_INFO "%s: Airport entering sleep mode\n", ndev->name); - netif_device_detach(ndev); - if (card->open) - dldwd_shutdown(priv); - disable_irq(ndev->irq); - feature_set_airport_power(card->node, 0); - priv->hw_ready = 0; + printk(KERN_INFO "%s: Airport entering sleep mode\n", dev->name); + if (card->open) { + netif_stop_queue(dev); + orinoco_shutdown(priv); + netif_device_detach(dev); + } + disable_irq(dev->irq); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); break; case PBOOK_WAKE: - printk(KERN_INFO "%s: Airport waking up\n", ndev->name); - feature_set_airport_power(card->node, 1); + printk(KERN_INFO "%s: Airport waking up\n", dev->name); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); mdelay(200); - hermes_reset(&priv->hw); - priv->hw_ready = 1; - rc = dldwd_reset(priv); + hermes_reset(hw); + rc = orinoco_reset(priv); if (rc) printk(KERN_ERR "airport: Error %d re-initing card !\n", rc); else if (card->open) - netif_device_attach(ndev); - enable_irq(ndev->irq); + netif_device_attach(dev); + enable_irq(dev->irq); break; } return PBOOK_SLEEP_OK; } #endif /* CONFIG_PMAC_PBOOK */ -static dldwd_priv_t* +static struct orinoco_private* airport_attach(struct device_node* of_node) { - dldwd_priv_t *priv; + struct orinoco_private *priv; struct net_device *ndev; - dldwd_card_t* card; + struct airport* card; hermes_t *hw; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); @@ -216,8 +210,15 @@ hw = &priv->hw; card->node = of_node; + if (!request_OF_resource(of_node, 0, " (airport)")) { + printk(KERN_ERR "airport: can't request IO resource !\n"); + kfree(card); + return NULL; + } + /* Setup the common part */ - if (dldwd_setup(priv) < 0) { + if (orinoco_setup(priv) < 0) { + release_OF_resource(of_node, 0); kfree(card); return NULL; } @@ -234,14 +235,14 @@ hermes_struct_init(hw, ndev->base_addr); /* Power up card */ - feature_set_airport_power(card->node, 1); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ); /* Reset it before we get the interrupt */ hermes_reset(hw); - if (request_irq(ndev->irq, dldwd_interrupt, 0, "Airport", (void *)priv)) { + if (request_irq(ndev->irq, orinoco_interrupt, 0, "Airport", (void *)priv)) { printk(KERN_ERR "airport: Couldn't get IRQ %d\n", ndev->irq); goto failed; } @@ -260,7 +261,7 @@ SET_MODULE_OWNER(ndev); /* And give us the proc nodes for debugging */ - if (dldwd_proc_dev_init(priv) != 0) + if (orinoco_proc_dev_init(priv) != 0) printk(KERN_ERR "airport: Failed to create /proc node for %s\n", ndev->name); @@ -279,14 +280,12 @@ ======================================================================*/ static void -airport_detach(dldwd_priv_t *priv) +airport_detach(struct orinoco_private *priv) { - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct airport* card = (struct airport *)priv->card; - priv->hw_ready = 0; - /* Unregister proc entry */ - dldwd_proc_dev_cleanup(priv); + orinoco_proc_dev_cleanup(priv); #ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&airport_sleep_notifier); @@ -299,12 +298,13 @@ free_irq(priv->ndev.irq, priv); card->irq_requested = 0; -// FIXME -// if (ndev->base_addr) -// iounmap(ndev->base_addr + _IO_BASE); -// ndev->base_addr = 0; + if (priv->ndev.base_addr) + iounmap((void *)(priv->ndev.base_addr + (unsigned long)_IO_BASE)); + priv->ndev.base_addr = 0; + + release_OF_resource(card->node, 0); - feature_set_airport_power(card->node, 0); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/hermes.c linux-2.5/drivers/net/wireless/hermes.c --- linux-2.5.1/drivers/net/wireless/hermes.c Tue Oct 9 22:13:03 2001 +++ linux-2.5/drivers/net/wireless/hermes.c Thu Jan 10 22:41:07 2002 @@ -75,9 +75,9 @@ #include <stdarg.h> #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \ - printk(#stuff);} while (0) + printk(stuff);} while (0) -#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff) +#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff) #else /* ! HERMES_DEBUG */ @@ -98,10 +98,17 @@ */ static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0) { + int k = CMD_BUSY_TIMEOUT; u16 reg; - /* First check that the command register is not busy */ + /* First wait for the command register to unbusy */ reg = hermes_read_regn(hw, CMD); + while ( (reg % HERMES_CMD_BUSY) && k ) { + k--; + udelay(1); + reg = hermes_read_regn(hw, CMD); + } + DEBUG(3, "hermes_issue_cmd: did %d retries.\n", CMD_BUSY_TIMEOUT-k); if (reg & HERMES_CMD_BUSY) { return -EBUSY; } @@ -223,8 +230,8 @@ hw->iobase); err = -ENODEV; } else - printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n", - hw->iobase); + printk(KERN_ERR "hermes @ 0x%x: Error %d issuing command.\n", + hw->iobase, err); goto out; } @@ -325,7 +332,7 @@ k = BAP_BUSY_TIMEOUT; reg = hermes_read_reg(hw, oreg); - while ((reg & HERMES_OFFSET_BUSY) & k) { + while ((reg & HERMES_OFFSET_BUSY) && k) { k--; udelay(1); reg = hermes_read_reg(hw, oreg); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/hermes.h linux-2.5/drivers/net/wireless/hermes.h --- linux-2.5.1/drivers/net/wireless/hermes.h Thu Oct 25 21:01:57 2001 +++ linux-2.5/drivers/net/wireless/hermes.h Thu Jan 10 22:41:07 2002 @@ -138,7 +138,7 @@ /*--- Regulate Commands --------------------------*/ #define HERMES_CMD_NOTIFY (0x0010) -#define HERMES_CMD_INQ (0x0011) +#define HERMES_CMD_INQUIRE (0x0011) /*--- Configure Commands --------------------------*/ #define HERMES_CMD_ACCESS (0x0021) @@ -150,88 +150,101 @@ #define HERMES_MONITOR_DISABLE (0x000f) /* - * Configuration RIDs - */ - -#define HERMES_RID_CNF_PORTTYPE (0xfc00) -#define HERMES_RID_CNF_MACADDR (0xfc01) -#define HERMES_RID_CNF_DESIRED_SSID (0xfc02) -#define HERMES_RID_CNF_CHANNEL (0xfc03) -#define HERMES_RID_CNF_OWN_SSID (0xfc04) -#define HERMES_RID_CNF_SYSTEM_SCALE (0xfc06) -#define HERMES_RID_CNF_MAX_DATA_LEN (0xfc07) -#define HERMES_RID_CNF_PM_ENABLE (0xfc09) -#define HERMES_RID_CNF_PM_MCAST_RX (0xfc0b) -#define HERMES_RID_CNF_PM_PERIOD (0xfc0c) -#define HERMES_RID_CNF_PM_HOLDOVER (0xfc0d) -#define HERMES_RID_CNF_NICKNAME (0xfc0e) -#define HERMES_RID_CNF_WEP_ON (0xfc20) -#define HERMES_RID_CNF_MWO_ROBUST (0xfc25) -#define HERMES_RID_CNF_MULTICAST_LIST (0xfc80) -#define HERMES_RID_CNF_CREATEIBSS (0xfc81) -#define HERMES_RID_CNF_FRAG_THRESH (0xfc82) -#define HERMES_RID_CNF_RTS_THRESH (0xfc83) -#define HERMES_RID_CNF_TX_RATE_CTRL (0xfc84) -#define HERMES_RID_CNF_PROMISCUOUS (0xfc85) -#define HERMES_RID_CNF_KEYS (0xfcb0) -#define HERMES_RID_CNF_TX_KEY (0xfcb1) -#define HERMES_RID_CNF_TICKTIME (0xfce0) - -#define HERMES_RID_CNF_INTERSIL_WEP_ON (0xfc28) -#define HERMES_RID_CNF_INTERSIL_TX_KEY (0xfc23) -#define HERMES_RID_CNF_INTERSIL_KEY0 (0xfc24) -#define HERMES_RID_CNF_INTERSIL_KEY1 (0xfc25) -#define HERMES_RID_CNF_INTERSIL_KEY2 (0xfc26) -#define HERMES_RID_CNF_INTERSIL_KEY3 (0xfc27) -#define HERMES_RID_CNF_SYMBOL_MANDATORY_BSSID (0xfc21) -#define HERMES_RID_CNF_SYMBOL_AUTH_TYPE (0xfc2A) -#define HERMES_RID_CNF_SYMBOL_BASIC_RATES (0xfc8A) -#define HERMES_RID_CNF_SYMBOL_PREAMBLE (0xfc8C) - -/* - * Information RIDs - */ -#define HERMES_RID_CHANNEL_LIST (0xfd10) -#define HERMES_RID_STAIDENTITY (0xfd20) -#define HERMES_RID_CURRENT_SSID (0xfd41) -#define HERMES_RID_CURRENT_BSSID (0xfd42) -#define HERMES_RID_COMMSQUALITY (0xfd43) -#define HERMES_RID_CURRENT_TX_RATE (0xfd44) -#define HERMES_RID_SHORT_RETRY_LIMIT (0xfd48) -#define HERMES_RID_LONG_RETRY_LIMIT (0xfd49) -#define HERMES_RID_MAX_TX_LIFETIME (0xfd4A) -#define HERMES_RID_WEP_AVAIL (0xfd4f) -#define HERMES_RID_CURRENT_CHANNEL (0xfdc1) -#define HERMES_RID_DATARATES (0xfdc6) -#define HERMES_RID_SYMBOL_SECONDARY_VER (0xfd24) -#define HERMES_RID_SYMBOL_KEY_LENGTH (0xfc2B) - -/* * Frame structures and constants */ -typedef struct hermes_frame_desc { - /* Hermes - i.e. little-endian byte-order */ +struct hermes_rx_descriptor { u16 status; - u16 res1, res2; - u16 q_info; - u16 res3, res4; - u16 tx_ctl; -} __attribute__ ((packed)) hermes_frame_desc_t; - -#define HERMES_RXSTAT_ERR (0x0003) -#define HERMES_RXSTAT_MACPORT (0x0700) -#define HERMES_RXSTAT_MSGTYPE (0xE000) - -#define HERMES_RXSTAT_BADCRC (0x0001) -#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) - -/* RFC-1042 encoded frame */ -#define HERMES_RXSTAT_1042 (0x2000) -/* Bridge-tunnel encoded frame */ -#define HERMES_RXSTAT_TUNNEL (0x4000) -/* Wavelan-II Management Protocol frame */ -#define HERMES_RXSTAT_WMP (0x6000) + u32 time; + u8 silence; + u8 signal; + u8 rate; + u8 rxflow; + u32 reserved; +} __attribute__ ((packed)); + +#define HERMES_RXSTAT_ERR (0x0003) +#define HERMES_RXSTAT_BADCRC (0x0001) +#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) +#define HERMES_RXSTAT_MACPORT (0x0700) +#define HERMES_RXSTAT_MSGTYPE (0xE000) +#define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */ +#define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */ +#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ + +struct hermes_tx_descriptor { + u16 status; + u16 reserved1; + u16 reserved2; + u32 sw_support; + u8 retry_count; + u8 tx_rate; + u16 tx_control; +} __attribute__ ((packed)); + +#define HERMES_TXSTAT_RETRYERR (0x0001) +#define HERMES_TXSTAT_AGEDERR (0x0002) +#define HERMES_TXSTAT_DISCON (0x0004) +#define HERMES_TXSTAT_FORMERR (0x0008) + +#define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */ +#define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */ +#define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */ +#define HERMES_TXCTRL_ALT_RTRY (0x0020) + +/* Inquiry constants and data types */ + +#define HERMES_INQ_TALLIES (0xF100) +#define HERMES_INQ_SCAN (0xF101) +#define HERMES_INQ_LINKSTATUS (0xF200) + +struct hermes_tallies_frame { + u16 TxUnicastFrames; + u16 TxMulticastFrames; + u16 TxFragments; + u16 TxUnicastOctets; + u16 TxMulticastOctets; + u16 TxDeferredTransmissions; + u16 TxSingleRetryFrames; + u16 TxMultipleRetryFrames; + u16 TxRetryLimitExceeded; + u16 TxDiscards; + u16 RxUnicastFrames; + u16 RxMulticastFrames; + u16 RxFragments; + u16 RxUnicastOctets; + u16 RxMulticastOctets; + u16 RxFCSErrors; + u16 RxDiscards_NoBuffer; + u16 TxDiscardsWrongSA; + u16 RxWEPUndecryptable; + u16 RxMsgInMsgFragments; + u16 RxMsgInBadMsgFragments; + /* Those last are probably not available in very old firmwares */ + u16 RxDiscards_WEPICVError; + u16 RxDiscards_WEPExcluded; +} __attribute__ ((packed)); + +/* Grabbed from wlan-ng - Thanks Mark... - Jean II + * This is the result of a scan inquiry command */ +/* Structure describing info about an Access Point */ +struct hermes_scan_apinfo { + u16 channel; /* Channel where the AP sits */ + u16 noise; /* Noise level */ + u16 level; /* Signal level */ + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ + u16 beacon_interv; /* Beacon interval ? */ + u16 capabilities; /* Capabilities ? */ + u8 essid[32]; /* ESSID of the network */ + u8 rates[10]; /* Bit rate supported */ + u16 proberesp_rate; /* ???? */ +} __attribute__ ((packed)); +/* Container */ +struct hermes_scan_frame { + u16 rsvd; /* ??? */ + u16 scanreason; /* ??? */ + struct hermes_scan_apinfo aps[35]; /* Scan result */ +} __attribute__ ((packed)); #ifdef __KERNEL__ @@ -246,16 +259,6 @@ u16 status, resp0, resp1, resp2; } hermes_response_t; -/* "ID" structure - used for ESSID and station nickname */ -typedef struct hermes_id { - u16 len; - u16 val[16]; -} __attribute__ ((packed)) hermes_id_t; - -typedef struct hermes_multicast { - u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; -} __attribute__ ((packed)) hermes_multicast_t; - /* Register access convenience macros */ #define hermes_read_reg(hw, off) (inw((hw)->iobase + (off))) #define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off))) @@ -310,8 +313,17 @@ { hermes_response_t resp; - return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), 0, &resp); +} + +/* Initiate an INQUIRE command (tallies or scan). The result will come as an + * information frame in __dldwd_ev_info() */ +static inline int hermes_inquire(hermes_t *hw, u16 rid) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, &resp); } #define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/hermes_rid.h linux-2.5/drivers/net/wireless/hermes_rid.h --- linux-2.5.1/drivers/net/wireless/hermes_rid.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/wireless/hermes_rid.h Fri Jan 11 14:53:27 2002 @@ -0,0 +1,153 @@ +#ifndef _HERMES_RID_H +#define _HERMES_RID_H + +/* + * Configuration RIDs + */ +#define HERMES_RID_CNFPORTTYPE 0xFC00 /* used */ +#define HERMES_RID_CNFOWNMACADDR 0xFC01 /* used */ +#define HERMES_RID_CNFDESIREDSSID 0xFC02 /* used */ +#define HERMES_RID_CNFOWNCHANNEL 0xFC03 /* used */ +#define HERMES_RID_CNFOWNSSID 0xFC04 /* used */ +#define HERMES_RID_CNFOWNATIMWINDOW 0xFC05 +#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 /* used */ +#define HERMES_RID_CNFMAXDATALEN 0xFC07 +#define HERMES_RID_CNFWDSADDRESS 0xFC08 +#define HERMES_RID_CNFPMENABLED 0xFC09 /* used */ +#define HERMES_RID_CNFPMEPS 0xFC0A +#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B /* used */ +#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C /* used */ +#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D /* used */ +#define HERMES_RID_CNFOWNNAME 0xFC0E /* used */ +#define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10 +#define HERMES_RID_CNFWDSADDRESS1 0xFC11 +#define HERMES_RID_CNFWDSADDRESS2 0xFC12 +#define HERMES_RID_CNFWDSADDRESS3 0xFC13 +#define HERMES_RID_CNFWDSADDRESS4 0xFC14 +#define HERMES_RID_CNFWDSADDRESS5 0xFC15 +#define HERMES_RID_CNFWDSADDRESS6 0xFC16 +#define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17 +#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 /* used */ +#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 +#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 /* used */ +#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 /* used */ +#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 /* used */ +#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 /* used */ +#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 /* used */ +#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 /* used */ +#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 /* used */ +#define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 +#define HERMES_RID_CNFAUTHENTICATION 0xFC2A /* used */ +#define HERMES_RID_CNFMAXASSOCSTA 0xFC2B +#define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B +#define HERMES_RID_CNFTXCONTROL 0xFC2C +#define HERMES_RID_CNFROAMINGMODE 0xFC2D +#define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E +#define HERMES_RID_CNFRCVCRCERROR 0xFC30 +#define HERMES_RID_CNFMMLIFE 0xFC31 +#define HERMES_RID_CNFALTRETRYCOUNT 0xFC32 +#define HERMES_RID_CNFBEACONINT 0xFC33 +#define HERMES_RID_CNFAPPCFINFO 0xFC34 +#define HERMES_RID_CNFSTAPCFINFO 0xFC35 +#define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37 +#define HERMES_RID_CNFTIMCTRL 0xFC40 +#define HERMES_RID_CNFTHIRTY2TALLY 0xFC42 +#define HERMES_RID_CNFENHSECURITY 0xFC43 +#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 /* used */ +#define HERMES_RID_CNFCREATEIBSS 0xFC81 /* used */ +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 /* used */ +#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 /* used */ +#define HERMES_RID_CNFTXRATECONTROL 0xFC84 /* used */ +#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 /* used */ +#define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A +#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C /* used */ +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96 +#define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97 +#define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98 +#define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99 +#define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A +#define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B +#define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C +#define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D +#define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0 +#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 /* used */ +#define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 +#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 /* used */ +#define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 +#define HERMES_RID_CNFBASICRATES 0xFCB3 +#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 +#define HERMES_RID_CNFTICKTIME 0xFCE0 /* used */ +#define HERMES_RID_CNFSCANREQUEST 0xFCE1 +#define HERMES_RID_CNFJOINREQUEST 0xFCE2 +#define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3 +#define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4 + +/* + * Information RIDs + */ +#define HERMES_RID_MAXLOADTIME 0xFD00 +#define HERMES_RID_DOWNLOADBUFFER 0xFD01 +#define HERMES_RID_PRIID 0xFD02 +#define HERMES_RID_PRISUPRANGE 0xFD03 +#define HERMES_RID_CFIACTRANGES 0xFD04 +#define HERMES_RID_NICSERNUM 0xFD0A +#define HERMES_RID_NICID 0xFD0B +#define HERMES_RID_MFISUPRANGE 0xFD0C +#define HERMES_RID_CFISUPRANGE 0xFD0D +#define HERMES_RID_CHANNELLIST 0xFD10 /* used */ +#define HERMES_RID_REGULATORYDOMAINS 0xFD11 +#define HERMES_RID_TEMPTYPE 0xFD12 +#define HERMES_RID_CIS 0xFD13 +#define HERMES_RID_STAID 0xFD20 /* used */ +#define HERMES_RID_STASUPRANGE 0xFD21 +#define HERMES_RID_MFIACTRANGES 0xFD22 +#define HERMES_RID_CFIACTRANGES2 0xFD23 +#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 /* used */ +#define HERMES_RID_PORTSTATUS 0xFD40 +#define HERMES_RID_CURRENTSSID 0xFD41 /* used */ +#define HERMES_RID_CURRENTBSSID 0xFD42 /* used */ +#define HERMES_RID_COMMSQUALITY 0xFD43 /* used */ +#define HERMES_RID_CURRENTTXRATE 0xFD44 /* used */ +#define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45 +#define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46 +#define HERMES_RID_PROTOCOLRSPTIME 0xFD47 +#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 /* used */ +#define HERMES_RID_LONGRETRYLIMIT 0xFD49 /* used */ +#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A /* used */ +#define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B +#define HERMES_RID_CFPOLLABLE 0xFD4C +#define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D +#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F +#define HERMES_RID_CURRENTTXRATE1 0xFD80 +#define HERMES_RID_CURRENTTXRATE2 0xFD81 +#define HERMES_RID_CURRENTTXRATE3 0xFD82 +#define HERMES_RID_CURRENTTXRATE4 0xFD83 +#define HERMES_RID_CURRENTTXRATE5 0xFD84 +#define HERMES_RID_CURRENTTXRATE6 0xFD85 +#define HERMES_RID_OWNMACADDR 0xFD86 +#define HERMES_RID_SCANRESULTSTABLE 0xFD88 +#define HERMES_RID_PHYTYPE 0xFDC0 +#define HERMES_RID_CURRENTCHANNEL 0xFDC1 /* used */ +#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 +#define HERMES_RID_CCAMODE 0xFDC3 +#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 /* used */ +#define HERMES_RID_BUILDSEQ 0xFFFE +#define HERMES_RID_FWID 0xFFFF + +/* "ID" structure - used for ESSID and station nickname */ +struct hermes_idstring { + u16 len; + u16 val[16]; +} __attribute__ ((packed)); + +typedef struct hermes_multicast { + u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; +} __attribute__ ((packed)) hermes_multicast_t; + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/ieee802_11.h linux-2.5/drivers/net/wireless/ieee802_11.h --- linux-2.5.1/drivers/net/wireless/ieee802_11.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/wireless/ieee802_11.h Fri Jan 11 14:53:27 2002 @@ -0,0 +1,67 @@ +#ifndef _IEEE802_11_H +#define _IEEE802_11_H + +struct ieee802_11_hdr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; + u8 addr4[ETH_ALEN]; + u16 data_len; +} __attribute__ ((packed)); + +/* Frame control field constants */ +#define IEEE802_11_FCTL_VERS 0x0002 +#define IEEE802_11_FCTL_FTYPE 0x000c +#define IEEE802_11_FCTL_STYPE 0x00f0 +#define IEEE802_11_FCTL_TODS 0x0100 +#define IEEE802_11_FCTL_FROMDS 0x0200 +#define IEEE802_11_FCTL_MOREFRAGS 0x0400 +#define IEEE802_11_FCTL_RETRY 0x0800 +#define IEEE802_11_FCTL_PM 0x1000 +#define IEEE802_11_FCTL_MOREDATA 0x2000 +#define IEEE802_11_FCTL_WEP 0x4000 +#define IEEE802_11_FCTL_ORDER 0x8000 + +#define IEEE802_11_FTYPE_MGMT 0x0000 +#define IEEE802_11_FTYPE_CTL 0x0004 +#define IEEE802_11_FTYPE_DATA 0x0008 + +/* management */ +#define IEEE802_11_STYPE_ASSOC_REQ 0x0000 +#define IEEE802_11_STYPE_ASSOC_RESP 0x0010 +#define IEEE802_11_STYPE_REASSOC_REQ 0x0020 +#define IEEE802_11_STYPE_REASSOC_RESP 0x0030 +#define IEEE802_11_STYPE_PROBE_REQ 0x0040 +#define IEEE802_11_STYPE_PROBE_RESP 0x0050 +#define IEEE802_11_STYPE_BEACON 0x0080 +#define IEEE802_11_STYPE_ATIM 0x0090 +#define IEEE802_11_STYPE_DISASSOC 0x00A0 +#define IEEE802_11_STYPE_AUTH 0x00B0 +#define IEEE802_11_STYPE_DEAUTH 0x00C0 + +/* control */ +#define IEEE802_11_STYPE_PSPOLL 0x00A0 +#define IEEE802_11_STYPE_RTS 0x00B0 +#define IEEE802_11_STYPE_CTS 0x00C0 +#define IEEE802_11_STYPE_ACK 0x00D0 +#define IEEE802_11_STYPE_CFEND 0x00E0 +#define IEEE802_11_STYPE_CFENDACK 0x00F0 + +/* data */ +#define IEEE802_11_STYPE_DATA 0x0000 +#define IEEE802_11_STYPE_DATA_CFACK 0x0010 +#define IEEE802_11_STYPE_DATA_CFPOLL 0x0020 +#define IEEE802_11_STYPE_DATA_CFACKPOLL 0x0030 +#define IEEE802_11_STYPE_NULLFUNC 0x0040 +#define IEEE802_11_STYPE_CFACK 0x0050 +#define IEEE802_11_STYPE_CFPOLL 0x0060 +#define IEEE802_11_STYPE_CFACKPOLL 0x0070 + +#define IEEE802_11_SCTL_FRAG 0x000F +#define IEEE802_11_SCTL_SEQ 0xFFF0 + +#endif /* _IEEE802_11_H */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/orinoco.c linux-2.5/drivers/net/wireless/orinoco.c --- linux-2.5.1/drivers/net/wireless/orinoco.c Tue Oct 9 22:13:03 2001 +++ linux-2.5/drivers/net/wireless/orinoco.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* orinoco.c 0.08a - (formerly known as dldwd_cs.c and orinoco_cs.c) +/* orinoco.c 0.09a - (formerly known as dldwd_cs.c and orinoco_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -197,18 +197,46 @@ * o Fixed bad bug in WEP key handling on Intersil and Symbol firmware, * which led to an instant crash on big-endian machines. * + * v0.08a -> v0.08b - 20/11/2001 - David Gibson + * o Lots of cleanup and bugfixes in orinoco_plx.c + * o Cleanup to handling of Tx rate setting. + * o Removed support for old encapsulation method. + * o Removed old "dldwd" names. + * o Split RID constants into a new file hermes_rid.h + * o Renamed RID constants to match linux-wlan-ng and prism2.o + * o Bugfixes in hermes.c + * o Poke the PLX's INTCSR register, so it actually starts + * generating interrupts. These cards might actually work now. + * o Update to wireless extensions v12 (Jean II) + * o Support for tallies and inquire command (Jean II) + * o Airport updates for newer PPC kernels (BenH) + * + * v0.08b -> v0.09 - 21/12/2001 - David Gibson + * o Some new PCI IDs for PLX cards. + * o Removed broken attempt to do ALLMULTI reception. Just use + * promiscuous mode instead + * o Preliminary work for list-AP (Jean II) + * o Airport updates from (BenH) + * o Eliminated racy hw_ready stuff + * o Fixed generation of fake events in irq handler. This should + * finally kill the EIO problems (Jean II & dgibson) + * o Fixed breakage of bitrate set/get on Agere firmware (Jean II) + * + * v0.09 -> v0.09a - 2/1/2002 - David Gibson + * o Fixed stupid mistake in multicast list handling, triggering + * a BUG() + * * TODO - Jean II * o inline functions (lots of candidate, need to reorder code) * o Test PrismII/Symbol cards & firmware versions - * o Mini-PCI support (some people have reported success - JII) - * o Find and kill remaining Tx timeout problems - */ + * o Find and kill remaining Tx timeout problems */ /* Notes on locking: * * The basic principle of operation is that everything except the * interrupt handler is serialized through a single spinlock in the - * dldwd_priv_t structure, using dldwd_lock() and - * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()). + * struct orinoco_private structure, using dldwd_lock() and + * dldwd_unlock() (which in turn use spin_lock_bh() and + * spin_unlock_bh()). * * The kernel's IRQ handling stuff ensures that the interrupt handler * does not re-enter itself. The interrupt handler is written such @@ -260,23 +288,44 @@ #include <pcmcia/bus_ops.h> #include "hermes.h" +#include "hermes_rid.h" #include "orinoco.h" +#include "ieee802_11.h" -static char version[] __initdata = "orinoco.c 0.08a (David Gibson <hermes@gibson.dropbear.id.au> and others)"; +/* Wireless extensions backwares compatibility */ +#ifndef SIOCIWFIRSTPRIV +#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE +#endif /* SIOCIWFIRSTPRIV */ + +static char version[] __initdata = "orinoco.c 0.09a (David Gibson <hermes@gibson.dropbear.id.au> and others)"; MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>"); MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards"); MODULE_LICENSE("Dual MPL/GPL"); /* Level of debugging. Used in the macros in orinoco.h */ #ifdef ORINOCO_DEBUG -int dldwd_debug = ORINOCO_DEBUG; -MODULE_PARM(dldwd_debug, "i"); +int orinoco_debug = ORINOCO_DEBUG; +MODULE_PARM(orinoco_debug, "i"); #endif -int use_old_encaps = 0; -MODULE_PARM(use_old_encaps, "i"); +#define ORINOCO_MIN_MTU 256 +#define ORINOCO_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) #define SYMBOL_MAX_VER_LEN (14) +#define LTV_BUF_SIZE 128 +#define USER_BAP 0 +#define IRQ_BAP 1 +#define ORINOCO_MACPORT 0 +#define MAX_IRQLOOPS_PER_IRQ 10 +#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of how many events the + device can legitimately generate */ +#define TX_NICBUF_SIZE 2048 +#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ +#define LARGE_KEY_SIZE 13 +#define SMALL_KEY_SIZE 5 +#define MAX_FRAME_SIZE 2304 + +#define DUMMY_FID 0xFFFF const long channel_frequency[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, @@ -287,37 +336,23 @@ /* This tables gives the actual meanings of the bitrate IDs returned by the firmware. It gives the rate in halfMb/s, negative indicates auto mode */ -const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0}; - -#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0])) - -struct p80211_hdr { - u16 frame_ctl; - u16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq_ctl; - u8 addr4[ETH_ALEN]; - u16 data_len; -} __attribute__ ((packed)); +struct { + int bitrate; /* in 100s of kilbits */ + int automatic; + u16 agere_txratectrl; + u16 intersil_txratectrl; +} bitrate_table[] = { + {110, 1, 3, 15}, /* Entry 0 is the default */ + {10, 0, 1, 1}, + {10, 1, 1, 1}, + {20, 0, 2, 2}, + {20, 1, 6, 3}, + {55, 0, 4, 4}, + {55, 1, 7, 7}, + {110, 0, 5, 8}, +}; -/* Frame control field constants */ -#define DLDWD_FCTL_VERS 0x0002 -#define DLDWD_FCTL_FTYPE 0x000c -#define DLDWD_FCTL_STYPE 0x00f0 -#define DLDWD_FCTL_TODS 0x0100 -#define DLDWD_FCTL_FROMDS 0x0200 -#define DLDWD_FCTL_MOREFRAGS 0x0400 -#define DLDWD_FCTL_RETRY 0x0800 -#define DLDWD_FCTL_PM 0x1000 -#define DLDWD_FCTL_MOREDATA 0x2000 -#define DLDWD_FCTL_WEP 0x4000 -#define DLDWD_FCTL_ORDER 0x8000 - -#define DLDWD_FTYPE_MGMT 0x0000 -#define DLDWD_FTYPE_CTL 0x0004 -#define DLDWD_FTYPE_DATA 0x0008 +#define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0])) struct p8022_hdr { u8 dsap; @@ -326,16 +361,24 @@ u8 oui[3]; } __attribute__ ((packed)); -struct dldwd_frame_hdr { - hermes_frame_desc_t desc; - struct p80211_hdr p80211; +struct orinoco_rxframe_hdr { + struct hermes_rx_descriptor desc; + struct ieee802_11_hdr p80211; + struct ethhdr p8023; + struct p8022_hdr p8022; + u16 ethertype; +} __attribute__ ((packed)); + +struct orinoco_txframe_hdr { + struct hermes_tx_descriptor desc; + struct ieee802_11_hdr p80211; struct ethhdr p8023; struct p8022_hdr p8022; u16 ethertype; } __attribute__ ((packed)); -#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ - sizeof(struct p80211_hdr)) +#define P8023_OFFSET (sizeof(struct hermes_rx_descriptor) + \ + sizeof(struct ieee802_11_hdr)) #define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2) /* 802.2 LLL header SNAP used for SNAP encapsulation over 802.11 */ @@ -343,114 +386,112 @@ 0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00} }; -struct p8022_hdr old_encaps_hdr = { - 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} -}; - /* How many times to retry if we get an EIO reading the BAP in the Rx path */ #define RX_EIO_RETRY 10 -typedef struct dldwd_commsqual { +typedef struct orinoco_commsqual { u16 qual, signal, noise; -} __attribute__ ((packed)) dldwd_commsqual_t; +} __attribute__ ((packed)) orinoco_commsqual_t; /* * Function prototypes */ -static void dldwd_stat_gather(struct net_device *dev, +static void orinoco_stat_gather(struct net_device *dev, struct sk_buff *skb, - struct dldwd_frame_hdr *hdr); + struct orinoco_rxframe_hdr *hdr); -static struct net_device_stats *dldwd_get_stats(struct net_device *dev); -static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev); +static struct net_device_stats *orinoco_get_stats(struct net_device *dev); +static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev); /* Hardware control routines */ -static int __dldwd_hw_reset(dldwd_priv_t *priv); -static int __dldwd_hw_setup_wep(dldwd_priv_t *priv); -static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]); -static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]); -static long dldwd_hw_get_freq(dldwd_priv_t *priv); -static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, - s32 *rates, int max); +static int __orinoco_hw_reset(struct orinoco_private *priv); +static int __orinoco_hw_set_bitrate(struct orinoco_private *priv); +static int __orinoco_hw_setup_wep(struct orinoco_private *priv); +static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]); +static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, + char buf[IW_ESSID_MAX_SIZE+1]); +static long orinoco_hw_get_freq(struct orinoco_private *priv); +static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, + int32_t *rates, int max); /* Interrupt handling routines */ -static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw); - -static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); -static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); -static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); -static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); -static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq); -static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq); -static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); -static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq); -static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq); -static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); -static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); -static void __dldwd_set_multicast_list(struct net_device *dev); +static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw); + +static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); +static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); +static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); +static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq); +static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq); +static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); +static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); +static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); +static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq); +static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq); +static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); +static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); +static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); +static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *frq); +static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *frq); +static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq); +static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq); +static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); +static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); +static void __orinoco_set_multicast_list(struct net_device *dev); /* /proc debugging stuff */ -static int dldwd_proc_init(void); -static void dldwd_proc_cleanup(void); +static int orinoco_proc_init(void); +static void orinoco_proc_cleanup(void); /* * Inline functions */ static inline void -dldwd_lock(dldwd_priv_t *priv) +orinoco_lock(struct orinoco_private *priv) { spin_lock_bh(&priv->lock); } static inline void -dldwd_unlock(dldwd_priv_t *priv) +orinoco_unlock(struct orinoco_private *priv) { spin_unlock_bh(&priv->lock); } static inline int -dldwd_irqs_allowed(dldwd_priv_t *priv) +orinoco_irqs_allowed(struct orinoco_private *priv) { - return test_bit(DLDWD_STATE_DOIRQ, &priv->state); + return test_bit(ORINOCO_STATE_DOIRQ, &priv->state); } static inline void -__dldwd_stop_irqs(dldwd_priv_t *priv) +__orinoco_stop_irqs(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; hermes_set_irqmask(hw, 0); - clear_bit(DLDWD_STATE_DOIRQ, &priv->state); - while (test_bit(DLDWD_STATE_INIRQ, &priv->state)) + clear_bit(ORINOCO_STATE_DOIRQ, &priv->state); + while (test_bit(ORINOCO_STATE_INIRQ, &priv->state)) ; } static inline void -__dldwd_start_irqs(dldwd_priv_t *priv, u16 irqmask) +__orinoco_start_irqs(struct orinoco_private *priv, u16 irqmask) { hermes_t *hw = &priv->hw; TRACE_ENTER(priv->ndev.name); __cli(); - set_bit(DLDWD_STATE_DOIRQ, &priv->state); + set_bit(ORINOCO_STATE_DOIRQ, &priv->state); hermes_set_irqmask(hw, irqmask); __sti(); @@ -458,7 +499,7 @@ } static inline void -set_port_type(dldwd_priv_t *priv) +set_port_type(struct orinoco_private *priv) { switch (priv->iw_mode) { case IW_MODE_INFRA: @@ -481,13 +522,13 @@ } extern void -dldwd_set_multicast_list(struct net_device *dev) +orinoco_set_multicast_list(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; - dldwd_lock(priv); - __dldwd_set_multicast_list(dev); - dldwd_unlock(priv); + orinoco_lock(priv); + __orinoco_set_multicast_list(dev); + orinoco_unlock(priv); } /* @@ -495,63 +536,54 @@ */ static int -__dldwd_hw_reset(dldwd_priv_t *priv) +__orinoco_hw_reset(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; - int err; - if (! priv->broken_reset) - return hermes_reset(hw); - else { - hw->inten = 0; - hermes_write_regn(hw, INTEN, 0); - err = hermes_disable_port(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - return err; - } + return hermes_reset(hw); } void -dldwd_shutdown(dldwd_priv_t *priv) +orinoco_shutdown(struct orinoco_private *priv) { /* hermes_t *hw = &priv->hw; */ int err = 0; TRACE_ENTER(priv->ndev.name); - dldwd_lock(priv); - __dldwd_stop_irqs(priv); + orinoco_lock(priv); + __orinoco_stop_irqs(priv); - err = __dldwd_hw_reset(priv); + err = __orinoco_hw_reset(priv); if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */ printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err); - dldwd_unlock(priv); + orinoco_unlock(priv); TRACE_EXIT(priv->ndev.name); } int -dldwd_reset(dldwd_priv_t *priv) +orinoco_reset(struct orinoco_private *priv) { struct net_device *dev = &priv->ndev; hermes_t *hw = &priv->hw; int err = 0; - hermes_id_t idbuf; + struct hermes_idstring idbuf; int frame_size; TRACE_ENTER(priv->ndev.name); /* Stop other people bothering us */ - dldwd_lock(priv); - __dldwd_stop_irqs(priv); + orinoco_lock(priv); + __orinoco_stop_irqs(priv); /* Check if we need a card reset */ if((priv->need_card_reset) && (priv->card_reset_handler != NULL)) priv->card_reset_handler(priv); /* Do standard firmware reset if we can */ - err = __dldwd_hw_reset(priv); + err = __orinoco_hw_reset(priv); if (err) goto out; @@ -568,11 +600,11 @@ /* Set up the link mode */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type); if (err) goto out; if (priv->has_ibss) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS, + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS, priv->allow_ibss); if (err) goto out; @@ -588,7 +620,7 @@ /* Set up encryption */ if (priv->has_wep) { - err = __dldwd_hw_setup_wep(priv); + err = __orinoco_hw_setup_wep(priv); if (err) { printk(KERN_ERR "%s: Error %d activating WEP.\n", dev->name, err); @@ -600,7 +632,7 @@ idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ? - HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID, + HERMES_RID_CNFOWNSSID : HERMES_RID_CNFDESIREDSSID, HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), &idbuf); if (err) @@ -609,58 +641,62 @@ /* Set the station name */ idbuf.len = cpu_to_le16(strlen(priv->nick)); memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), &idbuf); if (err) goto out; /* Set the channel/frequency */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel); if (err) goto out; /* Set AP density */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, priv->ap_density); if (err) goto out; /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh); if (err) goto out; /* Set fragmentation threshold or MWO robustness */ if (priv->has_mwo) err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust); + HERMES_RID_CNFMWOROBUST_AGERE, + priv->mwo_robust); else err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh); + HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + priv->frag_thresh); if (err) goto out; /* Set bitrate */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, - priv->tx_rate_ctrl); + err = __orinoco_hw_set_bitrate(priv); if (err) goto out; /* Set power management */ if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, priv->pm_on); if (err) goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMULTICASTRECEIVE, priv->pm_mcast); if (err) goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, priv->pm_period); if (err) goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, priv->pm_timeout); if (err) goto out; @@ -668,7 +704,8 @@ /* Set preamble - only for Symbol so far... */ if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, priv->preamble); if (err) { printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name); @@ -678,28 +715,62 @@ /* Set promiscuity / multicast*/ priv->promiscuous = 0; - priv->allmulti = 0; priv->mc_count = 0; - __dldwd_set_multicast_list(dev); - - err = hermes_enable_port(hw, DLDWD_MACPORT); - if (err) - goto out; + __orinoco_set_multicast_list(dev); - __dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | + __orinoco_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | HERMES_EV_TX | HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | HERMES_EV_INFDROP); + err = hermes_enable_port(hw, ORINOCO_MACPORT); + if (err) + goto out; + out: - dldwd_unlock(priv); + orinoco_unlock(priv); TRACE_EXIT(priv->ndev.name); return err; } -static int __dldwd_hw_setup_wep(dldwd_priv_t *priv) +static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + TRACE_ENTER(priv->ndev.name); + + if (priv->bitratemode >= BITRATE_TABLE_SIZE) { + printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", + priv->ndev.name, priv->bitratemode); + return -EINVAL; + } + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXRATECONTROL, + bitrate_table[priv->bitratemode].agere_txratectrl); + break; + case FIRMWARE_TYPE_INTERSIL: + case FIRMWARE_TYPE_SYMBOL: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXRATECONTROL, + bitrate_table[priv->bitratemode].intersil_txratectrl); + break; + default: + BUG(); + } + + TRACE_EXIT(priv->ndev.name); + + return err; +} + + +static int __orinoco_hw_setup_wep(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; int err = 0; @@ -709,17 +780,23 @@ TRACE_ENTER(priv->ndev.name); switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */ + case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ if (priv->wep_on) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXKEY_AGERE, + priv->tx_key); if (err) return err; - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys); + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFWEPKEYS_AGERE, + &priv->keys); if (err) return err; } - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPENABLED_AGERE, + priv->wep_on); if (err) return err; break; @@ -728,15 +805,15 @@ case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ master_wep_flag = 0; /* Off */ if (priv->wep_on) { -/* int keylen; */ + int keylen; int i; /* Fudge around firmware weirdness */ -/* keylen = priv->keys[priv->tx_key].len; */ + keylen = le16_to_cpu(priv->keys[priv->tx_key].len); /* Write all 4 keys */ - for(i = 0; i < MAX_KEYS; i++) { - int keylen = le16_to_cpu(priv->keys[i].len); + for(i = 0; i < ORINOCO_MAX_KEYS; i++) { +/* int keylen = le16_to_cpu(priv->keys[i].len); */ if (keylen > LARGE_KEY_SIZE) { printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", @@ -747,7 +824,7 @@ printk("About to write key %d, keylen=%d\n", i, keylen); err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNF_INTERSIL_KEY0 + i, + HERMES_RID_CNFDEFAULTKEY0 + i, HERMES_BYTES_TO_RECLEN(keylen), priv->keys[i].data); if (err) @@ -755,7 +832,7 @@ } /* Write the index of the key used in transmission */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_INTERSIL_TX_KEY, + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPDEFAULTKEYID, priv->tx_key); if (err) return err; @@ -771,7 +848,8 @@ auth_flag = 2; else auth_flag = 1; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, auth_flag); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFAUTHENTICATION, auth_flag); if (err) return err; /* Master WEP setting is always 3 */ @@ -787,7 +865,9 @@ } /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_INTERSIL_WEP_ON, master_wep_flag); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPFLAGS_INTERSIL, + master_wep_flag); if (err) return err; @@ -806,48 +886,48 @@ return 0; } -static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]) +static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]) { hermes_t *hw = &priv->hw; int err = 0; - dldwd_lock(priv); + orinoco_lock(priv); - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, buf); - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, +static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]) { hermes_t *hw = &priv->hw; int err = 0; - hermes_id_t essidbuf; + struct hermes_idstring essidbuf; char *p = (char *)(&essidbuf.val); int len; TRACE_ENTER(priv->ndev.name); - dldwd_lock(priv); + orinoco_lock(priv); if (strlen(priv->desired_essid) > 0) { /* We read the desired SSID from the hardware rather than from priv->desired_essid, just in case the firmware is allowed to change it on us. I'm not sure about this */ - /* My guess is that the OWN_SSID should always be whatever + /* My guess is that the OWNSSID should always be whatever * we set to the card, whereas CURRENT_SSID is the one that * may change... - Jean II */ u16 rid; *active = 1; - rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID : - HERMES_RID_CNF_DESIRED_SSID; + rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : + HERMES_RID_CNFDESIREDSSID; err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), NULL, &essidbuf); @@ -856,7 +936,7 @@ } else { *active = 0; - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, sizeof(essidbuf), NULL, &essidbuf); if (err) goto fail_unlock; @@ -869,14 +949,14 @@ buf[len] = '\0'; fail_unlock: - dldwd_unlock(priv); + orinoco_unlock(priv); TRACE_EXIT(priv->ndev.name); return err; } -static long dldwd_hw_get_freq(dldwd_priv_t *priv) +static long orinoco_hw_get_freq(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; @@ -884,9 +964,9 @@ u16 channel; long freq = 0; - dldwd_lock(priv); + orinoco_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); if (err) goto out; @@ -901,27 +981,27 @@ freq = channel_frequency[channel-1] * 100000; out: - dldwd_unlock(priv); + orinoco_unlock(priv); if (err > 0) err = -EBUSY; return err ? err : freq; } -static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, - s32 *rates, int max) +static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, + int32_t *rates, int max) { hermes_t *hw = &priv->hw; - hermes_id_t list; + struct hermes_idstring list; unsigned char *p = (unsigned char *)&list.val; int err = 0; int num; int i; - dldwd_lock(priv); - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list), - NULL, &list); - dldwd_unlock(priv); + orinoco_lock(priv); + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, + sizeof(list), NULL, &list); + orinoco_unlock(priv); if (err) return err; @@ -938,18 +1018,18 @@ } #ifndef ORINOCO_DEBUG -static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {} +static inline void show_rx_frame(struct orinoco_rxframe_hdr *frame) {} #else -static void show_rx_frame(struct dldwd_frame_hdr *frame) +static void show_rx_frame(struct orinoco_rxframe_hdr *frame) { printk(KERN_DEBUG "RX descriptor:\n"); printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); - printk(KERN_DEBUG " res1 = 0x%04x\n", frame->desc.res1); - printk(KERN_DEBUG " res2 = 0x%04x\n", frame->desc.res2); - printk(KERN_DEBUG " q_info = 0x%04x\n", frame->desc.q_info); - printk(KERN_DEBUG " res3 = 0x%04x\n", frame->desc.res3); - printk(KERN_DEBUG " res4 = 0x%04x\n", frame->desc.res4); - printk(KERN_DEBUG " tx_ctl = 0x%04x\n", frame->desc.tx_ctl); + printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time); + printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence); + printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal); + printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate); + printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow); + printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved); printk(KERN_DEBUG "IEEE 802.11 header:\n"); printk(KERN_DEBUG " frame_ctl = 0x%04x\n", @@ -1001,92 +1081,94 @@ /* * Interrupt handler */ -void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs) +void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs) { - dldwd_priv_t *priv = (dldwd_priv_t *) dev_id; + struct orinoco_private *priv = (struct orinoco_private *) dev_id; hermes_t *hw = &priv->hw; struct net_device *dev = &priv->ndev; - int count = IRQ_LOOP_MAX; + int count = MAX_IRQLOOPS_PER_IRQ; u16 evstat, events; - static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */ + /* These are used to detect a runaway interrupt situation */ + /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, + * we panic and shut down the hardware */ + static int last_irq_jiffy = 0; /* jiffies value the last time we were called */ + static int loops_this_jiffy = 0; - if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state)) + if (test_and_set_bit(ORINOCO_STATE_INIRQ, &priv->state)) BUG(); - if (! dldwd_irqs_allowed(priv)) { - clear_bit(DLDWD_STATE_INIRQ, &priv->state); + if (! orinoco_irqs_allowed(priv)) { + clear_bit(ORINOCO_STATE_INIRQ, &priv->state); return; } - DEBUG(3, "%s: dldwd_interrupt()\n", priv->ndev.name); + DEBUG(3, "%s: orinoco_interrupt()\n", priv->ndev.name); + + evstat = hermes_read_regn(hw, EVSTAT); + events = evstat & hw->inten; + + if (! events) { /* Sometimes the card generates Tx interrupts without setting EVSTAT, + or so I've heard - FIXME does it really happen? */ + printk(KERN_WARNING "%s: NULL event in orinoco_interrupt!\n", priv->ndev.name); + __orinoco_ev_alloc(priv, hw); + } - while (1) { - if (jiffies != old_time) - timecount = 0; - if ( (++timecount > 50) || (! count--) ) { + if (jiffies != last_irq_jiffy) + loops_this_jiffy = 0; + last_irq_jiffy = jiffies; + + while (events && count--) { + DEBUG(4, "__orinoco_interrupt(): count=%d EVSTAT=0x%04x\n", + count, evstat); + + if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { printk(KERN_CRIT "%s: IRQ handler is looping too \ much! Shutting down.\n", dev->name); /* Perform an emergency shutdown */ - clear_bit(DLDWD_STATE_DOIRQ, &priv->state); + clear_bit(ORINOCO_STATE_DOIRQ, &priv->state); hermes_set_irqmask(hw, 0); break; } - evstat = hermes_read_regn(hw, EVSTAT); - DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n", - count, evstat, hw->inten); - - events = evstat & hw->inten; - - if (! events) { - if (netif_queue_stopped(dev)) { - /* There seems to be a firmware bug which - sometimes causes the card to give an - interrupt with no event set, when there - sould be a Tx completed event. */ - DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n", - dev->name, (int)hermes_read_regn(hw, ALLOCFID)); - events = HERMES_EV_TX | HERMES_EV_ALLOC; - } else /* Nothing's happening, we're done */ - break; - } - /* Check the card hasn't been removed */ if (! hermes_present(hw)) { - DEBUG(0, "dldwd_interrupt(): card removed\n"); + DEBUG(0, "orinoco_interrupt(): card removed\n"); break; } if (events & HERMES_EV_TICK) - __dldwd_ev_tick(priv, hw); + __orinoco_ev_tick(priv, hw); if (events & HERMES_EV_WTERR) - __dldwd_ev_wterr(priv, hw); + __orinoco_ev_wterr(priv, hw); if (events & HERMES_EV_INFDROP) - __dldwd_ev_infdrop(priv, hw); + __orinoco_ev_infdrop(priv, hw); if (events & HERMES_EV_INFO) - __dldwd_ev_info(priv, hw); + __orinoco_ev_info(priv, hw); if (events & HERMES_EV_RX) - __dldwd_ev_rx(priv, hw); + __orinoco_ev_rx(priv, hw); if (events & HERMES_EV_TXEXC) - __dldwd_ev_txexc(priv, hw); + __orinoco_ev_txexc(priv, hw); if (events & HERMES_EV_TX) - __dldwd_ev_tx(priv, hw); + __orinoco_ev_tx(priv, hw); if (events & HERMES_EV_ALLOC) - __dldwd_ev_alloc(priv, hw); + __orinoco_ev_alloc(priv, hw); hermes_write_regn(hw, EVACK, events); - } - clear_bit(DLDWD_STATE_INIRQ, &priv->state); + evstat = hermes_read_regn(hw, EVSTAT); + events = evstat & hw->inten; + }; + + clear_bit(ORINOCO_STATE_INIRQ, &priv->state); } -static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw) { printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name); } -static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw) { /* This seems to happen a fair bit under load, but ignoring it seems to work fine...*/ @@ -1094,19 +1176,85 @@ priv->ndev.name); } -static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw) { printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name); } -static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw) { - DEBUG(3, "%s: Information frame received.\n", priv->ndev.name); - /* We don't actually do anything about it - we assume the MAC - controller can deal with it */ + struct net_device *dev = &priv->ndev; + u16 infofid; + struct { + u16 len; + u16 type; + } __attribute__ ((packed)) info; + int err; + + /* This is an answer to an INQUIRE command that we did earlier, + * or an information "event" generated by the card + * The controller return to us a pseudo frame containing + * the information in question - Jean II */ + infofid = hermes_read_regn(hw, INFOFID); + DEBUG(3, "%s: __dldwd_ev_info(): INFOFID=0x%04x\n", dev->name, + infofid); + + /* Read the info frame header - don't try too hard */ + err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info), + infofid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading info frame. " + "Frame dropped.\n", dev->name, err); + return; + } + + switch (le16_to_cpu(info.type)) { + case HERMES_INQ_TALLIES: { + struct hermes_tallies_frame tallies; + struct iw_statistics *wstats = &priv->wstats; + int len = le16_to_cpu(info.len) - 1; + + if (len > (sizeof(tallies) / 2)) { + DEBUG(1, "%s: tallies frame too long.\n", dev->name); + len = sizeof(tallies) / 2; + } + + /* Read directly the data (no seek) */ + hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, len); + + /* Increment our various counters */ + /* wstats->discard.nwid - no wrong BSSID stuff */ + wstats->discard.code += + le16_to_cpu(tallies.RxWEPUndecryptable); + if (len == (sizeof(tallies) / 2)) + wstats->discard.code += + le16_to_cpu(tallies.RxDiscards_WEPICVError) + + le16_to_cpu(tallies.RxDiscards_WEPExcluded); + wstats->discard.misc += + le16_to_cpu(tallies.TxDiscardsWrongSA); +#if WIRELESS_EXT > 11 + wstats->discard.fragment += + le16_to_cpu(tallies.RxMsgInBadMsgFragments); + wstats->discard.retries += + le16_to_cpu(tallies.TxRetryLimitExceeded); + /* wstats->miss.beacon - no match */ +#if ORINOCO_DEBUG > 3 + /* Hack for debugging - should not be taken as an example */ + wstats->discard.nwid += le16_to_cpu(tallies.TxUnicastFrames); + wstats->miss.beacon += le16_to_cpu(tallies.RxUnicastFrames); +#endif +#endif /* WIRELESS_EXT > 11 */ + } + break; + default: + DEBUG(1, "%s: Unknown information frame received (type %04x).\n", + priv->ndev.name, le16_to_cpu(info.type)); + /* We don't actually do anything about it */ + break; + } } -static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw) { struct net_device *dev = &priv->ndev; struct net_device_stats *stats = &priv->stats; @@ -1116,12 +1264,12 @@ u16 rxfid, status; int length, data_len, data_off; char *p; - struct dldwd_frame_hdr hdr; + struct orinoco_rxframe_hdr hdr; struct ethhdr *eh; int err; rxfid = hermes_read_regn(hw, RXFID); - DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid); + DEBUG(3, "__orinoco_ev_rx(): RXFID=0x%04x\n", rxfid); /* We read in the entire frame header here. This isn't really necessary, since we ignore most of it, but it's @@ -1140,7 +1288,6 @@ stats->rx_errors++; goto drop; } - DEBUG(2, "%s: BAP read suceeded: l=%d\n", dev->name, l); status = le16_to_cpu(hdr.desc.status); @@ -1148,7 +1295,6 @@ if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { stats->rx_crc_errors++; DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); - show_rx_frame(&hdr); } else if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_UNDECRYPTABLE) { wstats->discard.code++; @@ -1241,7 +1387,6 @@ stats->rx_errors++; goto drop; } - DEBUG(2, "%s: BAP read suceeded: l=%d\n", dev->name, l); dev->last_rx = jiffies; skb->dev = dev; @@ -1249,7 +1394,7 @@ skb->ip_summed = CHECKSUM_NONE; /* Process the wireless stats if needed */ - dldwd_stat_gather(dev, skb, &hdr); + orinoco_stat_gather(dev, skb, &hdr); /* Pass the packet to the networking stack */ netif_rx(skb); @@ -1264,45 +1409,60 @@ return; } -static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw) { struct net_device *dev = &priv->ndev; struct net_device_stats *stats = &priv->stats; + u16 fid = hermes_read_regn(hw, TXCOMPLFID); - printk(KERN_WARNING "%s: Tx error!\n", dev->name); + if (fid != DUMMY_FID) { + printk(KERN_INFO "%s: Tx error (FID=%04X)!\n", dev->name, fid); + stats->tx_errors++; + stats->tx_packets--; /* Reverse the increment done in _ev_alloc */ + } - netif_wake_queue(dev); - stats->tx_errors++; + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } -static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw) { - struct net_device *dev = &priv->ndev; - struct net_device_stats *stats = &priv->stats; + /* We don't generally use the Tx event (to cut down on + interrupts) - we do the transmit complet processing once + the transmit buffer is reclaimed in __orinoco_ev_alloc() , + hence nothing here */ - DEBUG(3, "%s: Transmit completed\n", dev->name); + DEBUG(2, "%s: Transmit completed (FID=%04X)\n", priv->ndev.name, fid); - stats->tx_packets++; - netif_wake_queue(dev); + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } -static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw) { - u16 allocfid; + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + u16 fid = hermes_read_regn(hw, ALLOCFID); - allocfid = hermes_read_regn(hw, ALLOCFID); - DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); + DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, fid); - /* For some reason we don't seem to get transmit completed events properly */ - if (allocfid == priv->txfid) - __dldwd_ev_tx(priv, hw); + /* We don't generally request Tx complete events to cut down + on the number of interrupts, so we do trasmit complete + processing here, which happens once the firmware is done + with the transmit buffer */ + + if (fid != priv->txfid) { + printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", + dev->name, fid); + return; + } + stats->tx_packets++; + netif_wake_queue(dev); -/* hermes_write_regn(hw, ALLOCFID, 0); */ + hermes_write_regn(hw, ALLOCFID, DUMMY_FID); } static void determine_firmware(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err; struct sta_id { @@ -1311,8 +1471,7 @@ u32 firmver; /* Get the firmware version */ - err = HERMES_READ_RECORD(hw, USER_BAP, - HERMES_RID_STAIDENTITY, &sta_id); + err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); if (err) { printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", dev->name, err); @@ -1338,10 +1497,8 @@ "version %d.%02d\n", dev->name, sta_id.major, sta_id.minor); - priv->firmware_type = FIRMWARE_TYPE_LUCENT; - priv->tx_rate_ctrl = 0x3; /* 11 Mb/s auto */ + priv->firmware_type = FIRMWARE_TYPE_AGERE; priv->need_card_reset = 0; - priv->broken_reset = 0; priv->broken_allocate = 0; priv->has_port3 = 1; /* Still works in 7.28 */ priv->has_ibss = (firmver >= 0x60006); @@ -1353,7 +1510,7 @@ priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ priv->has_preamble = 0; priv->ibss_port = 1; - /* Tested with Lucent firmware : + /* Tested with Agere firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II * Tested CableTron firmware : 4.32 => Anton */ } else if ((sta_id.vendor == 2) && @@ -1365,7 +1522,8 @@ memset(tmp, 0, sizeof(tmp)); /* Get the Symbol firmware version */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SYMBOL_SECONDARY_VER, + err = hermes_read_ltv(hw, USER_BAP, + HERMES_RID_SECONDARYVERSION_SYMBOL, SYMBOL_MAX_VER_LEN, NULL, &tmp); if (err) { printk(KERN_WARNING @@ -1390,9 +1548,7 @@ tmp, firmver); priv->firmware_type = FIRMWARE_TYPE_SYMBOL; - priv->tx_rate_ctrl = 0xF; /* 11 Mb/s auto */ priv->need_card_reset = 1; - priv->broken_reset = 0; priv->broken_allocate = 1; priv->has_port3 = 1; priv->has_ibss = (firmver >= 0x20000); @@ -1415,9 +1571,7 @@ sta_id.major, sta_id.minor); priv->firmware_type = FIRMWARE_TYPE_INTERSIL; - priv->tx_rate_ctrl = 0xF; /* 11 Mb/s auto */ priv->need_card_reset = 0; - priv->broken_reset = 0; priv->broken_allocate = 0; priv->has_port3 = 1; priv->has_ibss = (firmver >= 0x00007); /* FIXME */ @@ -1431,7 +1585,7 @@ priv->ibss_port = 0; else { printk(KERN_NOTICE "%s: Intersil firmware earlier " - "than v0.08 - several features not supported.", + "than v0.08 - several features not supported\n", dev->name); priv->ibss_port = 1; } @@ -1443,18 +1597,18 @@ */ int -dldwd_init(struct net_device *dev) +orinoco_init(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; - hermes_id_t nickbuf; + struct hermes_idstring nickbuf; u16 reclen; int len; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); - dldwd_lock(priv); + orinoco_lock(priv); /* Do standard firmware reset */ err = hermes_reset(hw); @@ -1467,20 +1621,20 @@ determine_firmware(dev); if (priv->has_port3) - printk(KERN_DEBUG "%s: Ad-hoc demo mode supported.\n", dev->name); + printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); if (priv->has_ibss) - printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported.\n", + printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n", dev->name); if (priv->has_wep) { printk(KERN_DEBUG "%s: WEP supported, ", dev->name); if (priv->has_big_wep) - printk("\"128\"-bit key.\n"); + printk("104-bit key\n"); else - printk("40-bit key.\n"); + printk("40-bit key\n"); } /* Get the MAC address */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, ETH_ALEN, NULL, dev->dev_addr); if (err) { printk(KERN_WARNING "%s: failed to read MAC address!\n", @@ -1494,15 +1648,15 @@ dev->dev_addr[5]); /* Get the station name */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, sizeof(nickbuf), &reclen, &nickbuf); if (err) { - printk(KERN_ERR "%s: failed to read station name!n", + printk(KERN_ERR "%s: failed to read station name\n", dev->name); goto out; } if (nickbuf.len) - len = min_t(u16, IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); + len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); else len = min(IW_ESSID_MAX_SIZE, 2 * reclen); memcpy(priv->nick, &nickbuf.val, len); @@ -1511,7 +1665,8 @@ printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); /* Get allowed channels */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, + &priv->channel_mask); if (err) { printk(KERN_ERR "%s: failed to read channel list!\n", dev->name); @@ -1519,14 +1674,15 @@ } /* Get initial AP density */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &priv->ap_density); if (err) { printk(KERN_ERR "%s: failed to read AP density!\n", dev->name); goto out; } /* Get initial RTS threshold */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + &priv->rts_thresh); if (err) { printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); goto out; @@ -1534,10 +1690,11 @@ /* Get initial fragmentation settings */ if (priv->has_mwo) - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, &priv->mwo_robust); else - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, &priv->frag_thresh); if (err) { printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); @@ -1548,14 +1705,16 @@ if (priv->has_pm) { priv->pm_on = 0; priv->pm_mcast = 1; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, &priv->pm_period); if (err) { printk(KERN_ERR "%s: failed to read power management period!\n", dev->name); goto out; } - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, &priv->pm_timeout); if (err) { printk(KERN_ERR "%s: failed to read power management timeout!\n", @@ -1566,7 +1725,8 @@ /* Preamble setup */ if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPREAMBLE_SYMBOL, + &priv->preamble); if (err) goto out; } @@ -1578,40 +1738,39 @@ set_port_type(priv); priv->promiscuous = 0; - priv->allmulti = 0; priv->wep_on = 0; priv->tx_key = 0; printk(KERN_DEBUG "%s: ready\n", dev->name); out: - dldwd_unlock(priv); + orinoco_unlock(priv); - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return err; } struct net_device_stats * -dldwd_get_stats(struct net_device *dev) +orinoco_get_stats(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; return &priv->stats; } struct iw_statistics * -dldwd_get_wireless_stats(struct net_device *dev) +orinoco_get_wireless_stats(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; hermes_t *hw = &priv->hw; struct iw_statistics *wstats = &priv->wstats; int err = 0; - if (!priv->hw_ready) - return NULL; + if (! netif_device_present(dev)) + return NULL; /* FIXME: We may be able to do better than this */ - dldwd_lock(priv); + orinoco_lock(priv); if (priv->iw_mode == IW_MODE_ADHOC) { memset(&wstats->qual, 0, sizeof(wstats->qual)); @@ -1626,7 +1785,7 @@ } #endif /* WIRELESS_SPY */ } else { - dldwd_commsqual_t cq; + orinoco_commsqual_t cq; err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_COMMSQUALITY, &cq); @@ -1640,7 +1799,14 @@ wstats->qual.updated = 7; } - dldwd_unlock(priv); + /* We can't really wait for the tallies inquiry command to + * complete, so we just use the previous results and trigger + * a new tallies inquiry command for next time - Jean II */ + /* Hmm.. seems a bit ugly, I wonder if there's a way to do + better - dgibson */ + err = hermes_inquire(hw, HERMES_INQ_TALLIES); + + orinoco_unlock(priv); if (err) return NULL; @@ -1649,10 +1815,10 @@ } #ifdef WIRELESS_SPY -static inline void dldwd_spy_gather(struct net_device *dev, u_char *mac, +static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, int level, int noise) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; int i; /* Gather wireless spy statistics: for each packet, compare the @@ -1668,11 +1834,11 @@ #endif /* WIRELESS_SPY */ void -dldwd_stat_gather( struct net_device *dev, +orinoco_stat_gather( struct net_device *dev, struct sk_buff *skb, - struct dldwd_frame_hdr *hdr) + struct orinoco_rxframe_hdr *hdr) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; /* Using spy support with lots of Rx packets, like in an * infrastructure (AP), will really slow down everything, because @@ -1686,20 +1852,16 @@ /* Note : gcc will optimise the whole section away if * WIRELESS_SPY is not defined... - Jean II */ if (priv->spy_number > 0) { - u8 *stats = (u8 *) &(hdr->desc.q_info); - /* This code may look strange. Everywhere we are using 16 bit - * ints except here. I've verified that these are are the - * correct values. Please check on PPC - Jean II */ - - dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, (int)stats[1], (int)stats[0]); + orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN, + hdr->desc.signal, hdr->desc.silence); } #endif /* WIRELESS_SPY */ } int -dldwd_xmit(struct sk_buff *skb, struct net_device *dev) +orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; int err = 0; @@ -1707,7 +1869,7 @@ char *p; struct ethhdr *eh; int len, data_len, data_off; - struct dldwd_frame_hdr hdr; + struct orinoco_txframe_hdr hdr; hermes_response_t resp; if (! netif_running(dev)) { @@ -1723,7 +1885,7 @@ return 1; } - dldwd_lock(priv); + orinoco_lock(priv); /* Length of the packet body */ len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN); @@ -1734,7 +1896,11 @@ memset(&hdr, 0, sizeof(hdr)); memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN); memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN); - hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA; + hdr.p80211.frame_ctl = IEEE802_11_FTYPE_DATA; + + /* Request an interrupt on Tx failures, but not sucesses (we + use the buffer reclaim allocation event instead */ + hdr.desc.tx_control = HERMES_TXCTRL_TX_EX; /* Encapsulate Ethernet-II frames */ if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ @@ -1751,17 +1917,13 @@ hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); /* 802.2 header */ - if (! use_old_encaps) - memcpy(&hdr.p8022, &encaps_hdr, - sizeof(encaps_hdr)); - else - memcpy(&hdr.p8022, &encaps_hdr, - sizeof(old_encaps_hdr)); + memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr)); hdr.ethertype = eh->h_proto; err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), txfid, 0); if (err) { +#if 0 if (err == -EIO) /* We get these errors reported by the firmware every so often apparently at @@ -1769,6 +1931,7 @@ handle the retry */ DEBUG(1, "%s: DEBUG: EIO writing packet header to BAP\n", dev->name); else +#endif printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", dev->name, err); stats->tx_errors++; @@ -1795,10 +1958,10 @@ /* Round up for odd length packets */ err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); if (err) { - if (err == -EIO) - DEBUG(1, "%s: DEBUG: EIO writing packet header to BAP\n", dev->name); - else - printk(KERN_ERR "%s: Error %d writing packet header to BAP", +/* if (err == -EIO) */ +/* DEBUG(1, "%s: DEBUG: EIO writing packet header to BAP\n", dev->name); */ +/* else */ + printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", dev->name, err); stats->tx_errors++; goto fail; @@ -1817,21 +1980,21 @@ netif_stop_queue(dev); - dldwd_unlock(priv); + orinoco_unlock(priv); dev_kfree_skb(skb); return 0; fail: - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } void -dldwd_tx_timeout(struct net_device *dev) +orinoco_tx_timeout(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; struct net_device_stats *stats = &priv->stats; int err = 0; @@ -1839,7 +2002,7 @@ stats->tx_errors++; - err = dldwd_reset(priv); + err = orinoco_reset(priv); if (err) printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", dev->name, err); @@ -1849,9 +2012,9 @@ } } -static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) +static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int err = 0; int mode; struct iw_range range; @@ -1866,9 +2029,9 @@ rrq->length = sizeof(range); - dldwd_lock(priv); + orinoco_lock(priv); mode = priv->iw_mode; - dldwd_unlock(priv); + orinoco_unlock(priv); memset(&range, 0, sizeof(range)); @@ -1904,13 +2067,25 @@ range.max_qual.qual = 0; range.max_qual.level = 0; range.max_qual.noise = 0; +#if WIRELESS_EXT > 11 + range.avg_qual.qual = 0; + range.avg_qual.level = 0; + range.avg_qual.noise = 0; +#endif /* WIRELESS_EXT > 11 */ + } else { range.max_qual.qual = 0x8b - 0x2f; range.max_qual.level = 0x2f - 0x95 - 1; range.max_qual.noise = 0x2f - 0x95 - 1; +#if WIRELESS_EXT > 11 + /* Need to get better values */ + range.avg_qual.qual = 0x24; + range.avg_qual.level = 0xC2; + range.avg_qual.noise = 0x9E; +#endif /* WIRELESS_EXT > 11 */ } - err = dldwd_hw_get_bitratelist(priv, &numrates, + err = orinoco_hw_get_bitratelist(priv, &numrates, range.bitrate, IW_MAX_BITRATES); if (err) return err; @@ -1929,9 +2104,9 @@ range.min_frag = 256; range.max_frag = 2346; - dldwd_lock(priv); + orinoco_lock(priv); if (priv->has_wep) { - range.max_encoding_tokens = MAX_KEYS; + range.max_encoding_tokens = ORINOCO_MAX_KEYS; range.encoding_size[0] = SMALL_KEY_SIZE; range.num_encoding_sizes = 1; @@ -1944,7 +2119,7 @@ range.num_encoding_sizes = 0; range.max_encoding_tokens = 0; } - dldwd_unlock(priv); + orinoco_unlock(priv); range.min_pmp = 0; range.max_pmp = 65535000; @@ -1976,30 +2151,30 @@ return 0; } -static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) +static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int index = (erq->flags & IW_ENCODE_INDEX) - 1; int setindex = priv->tx_key; int enable = priv->wep_on; int restricted = priv->wep_restrict; u16 xlen = 0; int err = 0; - char keybuf[MAX_KEY_SIZE]; + char keybuf[ORINOCO_MAX_KEY_SIZE]; if (erq->pointer) { /* We actually have a key to set */ - if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > MAX_KEY_SIZE) ) + if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > ORINOCO_MAX_KEY_SIZE) ) return -EINVAL; if (copy_from_user(keybuf, erq->pointer, erq->length)) return -EFAULT; } - dldwd_lock(priv); + orinoco_lock(priv); if (erq->pointer) { - if (erq->length > MAX_KEY_SIZE) { + if (erq->length > ORINOCO_MAX_KEY_SIZE) { err = -E2BIG; goto out; } @@ -2010,7 +2185,7 @@ goto out; } - if ((index < 0) || (index >= MAX_KEYS)) + if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; if (erq->length > SMALL_KEY_SIZE) { @@ -2029,7 +2204,7 @@ /* Important note : if the user do "iwconfig eth0 enc off", * we will arrive there with an index of -1. This is valid * but need to be taken care off... Jean II */ - if ((index < 0) || (index >= MAX_KEYS)) { + if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) { if((index != -1) || (erq->flags == 0)) { err = -EINVAL; goto out; @@ -2062,22 +2237,22 @@ priv->wep_restrict = restricted; out: - dldwd_unlock(priv); + orinoco_unlock(priv); - return 0; + return err; } -static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) +static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int index = (erq->flags & IW_ENCODE_INDEX) - 1; u16 xlen = 0; - char keybuf[MAX_KEY_SIZE]; + char keybuf[ORINOCO_MAX_KEY_SIZE]; - dldwd_lock(priv); + orinoco_lock(priv); - if ((index < 0) || (index >= MAX_KEYS)) + if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; erq->flags = 0; @@ -2086,7 +2261,7 @@ erq->flags |= index + 1; /* Only for symbol cards - Jean II */ - if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) { + if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { if(priv->wep_restrict) erq->flags |= IW_ENCODE_RESTRICTED; else @@ -2098,10 +2273,10 @@ erq->length = xlen; if (erq->pointer) { - memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE); + memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); } - dldwd_unlock(priv); + orinoco_unlock(priv); if (erq->pointer) { if (copy_to_user(erq->pointer, keybuf, xlen)) @@ -2111,9 +2286,9 @@ return 0; } -static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq) +static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; char essidbuf[IW_ESSID_MAX_SIZE+1]; /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it @@ -2131,25 +2306,25 @@ essidbuf[erq->length] = '\0'; } - dldwd_lock(priv); + orinoco_lock(priv); memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid)); - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq) +static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; char essidbuf[IW_ESSID_MAX_SIZE+1]; int active; int err = 0; TRACE_ENTER(dev->name); - err = dldwd_hw_get_essid(priv, &active, essidbuf); + err = orinoco_hw_get_essid(priv, &active, essidbuf); if (err) return err; @@ -2164,9 +2339,9 @@ return 0; } -static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) +static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; char nickbuf[IW_ESSID_MAX_SIZE+1]; if (nrq->length > IW_ESSID_MAX_SIZE) @@ -2179,23 +2354,23 @@ nickbuf[nrq->length] = '\0'; - dldwd_lock(priv); + orinoco_lock(priv); memcpy(priv->nick, nickbuf, sizeof(priv->nick)); - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) +static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; char nickbuf[IW_ESSID_MAX_SIZE+1]; - dldwd_lock(priv); + orinoco_lock(priv); memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); - dldwd_unlock(priv); + orinoco_unlock(priv); nrq->length = strlen(nickbuf)+1; @@ -2205,9 +2380,9 @@ return 0; } -static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) +static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int chan = -1; /* We can only use this in Ad-Hoc demo mode to set the operating @@ -2236,23 +2411,23 @@ ! (priv->channel_mask & (1 << (chan-1)) ) ) return -EINVAL; - dldwd_lock(priv); + orinoco_lock(priv); priv->channel = chan; - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq) +static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; u16 val; int err; - dldwd_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val); - dldwd_unlock(priv); + orinoco_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &val); + orinoco_unlock(priv); if (err) return err; @@ -2263,24 +2438,24 @@ return 0; } -static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq) +static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int val = srq->value; if ((val < 1) || (val > 3)) return -EINVAL; - dldwd_lock(priv); + orinoco_lock(priv); priv->ap_density = val; - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) +static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int val = rrq->value; if (rrq->disabled) @@ -2289,19 +2464,19 @@ if ( (val < 0) || (val > 2347) ) return -EINVAL; - dldwd_lock(priv); + orinoco_lock(priv); priv->rts_thresh = val; - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) +static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int err = 0; - dldwd_lock(priv); + orinoco_lock(priv); if (priv->has_mwo) { if (frq->disabled) @@ -2323,22 +2498,24 @@ } } - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) +static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; u16 val; - dldwd_lock(priv); + orinoco_lock(priv); if (priv->has_mwo) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val); + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, + &val); if (err) val = 0; @@ -2346,7 +2523,8 @@ frq->disabled = ! val; frq->fixed = 0; } else { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + &val); if (err) val = 0; @@ -2355,158 +2533,122 @@ frq->fixed = 1; } - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) +static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int err = 0; - int rate_ctrl = -1; - int fixed, upto; - int brate; + int ratemode = -1; + int bitrate; /* 100s of kilobits */ int i; + + /* As the user space doesn't know our highest rate, it uses -1 + * to ask us to set the highest rate. Test it using "iwconfig + * ethX rate auto" - Jean II */ + if (rrq->value == -1) + bitrate = 110; + else { + if (rrq->value % 100000) + return -EINVAL; + bitrate = rrq->value / 100000; + } - dldwd_lock(priv); - - /* Normalise value */ - brate = rrq->value / 500000; + if ( (bitrate != 10) && (bitrate != 20) && + (bitrate != 55) && (bitrate != 110) ) + return -EINVAL; - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ - if (! rrq->fixed) { - if (brate > 0) - brate = -brate; - else - brate = -22; - } - - for (i = 0; i < NUM_RATES; i++) - if (rate_list[i] == brate) { - rate_ctrl = i; - break; - } - - if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) ) - err = -EINVAL; - else - priv->tx_rate_ctrl = rate_ctrl; - break; - case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - switch(brate) { - case 0: - fixed = 0x0; - upto = 0xF; - break; - case 2: - fixed = 0x1; - upto = 0x1; - break; - case 4: - fixed = 0x2; - upto = 0x3; - break; - case 11: - fixed = 0x4; - upto = 0x7; - break; - case 22: - fixed = 0x8; - upto = 0xF; + for (i = 0; i < BITRATE_TABLE_SIZE; i++) + if ( (bitrate_table[i].bitrate == bitrate) && + (bitrate_table[i].automatic == ! rrq->fixed) ) { + ratemode = i; break; - default: - fixed = 0x0; - upto = 0x0; } - if (rrq->fixed) - rate_ctrl = fixed; - else - rate_ctrl = upto; - if (rate_ctrl == 0) - err = -EINVAL; - else - priv->tx_rate_ctrl = rate_ctrl; - break; - } + + if (ratemode == -1) + return -EINVAL; - dldwd_unlock(priv); + orinoco_lock(priv); + priv->bitratemode = ratemode; + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) +static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; + int ratemode; + int i; u16 val; - int brate = 0; - dldwd_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val); - if (err) - goto out; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ - brate = rate_list[val]; - - if (brate < 0) { - rrq->fixed = 0; + orinoco_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); - if (err) - goto out; + ratemode = priv->bitratemode; + + if ( (ratemode < 0) || (ratemode > BITRATE_TABLE_SIZE) ) + BUG(); + + rrq->value = bitrate_table[ratemode].bitrate * 100000; + rrq->fixed = ! bitrate_table[ratemode].automatic; + rrq->disabled = 0; + /* If the interface is running we try to find more about the + current mode */ + if (netif_running(dev)) { + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CURRENTTXRATE, &val); + if (err) + goto out; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ + /* Note : in Lucent firmware, the return value of + * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, + * and therefore is totally different from the + * encoding of HERMES_RID_CNFTXRATECONTROL. + * Don't forget that 6Mb/s is really 5.5Mb/s */ if (val == 6) - brate = 11; + rrq->value = 5500000; else - brate = 2*val; - } else - rrq->fixed = 1; - break; - case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - /* Check if auto or fixed (crude approximation) */ - if((val & 0x1) && (val > 1)) { - rrq->fixed = 0; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); - if (err) - goto out; - } else - rrq->fixed = 1; + rrq->value = val * 1000000; + break; + case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + for (i = 0; i < BITRATE_TABLE_SIZE; i++) + if (bitrate_table[i].intersil_txratectrl == val) { + ratemode = i; + break; + } + if (i >= BITRATE_TABLE_SIZE) + printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", + dev->name, val); - if(val >= 8) - brate = 22; - else if(val >= 4) - brate = 11; - else if(val >= 2) - brate = 4; - else - brate = 2; - break; + rrq->value = bitrate_table[ratemode].bitrate * 100000; + break; + default: + BUG(); + } } - rrq->value = brate * 500000; - rrq->disabled = 0; - out: - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq) +static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int err = 0; - dldwd_lock(priv); + orinoco_lock(priv); if (prq->disabled) { priv->pm_on = 0; @@ -2546,33 +2688,34 @@ } out: - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq) +static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; u16 enable, period, timeout, mcast; - dldwd_lock(priv); + orinoco_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable); if (err) goto out; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period); + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, &period); if (err) goto out; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &timeout); if (err) goto out; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, &mcast); if (err) goto out; @@ -2591,30 +2734,33 @@ prq->flags |= IW_POWER_UNICAST_R; out: - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } #if WIRELESS_EXT > 10 -static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) +static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; u16 short_limit, long_limit, lifetime; - dldwd_lock(priv); + orinoco_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, + &short_limit); if (err) goto out; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, + &long_limit); if (err) goto out; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, + &lifetime); if (err) goto out; @@ -2638,46 +2784,46 @@ } out: - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } #endif /* WIRELESS_EXT > 10 */ -static int dldwd_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) +static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int val = *( (int *) wrq->u.name ); - dldwd_lock(priv); + orinoco_lock(priv); priv->ibss_port = val ; /* Actually update the mode we are using */ set_port_type(priv); - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq) +static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int *val = (int *)wrq->u.name; - dldwd_lock(priv); + orinoco_lock(priv); *val = priv->ibss_port; - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) +static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int val = *( (int *) wrq->u.name ); int err = 0; - dldwd_lock(priv); + orinoco_lock(priv); switch (val) { case 0: /* Try to do IEEE ad-hoc mode */ if (! priv->has_ibss) { @@ -2706,28 +2852,28 @@ /* Actually update the mode we are using */ set_port_type(priv); - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) +static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int *val = (int *)wrq->u.name; - dldwd_lock(priv); + orinoco_lock(priv); *val = priv->prefer_port3; - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } /* Spy is used for link quality/strength measurements in Ad-Hoc mode * Jean II */ -static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq) +static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; struct sockaddr address[IW_MAX_SPY]; int number = srq->length; int i; @@ -2745,9 +2891,9 @@ } /* Make sure nobody mess with the structure while we do */ - dldwd_lock(priv); + orinoco_lock(priv); - /* dldwd_lock() doesn't disable interrupts, so make sure the + /* orinoco_lock() doesn't disable interrupts, so make sure the * interrupt rx path don't get confused while we copy */ priv->spy_number = 0; @@ -2774,20 +2920,20 @@ } /* Now, let the others play */ - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq) +static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; struct sockaddr address[IW_MAX_SPY]; struct iw_quality spy_stat[IW_MAX_SPY]; int number; int i; - dldwd_lock(priv); + orinoco_lock(priv); number = priv->spy_number; if ((number > 0) && (srq->pointer)) { @@ -2807,7 +2953,7 @@ priv->spy_stat[i].updated = 0; } - dldwd_unlock(priv); + orinoco_unlock(priv); /* Push stuff to user space */ srq->length = number; @@ -2822,22 +2968,22 @@ } int -dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; struct iwreq *wrq = (struct iwreq *)rq; int err = 0; int changed = 0; TRACE_ENTER(dev->name); - /* In theory, we could allow most of the the SET stuff to be done - * In practice, the laps of time at startup when the card is not - * ready is very short, so why bother... - * Note that hw_ready is different from up/down (ifconfig), when - * the device is not yet up, it is usually already ready... - * Jean II */ - if (!priv->hw_ready) + /* In theory, we could allow most of the the SET stuff to be + * done In practice, the laps of time at startup when the card + * is not ready is very short, so why bother... Note that + * netif_device_present is different from up/down (ifconfig), + * when the device is not yet up, it is usually already + * ready... Jean II */ + if (! netif_device_present(dev)) return -ENODEV; switch (cmd) { @@ -2849,17 +2995,17 @@ case SIOCGIWAP: DEBUG(1, "%s: SIOCGIWAP\n", dev->name); wrq->u.ap_addr.sa_family = ARPHRD_ETHER; - err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); + err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); break; case SIOCGIWRANGE: DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name); - err = dldwd_ioctl_getiwrange(dev, &wrq->u.data); + err = orinoco_ioctl_getiwrange(dev, &wrq->u.data); break; case SIOCSIWMODE: DEBUG(1, "%s: SIOCSIWMODE\n", dev->name); - dldwd_lock(priv); + orinoco_lock(priv); switch (wrq->u.mode) { case IW_MODE_ADHOC: if (! (priv->has_ibss || priv->has_port3) ) @@ -2880,14 +3026,14 @@ break; } set_port_type(priv); - dldwd_unlock(priv); + orinoco_unlock(priv); break; case SIOCGIWMODE: DEBUG(1, "%s: SIOCGIWMODE\n", dev->name); - dldwd_lock(priv); + orinoco_lock(priv); wrq->u.mode = priv->iw_mode; - dldwd_unlock(priv); + orinoco_unlock(priv); break; case SIOCSIWENCODE: @@ -2897,7 +3043,7 @@ break; } - err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding); + err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding); if (! err) changed = 1; break; @@ -2914,54 +3060,54 @@ break; } - err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding); + err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding); break; case SIOCSIWESSID: DEBUG(1, "%s: SIOCSIWESSID\n", dev->name); - err = dldwd_ioctl_setessid(dev, &wrq->u.essid); + err = orinoco_ioctl_setessid(dev, &wrq->u.essid); if (! err) changed = 1; break; case SIOCGIWESSID: DEBUG(1, "%s: SIOCGIWESSID\n", dev->name); - err = dldwd_ioctl_getessid(dev, &wrq->u.essid); + err = orinoco_ioctl_getessid(dev, &wrq->u.essid); break; case SIOCSIWNICKN: DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name); - err = dldwd_ioctl_setnick(dev, &wrq->u.data); + err = orinoco_ioctl_setnick(dev, &wrq->u.data); if (! err) changed = 1; break; case SIOCGIWNICKN: DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name); - err = dldwd_ioctl_getnick(dev, &wrq->u.data); + err = orinoco_ioctl_getnick(dev, &wrq->u.data); break; case SIOCGIWFREQ: DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name); - wrq->u.freq.m = dldwd_hw_get_freq(priv); + wrq->u.freq.m = orinoco_hw_get_freq(priv); wrq->u.freq.e = 1; break; case SIOCSIWFREQ: DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name); - err = dldwd_ioctl_setfreq(dev, &wrq->u.freq); + err = orinoco_ioctl_setfreq(dev, &wrq->u.freq); if (! err) changed = 1; break; case SIOCGIWSENS: DEBUG(1, "%s: SIOCGIWSENS\n", dev->name); - err = dldwd_ioctl_getsens(dev, &wrq->u.sens); + err = orinoco_ioctl_getsens(dev, &wrq->u.sens); break; case SIOCSIWSENS: DEBUG(1, "%s: SIOCSIWSENS\n", dev->name); - err = dldwd_ioctl_setsens(dev, &wrq->u.sens); + err = orinoco_ioctl_setsens(dev, &wrq->u.sens); if (! err) changed = 1; break; @@ -2975,45 +3121,45 @@ case SIOCSIWRTS: DEBUG(1, "%s: SIOCSIWRTS\n", dev->name); - err = dldwd_ioctl_setrts(dev, &wrq->u.rts); + err = orinoco_ioctl_setrts(dev, &wrq->u.rts); if (! err) changed = 1; break; case SIOCSIWFRAG: DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name); - err = dldwd_ioctl_setfrag(dev, &wrq->u.frag); + err = orinoco_ioctl_setfrag(dev, &wrq->u.frag); if (! err) changed = 1; break; case SIOCGIWFRAG: DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name); - err = dldwd_ioctl_getfrag(dev, &wrq->u.frag); + err = orinoco_ioctl_getfrag(dev, &wrq->u.frag); break; case SIOCSIWRATE: DEBUG(1, "%s: SIOCSIWRATE\n", dev->name); - err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate); + err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate); if (! err) changed = 1; break; case SIOCGIWRATE: DEBUG(1, "%s: SIOCGIWRATE\n", dev->name); - err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate); + err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate); break; case SIOCSIWPOWER: DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name); - err = dldwd_ioctl_setpower(dev, &wrq->u.power); + err = orinoco_ioctl_setpower(dev, &wrq->u.power); if (! err) changed = 1; break; case SIOCGIWPOWER: DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name); - err = dldwd_ioctl_getpower(dev, &wrq->u.power); + err = orinoco_ioctl_getpower(dev, &wrq->u.power); break; case SIOCGIWTXPOW: @@ -3033,44 +3179,44 @@ case SIOCGIWRETRY: DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name); - err = dldwd_ioctl_getretry(dev, &wrq->u.retry); + err = orinoco_ioctl_getretry(dev, &wrq->u.retry); break; #endif /* WIRELESS_EXT > 10 */ case SIOCSIWSPY: DEBUG(1, "%s: SIOCSIWSPY\n", dev->name); - err = dldwd_ioctl_setspy(dev, &wrq->u.data); + err = orinoco_ioctl_setspy(dev, &wrq->u.data); break; case SIOCGIWSPY: DEBUG(1, "%s: SIOCGIWSPY\n", dev->name); - err = dldwd_ioctl_getspy(dev, &wrq->u.data); + err = orinoco_ioctl_getspy(dev, &wrq->u.data); break; case SIOCGIWPRIV: DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name); if (wrq->u.data.pointer) { struct iw_priv_args privtab[] = { - { SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" }, - { SIOCDEVPRIVATE + 0x1, 0, 0, "card_reset" }, - { SIOCDEVPRIVATE + 0x2, + { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, + { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, + { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_port3" }, - { SIOCDEVPRIVATE + 0x3, 0, + { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_port3" }, - { SIOCDEVPRIVATE + 0x4, + { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble" }, - { SIOCDEVPRIVATE + 0x5, 0, + { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_preamble" }, - { SIOCDEVPRIVATE + 0x6, + { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_ibssport" }, - { SIOCDEVPRIVATE + 0x7, 0, + { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_ibssport" } }; @@ -3085,8 +3231,8 @@ } break; - case SIOCDEVPRIVATE + 0x0: /* force_reset */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n", + case SIOCIWFIRSTPRIV + 0x0: /* force_reset */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x0 (force_reset)\n", dev->name); if (! capable(CAP_NET_ADMIN)) { err = -EPERM; @@ -3094,11 +3240,11 @@ } printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); - dldwd_reset(priv); + orinoco_reset(priv); break; - case SIOCDEVPRIVATE + 0x1: /* card_reset */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x1 (card_reset)\n", + case SIOCIWFIRSTPRIV + 0x1: /* card_reset */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x1 (card_reset)\n", dev->name); if (! capable(CAP_NET_ADMIN)) { err = -EPERM; @@ -3108,30 +3254,30 @@ printk(KERN_DEBUG "%s: Forcing card reset!\n", dev->name); if(priv->card_reset_handler != NULL) priv->card_reset_handler(priv); - dldwd_reset(priv); + orinoco_reset(priv); break; - case SIOCDEVPRIVATE + 0x2: /* set_port3 */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n", + case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x2 (set_port3)\n", dev->name); if (! capable(CAP_NET_ADMIN)) { err = -EPERM; break; } - err = dldwd_ioctl_setport3(dev, wrq); + err = orinoco_ioctl_setport3(dev, wrq); if (! err) changed = 1; break; - case SIOCDEVPRIVATE + 0x3: /* get_port3 */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n", + case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x3 (get_port3)\n", dev->name); - err = dldwd_ioctl_getport3(dev, wrq); + err = orinoco_ioctl_getport3(dev, wrq); break; - case SIOCDEVPRIVATE + 0x4: /* set_preamble */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n", + case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x4 (set_preamble)\n", dev->name); if (! capable(CAP_NET_ADMIN)) { err = -EPERM; @@ -3146,46 +3292,46 @@ if(priv->has_preamble) { int val = *( (int *) wrq->u.name ); - dldwd_lock(priv); + orinoco_lock(priv); if(val) priv->preamble = 1; else priv->preamble = 0; - dldwd_unlock(priv); + orinoco_unlock(priv); changed = 1; } else err = -EOPNOTSUPP; break; - case SIOCDEVPRIVATE + 0x5: /* get_preamble */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n", + case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x5 (get_preamble)\n", dev->name); if(priv->has_preamble) { int *val = (int *)wrq->u.name; - dldwd_lock(priv); + orinoco_lock(priv); *val = priv->preamble; - dldwd_unlock(priv); + orinoco_unlock(priv); } else err = -EOPNOTSUPP; break; - case SIOCDEVPRIVATE + 0x6: /* set_ibssport */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x6 (set_ibssport)\n", + case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x6 (set_ibssport)\n", dev->name); if (! capable(CAP_NET_ADMIN)) { err = -EPERM; break; } - err = dldwd_ioctl_setibssport(dev, wrq); + err = orinoco_ioctl_setibssport(dev, wrq); if (! err) changed = 1; break; - case SIOCDEVPRIVATE + 0x7: /* get_ibssport */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x7 (get_ibssport)\n", + case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x7 (get_ibssport)\n", dev->name); - err = dldwd_ioctl_getibssport(dev, wrq); + err = orinoco_ioctl_getibssport(dev, wrq); break; @@ -3194,14 +3340,13 @@ } if (! err && changed && netif_running(dev)) { - err = dldwd_reset(priv); + err = orinoco_reset(priv); if (err) { /* Ouch ! What are we supposed to do ? */ printk(KERN_ERR "orinoco_cs: Failed to set parameters on %s\n", dev->name); - netif_stop_queue(dev); - dldwd_shutdown(priv); - priv->hw_ready = 0; + netif_device_detach(dev); + orinoco_shutdown(priv); } } @@ -3211,11 +3356,11 @@ } int -dldwd_change_mtu(struct net_device *dev, int new_mtu) +orinoco_change_mtu(struct net_device *dev, int new_mtu) { TRACE_ENTER(dev->name); - if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) ) + if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) return -EINVAL; dev->mtu = new_mtu; @@ -3226,19 +3371,19 @@ } static void -__dldwd_set_multicast_list(struct net_device *dev) +__orinoco_set_multicast_list(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; - int promisc, allmulti, mc_count; + int promisc, mc_count; /* We'll wait until it's ready. Anyway, the network doesn't call us * here until we are open - Jean II */ - if (!priv->hw_ready) + /* FIXME: do we need this test at all? */ + if (! netif_device_present(dev)) return; - TRACE_ENTER(dev->name); DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n", @@ -3246,88 +3391,57 @@ /* The Hermes doesn't seem to have an allmulti mode, so we go * into promiscuous mode and let the upper levels deal. */ - if ( (dev->flags & IFF_PROMISC) ) { + if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > HERMES_MAX_MULTICAST) ) { promisc = 1; - allmulti = 0; mc_count = 0; - } else if ( (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > HERMES_MAX_MULTICAST) ) { - promisc = 0; - allmulti = 1; - mc_count = HERMES_MAX_MULTICAST; } else { promisc = 0; - allmulti = 0; mc_count = dev->mc_count; } - DEBUG(3, "promisc=%d mc_count=%d\n", - promisc, mc_count); - - if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS, + if (promisc != priv->promiscuous) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPROMISCUOUSMODE, promisc); if (err) { - printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n", - dev->name, err, promisc); + printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", + dev->name, err); } else priv->promiscuous = promisc; - } - if (allmulti) { - /* FIXME: This method of doing allmulticast reception - comes from the NetBSD driver. Haven't actually - tested whether it works or not. */ - hermes_multicast_t mclist; + mc_count = 0; + } - memset(&mclist, 0, sizeof(mclist)); - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - dev->name, err); - else - priv->allmulti = 1; - - } else if (mc_count || (! mc_count && priv->mc_count) ) { + if (mc_count || priv->mc_count) { struct dev_mc_list *p = dev->mc_list; hermes_multicast_t mclist; int i; for (i = 0; i < mc_count; i++) { - /* First some paranoid checks */ - if (! p) { - printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n", - dev->name); - break; - } - if (p->dmi_addrlen != ETH_ALEN) { - - printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n", - dev->name, p->dmi_addrlen); - break; - } - + /* Paranoia: */ + if (! p) + BUG(); /* Multicast list shorter than mc_count */ + if (p->dmi_addrlen != ETH_ALEN) + BUG(); /* Bad address size in multicast list */ + memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); p = p->next; } - + /* More paranoia */ - if (p) - printk(KERN_ERR "%s: Multicast list longer than mc_count.\n", - dev->name); - - priv->mc_count = i; - - DEBUG(3, "priv->mc_count = %d\n", priv->mc_count); - - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, + if (p != dev->mc_list) { + printk(KERN_ERR "Multicast list is longer than mc_count\n"); + } + + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), &mclist); if (err) printk(KERN_ERR "%s: Error %d setting multicast list.\n", dev->name, err); else - priv->allmulti = 0; + priv->mc_count = mc_count; } /* Since we can set the promiscuous flag when it wasn't asked @@ -3337,11 +3451,6 @@ else dev->flags &= ~IFF_PROMISC; - if (priv->allmulti) - dev->flags |= IFF_ALLMULTI; - else - dev->flags &= ~IFF_ALLMULTI; - TRACE_EXIT(dev->name); } @@ -3420,16 +3529,17 @@ } static int -dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset, +orinoco_proc_get_hermes_regs(char *page, char **start, off_t requested_offset, int requested_len, int *eof, void *data) { - dldwd_priv_t *dev = (dldwd_priv_t *)data; - hermes_t *hw = &dev->hw; + struct orinoco_private *priv = (struct orinoco_private *)data; + struct net_device *dev = &priv->ndev; + hermes_t *hw = &priv->hw; char *buf; int total = 0, slop = 0; /* Hum, in this case hardware register are probably not readable... */ - if (!dev->hw_ready) + if (! netif_device_present(dev)) return -ENODEV; buf = page; @@ -3478,57 +3588,130 @@ #define DISPLAY_WORDS 0 #define DISPLAY_BYTES 1 #define DISPLAY_STRING 2 +#define DISPLAY_XSTRING 3 } record_table[] = { -#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type } - RTCNFENTRY(PORTTYPE, DISPLAY_WORDS), - RTCNFENTRY(MACADDR, DISPLAY_BYTES), - RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING), - RTCNFENTRY(CHANNEL, DISPLAY_WORDS), - RTCNFENTRY(OWN_SSID, DISPLAY_STRING), - RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS), - RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS), - RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS), - RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS), - RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS), - RTCNFENTRY(NICKNAME, DISPLAY_STRING), - RTCNFENTRY(WEP_ON, DISPLAY_WORDS), - RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS), - RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES), - RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS), - RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS), - RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS), - RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS), - RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS), - RTCNFENTRY(KEYS, DISPLAY_BYTES), - RTCNFENTRY(TX_KEY, DISPLAY_WORDS), - RTCNFENTRY(TICKTIME, DISPLAY_WORDS), - RTCNFENTRY(INTERSIL_TX_KEY, DISPLAY_WORDS), - RTCNFENTRY(INTERSIL_KEY0, DISPLAY_BYTES), - RTCNFENTRY(INTERSIL_KEY1, DISPLAY_BYTES), - RTCNFENTRY(INTERSIL_KEY2, DISPLAY_BYTES), - RTCNFENTRY(INTERSIL_KEY3, DISPLAY_BYTES), - RTCNFENTRY(INTERSIL_WEP_ON, DISPLAY_WORDS), -#undef RTCNFENTRY -#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type } - RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS), - RTINFENTRY(STAIDENTITY, DISPLAY_WORDS), - RTINFENTRY(CURRENT_SSID, DISPLAY_STRING), - RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES), - RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS), - RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS), - RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS), - RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS), - RTINFENTRY(DATARATES, DISPLAY_BYTES), -#undef RTINFENTRY +#define CNF_WORDS(name) { HERMES_RID_CNF##name, #name, 0, LTV_BUF_SIZE, DISPLAY_WORDS } +#define CNF_BYTES(name) { HERMES_RID_CNF##name, #name, 0, LTV_BUF_SIZE, DISPLAY_BYTES } +#define CNF_STRING(name) { HERMES_RID_CNF##name, #name, 0, LTV_BUF_SIZE, DISPLAY_STRING } + CNF_WORDS(PORTTYPE), + CNF_BYTES(OWNMACADDR), + CNF_STRING(DESIREDSSID), + CNF_WORDS(OWNCHANNEL), + CNF_STRING(OWNSSID), + CNF_WORDS(OWNATIMWINDOW), + CNF_WORDS(SYSTEMSCALE), + CNF_WORDS(MAXDATALEN), + CNF_WORDS(PMENABLED), + CNF_WORDS(PMEPS), + CNF_WORDS(MULTICASTRECEIVE), + CNF_WORDS(MAXSLEEPDURATION), + CNF_WORDS(PMHOLDOVERDURATION), + CNF_STRING(OWNNAME), + CNF_WORDS(OWNDTIMPERIOD), + CNF_WORDS(MULTICASTPMBUFFERING), + CNF_WORDS(WEPENABLED_AGERE), + CNF_WORDS(MANDATORYBSSID_SYMBOL), + CNF_WORDS(WEPDEFAULTKEYID), + CNF_BYTES(DEFAULTKEY0), + CNF_BYTES(DEFAULTKEY1), + CNF_WORDS(MWOROBUST_AGERE), + CNF_BYTES(DEFAULTKEY2), + CNF_BYTES(DEFAULTKEY3), + CNF_WORDS(WEPFLAGS_INTERSIL), + CNF_WORDS(WEPKEYMAPPINGTABLE), + CNF_WORDS(AUTHENTICATION), + CNF_WORDS(MAXASSOCSTA), + CNF_WORDS(KEYLENGTH_SYMBOL), + CNF_WORDS(TXCONTROL), + CNF_WORDS(ROAMINGMODE), + CNF_WORDS(HOSTAUTHENTICATION), + CNF_WORDS(RCVCRCERROR), + CNF_WORDS(MMLIFE), + CNF_WORDS(ALTRETRYCOUNT), + CNF_WORDS(BEACONINT), + CNF_WORDS(APPCFINFO), + CNF_WORDS(STAPCFINFO), + CNF_WORDS(PRIORITYQUSAGE), + CNF_WORDS(TIMCTRL), + CNF_WORDS(THIRTY2TALLY), + CNF_WORDS(ENHSECURITY), + CNF_BYTES(GROUPADDRESSES), + CNF_WORDS(CREATEIBSS), + CNF_WORDS(FRAGMENTATIONTHRESHOLD), + CNF_WORDS(RTSTHRESHOLD), + CNF_WORDS(TXRATECONTROL), + CNF_WORDS(PROMISCUOUSMODE), + CNF_WORDS(BASICRATES_SYMBOL), + CNF_WORDS(PREAMBLE_SYMBOL), + CNF_WORDS(SHORTPREAMBLE), + CNF_BYTES(WEPKEYS_AGERE), + CNF_WORDS(EXCLUDELONGPREAMBLE), + CNF_WORDS(TXKEY_AGERE), + CNF_WORDS(AUTHENTICATIONRSPTO), + CNF_WORDS(BASICRATES), + CNF_WORDS(SUPPORTEDRATES), + CNF_WORDS(TICKTIME), + CNF_WORDS(SCANREQUEST), + CNF_WORDS(JOINREQUEST), + CNF_WORDS(AUTHENTICATESTATION), + CNF_WORDS(CHANNELINFOREQUEST), +#undef CNF_WORDS +#undef CNF_BYTES +#undef CNF_STRING +#define INF_WORDS(name) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, DISPLAY_WORDS } +#define INF_BYTES(name) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, DISPLAY_BYTES } +#define INF_STRING(name) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, DISPLAY_STRING } +#define INF_XSTRING(name) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, DISPLAY_XSTRING } + INF_WORDS(MAXLOADTIME), + INF_WORDS(DOWNLOADBUFFER), + INF_WORDS(PRIID), + INF_WORDS(PRISUPRANGE), + INF_WORDS(CFIACTRANGES), + INF_WORDS(NICSERNUM), + INF_WORDS(NICID), + INF_WORDS(MFISUPRANGE), + INF_WORDS(CFISUPRANGE), + INF_WORDS(CHANNELLIST), + INF_WORDS(REGULATORYDOMAINS), + INF_WORDS(TEMPTYPE), +/* INF_BYTES(CIS), */ + INF_WORDS(STAID), + INF_STRING(CURRENTSSID), + INF_BYTES(CURRENTBSSID), + INF_WORDS(COMMSQUALITY), + INF_WORDS(CURRENTTXRATE), + INF_WORDS(CURRENTBEACONINTERVAL), + INF_WORDS(CURRENTSCALETHRESHOLDS), + INF_WORDS(PROTOCOLRSPTIME), + INF_WORDS(SHORTRETRYLIMIT), + INF_WORDS(LONGRETRYLIMIT), + INF_WORDS(MAXTRANSMITLIFETIME), + INF_WORDS(MAXRECEIVELIFETIME), + INF_WORDS(CFPOLLABLE), + INF_WORDS(AUTHENTICATIONALGORITHMS), + INF_WORDS(PRIVACYOPTIONIMPLEMENTED), + INF_BYTES(OWNMACADDR), + INF_WORDS(SCANRESULTSTABLE), + INF_WORDS(PHYTYPE), + INF_WORDS(CURRENTCHANNEL), + INF_WORDS(CURRENTPOWERSTATE), + INF_WORDS(CCAMODE), + INF_WORDS(SUPPORTEDDATARATES), + INF_BYTES(BUILDSEQ), + INF_XSTRING(FWID) +#undef INF_WORDS +#undef INF_BYTES +#undef INF_STRING }; #define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) static int -dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, +orinoco_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, int requested_len, int *eof, void *data) { - dldwd_priv_t *dev = (dldwd_priv_t *)data; - hermes_t *hw = &dev->hw; + struct orinoco_private *priv = (struct orinoco_private *)data; + struct net_device *dev = &priv->ndev; + hermes_t *hw = &priv->hw; char *buf; int total = 0, slop = 0; int i; @@ -3536,7 +3719,7 @@ int err; /* Hum, in this case hardware register are probably not readable... */ - if (!dev->hw_ready) + if (! netif_device_present(dev)) return -ENODEV; buf = page; @@ -3554,6 +3737,7 @@ val8 = kmalloc(maxlen + 2, GFP_KERNEL); if (! val8) return -ENOMEM; + memset(val8, 0, maxlen + 2); err = hermes_read_ltv(hw, USER_BAP, rid, maxlen, &length, val8); @@ -3562,6 +3746,8 @@ continue; } val16 = (u16 *)val8; + if (length == 0) + continue; buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, rid, length, (length-1)*2); @@ -3588,6 +3774,9 @@ val8[len] = '\0'; buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); break; + case DISPLAY_XSTRING: + + buf += sprintf(buf, "'%s'", (char *)val8); } buf += sprintf(buf, "\n"); @@ -3609,65 +3798,67 @@ /* initialise the /proc subsystem for the hermes driver, creating the * separate entries */ static int -dldwd_proc_init(void) +orinoco_proc_init(void) { int err = 0; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); /* create the directory for it to sit in */ dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root); if (dir_base == NULL) { printk(KERN_ERR "Unable to initialise /proc/hermes.\n"); - dldwd_proc_cleanup(); + orinoco_proc_cleanup(); err = -ENOMEM; } - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return err; } int -dldwd_proc_dev_init(dldwd_priv_t *dev) +orinoco_proc_dev_init(struct orinoco_private *priv) { - struct net_device *ndev = &dev->ndev; + struct net_device *dev = &priv->ndev; - dev->dir_dev = NULL; + priv->dir_dev = NULL; /* create the directory for it to sit in */ - dev->dir_dev = create_proc_entry(ndev->name, S_IFDIR | S_IRUGO | S_IXUGO, - dir_base); - if (dev->dir_dev == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", ndev->name); + priv->dir_dev = create_proc_entry(dev->name, S_IFDIR | S_IRUGO | S_IXUGO, + dir_base); + if (priv->dir_dev == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", dev->name); goto fail; } - dev->dir_regs = NULL; - dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO, - dev->dir_dev, dldwd_proc_get_hermes_regs, dev); - if (dev->dir_regs == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n", ndev->name); + priv->dir_regs = NULL; + priv->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO, + priv->dir_dev, orinoco_proc_get_hermes_regs, priv); + if (priv->dir_regs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n", dev->name); goto fail; } - dev->dir_recs = NULL; - dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO, - dev->dir_dev, dldwd_proc_get_hermes_recs, dev); - if (dev->dir_recs == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", ndev->name); + priv->dir_recs = NULL; + priv->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO, + priv->dir_dev, orinoco_proc_get_hermes_recs, priv); + if (priv->dir_recs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", dev->name); goto fail; } return 0; fail: - dldwd_proc_dev_cleanup(dev); + orinoco_proc_dev_cleanup(priv); return -ENOMEM; } void -dldwd_proc_dev_cleanup(dldwd_priv_t *priv) +orinoco_proc_dev_cleanup(struct orinoco_private *priv) { - struct net_device *ndev = &priv->ndev; + struct net_device *dev = &priv->ndev; + + TRACE_ENTER(priv->ndev.name); if (priv->dir_regs) { remove_proc_entry("regs", priv->dir_dev); @@ -3678,26 +3869,28 @@ priv->dir_recs = NULL; } if (priv->dir_dev) { - remove_proc_entry(ndev->name, dir_base); + remove_proc_entry(dev->name, dir_base); priv->dir_dev = NULL; } + + TRACE_EXIT(priv->ndev.name); } static void -dldwd_proc_cleanup(void) +orinoco_proc_cleanup(void) { - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); if (dir_base) { remove_proc_entry("hermes", &proc_root); dir_base = NULL; } - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); } int -dldwd_setup(dldwd_priv_t* priv) +orinoco_setup(struct orinoco_private* priv) { struct net_device *dev = &priv->ndev;; @@ -3709,20 +3902,20 @@ /* Setup up default routines */ priv->card_reset_handler = NULL; /* Caller may override */ - dev->init = dldwd_init; + dev->init = orinoco_init; dev->open = NULL; /* Caller *must* override */ dev->stop = NULL; - dev->hard_start_xmit = dldwd_xmit; - dev->tx_timeout = dldwd_tx_timeout; - dev->watchdog_timeo = HZ; /* 4 second timeout */ + dev->hard_start_xmit = orinoco_xmit; + dev->tx_timeout = orinoco_tx_timeout; + dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->get_stats = dldwd_get_stats; - dev->get_wireless_stats = dldwd_get_wireless_stats; + dev->get_stats = orinoco_get_stats; + dev->get_wireless_stats = orinoco_get_wireless_stats; - dev->do_ioctl = dldwd_ioctl; + dev->do_ioctl = orinoco_ioctl; - dev->change_mtu = dldwd_change_mtu; - dev->set_multicast_list = dldwd_set_multicast_list; + dev->change_mtu = orinoco_change_mtu; + dev->set_multicast_list = orinoco_set_multicast_list; netif_stop_queue(dev); @@ -3730,36 +3923,31 @@ } #ifdef ORINOCO_DEBUG -EXPORT_SYMBOL(dldwd_debug); +EXPORT_SYMBOL(orinoco_debug); #endif -EXPORT_SYMBOL(dldwd_init); -EXPORT_SYMBOL(dldwd_xmit); -EXPORT_SYMBOL(dldwd_tx_timeout); -EXPORT_SYMBOL(dldwd_ioctl); -EXPORT_SYMBOL(dldwd_change_mtu); -EXPORT_SYMBOL(dldwd_set_multicast_list); -EXPORT_SYMBOL(dldwd_shutdown); -EXPORT_SYMBOL(dldwd_reset); -EXPORT_SYMBOL(dldwd_setup); -EXPORT_SYMBOL(dldwd_proc_dev_init); -EXPORT_SYMBOL(dldwd_proc_dev_cleanup); -EXPORT_SYMBOL(dldwd_interrupt); +EXPORT_SYMBOL(orinoco_init); +EXPORT_SYMBOL(orinoco_xmit); +EXPORT_SYMBOL(orinoco_tx_timeout); +EXPORT_SYMBOL(orinoco_ioctl); +EXPORT_SYMBOL(orinoco_change_mtu); +EXPORT_SYMBOL(orinoco_set_multicast_list); +EXPORT_SYMBOL(orinoco_shutdown); +EXPORT_SYMBOL(orinoco_reset); +EXPORT_SYMBOL(orinoco_setup); +EXPORT_SYMBOL(orinoco_proc_dev_init); +EXPORT_SYMBOL(orinoco_proc_dev_cleanup); +EXPORT_SYMBOL(orinoco_interrupt); -static int __init init_dldwd(void) +static int __init init_orinoco(void) { - int err; - - err = dldwd_proc_init(); - printk(KERN_DEBUG "%s\n", version); - - return 0; + return orinoco_proc_init(); } -static void __exit exit_dldwd(void) +static void __exit exit_orinoco(void) { - dldwd_proc_cleanup(); + orinoco_proc_cleanup(); } -module_init(init_dldwd); -module_exit(exit_dldwd); +module_init(init_orinoco); +module_exit(exit_orinoco); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/orinoco.h linux-2.5/drivers/net/wireless/orinoco.h --- linux-2.5.1/drivers/net/wireless/orinoco.h Tue Oct 9 22:13:03 2001 +++ linux-2.5/drivers/net/wireless/orinoco.h Thu Jan 10 22:41:07 2002 @@ -8,50 +8,34 @@ #define _ORINOCO_H /* To enable debug messages */ -/* #define ORINOCO_DEBUG 3 */ +// #define ORINOCO_DEBUG 3 #if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) -#error "orinoco_cs requires Wireless extensions v10 or later." +#error "orinoco driver requires Wireless extensions v10 or later." #endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ #define WIRELESS_SPY // enable iwspy support +#define ORINOCO_MAX_KEY_SIZE 14 +#define ORINOCO_MAX_KEYS 4 -#define DLDWD_MIN_MTU 256 -#define DLDWD_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) +typedef struct orinoco_key { + u16 len; /* always store little-endian */ + char data[ORINOCO_MAX_KEY_SIZE]; +} __attribute__ ((packed)) orinoco_key_t; -#define LTV_BUF_SIZE 128 -#define USER_BAP 0 -#define IRQ_BAP 1 -#define DLDWD_MACPORT 0 -#define IRQ_LOOP_MAX 10 -#define TX_NICBUF_SIZE 2048 -#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ -#define MAX_KEYS 4 -#define MAX_KEY_SIZE 14 -#define LARGE_KEY_SIZE 13 -#define SMALL_KEY_SIZE 5 -#define MAX_FRAME_SIZE 2304 - -typedef struct dldwd_key { - uint16_t len; /* always store little-endian */ - char data[MAX_KEY_SIZE]; -} __attribute__ ((packed)) dldwd_key_t; - -typedef dldwd_key_t dldwd_keys_t[MAX_KEYS]; +typedef orinoco_key_t orinoco_keys_t[ORINOCO_MAX_KEYS]; /*====================================================================*/ - -typedef struct dldwd_priv { +struct orinoco_private { void* card; /* Pointer to card dependant structure */ /* card dependant extra reset code (i.e. bus/interface specific */ - int (*card_reset_handler)(struct dldwd_priv *); + int (*card_reset_handler)(struct orinoco_private *); spinlock_t lock; long state; -#define DLDWD_STATE_INIRQ 0 -#define DLDWD_STATE_DOIRQ 1 - int hw_ready; /* HW may be suspended by platform */ +#define ORINOCO_STATE_INIRQ 0 +#define ORINOCO_STATE_DOIRQ 1 /* Net device stuff */ struct net_device ndev; @@ -61,11 +45,11 @@ /* Hardware control variables */ hermes_t hw; - uint16_t txfid; + u16 txfid; /* Capabilities of the hardware/firmware */ int firmware_type; -#define FIRMWARE_TYPE_LUCENT 1 +#define FIRMWARE_TYPE_AGERE 1 #define FIRMWARE_TYPE_INTERSIL 2 #define FIRMWARE_TYPE_SYMBOL 3 int has_ibss, has_port3, prefer_port3, has_ibss_any, ibss_port; @@ -74,23 +58,26 @@ int has_pm; int has_preamble; int need_card_reset, broken_reset, broken_allocate; - uint16_t channel_mask; + u16 channel_mask; /* Current configuration */ - uint32_t iw_mode; + u32 iw_mode; int port_type, allow_ibss; - uint16_t wep_on, wep_restrict, tx_key; - dldwd_keys_t keys; + + u16 wep_on, wep_restrict, tx_key; + orinoco_keys_t keys; + + int bitratemode; + char nick[IW_ESSID_MAX_SIZE+1]; char desired_essid[IW_ESSID_MAX_SIZE+1]; - uint16_t frag_thresh, mwo_robust; - uint16_t channel; - uint16_t ap_density, rts_thresh; - uint16_t tx_rate_ctrl; - uint16_t pm_on, pm_mcast, pm_period, pm_timeout; - uint16_t preamble; + u16 frag_thresh, mwo_robust; + u16 channel; + u16 ap_density, rts_thresh; + u16 pm_on, pm_mcast, pm_period, pm_timeout; + u16 preamble; - int promiscuous, allmulti, mc_count; + int promiscuous, mc_count; #ifdef WIRELESS_SPY int spy_number; @@ -102,16 +89,16 @@ struct proc_dir_entry *dir_dev; struct proc_dir_entry *dir_regs; struct proc_dir_entry *dir_recs; -} dldwd_priv_t; +}; /*====================================================================*/ -extern struct list_head dldwd_instances; +extern struct list_head orinoco_instances; #ifdef ORINOCO_DEBUG -extern int dldwd_debug; -#define DEBUG(n, args...) do { if (dldwd_debug>(n)) printk(KERN_DEBUG args); } while(0) -#define DEBUGMORE(n, args...) do { if (dldwd_debug>(n)) printk(args); } while (0) +extern int orinoco_debug; +#define DEBUG(n, args...) do { if (orinoco_debug>(n)) printk(KERN_DEBUG args); } while(0) +#define DEBUGMORE(n, args...) do { if (orinoco_debug>(n)) printk(args); } while (0) #else #define DEBUG(n, args...) do { } while (0) #define DEBUGMORE(n, args...) do { } while (0) @@ -123,20 +110,20 @@ #define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) /* struct net_device methods */ -extern int dldwd_init(struct net_device *dev); -extern int dldwd_xmit(struct sk_buff *skb, struct net_device *dev); -extern void dldwd_tx_timeout(struct net_device *dev); - -extern int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -extern int dldwd_change_mtu(struct net_device *dev, int new_mtu); -extern void dldwd_set_multicast_list(struct net_device *dev); +extern int orinoco_init(struct net_device *dev); +extern int orinoco_xmit(struct sk_buff *skb, struct net_device *dev); +extern void orinoco_tx_timeout(struct net_device *dev); + +extern int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +extern int orinoco_change_mtu(struct net_device *dev, int new_mtu); +extern void orinoco_set_multicast_list(struct net_device *dev); /* utility routines */ -extern void dldwd_shutdown(dldwd_priv_t *dev); -extern int dldwd_reset(dldwd_priv_t *dev); -extern int dldwd_setup(dldwd_priv_t* priv); -extern int dldwd_proc_dev_init(dldwd_priv_t *dev); -extern void dldwd_proc_dev_cleanup(dldwd_priv_t *priv); -extern void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs); +extern void orinoco_shutdown(struct orinoco_private *dev); +extern int orinoco_reset(struct orinoco_private *dev); +extern int orinoco_setup(struct orinoco_private* priv); +extern int orinoco_proc_dev_init(struct orinoco_private *dev); +extern void orinoco_proc_dev_cleanup(struct orinoco_private *priv); +extern void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs); -#endif +#endif /* _ORINOCO_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/orinoco_cs.c linux-2.5/drivers/net/wireless/orinoco_cs.c --- linux-2.5.1/drivers/net/wireless/orinoco_cs.c Tue Oct 9 22:13:03 2001 +++ linux-2.5/drivers/net/wireless/orinoco_cs.c Thu Jan 10 22:41:07 2002 @@ -1,4 +1,4 @@ -/* orinoco_cs.c 0.08a - (formerly known as dldwd_cs.c) +/* orinoco_cs.c 0.09 - (formerly known as dldwd_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -44,7 +44,7 @@ /*====================================================================*/ -static char version[] __initdata = "orinoco_cs.c 0.08a (David Gibson <hermes@gibson.dropbear.id.au> and others)"; +static char version[] __initdata = "orinoco_cs.c 0.09 (David Gibson <hermes@gibson.dropbear.id.au> and others)"; MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>"); MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards"); @@ -68,33 +68,31 @@ MODULE_PARM(reset_cor, "i"); MODULE_PARM(ignore_cis_vcc, "i"); - /* Pcmcia specific structure */ -typedef struct dldwd_card { +struct orinoco_pccard { dev_link_t link; dev_node_t node; - int instance; /* Common structure (fully included), see orinoco.h */ - struct dldwd_priv priv; -} dldwd_card_t; + struct orinoco_private priv; +}; /* * Function prototypes */ /* struct net_device methods */ -static int dldwd_cs_open(struct net_device *dev); -static int dldwd_cs_stop(struct net_device *dev); +static int orinoco_cs_open(struct net_device *dev); +static int orinoco_cs_stop(struct net_device *dev); /* PCMCIA gumpf */ -static void dldwd_cs_config(dev_link_t * link); -static void dldwd_cs_release(u_long arg); -static int dldwd_cs_event(event_t event, int priority, +static void orinoco_cs_config(dev_link_t * link); +static void orinoco_cs_release(u_long arg); +static int orinoco_cs_event(event_t event, int priority, event_callback_args_t * args); -static dev_link_t *dldwd_cs_attach(void); -static void dldwd_cs_detach(dev_link_t *); +static dev_link_t *orinoco_cs_attach(void); +static void orinoco_cs_detach(dev_link_t *); /* The dev_info variable is the "key" that is used to match up this @@ -115,7 +113,6 @@ */ static dev_link_t *dev_list; /* = NULL */ -static int num_instances; /* = 0 */ /*====================================================================*/ @@ -127,10 +124,10 @@ } static int -dldwd_cs_open(struct net_device *dev) +orinoco_cs_open(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card; dev_link_t *link = &card->link; int err; @@ -139,9 +136,9 @@ link->open++; netif_device_attach(dev); - err = dldwd_reset(priv); + err = orinoco_reset(priv); if (err) - dldwd_cs_stop(dev); + orinoco_cs_stop(dev); else netif_start_queue(dev); @@ -151,17 +148,17 @@ } static int -dldwd_cs_stop(struct net_device *dev) +orinoco_cs_stop(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card; dev_link_t *link = &card->link; TRACE_ENTER(priv->ndev.name); netif_stop_queue(dev); - dldwd_shutdown(priv); + orinoco_shutdown(priv); link->open--; @@ -179,9 +176,9 @@ * In fact, this seem necessary for Spectrum cards... */ static int -dldwd_cs_cor_reset(dldwd_priv_t *priv) +orinoco_cs_cor_reset(struct orinoco_private *priv) { - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card; dev_link_t *link = &card->link; conf_reg_t reg; u_int default_cor; @@ -189,8 +186,8 @@ TRACE_ENTER(priv->ndev.name); /* Doing it if hardware is gone is guaranteed crash */ - if(!priv->hw_ready) - return(0); + if(! (link->state & DEV_CONFIG) ) + return -ENODEV; /* Save original COR value */ reg.Function = 0; @@ -200,7 +197,7 @@ CardServices(AccessConfigurationRegister, link->handle, ®); default_cor = reg.Value; - DEBUG(2, "dldwd : dldwd_cs_cor_reset() : cor=0x%X\n", default_cor); + DEBUG(2, "orinoco : orinoco_cs_cor_reset() : cor=0x%X\n", default_cor); /* Soft-Reset card */ reg.Action = CS_WRITE; @@ -209,6 +206,7 @@ CardServices(AccessConfigurationRegister, link->handle, ®); /* Wait until the card has acknowledged our reset */ + /* FIXME: mdelay() is deprecated -dgibson */ mdelay(1); /* Restore original COR configuration index */ @@ -216,11 +214,12 @@ CardServices(AccessConfigurationRegister, link->handle, ®); /* Wait until the card has finished restarting */ + /* FIXME: mdelay() is deprecated -dgibson */ mdelay(1); TRACE_EXIT(priv->ndev.name); - return(0); + return 0; } /* Remove zombie instances (card removed, detach pending) */ @@ -228,17 +227,17 @@ flush_stale_links(void) { dev_link_t *link, *next; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); for (link = dev_list; link; link = next) { next = link->next; if (link->state & DEV_STALE_LINK) - dldwd_cs_detach(link); + orinoco_cs_detach(link); } - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); } /*====================================================================== - dldwd_cs_attach() creates an "instance" of the driver, allocating + orinoco_cs_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services. @@ -248,16 +247,16 @@ ======================================================================*/ static dev_link_t * -dldwd_cs_attach(void) +orinoco_cs_attach(void) { - dldwd_card_t *card; - dldwd_priv_t *priv; + struct orinoco_pccard *card; + struct orinoco_private *priv; dev_link_t *link; struct net_device *ndev; client_reg_t client_reg; int ret, i; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); /* A bit of cleanup */ flush_stale_links(); @@ -272,13 +271,12 @@ /* Link both structure together */ priv = &(card->priv); priv->card = card; - card->instance = num_instances++; /* FIXME: Racy? */ link = &card->link; ndev = &priv->ndev; link->priv = priv; /* Initialize the dev_link_t structure */ - link->release.function = &dldwd_cs_release; + link->release.function = &orinoco_cs_release; link->release.data = (u_long) link; /* Interrupt setup */ @@ -302,15 +300,15 @@ link->conf.IntType = INT_MEMORY_AND_IO; /* Setup the common part */ - if(dldwd_setup(priv) < 0) { + if(orinoco_setup(priv) < 0) { kfree(card); return NULL; } /* Overrides */ - ndev->open = dldwd_cs_open; - ndev->stop = dldwd_cs_stop; - priv->card_reset_handler = dldwd_cs_cor_reset; + ndev->open = orinoco_cs_open; + ndev->stop = orinoco_cs_stop; + priv->card_reset_handler = orinoco_cs_cor_reset; /* Register with Card Services */ link->next = dev_list; @@ -321,21 +319,21 @@ 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 = &dldwd_cs_event; + client_reg.event_handler = &orinoco_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); - dldwd_cs_detach(link); + orinoco_cs_detach(link); link = NULL; goto out; } out: - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return link; -} /* dldwd_cs_attach */ +} /* orinoco_cs_attach */ /*====================================================================== This deletes a driver "instance". The device is de-registered @@ -345,12 +343,12 @@ ======================================================================*/ static void -dldwd_cs_detach(dev_link_t * link) +orinoco_cs_detach(dev_link_t * link) { dev_link_t **linkp; - dldwd_priv_t *priv = link->priv; + struct orinoco_private *priv = link->priv; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) @@ -388,14 +386,12 @@ } kfree(priv->card); - num_instances--; /* FIXME: Racy? */ - out: - TRACE_EXIT("dldwd"); -} /* dldwd_cs_detach */ + TRACE_EXIT("orinoco"); +} /* orinoco_cs_detach */ /*====================================================================== - dldwd_cs_config() is scheduled to run after a CARD_INSERTION event + orinoco_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. ======================================================================*/ @@ -407,11 +403,11 @@ if (CardServices(fn, args) != 0) goto next_entry static void -dldwd_cs_config(dev_link_t * link) +orinoco_cs_config(dev_link_t * link) { client_handle_t handle = link->handle; - dldwd_priv_t *priv = link->priv; - dldwd_card_t *card = (dldwd_card_t *)priv->card; + struct orinoco_private *priv = link->priv; + struct orinoco_pccard *card = (struct orinoco_pccard *)priv->card; hermes_t *hw = &priv->hw; struct net_device *ndev = &priv->ndev; tuple_t tuple; @@ -422,7 +418,7 @@ cistpl_cftable_entry_t dflt = { 0 }; cisinfo_t info; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); CS_CHECK(ValidateCIS, handle, &info); @@ -448,7 +444,7 @@ CS_CHECK(GetConfigurationInfo, handle, &conf); link->conf.Vcc = conf.Vcc; - DEBUG(0, "dldwd_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", + DEBUG(0, "orinoco_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", link->conf.ConfigBase, link->conf.Vcc); /* @@ -470,7 +466,7 @@ CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); - DEBUG(0, "dldwd_cs_config: index = 0x%x, flags = 0x%x\n", + DEBUG(0, "orinoco_cs_config: index = 0x%x, flags = 0x%x\n", cfg->index, cfg->flags); if (cfg->flags & CISTPL_CFTABLE_DEFAULT) @@ -490,14 +486,14 @@ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if(!ignore_cis_vcc) goto next_entry; } } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); if(!ignore_cis_vcc) goto next_entry; } @@ -510,7 +506,7 @@ link->conf.Vpp1 = link->conf.Vpp2 = dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - DEBUG(0, "dldwd_cs_config: We seem to have configured Vcc and Vpp\n"); + DEBUG(0, "orinoco_cs_config: We seem to have configured Vcc and Vpp\n"); /* Do we need to allocate an interrupt? */ if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) @@ -570,7 +566,7 @@ for (i=0; i<4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; - link->irq.Handler = dldwd_interrupt; + link->irq.Handler = orinoco_interrupt; link->irq.Instance = priv; CS_CHECK(RequestIRQ, link->handle, &link->irq); @@ -591,6 +587,12 @@ ndev->base_addr = link->io.BasePort1; ndev->irq = link->irq.AssignedIRQ; + /* Now do a PCMCIA soft reset on the card, to make sure its in + a sane state */ + /* Optional because it really mess up old Lucent firmwares - Jean II */ + if (reset_cor) + orinoco_cs_cor_reset(priv); + /* register_netdev will give us an ethX name */ ndev->name[0] = '\0'; /* Tell the stack we exist */ @@ -618,7 +620,7 @@ printk("\n"); /* And give us the proc nodes for debugging */ - if (dldwd_proc_dev_init(priv) != 0) { + if (orinoco_proc_dev_init(priv) != 0) { printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", ndev->name); goto failed; @@ -627,12 +629,9 @@ /* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */ SET_MODULE_OWNER(ndev); - /* Allow cor_reset, /proc & ioctls to act */ - priv->hw_ready = 1; - /* Do a Pcmcia soft reset of the card (optional) */ - if(reset_cor) - dldwd_cs_cor_reset(priv); + if (reset_cor) + orinoco_cs_cor_reset(priv); /* At this point, the dev_node_t structure(s) need to be @@ -642,29 +641,29 @@ link->dev = &card->node; link->state &= ~DEV_CONFIG_PENDING; - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return; cs_failed: cs_error(link->handle, last_fn, last_ret); failed: - dldwd_cs_release((u_long) link); + orinoco_cs_release((u_long) link); - TRACE_EXIT("dldwd"); -} /* dldwd_cs_config */ + TRACE_EXIT("orinoco"); +} /* orinoco_cs_config */ /*====================================================================== - After a card is removed, dldwd_cs_release() will unregister the + After a card is removed, orinoco_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. ======================================================================*/ static void -dldwd_cs_release(u_long arg) +orinoco_cs_release(u_long arg) { dev_link_t *link = (dev_link_t *) arg; - dldwd_priv_t *priv = link->priv; + struct orinoco_private *priv = link->priv; TRACE_ENTER(link->dev->dev_name); @@ -681,7 +680,7 @@ } /* Unregister proc entry */ - dldwd_proc_dev_cleanup(priv); + orinoco_proc_dev_cleanup(priv); /* Don't bother checking to see if these succeed or not */ CardServices(ReleaseConfiguration, link->handle); @@ -692,7 +691,7 @@ link->state &= ~DEV_CONFIG; TRACE_EXIT(link->dev->dev_name); -} /* dldwd_cs_release */ +} /* orinoco_cs_release */ /*====================================================================== The card status event handler. Mostly, this schedules other @@ -705,39 +704,37 @@ ======================================================================*/ static int -dldwd_cs_event(event_t event, int priority, +orinoco_cs_event(event_t event, int priority, event_callback_args_t * args) { dev_link_t *link = args->client_data; - dldwd_priv_t *priv = (dldwd_priv_t *)link->priv; + struct orinoco_private *priv = (struct orinoco_private *)link->priv; struct net_device *dev = &priv->ndev; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); switch (event) { case CS_EVENT_CARD_REMOVAL: - /* FIXME: Erg.. this whole hw_ready thing looks racy - to me. this may not be fixable without changin the - PCMCIA subsystem, though */ - priv->hw_ready = 0; - dldwd_shutdown(priv); link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { netif_stop_queue(dev); + } + orinoco_shutdown(priv); + if (link->state & DEV_CONFIG) { netif_device_detach(dev); mod_timer(&link->release, jiffies + HZ / 20); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - dldwd_cs_config(link); + orinoco_cs_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: - dldwd_shutdown(priv); + orinoco_shutdown(priv); /* Mark the device as stopped, to block IO until later */ if (link->state & DEV_CONFIG) { @@ -757,13 +754,13 @@ &link->conf); if (link->open) { - if (dldwd_reset(priv) == 0) { + if (orinoco_reset(priv) == 0) { netif_device_attach(dev); netif_start_queue(dev); } else { printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n", dev->name); - dldwd_cs_stop(dev); + orinoco_cs_stop(dev); } } } @@ -774,17 +771,17 @@ break; } - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return 0; -} /* dldwd_cs_event */ +} /* orinoco_cs_event */ static int __init -init_dldwd_cs(void) +init_orinoco_cs(void) { servinfo_t serv; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); printk(KERN_DEBUG "%s\n", version); @@ -795,17 +792,17 @@ return -1; } - register_pccard_driver(&dev_info, &dldwd_cs_attach, &dldwd_cs_detach); + register_pccard_driver(&dev_info, &orinoco_cs_attach, &orinoco_cs_detach); - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return 0; } static void __exit -exit_dldwd_cs(void) +exit_orinoco_cs(void) { - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); unregister_pccard_driver(&dev_info); @@ -814,12 +811,12 @@ while (dev_list != NULL) { del_timer(&dev_list->release); if (dev_list->state & DEV_CONFIG) - dldwd_cs_release((u_long) dev_list); - dldwd_cs_detach(dev_list); + orinoco_cs_release((u_long) dev_list); + orinoco_cs_detach(dev_list); } - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); } -module_init(init_dldwd_cs); -module_exit(exit_dldwd_cs); +module_init(init_orinoco_cs); +module_exit(exit_orinoco_cs); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/wireless/orinoco_plx.c linux-2.5/drivers/net/wireless/orinoco_plx.c --- linux-2.5.1/drivers/net/wireless/orinoco_plx.c Tue Oct 9 22:13:03 2001 +++ linux-2.5/drivers/net/wireless/orinoco_plx.c Thu Jan 10 22:41:07 2002 @@ -1,16 +1,8 @@ -/* orinoco_plx.c 0.01 +/* orinoco_plx.c 0.09 * * Driver for Prism II devices which would usually be driven by orinoco_cs, * but are connected to the PCI bus by a PLX9052. * - * Specifically here we're talking about the SMC2602W (EZConnect - * Wireless PCI Adaptor) - * - * The actual driving is done by orinoco.c, this is just resource - * allocation stuff. The explanation below is courtesy of Ryan Niemi - * on the linux-wlan-ng list at - * http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html - * * Copyright (C) 2001 Daniel Barlow <dan@telent.net> * * The contents of this file are subject to the Mozilla Public License @@ -34,6 +26,22 @@ * provisions above, a recipient may use your version of this file * under either the MPL or the GPL. + * Caution: this is experimental and probably buggy. For success and + * failure reports for different cards and adaptors, see + * orinoco_plx_pci_id_table near the end of the file. If you have a + * card we don't have the PCI id for, and looks like it should work, + * drop me mail with the id and "it works"/"it doesn't work". + * + * Note: if everything gets detected fine but it doesn't actually send + * or receive packets, your first port of call should probably be to + * try newer firmware in the card. Especially if you're doing Ad-Hoc + * modes + * + * The actual driving is done by orinoco.c, this is just resource + * allocation stuff. The explanation below is courtesy of Ryan Niemi + * on the linux-wlan-ng list at + * http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html + The PLX9052-based cards (WL11000 and several others) are a different beast than the usual PCMCIA-based PRISM2 configuration expected by wlan-ng. Here's the general details on how the WL11000 PCI adapter @@ -95,14 +103,6 @@ not have time for a while.. ---end of mail--- - - Bus 0, device 4, function 0: - Network controller: Unknown vendor Unknown device (rev 2). - Vendor id=1638. Device id=1100. - Medium devsel. Fast back-to-back capable. IRQ 10. - I/O at 0x1000 [0x1001]. - Non-prefetchable 32 bit memory at 0x40000000 [0x40000000]. - I/O at 0x10c0 [0x10c1]. */ #include <linux/config.h> @@ -140,25 +140,31 @@ #include "hermes.h" #include "orinoco.h" +static char version[] __initdata = "orinoco_plx.c 0.09 (Daniel Barlow <dan@telent.net>)"; MODULE_AUTHOR("Daniel Barlow <dan@telent.net>"); MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); MODULE_LICENSE("Dual MPL/GPL"); + + static dev_info_t dev_info = "orinoco_plx"; -#define COR_OFFSET 0x3e0 /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE 0x41 /* Enable PC card with interrupt in level trigger */ +#define COR_OFFSET (0x3e0 / 2) /* COR attribute offset of Prism2 PC card */ +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ + +#define PLX_INTCSR 0x4c /* Interrupt Control and Status Register */ +#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ static int orinoco_plx_open(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *) dev->priv; + struct orinoco_private *priv = (struct orinoco_private *) dev->priv; int err; netif_device_attach(dev); - err = dldwd_reset(priv); + err = orinoco_reset(priv); if (err) - printk(KERN_ERR "%s: dldwd_reset failed in orinoco_plx_open()", + printk(KERN_ERR "%s: orinoco_reset failed in orinoco_plx_open()", dev->name); else netif_start_queue(dev); @@ -168,108 +174,217 @@ static int orinoco_plx_stop(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *) dev->priv; + struct orinoco_private *priv = (struct orinoco_private *) dev->priv; netif_stop_queue(dev); - dldwd_shutdown(priv); + orinoco_shutdown(priv); return 0; } static void orinoco_plx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - dldwd_interrupt(irq, ((struct net_device *) dev_id)->priv, regs); + orinoco_interrupt(irq, (struct orinoco_private *)dev_id, regs); } +static const u16 cis_magic[] = { + 0x0001, 0x0003, 0x0000, 0x0000, 0x00ff, 0x0017, 0x0004, 0x0067 +}; + static int orinoco_plx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev; - unsigned long pccard_ioaddr; + int err = 0; + u16 *attr_mem = NULL; + u32 reg, addr; + struct orinoco_private *priv = NULL; + unsigned long pccard_ioaddr = 0; + unsigned long pccard_iolen = 0; + struct net_device *dev = NULL; + int netdev_registered = 0; int i; - int reg; - unsigned char *attr_mem; - dldwd_priv_t *priv; - if ((i = pci_enable_device(pdev))) + TRACE_ENTER("orinoco_plx"); + + err = pci_enable_device(pdev); + if (err) return -EIO; /* Resource 2 is mapped to the PCMCIA space */ - attr_mem = ioremap(pci_resource_start(pdev, 2), 0x1000); - /* and 3 to the PCMCIA slot I/O address space */ - pccard_ioaddr = pci_resource_start(pdev, 3); + attr_mem = ioremap(pci_resource_start(pdev, 2), PAGE_SIZE); + if (! attr_mem) + goto fail; + + printk(KERN_DEBUG "orinoco_plx: CIS: "); + for (i = 0; i < 16; i++) { + printk("%02X:", (int)attr_mem[i]); + } + printk("\n"); /* Verify whether PC card is present */ - if (attr_mem[0] != 0x01 || attr_mem[2] != 0x03 || - attr_mem[4] != 0x00 || attr_mem[6] != 0x00 || - attr_mem[8] != 0xFF || attr_mem[10] != 0x17 || - attr_mem[12] != 0x04 || attr_mem[14] != 0x67) { + /* FIXME: we probably need to be smarted about this */ + if (memcmp(attr_mem, cis_magic, sizeof(cis_magic)) != 0) { printk(KERN_ERR "orinoco_plx: The CIS value of Prism2 PC card is invalid.\n"); - return -EIO; + err = -EIO; + goto fail; } + /* PCMCIA COR is the first byte following CIS: this write should * enable I/O mode and select level-triggered interrupts */ attr_mem[COR_OFFSET] = COR_VALUE; + mdelay(1); reg = attr_mem[COR_OFFSET]; - /* assert(reg==COR_VALUE); doesn't work */ - iounmap(attr_mem); /* done with this now, it seems */ - if (!request_region(pccard_ioaddr, - pci_resource_len(pdev, 3), dev_info)) { + if (reg != COR_VALUE) { + printk(KERN_ERR "orinoco_plx: Error setting COR value (reg=%x)\n", reg); + goto fail; + } + + iounmap(attr_mem); + attr_mem = NULL; /* done with this now, it seems */ + + /* bjoern: We need to tell the card to enable interrupts, in + case the serial eprom didn't do this already. See the + PLX9052 data book, p8-1 and 8-24 for reference. */ + addr = pci_resource_start(pdev, 1); + reg = 0; + reg = inl(addr+PLX_INTCSR); + if(reg & PLX_INTCSR_INTEN) + printk(KERN_DEBUG "orinoco_plx: " + "Local Interrupt already enabled\n"); + else { + reg |= PLX_INTCSR_INTEN; + outl(reg, addr+PLX_INTCSR); + reg = inl(addr+PLX_INTCSR); + if(!(reg & PLX_INTCSR_INTEN)) { + printk(KERN_ERR "orinoco_plx: " + "Couldn't enable Local Interrupts\n"); + goto fail; + } + } + + /* and 3 to the PCMCIA slot I/O address space */ + pccard_ioaddr = pci_resource_start(pdev, 3); + pccard_iolen = pci_resource_len(pdev, 3); + if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) { printk(KERN_ERR "orinoco_plx: I/O resource 0x%lx @ 0x%lx busy\n", - pci_resource_len(pdev, 3), pccard_ioaddr); - return -EBUSY; + pccard_iolen, pccard_ioaddr); + pccard_ioaddr = 0; + err = -EBUSY; + goto fail; + } + + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (! priv) { + err = -ENOMEM; + goto fail; } - if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) - return -ENOMEM; memset(priv, 0, sizeof(*priv)); + dev = &priv->ndev; - dldwd_setup(priv); /* XXX clean up if <0 */ - dev->irq = pdev->irq; + err = orinoco_setup(priv); + if (err) + goto fail; dev->base_addr = pccard_ioaddr; dev->open = orinoco_plx_open; dev->stop = orinoco_plx_stop; priv->card_reset_handler = NULL; /* We have no reset handler */ + SET_MODULE_OWNER(dev); printk(KERN_DEBUG - "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lx, irq:%d, io addr:0x%lx\n", - pdev->slot_name, (long) attr_mem, pdev->irq, pccard_ioaddr); + "Detected Orinoco/Prism2 PLX device at %s irq:%d, io addr:0x%lx\n", + pdev->slot_name, pdev->irq, pccard_ioaddr); - hermes_struct_init(&(priv->hw), dev->base_addr); /* XXX */ - dev->name[0] = '\0'; /* name defaults to ethX */ - register_netdev(dev); - request_irq(pdev->irq, orinoco_plx_interrupt, SA_SHIRQ, dev->name, - dev); - if (dldwd_proc_dev_init(priv) != 0) { - printk(KERN_ERR "%s: Failed to create /proc node\n", dev->name); - return -EIO; + hermes_struct_init(&(priv->hw), dev->base_addr); + pci_set_drvdata(pdev, priv); + + err = request_irq(pdev->irq, orinoco_plx_interrupt, SA_SHIRQ, dev->name, priv); + if (err) { + printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq); + err = -EBUSY; + goto fail; } + dev->irq = pdev->irq; - SET_MODULE_OWNER(dev); - priv->hw_ready = 1; + err = register_netdev(dev); + if (err) + goto fail; + netdev_registered = 1; + + err = orinoco_proc_dev_init(priv); + if (err) + goto fail; + + TRACE_EXIT("orinoco_plx"); - /* if(reset_cor) dldwd_cs_cor_reset(priv); */ return 0; /* succeeded */ + + fail: + printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n"); + + if (priv) { + orinoco_proc_dev_cleanup(priv); + + if (netdev_registered) + unregister_netdev(dev); + + if (dev->irq) + free_irq(dev->irq, priv); + + kfree(priv); + } + + if (pccard_ioaddr) + release_region(pccard_ioaddr, pccard_iolen); + + if (attr_mem) + iounmap(attr_mem); + + pci_disable_device(pdev); + + TRACE_EXIT("orinoco_plx"); + + return err; } static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = &priv->ndev; - if (!dev) + TRACE_ENTER("orinoco_plx"); + + if (!priv) BUG(); - dldwd_proc_dev_cleanup(priv); - free_irq(dev->irq, dev); + orinoco_proc_dev_cleanup(priv); + unregister_netdev(dev); - release_region(dev->base_addr, 0x40); - kfree(dev->priv); - pci_set_drvdata(pdev, NULL); + + if (dev->irq) + free_irq(dev->irq, priv); + + kfree(priv); + + release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3)); + + pci_disable_device(pdev); + + TRACE_EXIT("orinoco_plx"); } static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = { - {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, + {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ +#if 0 + {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga */ +#endif + {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, + Eumitcom PCI WL11000, + Addtron AWA-100*/ + {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ + {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ + {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ + {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ {0,}, }; @@ -286,12 +401,15 @@ static int __init orinoco_plx_init(void) { + printk(KERN_DEBUG "%s\n", version); return pci_module_init(&orinoco_plx_driver); } extern void __exit orinoco_plx_exit(void) { pci_unregister_driver(&orinoco_plx_driver); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); } module_init(orinoco_plx_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/net/yellowfin.c linux-2.5/drivers/net/yellowfin.c --- linux-2.5.1/drivers/net/yellowfin.c Fri Oct 19 15:32:28 2001 +++ linux-2.5/drivers/net/yellowfin.c Thu Dec 13 16:32:36 2001 @@ -1506,7 +1506,7 @@ name: DRV_NAME, id_table: yellowfin_pci_tbl, probe: yellowfin_init_one, - remove: yellowfin_remove_one, + remove: __devexit_p(yellowfin_remove_one), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/parport/ChangeLog linux-2.5/drivers/parport/ChangeLog --- linux-2.5.1/drivers/parport/ChangeLog Mon Nov 12 17:45:32 2001 +++ linux-2.5/drivers/parport/ChangeLog Mon Jan 14 22:39:45 2002 @@ -1,3 +1,86 @@ +2002-01-13 Niels Kristian Bech Jensen <nkbj@image.dk> + + * parport_pc.c: Change some occurrences of frob_set_mode to + ECR_WRITE. This fixes PLIP. + +2002-01-04 Tim Waugh <twaugh@redhat.com> + + * share.c (parport_claim_or_block): Sleep interruptibly to prevent + a possible deadlock. + +2001-12-07 Damian Gruszka <damian.gruszka@VisionSystems.de> + + * parport_pc.c (ECR_WRITE): Define. If there are forbidden bits + in the ECR register for some chips, this will be a useful place to + put that knowledge. + (change_mode): Use ECR_WRITE. + (parport_pc_restore_state): Likewise. + (parport_ECPPS2_supported): Likewise. + (parport_ECPEPP_supported): Likewise. + (irq_probe_EPP): Likewise. + (programmable_irq_support): Likewise. + (programmable_dma_support): Likewise. + (parport_pc_probe_port): Likewise. + + (frob_set_mode): New function. Set the mode bits of the ECR. + (get_fifo_residue): Use frob_set_mode. + (parport_pc_ecpepp_read_data): Likewise. + (parport_pc_ecpepp_write_data): Likewise. + (parport_pc_ecpepp_read_addr): Likewise. + (parport_pc_ecpepp_write_addr): Likewise. + (parport_pc_compat_write_block_pio): Likewise. + (parport_pc_ecp_write_block_pio): Likewise. + (parport_ECR_present): Likewise. + (parport_ECP_supported): Likewise. + (parport_EPP_supported): Likewise. + (parport_ECPEPP_supported): Likewise. + (programmable_irq_support): Likewise. + (irq_probe_ECP): Likewise. + (programmable_dma_support): Likewise. + + (parport_pc_enable_irq): Only enable interrupts if we know which + IRQ line they will come from. + (parport_pc_init_state): Set nErrIntrEn at initialisation. + (parport_pc_restore_state): Only write writable bits of CTR. + (parport_irq_probe): If no IRQ is found, take ackIntEn out of the + writable bit set. + +2001-12-07 Tim Waugh <twaugh@redhat.com> + + * parport_pc.c (parport_pc_fifo_write_block_pio): Correct typo. + (parport_pc_init_state): Only set ackIntEn if we know which IRQ + line the interrupts will come from. + +2001-12-07 Tim Waugh <twaugh@redhat.com> + + * ieee1284_ops.c (parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr): Actually do something useful. + +2001-12-07 Tim Waugh <twaugh@redhat.com> + + * parport_pc.c (dmaval): Don't use DMA by default. It seems to be + too buggy at the moment. Use 'dma=auto' to restore the previous + behaviour. + +2001-12-03 Rich Liu <Rich.Liu@ite.com.tw> + + * parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port + serial board, not a serial+parallel. + +2001-11-30 Niels Kristian Bech Jensen <nkbj@image.dk> + + * parport_pc.c: Fix compiler warning. + +2001-12-07 Tim Waugh <twaugh@redhat.com> + + * daisy.c (DEBUG): Undefine. + +2001-12-06 Tim Waugh <twaugh@redhat.com> + + * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off + PARPORT_CONTROL_AUTOFD as well. Bug spotted by Joe + <joeja@mindspring.com>. + 2001-11-12 Tim Waugh <twaugh@redhat.com> * parport_pc.c (init_module): Warn when parameters are ignored. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/parport/Config.in linux-2.5/drivers/parport/Config.in --- linux-2.5.1/drivers/parport/Config.in Sun Nov 11 18:09:33 2001 +++ linux-2.5/drivers/parport/Config.in Thu Dec 13 16:32:36 2001 @@ -24,9 +24,13 @@ bool ' Use FIFO/DMA if available (EXPERIMENTAL)' CONFIG_PARPORT_PC_FIFO bool ' SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO fi - 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 + if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then + if [ "$CONFIG_PARPORT_PC" = "y" ]; then + dep_tristate ' Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA + else + dep_tristate ' Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PARPORT_PC + fi + fi fi if [ "$CONFIG_ARM" = "y" ]; then dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/parport/daisy.c linux-2.5/drivers/parport/daisy.c --- linux-2.5.1/drivers/parport/daisy.c Fri Jul 21 21:21:58 2000 +++ linux-2.5/drivers/parport/daisy.c Thu Dec 13 16:32:36 2001 @@ -23,7 +23,7 @@ #include <linux/delay.h> #include <asm/uaccess.h> -#define DEBUG /* undef me for production */ +#undef DEBUG /* undef me for production */ #ifdef DEBUG #define DPRINTK(stuff...) printk (stuff) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/parport/ieee1284_ops.c linux-2.5/drivers/parport/ieee1284_ops.c --- linux-2.5.1/drivers/parport/ieee1284_ops.c Thu Oct 25 07:07:39 2001 +++ linux-2.5/drivers/parport/ieee1284_ops.c Thu Dec 13 16:32:36 2001 @@ -514,7 +514,8 @@ /* Set HostAck low to start accepting data. */ ctl = parport_read_control (port); - ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT); + ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT | + PARPORT_CONTROL_AUTOFD); parport_write_control (port, ctl | PARPORT_CONTROL_AUTOFD); while (count < len) { @@ -823,35 +824,40 @@ const void *buffer, size_t len, int flags) { - /* This is untested */ unsigned char *bp = (unsigned char *) buffer; size_t ret = 0; + /* set EPP idle state (just to make sure) with strobe low */ parport_frob_control (port, PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT | - PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_INIT, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT); + PARPORT_CONTROL_INIT); port->ops->data_forward (port); for (; len > 0; len--, bp++) { - /* Write data and assert nAStrb. */ + /* Event 56: Write data and set nAStrb low. */ parport_write_data (port, *bp); parport_frob_control (port, PARPORT_CONTROL_SELECT, PARPORT_CONTROL_SELECT); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY, 10)) + /* Event 58: wait for busy (nWait) to go high */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10)) break; + /* Event 59: set nAStrb high */ parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) + /* Event 60: wait for busy (nWait) to go low */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 5)) break; ret++; } + /* Event 61: set strobe (nWrite) high */ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); return ret; @@ -862,28 +868,36 @@ void *buffer, size_t len, int flags) { - /* This is untested. */ unsigned char *bp = (unsigned char *) buffer; unsigned ret = 0; + /* Set EPP idle state (just to make sure) with strobe high */ parport_frob_control (port, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD, 0); + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); port->ops->data_reverse (port); for (; len > 0; len--, bp++) { - parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); + /* Event 64: set nSelectIn (nAStrb) low */ + parport_frob_control (port, PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); - /* Event 58 */ - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY, 10)) + /* Event 58: wait for Busy to go high */ + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) { break; + } *bp = parport_read_data (port); + /* Event 59: set nSelectIn (nAStrb) high */ parport_frob_control (port, PARPORT_CONTROL_SELECT, PARPORT_CONTROL_SELECT); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) + /* Event 60: wait for Busy to go low */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 5)) break; ret++; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/parport/parport_cs.c linux-2.5/drivers/parport/parport_cs.c --- linux-2.5.1/drivers/parport/parport_cs.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/parport/parport_cs.c Tue Dec 18 14:53:28 2001 @@ -5,7 +5,7 @@ (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 + parport_cs.c 1.24 2001/10/13 14:04:05 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -45,6 +45,7 @@ #include <linux/string.h> #include <linux/timer.h> #include <linux/ioport.h> +#include <linux/major.h> #include <linux/parport.h> #include <linux/parport_pc.h> @@ -57,32 +58,31 @@ #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 +/* Module parameters */ -/*====================================================================*/ +MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); +MODULE_DESCRIPTION("PCMCIA parallel port card driver"); +MODULE_LICENSE("Dual MPL/GPL"); -/* Parameters that can be set with 'insmod' */ +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(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"); + +INT_MODULE_PARM(epp_mode, 1); + +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"parport_cs.c 1.24 2001/10/13 14:04:05 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -105,9 +105,6 @@ 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) @@ -307,19 +304,6 @@ 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; @@ -365,14 +349,8 @@ 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; @@ -430,24 +408,6 @@ /*====================================================================*/ -#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; @@ -459,13 +419,6 @@ 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; } @@ -480,4 +433,3 @@ module_init(init_parport_cs); module_exit(exit_parport_cs); -MODULE_LICENSE("Dual MPL/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/parport/parport_pc.c linux-2.5/drivers/parport/parport_pc.c --- linux-2.5.1/drivers/parport/parport_pc.c Mon Nov 12 17:44:58 2001 +++ linux-2.5/drivers/parport/parport_pc.c Mon Jan 14 22:39:45 2002 @@ -73,6 +73,8 @@ #define ECR_VND 05 #define ECR_TST 06 #define ECR_CNF 07 +#define ECR_MODE_MASK 0xe0 +#define ECR_WRITE(p,v) frob_econtrol((p),0xff,(v)) #undef DEBUG @@ -91,20 +93,31 @@ } superios[NR_SUPERIOS] __devinitdata = { {0,},}; static int user_specified __devinitdata = 0; +#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO) static int verbose_probing; +#endif static int registered_parport; /* frob_control, but for ECR */ static void frob_econtrol (struct parport *pb, unsigned char m, unsigned char v) { - unsigned char ectr = inb (ECONTROL (pb)); + unsigned char ectr = 0; + + if (m != 0xff) + ectr = inb (ECONTROL (pb)); + DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n", m, v, ectr, (ectr & ~m) ^ v); outb ((ectr & ~m) ^ v, ECONTROL (pb)); } +static void __inline__ frob_set_mode (struct parport *p, int mode) +{ + frob_econtrol (p, ECR_MODE_MASK, mode << 5); +} + #ifdef CONFIG_PARPORT_PC_FIFO /* Safely change the mode bits in the ECR Returns: @@ -115,7 +128,6 @@ static int change_mode(struct parport *p, int m) { const struct parport_pc_private *priv = p->physport->private_data; - int ecr = ECONTROL(p); unsigned char oecr; int mode; @@ -127,7 +139,7 @@ } /* Bits <7:5> contain the mode. */ - oecr = inb (ecr); + oecr = inb (ECONTROL (p)); mode = (oecr >> 5) & 0x7; if (mode == m) return 0; @@ -164,13 +176,13 @@ /* We have to go through mode 001 */ oecr &= ~(7 << 5); oecr |= ECR_PS2 << 5; - outb (oecr, ecr); + ECR_WRITE (p, oecr); } /* Set the mode. */ oecr &= ~(7 << 5); oecr |= m << 5; - outb (oecr, ecr); + ECR_WRITE (p, oecr); return 0; } @@ -195,10 +207,10 @@ residue); /* Reset the FIFO. */ - frob_econtrol (p, 0xe0, ECR_PS2 << 5); + frob_set_mode (p, ECR_PS2); /* Now change to config mode and clean up. FIXME */ - frob_econtrol (p, 0xe0, ECR_CNF << 5); + frob_set_mode (p, ECR_CNF); cnfga = inb (CONFIGA (p)); printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga); @@ -211,7 +223,7 @@ * PWord != 1 byte. */ /* Back to PS2 mode. */ - frob_econtrol (p, 0xe0, ECR_PS2 << 5); + frob_set_mode (p, ECR_PS2); DPRINTK (KERN_DEBUG "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", inb (ECONTROL (p))); return residue; @@ -329,7 +341,8 @@ void parport_pc_enable_irq(struct parport *p) { - __parport_pc_frob_control (p, 0x10, 0x10); + if (p->irq != PARPORT_IRQ_NONE) + __parport_pc_frob_control (p, 0x10, 0x10); } void parport_pc_data_forward (struct parport *p) @@ -344,8 +357,14 @@ void parport_pc_init_state(struct pardevice *dev, struct parport_state *s) { - s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); - s->u.pc.ecr = 0x24; + s->u.pc.ctr = 0xc; + if (dev->irq_func && + dev->port->irq != PARPORT_IRQ_NONE) + /* Set ackIntEn */ + s->u.pc.ctr |= 0x10; + + s->u.pc.ecr = 0x34; /* NetMos chip can cause problems 0x24; + * D.Gruszka VScom */ } void parport_pc_save_state(struct parport *p, struct parport_state *s) @@ -359,10 +378,11 @@ void parport_pc_restore_state(struct parport *p, struct parport_state *s) { struct parport_pc_private *priv = p->physport->private_data; - outb (s->u.pc.ctr, CONTROL (p)); - priv->ctr = s->u.pc.ctr; + register unsigned char c = s->u.pc.ctr & priv->ctr_writable; + outb (c, CONTROL (p)); + priv->ctr = c; if (priv->ecr) - outb (s->u.pc.ecr, ECONTROL (p)); + ECR_WRITE (p, s->u.pc.ecr); } #ifdef CONFIG_PARPORT_1284 @@ -514,11 +534,11 @@ { size_t got; - frob_econtrol (port, 0xe0, ECR_EPP << 5); + frob_set_mode (port, ECR_EPP); parport_pc_data_reverse (port); parport_pc_write_control (port, 0x4); got = parport_pc_epp_read_data (port, buf, length, flags); - frob_econtrol (port, 0xe0, ECR_PS2 << 5); + frob_set_mode (port, ECR_PS2); return got; } @@ -529,11 +549,11 @@ { size_t written; - frob_econtrol (port, 0xe0, ECR_EPP << 5); + frob_set_mode (port, ECR_EPP); parport_pc_write_control (port, 0x4); parport_pc_data_forward (port); written = parport_pc_epp_write_data (port, buf, length, flags); - frob_econtrol (port, 0xe0, ECR_PS2 << 5); + frob_set_mode (port, ECR_PS2); return written; } @@ -543,11 +563,11 @@ { size_t got; - frob_econtrol (port, 0xe0, ECR_EPP << 5); + frob_set_mode (port, ECR_EPP); parport_pc_data_reverse (port); parport_pc_write_control (port, 0x4); got = parport_pc_epp_read_addr (port, buf, length, flags); - frob_econtrol (port, 0xe0, ECR_PS2 << 5); + frob_set_mode (port, ECR_PS2); return got; } @@ -558,11 +578,11 @@ { size_t written; - frob_econtrol (port, 0xe0, ECR_EPP << 5); + frob_set_mode (port, ECR_EPP); parport_pc_write_control (port, 0x4); parport_pc_data_forward (port); written = parport_pc_epp_write_addr (port, buf, length, flags); - frob_econtrol (port, 0xe0, ECR_PS2 << 5); + frob_set_mode (port, ECR_PS2); return written; } @@ -610,7 +630,7 @@ /* FIFO is full. Wait for interrupt. */ /* Clear serviceIntr */ - outb (ecrval & ~(1<<2), ECONTROL (port)); + ECR_WRITE (port, ecrval & ~(1<<2)); false_alarm: ret = parport_wait_event (port, HZ); if (ret < 0) break; @@ -661,7 +681,7 @@ left--; } -dump_parport_state ("leave fifo_write_block_dma", port); +dump_parport_state ("leave fifo_write_block_pio", port); return length - left; } @@ -838,7 +858,7 @@ printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); /* Prevent further data transfer. */ - frob_econtrol (port, 0xe0, ECR_TST << 5); + frob_set_mode (port, ECR_TST); /* Adjust for the contents of the FIFO. */ for (written -= priv->fifo_depth; ; written++) { @@ -850,7 +870,7 @@ } /* Reset the FIFO and return to PS2 mode. */ - frob_econtrol (port, 0xe0, ECR_PS2 << 5); + frob_set_mode (port, ECR_PS2); } r = parport_wait_peripheral (port, @@ -935,7 +955,7 @@ printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); /* Prevent further data transfer. */ - frob_econtrol (port, 0xe0, ECR_TST << 5); + frob_set_mode (port, ECR_TST); /* Adjust for the contents of the FIFO. */ for (written -= priv->fifo_depth; ; written++) { @@ -947,7 +967,7 @@ } /* Reset the FIFO and return to PS2 mode. */ - frob_econtrol (port, 0xe0, ECR_PS2 << 5); + frob_set_mode (port, ECR_PS2); /* Host transfer recovery. */ parport_pc_data_reverse (port); /* Must be in PS2 mode */ @@ -1114,7 +1134,7 @@ } /* Clear serviceIntr */ - outb (ecrval & ~(1<<2), ECONTROL (port)); + ECR_WRITE (port, ecrval & ~(1<<2)); false_alarm: dump_parport_state ("waiting", port); ret = parport_wait_event (port, HZ); @@ -1717,7 +1737,7 @@ if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1) goto no_reg; - outb (0x34, ECONTROL (pb)); + ECR_WRITE (pb, 0x34); if (inb (ECONTROL (pb)) != 0x35) goto no_reg; @@ -1725,7 +1745,7 @@ outb (0xc, CONTROL (pb)); /* Go to mode 000 */ - frob_econtrol (pb, 0xe0, ECR_SPP << 5); + frob_set_mode (pb, ECR_SPP); return 1; @@ -1780,6 +1800,7 @@ return ok; } +#ifdef CONFIG_PARPORT_PC_FIFO static int __devinit parport_ECP_supported(struct parport *pb) { int i; @@ -1794,8 +1815,8 @@ return 0; /* Find out FIFO depth */ - outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */ - outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */ + ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */ + ECR_WRITE (pb, ECR_TST << 5); /* TEST FIFO */ for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++) outb (0xaa, FIFO (pb)); @@ -1804,7 +1825,7 @@ * it doesn't support ECP or FIFO MODE */ if (i == 1024) { - outb (ECR_SPP << 5, ECONTROL (pb)); + ECR_WRITE (pb, ECR_SPP << 5); return 0; } @@ -1834,9 +1855,9 @@ priv->writeIntrThreshold = i; /* Find out readIntrThreshold */ - frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO and enable PS2 */ + frob_set_mode (pb, ECR_PS2); /* Reset FIFO and enable PS2 */ parport_pc_data_reverse (pb); /* Must be in PS2 mode */ - frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */ + frob_set_mode (pb, ECR_TST); /* Test FIFO */ frob_econtrol (pb, 1<<2, 1<<2); frob_econtrol (pb, 1<<2, 0); for (i = 1; i <= priv->fifo_depth; i++) { @@ -1855,8 +1876,8 @@ priv->readIntrThreshold = i; - outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */ - outb (0xf4, ECONTROL (pb)); /* Configuration mode */ + ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */ + ECR_WRITE (pb, 0xf4); /* Configuration mode */ config = inb (CONFIGA (pb)); pword = (config >> 4) & 0x7; switch (pword) { @@ -1901,10 +1922,11 @@ } /* Go back to mode 000 */ - frob_econtrol (pb, 0xe0, ECR_SPP << 5); + frob_set_mode (pb, ECR_SPP); return 1; } +#endif static int __devinit parport_ECPPS2_supported(struct parport *pb) { @@ -1916,11 +1938,9 @@ return 0; oecr = inb (ECONTROL (pb)); - outb (ECR_PS2 << 5, ECONTROL (pb)); - + ECR_WRITE (pb, ECR_PS2 << 5); result = parport_PS2_supported(pb); - - outb (oecr, ECONTROL (pb)); + ECR_WRITE (pb, oecr); return result; } @@ -1952,7 +1972,7 @@ if (priv->ecr) { unsigned char i; for (i = 0x00; i < 0x80; i += 0x20) { - outb (i, ECONTROL (pb)); + ECR_WRITE (pb, i); if (clear_epp_timeout (pb)) { /* Phony EPP in ECP. */ return 0; @@ -1983,11 +2003,11 @@ oecr = inb (ECONTROL (pb)); /* Search for SMC style EPP+ECP mode */ - outb (0x80, ECONTROL (pb)); + ECR_WRITE (pb, 0x80); outb (0x04, CONTROL (pb)); result = parport_EPP_supported(pb); - outb (oecr, ECONTROL (pb)); + ECR_WRITE (pb, oecr); if (result) { /* Set up access functions to use ECP+EPP hardware. */ @@ -2004,7 +2024,9 @@ /* Don't bother probing for modes we know we won't use. */ static int __devinit parport_PS2_supported(struct parport *pb) { return 0; } +#ifdef CONFIG_PARPORT_PC_FIFO static int __devinit parport_ECP_supported(struct parport *pb) { return 0; } +#endif static int __devinit parport_EPP_supported(struct parport *pb) { return 0; } static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;} static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;} @@ -2022,12 +2044,12 @@ PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5 }; - outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */ + ECR_WRITE (pb, ECR_CNF << 5); /* Configuration MODE */ intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07; irq = lookup[intrLine]; - outb (oecr, ECONTROL (pb)); + ECR_WRITE (pb, oecr); return irq; } @@ -2039,16 +2061,16 @@ sti(); irqs = probe_irq_on(); - outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */ - outb ((ECR_TST << 5) | 0x04, ECONTROL (pb)); - outb (ECR_TST << 5, ECONTROL (pb)); + ECR_WRITE (pb, ECR_SPP << 5); /* Reset FIFO */ + ECR_WRITE (pb, (ECR_TST << 5) | 0x04); + ECR_WRITE (pb, ECR_TST << 5); /* If Full FIFO sure that writeIntrThreshold is generated */ for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) outb (0xaa, FIFO (pb)); pb->irq = probe_irq_off(irqs); - outb (ECR_SPP << 5, ECONTROL (pb)); + ECR_WRITE (pb, ECR_SPP << 5); if (pb->irq <= 0) pb->irq = PARPORT_IRQ_NONE; @@ -2090,7 +2112,7 @@ pb->irq = probe_irq_off (irqs); if (pb->modes & PARPORT_MODE_PCECR) - outb (oecr, ECONTROL (pb)); + ECR_WRITE (pb, oecr); parport_pc_write_control(pb, 0xc); if (pb->irq <= 0) @@ -2115,7 +2137,9 @@ */ static int __devinit parport_irq_probe(struct parport *pb) { - const struct parport_pc_private *priv = pb->private_data; + struct parport_pc_private *priv = pb->private_data; + + priv->ctr_writable |= 0x10; if (priv->ecr) { pb->irq = programmable_irq_support(pb); @@ -2141,6 +2165,9 @@ if (pb->irq == PARPORT_IRQ_NONE) pb->irq = get_superio_irq(pb); + if (pb->irq == PARPORT_IRQ_NONE) + priv->ctr_writable &= ~0x10; + return pb->irq; } @@ -2152,7 +2179,7 @@ unsigned char oecr = inb (ECONTROL (p)); int dma; - frob_econtrol (p, 0xe0, ECR_CNF << 5); + frob_set_mode (p, ECR_CNF); dma = inb (CONFIGB(p)) & 0x07; /* 000: Indicates jumpered 8-bit DMA if read-only. @@ -2160,7 +2187,7 @@ if ((dma & 0x03) == 0) dma = PARPORT_DMA_NONE; - outb (oecr, ECONTROL (p)); + ECR_WRITE (p, oecr); return dma; } @@ -2206,7 +2233,7 @@ } memcpy (ops, &parport_pc_ops, sizeof (struct parport_operations)); priv->ctr = 0xc; - priv->ctr_writable = 0xff; + priv->ctr_writable = ~0x10; priv->ecr = 0; priv->fifo_depth = 0; priv->dma_buf = 0; @@ -2368,7 +2395,7 @@ * Put the ECP detected port in PS2 mode. * Do this also for ports that have ECR but don't do ECP. */ - outb (0x34, ECONTROL (p)); + ECR_WRITE (p, 0x34); parport_pc_write_data(p, 0); parport_pc_data_forward (p); @@ -2453,9 +2480,8 @@ ite8872set = 0x64e00000; break; case 0x6: - printk (KERN_INFO "parport_pc: ITE8873 found (1S1P)\n"); - ite8872set = 0x64a00000; - break; + printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n"); + return 0; case 0x8: DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n"); return 0; @@ -3007,7 +3033,7 @@ static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO }; -static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO }; +static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE }; static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, }; static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, }; @@ -3024,8 +3050,10 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); MODULE_PARM_DESC(dma, "DMA channel"); MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); -MODULE_PARM(verbose_probing, "i"); +#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO) MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation"); +MODULE_PARM(verbose_probing, "i"); +#endif int init_module(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/parport/parport_serial.c linux-2.5/drivers/parport/parport_serial.c --- linux-2.5.1/drivers/parport/parport_serial.c Fri Nov 9 22:30:55 2001 +++ linux-2.5/drivers/parport/parport_serial.c Thu Dec 13 16:32:36 2001 @@ -331,7 +331,7 @@ name: "parport_serial", id_table: parport_serial_pci_tbl, probe: parport_serial_pci_probe, - remove: parport_serial_pci_remove, + remove: __devexit_p(parport_serial_pci_remove), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/parport/share.c linux-2.5/drivers/parport/share.c --- linux-2.5.1/drivers/parport/share.c Mon Oct 8 18:54:10 2001 +++ linux-2.5/drivers/parport/share.c Tue Jan 8 01:17:10 2002 @@ -1011,7 +1011,11 @@ /* If dev->waiting is clear now, an interrupt gave us the port and we would deadlock if we slept. */ if (dev->waiting) { - sleep_on(&dev->wait_q); + interruptible_sleep_on (&dev->wait_q); + if (signal_pending (current)) { + restore_flags (flags); + return -EINTR; + } r = 1; } else { r = 0; @@ -1084,7 +1088,7 @@ if (pd->waiting & 2) { /* sleeping in claim_or_block */ parport_claim(pd); if (waitqueue_active(&pd->wait_q)) - wake_up(&pd->wait_q); + wake_up_interruptible(&pd->wait_q); return; } else if (pd->wakeup) { pd->wakeup(pd->private); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pci/pci.ids linux-2.5/drivers/pci/pci.ids --- linux-2.5.1/drivers/pci/pci.ids Fri Nov 9 22:03:11 2001 +++ linux-2.5/drivers/pci/pci.ids Thu Jan 10 22:41:07 2002 @@ -812,6 +812,7 @@ 0074 56k Voice Modem 1033 8014 RCV56ACF 56k Voice Modem 009b Vrc5476 + 00e0 USB 2.0 1034 Framatome Connectors USA Inc. 1035 Comp. & Comm. Research Lab 1036 Future Domain Corp. @@ -1179,11 +1180,21 @@ 0017 Paddington Mac I/O 0018 UniNorth FireWire 0019 KeyLargo USB - 001e UniNorth PCI + 001e UniNorth Internal PCI 001f UniNorth PCI 0020 UniNorth AGP - 0021 UniNorth GMAC + 0021 UniNorth GMAC (Sun GEM) 0022 KeyLargo Mac I/O + 0024 UniNorth/Pangea GMAC (Sun GEM) + 0025 KeyLargo/Pangea Mac I/O + 0026 KeyLargo/Pangea USB + 0027 UniNorth/Pangea AGP + 0028 UniNorth/Pangea PCI + 0029 UniNorth/Pangea Internal PCI + 002d UniNorth 1.5 AGP + 002e UniNorth 1.5 PCI + 002f UniNorth 1.5 Internal PCI + 0030 UniNorth/Pangea FireWire 106c Hyundai Electronics America 8801 Dual Pentium ISA/PCI Motherboard 8802 PowerPC ISA/PCI Motherboard @@ -2601,6 +2612,8 @@ 0005 ATP850UF 0006 ATP860 NO-BIOS 0007 ATP860 + 0008 ATP865 NO-ROM + 0009 ATP865 8002 AEC6710 SCSI-2 Host Adapter 8010 AEC6712UW SCSI 8020 AEC6712U SCSI @@ -5417,6 +5430,7 @@ 03 USB Controller 00 UHCI 10 OHCI + 20 EHCI 80 Unspecified fe USB Device 04 Fibre Channel diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pci/setup-bus.c linux-2.5/drivers/pci/setup-bus.c --- linux-2.5.1/drivers/pci/setup-bus.c Fri Oct 5 01:47:08 2001 +++ linux-2.5/drivers/pci/setup-bus.c Mon Jan 14 22:39:45 2002 @@ -201,6 +201,16 @@ b->resource[0]->end = ranges->io_end - 1; b->resource[1]->end = ranges->mem_end - 1; + /* Add bridge resources to the resource tree. */ + if (b->resource[0]->end > b->resource[0]->start && + request_resource(bus->resource[0], b->resource[0]) < 0) + printk(KERN_ERR "PCI: failed to reserve IO " + "for bus %d\n", b->number); + if (b->resource[1]->end > b->resource[1]->start && + request_resource(bus->resource[1], b->resource[1]) < 0) + printk(KERN_ERR "PCI: failed to reserve MEM " + "for bus %d\n", b->number); + pci_setup_bridge(b); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pcmcia/cistpl.c linux-2.5/drivers/pcmcia/cistpl.c --- linux-2.5.1/drivers/pcmcia/cistpl.c Mon Nov 12 17:39:01 2001 +++ linux-2.5/drivers/pcmcia/cistpl.c Thu Dec 13 16:32:36 2001 @@ -264,11 +264,11 @@ (s->cis_mem.sys_start == 0)) { int low = !(s->cap.features & SS_CAP_PAGE_REGS); vs = s; - validate_mem(cis_readable, checksum_match, low); + validate_mem(cis_readable, checksum_match, low, s); s->cis_mem.sys_start = 0; vs = NULL; if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size, - s->cap.map_size, low, "card services")) { + s->cap.map_size, low, "card services", s)) { printk(KERN_NOTICE "cs: unable to map card memory!\n"); return CS_OUT_OF_RESOURCE; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pcmcia/cs.c linux-2.5/drivers/pcmcia/cs.c --- linux-2.5.1/drivers/pcmcia/cs.c Mon Nov 12 17:48:43 2001 +++ linux-2.5/drivers/pcmcia/cs.c Thu Dec 13 16:32:36 2001 @@ -809,7 +809,7 @@ return 1; for (i = 0; i < MAX_IO_WIN; i++) { if (s->io[i].NumPorts == 0) { - if (find_io_region(base, num, align, name) == 0) { + if (find_io_region(base, num, align, name, s) == 0) { s->io[i].Attributes = attr; s->io[i].BasePort = *base; s->io[i].NumPorts = s->io[i].InUse = num; @@ -821,7 +821,7 @@ /* Try to extend top of window */ try = s->io[i].BasePort + s->io[i].NumPorts; if ((*base == 0) || (*base == try)) - if (find_io_region(&try, num, 0, name) == 0) { + if (find_io_region(&try, num, 0, name, s) == 0) { *base = try; s->io[i].NumPorts += num; s->io[i].InUse += num; @@ -830,7 +830,7 @@ /* Try to extend bottom of window */ try = s->io[i].BasePort - num; if ((*base == 0) || (*base == try)) - if (find_io_region(&try, num, 0, name) == 0) { + if (find_io_region(&try, num, 0, name, s) == 0) { s->io[i].BasePort = *base = try; s->io[i].NumPorts += num; s->io[i].InUse += num; @@ -1974,7 +1974,7 @@ find_mem_region(&win->base, win->size, align, (req->Attributes & WIN_MAP_BELOW_1MB) || !(s->cap.features & SS_CAP_PAGE_REGS), - (*handle)->dev_info)) + (*handle)->dev_info, s)) return CS_IN_USE; (*handle)->state |= CLIENT_WIN_REQ(w); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pcmcia/cs_internal.h linux-2.5/drivers/pcmcia/cs_internal.h --- linux-2.5.1/drivers/pcmcia/cs_internal.h Sun Dec 16 23:46:33 2001 +++ linux-2.5/drivers/pcmcia/cs_internal.h Mon Jan 7 21:38:31 2002 @@ -238,11 +238,11 @@ /* In rsrc_mgr */ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low); + int force_low, socket_info_t *s); int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, - char *name); + char *name, socket_info_t *s); int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name); + int force_low, char *name, socket_info_t *s); int try_irq(u_int Attributes, int irq, int specific); void undo_irq(u_int Attributes, int irq); int adjust_resource_info(client_handle_t handle, adjust_t *adj); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pcmcia/ds.c linux-2.5/drivers/pcmcia/ds.c --- linux-2.5.1/drivers/pcmcia/ds.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/pcmcia/ds.c Tue Jan 1 23:42:42 2002 @@ -558,7 +558,7 @@ static int ds_open(struct inode *inode, struct file *file) { - socket_t i = MINOR(inode->i_rdev); + socket_t i = minor(inode->i_rdev); socket_info_t *s; user_info_t *user; @@ -590,7 +590,7 @@ static int ds_release(struct inode *inode, struct file *file) { - socket_t i = MINOR(inode->i_rdev); + socket_t i = minor(inode->i_rdev); socket_info_t *s; user_info_t *user, **link; @@ -622,7 +622,7 @@ static ssize_t ds_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - socket_t i = MINOR(file->f_dentry->d_inode->i_rdev); + socket_t i = minor(file->f_dentry->d_inode->i_rdev); socket_info_t *s; user_info_t *user; @@ -651,7 +651,7 @@ static ssize_t ds_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - socket_t i = MINOR(file->f_dentry->d_inode->i_rdev); + socket_t i = minor(file->f_dentry->d_inode->i_rdev); socket_info_t *s; user_info_t *user; @@ -684,7 +684,7 @@ /* No kernel lock - fine */ static u_int ds_poll(struct file *file, poll_table *wait) { - socket_t i = MINOR(file->f_dentry->d_inode->i_rdev); + socket_t i = minor(file->f_dentry->d_inode->i_rdev); socket_info_t *s; user_info_t *user; @@ -707,7 +707,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, u_int cmd, u_long arg) { - socket_t i = MINOR(inode->i_rdev); + socket_t i = minor(inode->i_rdev); socket_info_t *s; u_int size; int ret, err; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pcmcia/i82092.c linux-2.5/drivers/pcmcia/i82092.c --- linux-2.5.1/drivers/pcmcia/i82092.c Fri Nov 9 21:45:35 2001 +++ linux-2.5/drivers/pcmcia/i82092.c Thu Dec 13 17:35:27 2001 @@ -42,7 +42,7 @@ name: "i82092aa", id_table: i82092aa_pci_ids, probe: i82092aa_pci_probe, - remove: i82092aa_pci_remove, + remove: __devexit_p(i82092aa_pci_remove), suspend: NULL, resume: NULL }; @@ -160,7 +160,7 @@ return 0; } -static void __exit i82092aa_pci_remove(struct pci_dev *dev) +static void __devexit i82092aa_pci_remove(struct pci_dev *dev) { enter("i82092aa_pci_remove"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pcmcia/i82365.c linux-2.5/drivers/pcmcia/i82365.c --- linux-2.5.1/drivers/pcmcia/i82365.c Sun Nov 25 17:43:42 2001 +++ linux-2.5/drivers/pcmcia/i82365.c Sun Dec 30 21:17:30 2001 @@ -49,7 +49,6 @@ #include <asm/irq.h> #include <asm/io.h> #include <asm/bitops.h> -#include <asm/segment.h> #include <asm/system.h> #include <pcmcia/version.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pcmcia/pci_socket.c linux-2.5/drivers/pcmcia/pci_socket.c --- linux-2.5.1/drivers/pcmcia/pci_socket.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/pcmcia/pci_socket.c Thu Dec 13 16:32:36 2001 @@ -249,7 +249,7 @@ name: "cardbus", id_table: cardbus_table, probe: cardbus_probe, - remove: cardbus_remove, + remove: __devexit_p(cardbus_remove), suspend: cardbus_suspend, resume: cardbus_resume, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pcmcia/rsrc_mgr.c linux-2.5/drivers/pcmcia/rsrc_mgr.c --- linux-2.5.1/drivers/pcmcia/rsrc_mgr.c Mon Nov 12 17:39:01 2001 +++ linux-2.5/drivers/pcmcia/rsrc_mgr.c Thu Dec 13 16:32:36 2001 @@ -44,6 +44,7 @@ #include <linux/ioport.h> #include <linux/timer.h> #include <linux/proc_fs.h> +#include <linux/pci.h> #include <asm/irq.h> #include <asm/io.h> @@ -103,8 +104,82 @@ ======================================================================*/ -#define check_io_resource(b,n) check_resource(&ioport_resource, (b), (n)) -#define check_mem_resource(b,n) check_resource(&iomem_resource, (b), (n)) +static struct resource *resource_parent(unsigned long b, unsigned long n, + int flags, struct pci_dev *dev) +{ +#ifdef CONFIG_PCI + struct resource res, *pr; + + if (dev != NULL) { + res.start = b; + res.end = b + n - 1; + res.flags = flags; + pr = pci_find_parent_resource(dev, &res); + if (pr) + return pr; + } +#endif /* CONFIG_PCI */ + if (flags & IORESOURCE_MEM) + return &iomem_resource; + return &ioport_resource; +} + +static inline int check_io_resource(unsigned long b, unsigned long n, + struct pci_dev *dev) +{ + return check_resource(resource_parent(b, n, IORESOURCE_IO, dev), b, n); +} + +static inline int check_mem_resource(unsigned long b, unsigned long n, + struct pci_dev *dev) +{ + return check_resource(resource_parent(b, n, IORESOURCE_MEM, dev), b, n); +} + +static struct resource *make_resource(unsigned long b, unsigned long n, + int flags, char *name) +{ + struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL); + + if (res) { + memset(res, 0, sizeof(*res)); + res->name = name; + res->start = b; + res->end = b + n - 1; + res->flags = flags | IORESOURCE_BUSY; + } + return res; +} + +static int request_io_resource(unsigned long b, unsigned long n, + char *name, struct pci_dev *dev) +{ + struct resource *res = make_resource(b, n, IORESOURCE_IO, name); + struct resource *pr = resource_parent(b, n, IORESOURCE_IO, dev); + int err = -ENOMEM; + + if (res) { + err = request_resource(pr, res); + if (err) + kfree(res); + } + return err; +} + +static int request_mem_resource(unsigned long b, unsigned long n, + char *name, struct pci_dev *dev) +{ + struct resource *res = make_resource(b, n, IORESOURCE_MEM, name); + struct resource *pr = resource_parent(b, n, IORESOURCE_MEM, dev); + int err = -ENOMEM; + + if (res) { + err = request_resource(pr, res); + if (err) + kfree(res); + } + return err; +} /*====================================================================== @@ -194,7 +269,7 @@ } memset(b, 0, 256); for (i = base, most = 0; i < base+num; i += 8) { - if (check_io_resource(i, 8)) + if (check_io_resource(i, 8, NULL)) continue; hole = inb(i); for (j = 1; j < 8; j++) @@ -207,7 +282,7 @@ bad = any = 0; for (i = base; i < base+num; i += 8) { - if (check_io_resource(i, 8)) + if (check_io_resource(i, 8, NULL)) continue; for (j = 0; j < 8; j++) if (inb(i+j) != most) break; @@ -247,7 +322,8 @@ ======================================================================*/ static int do_mem_probe(u_long base, u_long num, - int (*is_valid)(u_long), int (*do_cksum)(u_long)) + int (*is_valid)(u_long), int (*do_cksum)(u_long), + socket_info_t *s) { u_long i, j, bad, fail, step; @@ -258,13 +334,14 @@ for (i = j = base; i < base+num; i = j + step) { if (!fail) { for (j = i; j < base+num; j += step) - if ((check_mem_resource(j, step) == 0) && is_valid(j)) + if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) && + is_valid(j)) break; fail = ((i == base) && (j == base+num)); } if (fail) { for (j = i; j < base+num; j += 2*step) - if ((check_mem_resource(j, 2*step) == 0) && + if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) && do_cksum(j) && do_cksum(j+step)) break; } @@ -283,12 +360,12 @@ static u_long inv_probe(int (*is_valid)(u_long), int (*do_cksum)(u_long), - resource_map_t *m) + resource_map_t *m, socket_info_t *s) { u_long ok; if (m == &mem_db) return 0; - ok = inv_probe(is_valid, do_cksum, m->next); + ok = inv_probe(is_valid, do_cksum, m->next, s); if (ok) { if (m->base >= 0x100000) sub_interval(&mem_db, m->base, m->num); @@ -296,11 +373,11 @@ } if (m->base < 0x100000) return 0; - return do_mem_probe(m->base, m->num, is_valid, do_cksum); + return do_mem_probe(m->base, m->num, is_valid, do_cksum, s); } void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low) + int force_low, socket_info_t *s) { resource_map_t *m, *n; static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; @@ -310,7 +387,7 @@ if (!probe_mem) return; /* We do up to four passes through the list */ if (!force_low) { - if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0)) + if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0)) return; printk(KERN_NOTICE "cs: warning: no high memory space " "available!\n"); @@ -321,7 +398,7 @@ /* Only probe < 1 MB */ if (m->base >= 0x100000) continue; if ((m->base | m->num) & 0xffff) { - ok += do_mem_probe(m->base, m->num, is_valid, do_cksum); + ok += do_mem_probe(m->base, m->num, is_valid, do_cksum, s); continue; } /* Special probe for 64K-aligned block */ @@ -331,7 +408,7 @@ if (ok >= mem_limit) sub_interval(&mem_db, b, 0x10000); else - ok += do_mem_probe(b, 0x10000, is_valid, do_cksum); + ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s); } } } @@ -340,7 +417,7 @@ #else /* CONFIG_ISA */ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low) + int force_low, socket_info_t *s) { resource_map_t *m; static int done = 0; @@ -348,7 +425,7 @@ if (!probe_mem || done++) return; for (m = mem_db.next; m != &mem_db; m = m->next) - if (do_mem_probe(m->base, m->num, is_valid, do_cksum)) + if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s)) return; } @@ -368,7 +445,7 @@ ======================================================================*/ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, - char *name) + char *name, socket_info_t *s) { ioaddr_t try; resource_map_t *m; @@ -378,9 +455,8 @@ for (try = (try >= m->base) ? try : try+align; (try >= m->base) && (try+num <= m->base+m->num); try += align) { - if (check_io_resource(try, num) == 0) { + if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) { *base = try; - request_region(try, num, name); return 0; } if (!align) break; @@ -390,7 +466,7 @@ } int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name) + int force_low, char *name, socket_info_t *s) { u_long try; resource_map_t *m; @@ -403,8 +479,7 @@ for (try = (try >= m->base) ? try : try+align; (try >= m->base) && (try+num <= m->base+m->num); try += align) { - if (check_mem_resource(try, num) == 0) { - request_mem_region(try, num, name); + if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) { *base = try; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pcmcia/tcic.c linux-2.5/drivers/pcmcia/tcic.c --- linux-2.5.1/drivers/pcmcia/tcic.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/pcmcia/tcic.c Sun Dec 30 21:17:30 2001 @@ -39,7 +39,6 @@ #include <asm/io.h> #include <asm/bitops.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/kernel.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pcmcia/yenta.c linux-2.5/drivers/pcmcia/yenta.c --- linux-2.5.1/drivers/pcmcia/yenta.c Wed Nov 21 07:19:48 2001 +++ linux-2.5/drivers/pcmcia/yenta.c Thu Dec 13 16:32:36 2001 @@ -688,7 +688,7 @@ /* * This does not work currently. The controller - * loses too much informationduring D3 to come up + * loses too much information during D3 to come up * cleanly. We should probably fix yenta_init() * to update all the critical registers, notably * the IO and MEM bridging region data.. That is diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pnp/Config.in linux-2.5/drivers/pnp/Config.in --- linux-2.5.1/drivers/pnp/Config.in Thu Oct 25 21:01:51 2001 +++ linux-2.5/drivers/pnp/Config.in Sat Dec 29 12:07:19 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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pnp/Makefile linux-2.5/drivers/pnp/Makefile --- linux-2.5.1/drivers/pnp/Makefile Mon Mar 26 23:36:30 2001 +++ linux-2.5/drivers/pnp/Makefile Sat Dec 29 12:07:19 2001 @@ -10,15 +10,22 @@ O_TARGET := pnp.o -export-objs := isapnp.o -list-multi := isa-pnp.o +export-objs := isapnp.o pnpbios_core.o +multi-objs := isa-pnp.o pnpbios.o -proc-$(CONFIG_PROC_FS) = isapnp_proc.o -isa-pnp-objs := isapnp.o quirks.o $(proc-y) +isa-pnp-proc-$(CONFIG_PROC_FS) = isapnp_proc.o +pnpbios-proc-$(CONFIG_PROC_FS) = pnpbios_proc.o + +isa-pnp-objs := isapnp.o quirks.o $(isa-pnp-proc-y) +pnpbios-objs := pnpbios_core.o $(pnpbios-proc-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) + +pnpbios.o: $(pnpbios-objs) + $(LD) $(LD_RFLAG) -r -o $@ $(pnpbios-objs) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pnp/isapnp.c linux-2.5/drivers/pnp/isapnp.c --- linux-2.5.1/drivers/pnp/isapnp.c Mon Nov 12 18:02:54 2001 +++ linux-2.5/drivers/pnp/isapnp.c Mon Jan 14 22:39:45 2002 @@ -892,6 +892,7 @@ case _STAG_END: if (size > 0) isapnp_skip_bytes(size); + isapnp_config_prepare(dev); return 1; default: printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->devfn, card->number); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pnp/pnpbios_core.c linux-2.5/drivers/pnp/pnpbios_core.c --- linux-2.5.1/drivers/pnp/pnpbios_core.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/pnp/pnpbios_core.c Sat Dec 29 12:07:19 2001 @@ -0,0 +1,1274 @@ +/* + * PnP BIOS services + * + * Originally (C) 1998 Christian Schmidt <schmidt@digadd.de> + * Modifications (c) 1998 Tom Lees <tom@lpsg.demon.co.uk> + * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net> + * Modifications (c) 2001 by Thomas Hood <jdthood@mail.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * References: + * 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/types.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/linkage.h> +#include <linux/kernel.h> +#include <linux/pnpbios.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> +#include <linux/kmod.h> +#include <linux/completion.h> +#include <linux/spinlock.h> +#include <asm/system.h> + + +/* + * + * PnP BIOS INTERFACE + * + */ + +/* PnP BIOS signature: "$PnP" */ +#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24)) + +#pragma pack(1) +union pnp_bios_expansion_header { + 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() + +static struct { + u16 offset; + u16 segment; +} pnp_bios_callpoint; + +static union pnp_bios_expansion_header * pnp_bios_hdr = NULL; + +/* The PnP BIOS 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 */ + +/* + * 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 3GB... + */ + +asmlinkage void pnp_bios_callfunc(void); + +__asm__( + ".text \n" + __ALIGN_STR "\n" + SYMBOL_NAME_STR(pnp_bios_callfunc) ":\n" + " pushl %edx \n" + " pushl %ecx \n" + " pushl %ebx \n" + " pushl %eax \n" + " lcallw " SYMBOL_NAME_STR(pnp_bios_callpoint) "\n" + " addl $16, %esp \n" + " lret \n" + ".previous \n" +); + +#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) + +/* + * At some point we want to use this stack frame pointer to unwind + * after PnP BIOS oopses. + */ + +u32 pnp_bios_fault_esp; +u32 pnp_bios_fault_eip; +u32 pnp_bios_is_utter_crap = 0; + +static spinlock_t pnp_bios_lock; + +static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, + u16 arg4, u16 arg5, u16 arg6, u16 arg7) +{ + unsigned long flags; + u16 status; + + /* + * PnP BIOSes are generally not terribly re-entrant. + * Also, don't rely on them to save everything correctly. + */ + if(pnp_bios_is_utter_crap) + return PNP_FUNCTION_NOT_SUPPORTED; + + /* On some boxes IRQ's during PnP BIOS calls are deadly. */ + spin_lock_irqsave(&pnp_bios_lock, flags); + __cli(); + __asm__ __volatile__( + "pushl %%ebp\n\t" + "pushl %%edi\n\t" + "pushl %%esi\n\t" + "pushl %%ds\n\t" + "pushl %%es\n\t" + "pushl %%fs\n\t" + "pushl %%gs\n\t" + "pushfl\n\t" + "movl %%esp, pnp_bios_fault_esp\n\t" + "movl $1f, pnp_bios_fault_eip\n\t" + "lcall %5,%6\n\t" + "1:popfl\n\t" + "popl %%gs\n\t" + "popl %%fs\n\t" + "popl %%es\n\t" + "popl %%ds\n\t" + "popl %%esi\n\t" + "popl %%edi\n\t" + "popl %%ebp\n\t" + : "=a" (status) + : "0" ((func) | (((u32)arg1) << 16)), + "b" ((arg2) | (((u32)arg3) << 16)), + "c" ((arg4) | (((u32)arg5) << 16)), + "d" ((arg6) | (((u32)arg7) << 16)), + "i" (PNP_CS32), + "i" (0) + : "memory" + ); + spin_unlock_irqrestore(&pnp_bios_lock, flags); + + /* If we get here and this is set then the PnP BIOS faulted on us. */ + if(pnp_bios_is_utter_crap) + { + printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue.\n"); + printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably.\n"); + printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n"); + } + + return status; +} + + +/* + * + * UTILITY FUNCTIONS + * + */ + +void *pnpbios_kmalloc(size_t size, int f) +{ + void *p = kmalloc( size, f ); + if ( p == NULL ) + printk(KERN_ERR "PnPBIOS: kmalloc() failed.\n"); + return p; +} + +/* + * Call this only after init time + */ +static int pnp_bios_present(void) +{ + return (pnp_bios_hdr != NULL); +} + +/* Forward declaration */ +static void update_devlist( u8 nodenum, struct pnp_bios_node *data ); + + +/* + * + * PnP BIOS ACCESS 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" + */ +static 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)); + status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0); + data->no_nodes &= 0xff; + return status; +} + +int pnp_bios_dev_node_info(struct pnp_dev_node_info *data) +{ + int status = __pnp_bios_dev_node_info( data ); + if ( status ) + printk(KERN_WARNING "PnPBIOS: dev_node_info: Unexpected status 0x%x\n", status); + return status; +} + +/* + * Note that some PnP BIOSes (e.g., on Sony Vaio laptops) die a horrible + * death if they are asked to access the "current" configuration. + * Therefore, if it's a matter of indifference, it's better to call + * get_dev_node() and set_dev_node() with boot=1 rather than with boot=0. + */ + +/* + * Call PnP BIOS with function 0x01, "get system device node" + * Input: *nodenum = desired node, + * boot = whether to get nonvolatile boot (!=0) + * or volatile current (0) config + * Output: *nodenum=next node or 0xff if no more nodes + */ +static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + if ( !boot & pnpbios_dont_use_current_config ) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, nodenum, sizeof(char)); + Q2_SET_SEL(PNP_TS2, data, 64 * 1024); + status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0); + return status; +} + +int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data) +{ + int status; + status = __pnp_bios_get_dev_node( nodenum, boot, data ); + if ( status ) + printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected 0x%x\n", status); + return status; +} + + +/* + * Call PnP BIOS with function 0x02, "set system device node" + * Input: *nodenum = desired node, + * boot = whether to set nonvolatile boot (!=0) + * or volatile current (0) config + */ +static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + if ( !boot & pnpbios_dont_use_current_config ) + return PNP_FUNCTION_NOT_SUPPORTED; + Q2_SET_SEL(PNP_TS1, data, /* *((u16 *) data)*/ 65536); + status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0); + return status; +} + +int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data) +{ + int status; + status = __pnp_bios_set_dev_node( nodenum, boot, data ); + if ( status ) { + printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected set_dev_node status 0x%x\n", status); + return status; + } + if ( !boot ) { + /* Update devlist */ + u8 thisnodenum = nodenum; + status = __pnp_bios_get_dev_node( &nodenum, boot, data ); + if ( status ) { + printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected get_dev_node status 0x%x\n", status); + return status; + } + update_devlist( thisnodenum, data ); + } + return status; +} + +#if needed +/* + * Call PnP BIOS with function 0x03, "get event" + */ +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)); + status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0); + return status; +} +#endif + +#if needed +/* + * Call PnP BIOS with function 0x04, "send message" + */ +static int pnp_bios_send_message(u16 message) +{ + u16 status; + if (!pnp_bios_present ()) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0); + return status; +} +#endif + +#ifdef CONFIG_HOTPLUG +/* + * Call PnP BIOS with function 0x05, "get docking station information" + */ +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)); + status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0); + return status; +} +#endif + +#if needed +/* + * Call PnP BIOS with function 0x09, "set statically allocated resource + * information" + */ +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)); + status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0); + return status; +} +#endif + +#if needed +/* + * Call PnP BIOS with function 0x0a, "get statically allocated resource + * information" + */ +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); + status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0); + return status; +} +#endif + +#if needed +/* + * Call PnP BIOS with function 0x0b, "get APM id table" + */ +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)); + status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0); + return status; +} +#endif + +#if needed +/* + * Call PnP BIOS with function 0x40, "get isa pnp configuration structure" + */ +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)); + status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0); + return status; +} +#endif + +#if needed +/* + * Call PnP BIOS with function 0x41, "get ESCD info" + */ +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)); + status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS); + return status; +} +#endif + +#if needed +/* + * Call PnP BIOS function 0x42, "read ESCD" + * nvram_base is determined by calling escd_info + */ +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); + status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0); + return status; +} +#endif + +#if needed +/* + * Call PnP BIOS function 0x43, "write ESCD" + */ +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); + status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0); + return status; +} +#endif + + +/* + * + * DOCKING FUNCTIONS + * + */ + +#ifdef CONFIG_HOTPLUG + +static int unloading = 0; +static struct completion unload_sem; + +/* + * (Much of this belongs in a shared routine somewhere) + */ + +static int pnp_dock_event(int dock, struct pnp_docking_station_info *info) +{ + char *argv [3], **envp, *buf, *scratch; + int i = 0, value; + + if (!hotplug_path [0]) + return -ENOENT; + if (!current->fs->root) { + return -EAGAIN; + } + if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) { + return -ENOMEM; + } + if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) { + kfree (envp); + return -ENOMEM; + } + + /* only one standardized param to hotplug command: type */ + argv [0] = hotplug_path; + argv [1] = "dock"; + argv [2] = 0; + + /* minimal command environment */ + envp [i++] = "HOME=/"; + envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + +#ifdef DEBUG + /* hint that policy agent should enter no-stdout debug mode */ + envp [i++] = "DEBUG=kernel"; +#endif + /* extensible set of named bus-specific parameters, + * supporting multiple driver selection algorithms. + */ + scratch = buf; + + /* action: add, remove */ + envp [i++] = scratch; + scratch += sprintf (scratch, "ACTION=%s", dock?"add":"remove") + 1; + + /* Report the ident for the dock */ + envp [i++] = scratch; + scratch += sprintf (scratch, "DOCK=%x/%x/%x", + info->location_id, info->serial, info->capabilities); + envp[i] = 0; + + value = call_usermodehelper (argv [0], argv, envp); + kfree (buf); + kfree (envp); + return 0; +} + +/* + * Poll the PnP docking at regular intervals + */ +static int pnp_dock_thread(void * unused) +{ + static struct pnp_docking_station_info now; + int docked = -1, d; + daemonize(); + reparent_to_init(); + strcpy(current->comm, "kpnpbios"); + while(!unloading && !signal_pending(current)) + { + int err; + + /* + * Poll every 2 seconds + */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ*2); + if(signal_pending(current)) + break; + + err = pnp_bios_dock_station_info(&now); + + switch(err) + { + /* + * No dock to manage + */ + case PNP_FUNCTION_NOT_SUPPORTED: + complete_and_exit(&unload_sem, 0); + case PNP_SYSTEM_NOT_DOCKED: + d = 0; + break; + case PNP_SUCCESS: + d = 1; + break; + default: + printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x returned by BIOS.\n", err); + continue; + } + if(d != docked) + { + if(pnp_dock_event(d, &now)==0) + { + docked = d; +#if 0 + printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de"); +#endif + } + } + } + complete_and_exit(&unload_sem, 0); +} + +#endif /* CONFIG_HOTPLUG */ + + +/* + * + * NODE DATA PARSING FUNCTIONS + * + */ + +static void add_irqresource(struct pci_dev *dev, int irq) +{ + int i = 0; + while (!(dev->irq_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_IRQ) i++; + if (i < DEVICE_COUNT_IRQ) { + dev->irq_resource[i].start = (unsigned long) irq; + dev->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag + } +} + +static void add_dmaresource(struct pci_dev *dev, int dma) +{ + int i = 0; + while (!(dev->dma_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_DMA) i++; + if (i < DEVICE_COUNT_DMA) { + dev->dma_resource[i].start = (unsigned long) dma; + dev->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag + } +} + +static void add_ioresource(struct pci_dev *dev, int io, int len) +{ + int i = 0; + while (!(dev->resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_RESOURCE) i++; + if (i < DEVICE_COUNT_RESOURCE) { + dev->resource[i].start = (unsigned long) io; + dev->resource[i].end = (unsigned long)(io + len - 1); + dev->resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag + } +} + +static void add_memresource(struct pci_dev *dev, int mem, int len) +{ + int i = 0; + while (!(dev->resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_RESOURCE) i++; + if (i < DEVICE_COUNT_RESOURCE) { + dev->resource[i].start = (unsigned long) mem; + dev->resource[i].end = (unsigned long)(mem + len - 1); + dev->resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag + } +} + +static void node_resource_data_to_dev(struct pnp_bios_node *node, struct pci_dev *dev) +{ + unsigned char *p = node->data, *lastp=NULL; + int i; + + /* + * First, set resource info to default values + */ + for (i=0;i<DEVICE_COUNT_RESOURCE;i++) { + dev->resource[i].start = 0; // "disabled" + dev->resource[i].flags = IORESOURCE_UNSET; + } + for (i=0;i<DEVICE_COUNT_IRQ;i++) { + dev->irq_resource[i].start = (unsigned long)-1; // "disabled" + dev->irq_resource[i].flags = IORESOURCE_UNSET; + } + for (i=0;i<DEVICE_COUNT_DMA;i++) { + dev->dma_resource[i].start = (unsigned long)-1; // "disabled" + dev->dma_resource[i].flags = IORESOURCE_UNSET; + } + + /* + * Fill in dev resource info + */ + while ( (char *)p < ((char *)node->data + node->size )) { + if(p==lastp) break; + + if( p[0] & 0x80 ) {// large item + switch (p[0] & 0x7f) { + case 0x01: // memory + { + int io = *(short *) &p[4]; + int len = *(short *) &p[10]; + add_memresource(dev, io, len); + break; + } + case 0x02: // device name + { + int len = *(short *) &p[1]; + memcpy(dev->name, p + 3, len >= 80 ? 79 : len); + break; + } + case 0x05: // 32-bit memory + { + int io = *(int *) &p[4]; + int len = *(int *) &p[16]; + add_memresource(dev, io, len); + break; + } + case 0x06: // fixed location 32-bit memory + { + int io = *(int *) &p[4]; + int len = *(int *) &p[8]; + add_memresource(dev, io, len); + break; + } + } /* switch */ + 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 + { + int i, mask, irq = -1; + mask= p[1] + p[2]*256; + for (i=0;i<16;i++, mask=mask>>1) + if(mask & 0x01) irq=i; + add_irqresource(dev, irq); + break; + } + case 0x05: // dma + { + int i, mask, dma = -1; + mask = p[1]; + for (i=0;i<8;i++, mask = mask>>1) + if(mask & 0x01) dma=i; + add_dmaresource(dev, dma); + break; + } + case 0x08: // io + { + int io= p[2] + p[3] *256; + int len = p[7]; + add_ioresource(dev, io, len); + break; + } + case 0x09: // fixed location io + { + int io = p[1] + p[2] * 256; + int len = p[3]; + add_ioresource(dev, io, len); + break; + } + } /* switch */ + lastp=p+1; + p = p + (p[0] & 0x07) + 1; + + } /* while */ + + return; +} + + +/* + * + * DEVICE LIST MANAGEMENT FUNCTIONS + * + * + * Some of these are exported to give public access + * + * Question: Why maintain a device list when the PnP BIOS can + * list devices for us? Answer: Some PnP BIOSes can't report + * the current configuration, only the boot configuration. + * The boot configuration can be changed, so we need to keep + * a record of what the configuration was when we booted; + * presumably it continues to describe the current config. + * For those BIOSes that can change the current config, we + * keep the information in the devlist up to date. + * + * Note that it is currently assumed that the list does not + * grow or shrink in size after init time, and slot_name + * never changes. The list is protected by a spinlock. + */ + +static LIST_HEAD(pnpbios_devices); + +static spinlock_t pnpbios_devices_lock; + +static int inline insert_device(struct pci_dev *dev) +{ + + /* + * FIXME: Check for re-add of existing node; + * return -1 if node already present + */ + + /* We don't lock because we only do this at init time */ + list_add_tail(&dev->global_list, &pnpbios_devices); + + return 0; +} + +#define HEX(id,a) hex[((id)>>a) & 15] +#define CHAR(id,a) (0x40 + (((id)>>a) & 31)) +// +static void inline pnpid32_to_pnpid(u32 id, char *str) +{ + const char *hex = "0123456789abcdef"; + + id = be32_to_cpu(id); + str[0] = CHAR(id, 26); + str[1] = CHAR(id, 21); + str[2] = CHAR(id,16); + str[3] = HEX(id, 12); + str[4] = HEX(id, 8); + str[5] = HEX(id, 4); + str[6] = HEX(id, 0); + str[7] = '\0'; + + return; +} +// +#undef CHAR +#undef HEX + +/* + * Build a linked list of pci_devs in order of ascending node number + * Called only at init time. + */ +static void __init build_devlist(void) +{ + int i; + int nodenum; + int nodes_got = 0; + int devs = 0; + struct pnp_bios_node *node; + struct pnp_dev_node_info node_info; + struct pci_dev *dev; + + if (!pnp_bios_present ()) + return; + + if (pnp_bios_dev_node_info(&node_info) != 0) + return; + + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) + return; + + for(i=0,nodenum=0; i<0xff && nodenum!=0xff; i++) { + int thisnodenum = nodenum; + /* For now we build the list from the "boot" config + * because asking for the "current" config causes + * some BIOSes to crash. */ + if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node)) { + printk(KERN_WARNING "PnPBIOS: PnP BIOS reported error on attempt to get dev node.\n"); + break; + } + /* The BIOS returns with nodenum = the next node number */ + if (nodenum < thisnodenum) { + printk(KERN_WARNING "PnPBIOS: Node number is out of sequence. Naughty BIOS!\n"); + break; + } + nodes_got++; + dev = pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL); + if (!dev) + break; + memset(dev,0,sizeof(struct pci_dev)); + dev->devfn=thisnodenum; + memcpy(dev->name,"PNPBIOS",8); + pnpid32_to_pnpid(node->eisa_id,dev->slot_name); + node_resource_data_to_dev(node,dev); + if(insert_device(dev)<0) + kfree(dev); + else + devs++; + } + kfree(node); + + printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver.\n", + nodes_got, nodes_got != 1 ? "s" : "", devs); +} + +static struct pci_dev *find_device_by_nodenum( u8 nodenum ) +{ + struct pci_dev *dev; + + pnpbios_for_each_dev(dev) { + if(dev->devfn == nodenum) + return dev; + } + + return NULL; +} + +static void update_devlist( u8 nodenum, struct pnp_bios_node *data ) +{ + unsigned long flags; + struct pci_dev *dev; + + spin_lock_irqsave(&pnpbios_devices_lock, flags); + dev = find_device_by_nodenum( nodenum ); + if ( dev ) { + node_resource_data_to_dev(data,dev); + } + spin_unlock_irqrestore(&pnpbios_devices_lock, flags); + + return; +} + + +/* + * + * DRIVER REGISTRATION FUNCTIONS + * + * + * Exported to give public access + * + */ + +static LIST_HEAD(pnpbios_drivers); + +static const struct pnpbios_device_id * +match_device(const struct pnpbios_device_id *ids, const struct pci_dev *dev) +{ + while (*ids->id) + { + if(memcmp(ids->id, dev->slot_name, 7)==0) + return ids; + ids++; + } + return NULL; +} + +static int announce_device(struct pnpbios_driver *drv, struct pci_dev *dev) +{ + const struct pnpbios_device_id *id; + struct pci_dev tmpdev; + int ret; + + if (drv->id_table) { + id = match_device(drv->id_table, dev); + if (!id) + return 0; + } else + id = NULL; + + memcpy( &tmpdev, dev, sizeof(struct pci_dev)); + tmpdev.global_list.prev = NULL; + tmpdev.global_list.next = NULL; + + dev_probe_lock(); + /* Obviously, probe() should not call any pnpbios functions */ + ret = drv->probe(&tmpdev, id); + dev_probe_unlock(); + if (ret < 1) + return 0; + + dev->driver = (void *)drv; + + return 1; +} + +/** + * pnpbios_register_driver - register a new pci driver + * @drv: the driver structure to register + * + * Adds the driver structure to the list of registered drivers + * + * For each device in the pnpbios device list that matches one of + * the ids in drv->id_table, calls the driver's "probe" function with + * arguments (1) a pointer to a *temporary* struct pci_dev containing + * resource info for the device, and (2) a pointer to the id string + * of the device. Expects the probe function to return 1 if the + * driver claims the device (otherwise 0) in which case, marks the + * device as having this driver. + * + * Returns the number of pci devices which were claimed by the driver + * during registration. The driver remains registered even if the + * return value is zero. + */ +int pnpbios_register_driver(struct pnpbios_driver *drv) +{ + struct pci_dev *dev; + unsigned long flags; + int count = 0; + + list_add_tail(&drv->node, &pnpbios_drivers); + spin_lock_irqsave(&pnpbios_devices_lock, flags); + pnpbios_for_each_dev(dev) { + if (!pnpbios_dev_driver(dev)) + count += announce_device(drv, dev); + } + spin_unlock_irqrestore(&pnpbios_devices_lock, flags); + return count; +} + +EXPORT_SYMBOL(pnpbios_register_driver); + +/** + * pnpbios_unregister_driver - unregister a pci driver + * @drv: the driver structure to unregister + * + * Deletes the driver structure from the list of registered PnPBIOS + * drivers, gives it a chance to clean up by calling its "remove" + * function for each device it was responsible for, and marks those + * devices as driverless. + */ +void pnpbios_unregister_driver(struct pnpbios_driver *drv) +{ + unsigned long flags; + struct pci_dev *dev; + + list_del(&drv->node); + spin_lock_irqsave(&pnpbios_devices_lock, flags); + pnpbios_for_each_dev(dev) { + if (dev->driver == (void *)drv) { + if (drv->remove) + drv->remove(dev); + dev->driver = NULL; + } + } + spin_unlock_irqrestore(&pnpbios_devices_lock, flags); +} + +EXPORT_SYMBOL(pnpbios_unregister_driver); + + +/* + * + * RESOURCE RESERVATION FUNCTIONS + * + * + * Used only at init time + * + */ + +static void __init reserve_ioport_range(char *pnpid, int start, int end) +{ + struct resource *res; + char *regionid; + + regionid = pnpbios_kmalloc(16, GFP_KERNEL); + if ( regionid == NULL ) + return; + sprintf(regionid, "PnPBIOS %s", pnpid); + res = request_region(start,end-start+1,regionid); + if ( res == NULL ) + kfree( regionid ); + else + res->flags &= ~IORESOURCE_BUSY; + /* + * Failures at this point are usually harmless. pci quirks for + * example do reserve stuff they know about too, so we may well + * have double reservations. + */ + printk(KERN_INFO + "PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved.\n", + pnpid, start, end, + NULL != res ? "has been" : "could not be" + ); + + return; +} + +static void __init reserve_resources_of_dev( struct pci_dev *dev ) +{ + int i; + + for (i=0;i<DEVICE_COUNT_RESOURCE;i++) { + if ( dev->resource[i].flags & IORESOURCE_UNSET ) + /* end of resources */ + break; + if (dev->resource[i].flags & IORESOURCE_IO) { + /* ioport */ + if ( dev->resource[i].start == 0 ) + /* disabled */ + /* Do nothing */ + continue; + if ( dev->resource[i].start < 0x100 ) + /* + * Below 0x100 is only standard PC hardware + * (pics, kbd, timer, dma, ...) + * We should not get resource conflicts there, + * and the kernel reserves these anyway + * (see arch/i386/kernel/setup.c). + * So, do nothing + */ + continue; + if ( dev->resource[i].end < dev->resource[i].start ) + /* invalid endpoint */ + /* Do nothing */ + continue; + reserve_ioport_range( + dev->slot_name, + dev->resource[i].start, + dev->resource[i].end + ); + } else if (dev->resource[i].flags & IORESOURCE_MEM) { + /* iomem */ + /* For now do nothing */ + continue; + } else { + /* Neither ioport nor iomem */ + /* Do nothing */ + continue; + } + } + + return; +} + +static void __init reserve_resources( void ) +{ + struct pci_dev *dev; + + pnpbios_for_each_dev(dev) { + if ( + 0 != strcmp(dev->slot_name,"PNP0c01") && /* memory controller */ + 0 != strcmp(dev->slot_name,"PNP0c02") /* system peripheral: other */ + ) { + continue; + } + reserve_resources_of_dev(dev); + } + + return; +} + + +/* + * + * INIT AND EXIT + * + */ + +extern int is_sony_vaio_laptop; + +static int pnpbios_disabled; /* = 0 */ +static int dont_reserve_resources; /* = 0 */ +int pnpbios_dont_use_current_config; /* = 0 */ + +#ifndef MODULE +static int __init pnpbios_setup(char *str) +{ + int invert; + + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "off", 3) == 0) + pnpbios_disabled=1; + if (strncmp(str, "on", 2) == 0) + pnpbios_disabled=0; + invert = (strncmp(str, "no-", 3) == 0); + if (invert) + str += 3; + if (strncmp(str, "curr", 4) == 0) + pnpbios_dont_use_current_config = invert; + if (strncmp(str, "res", 3) == 0) + dont_reserve_resources = invert; + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); + } + + return 1; +} + +__setup("pnpbios=", pnpbios_setup); +#endif + +void __init pnpbios_init(void) +{ + union pnp_bios_expansion_header *check; + u8 sum; + int i, length; + + spin_lock_init(&pnp_bios_lock); + spin_lock_init(&pnpbios_devices_lock); + + if(pnpbios_disabled) { + printk(KERN_INFO "PnPBIOS: Disabled.\n"); + return; + } + + if ( is_sony_vaio_laptop ) + pnpbios_dont_use_current_config = 1; + + /* + * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS + * structure and, if one is found, sets up the selectors and + * entry points + */ + for (check = (union pnp_bios_expansion_header *) __va(0xf0000); + check < (union pnp_bios_expansion_header *) __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 "PnPBIOS: PnP BIOS version %d.%d is not supported.\n", + check->fields.version >> 4, + check->fields.version & 15); + continue; + } + printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p.\n", check); + printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%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, 64 * 1024); + Q_SET_SEL(PNP_CS16, check->fields.pm16cseg, 64 * 1024); + Q_SET_SEL(PNP_DS, check->fields.pm16dseg, 64 * 1024); + pnp_bios_callpoint.offset = check->fields.pm16offset; + pnp_bios_callpoint.segment = PNP_CS16; + pnp_bios_hdr = check; + break; + } + build_devlist(); + if ( ! dont_reserve_resources ) + reserve_resources(); +#ifdef CONFIG_PROC_FS + pnpbios_proc_init(); +#endif +#ifdef CONFIG_HOTPLUG + init_completion(&unload_sem); + if(kernel_thread(pnp_dock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL)>0) + unloading = 0; +#endif +} + +#ifdef MODULE + +MODULE_LICENSE("GPL"); + +/* We have to run it early and not as a module. */ +module_init(pnpbios_init); + +#ifdef CONFIG_HOTPLUG +static void pnpbios_exit(void) +{ + /* free_resources() ought to go here */ + /* pnpbios_proc_done() */ + unloading = 1; + wait_for_completion(&unload_sem); +} + +module_exit(pnpbios_exit); + +#endif +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/pnp/pnpbios_proc.c linux-2.5/drivers/pnp/pnpbios_proc.c --- linux-2.5.1/drivers/pnp/pnpbios_proc.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/pnp/pnpbios_proc.c Sat Dec 29 12:07:19 2001 @@ -0,0 +1,151 @@ +/* + * 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/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/pnpbios.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; + int i; + u8 nodenum; + char *p = buf; + + if (pos != 0) { + *eof = 1; + return 0; + } + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return -ENOMEM; + for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) { + if ( pnp_bios_get_dev_node(&nodenum, 1, node) ) + break; + 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 nodenum = (long)data; + int len; + + if (pos != 0) { + *eof = 1; + return 0; + } + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return -ENOMEM; + if ( pnp_bios_get_dev_node(&nodenum, boot, node) ) + return -EIO; + 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 nodenum = (long)data; + + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return -ENOMEM; + if ( pnp_bios_get_dev_node(&nodenum, boot, node) ) + return -EIO; + 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; +} + +/* + * When this is called, pnpbios functions are assumed to + * work and the pnpbios_dont_use_current_config flag + * should already have been set to the appropriate value + */ +void pnpbios_proc_init( void ) +{ + struct pnp_bios_node *node; + struct proc_dir_entry *ent; + char name[3]; + int i; + u8 nodenum; + + 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 = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return; + for (i=0,nodenum = 0; i<0xff && nodenum != 0xff; i++) { + if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0) + break; + sprintf(name, "%02x", node->handle); + if ( !pnpbios_dont_use_current_config ) { + 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 pnpbios_proc_done(void) +{ + int i; + char name[3]; + + if (!proc_pnp) return; + + for (i=0; i<0xff; i++) { + sprintf(name, "%02x", i); + if ( !pnpbios_dont_use_current_config ) + 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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/Makefile linux-2.5/drivers/s390/Makefile --- linux-2.5.1/drivers/s390/Makefile Wed Jul 25 21:12:02 2001 +++ linux-2.5/drivers/s390/Makefile Thu Dec 27 16:32:31 2001 @@ -7,7 +7,7 @@ subdir-y := block char misc net subdir-m := $(subdir-y) -obj-y := s390io.o s390mach.o s390dyn.o idals.o ccwcache.o +obj-y := s390io.o s390mach.o s390dyn.o idals.o ccwcache.o sysinfo.o export-objs += ccwcache.o idals.o s390dyn.o s390io.o obj-y += $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/block/dasd.c linux-2.5/drivers/s390/block/dasd.c --- linux-2.5.1/drivers/s390/block/dasd.c Sun Dec 9 04:02:47 2001 +++ linux-2.5/drivers/s390/block/dasd.c Wed Jan 2 23:16:43 2002 @@ -113,6 +113,7 @@ EXPORT_SYMBOL (dasd_default_erp_postaction); EXPORT_SYMBOL (dasd_sleep_on_req); EXPORT_SYMBOL (dasd_set_normalized_cda); +EXPORT_SYMBOL (dasd_device_from_kdev); /* SECTION: Constant definitions to be used within this file */ @@ -668,12 +669,18 @@ /* init devfs array */ major_info->gendisk.de_arr = (devfs_handle_t *) kmalloc (DASD_PER_MAJOR * sizeof (devfs_handle_t), GFP_KERNEL); + if(major_info->gendisk.de_arr == NULL) + goto out_gd_de_arr; + memset (major_info->gendisk.de_arr, 0, DASD_PER_MAJOR * sizeof (devfs_handle_t)); /* init flags */ major_info->gendisk.flags = (char *) kmalloc (DASD_PER_MAJOR * sizeof (char), GFP_KERNEL); + if(major_info->gendisk.flags == NULL) + goto out_gd_flags; + memset (major_info->gendisk.flags, 0, DASD_PER_MAJOR * sizeof (char)); /* register blockdevice */ @@ -781,10 +788,13 @@ major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED; } - out_reg_blkdev: - kfree (major_info->gendisk.flags); - kfree (major_info->gendisk.de_arr); +out_reg_blkdev: + kfree (major_info->gendisk.flags); + +out_gd_flags: + kfree (major_info->gendisk.de_arr); +out_gd_de_arr: /* Delete the new major info from dasd_major_info if needed */ if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) { kfree (major_info); @@ -846,7 +856,7 @@ * finds the device structure corresponding to the kdev supplied as argument * in the major_info structures and returns it or NULL when not found */ -static inline dasd_device_t * +dasd_device_t * dasd_device_from_kdev (kdev_t kdev) { major_info_t *major_info = NULL; @@ -1851,15 +1861,15 @@ dasd_era_t era = dasd_era_none; /* default is everything is okay */ devstat_t *stat = (devstat_t *)ds; + if (stat == NULL) { + BUG(); + } DASD_DRIVER_DEBUG_EVENT (6, dasd_int_handler, "Interrupt: IRQ %02x, stat %02x, devno %04x", irq, stat->dstat, stat->devno); asm volatile ("STCK %0":"=m" (now)); - if (stat == NULL) { - BUG(); - } /* first of all check for state change pending interrupt */ if ((stat->dstat & DEV_STAT_ATTENTION ) && @@ -2623,7 +2633,6 @@ invalidate_buffers (inp->i_rdev); if ( device->discipline->owner ) __MOD_DEC_USE_COUNT(device->discipline->owner); - MOD_DEC_USE_COUNT; } else if ( count == -1 ) { /* paranoia only */ atomic_set (&device->open_count,0); printk (KERN_WARNING PRINTK_HEADER diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/block/dasd_3990_erp.c linux-2.5/drivers/s390/block/dasd_3990_erp.c --- linux-2.5.1/drivers/s390/block/dasd_3990_erp.c Fri Nov 9 22:05:02 2001 +++ linux-2.5/drivers/s390/block/dasd_3990_erp.c Thu Dec 27 16:32:31 2001 @@ -237,8 +237,9 @@ /* check for 'No Record Found' */ if (sense[1] & SNS1_NO_REC_FOUND) { - DASD_MESSAGE (KERN_ERR, device, "%s", - "EXAMINE 24: No Record Found detected " + DASD_MESSAGE (KERN_ERR, device, + "EXAMINE 24: No Record Found detected %s", + cqr == device->init_cqr ? " " : "- fatal error"); return dasd_era_fatal; @@ -305,8 +306,9 @@ devstat_t *stat) { - char *sense = stat->ii.sense.data; - dasd_era_t era = dasd_era_recover; + char *sense = stat->ii.sense.data; + dasd_era_t era = dasd_era_recover; + dasd_device_t *device = cqr->device; /* check for successful execution first */ if (stat->cstat == 0x00 && @@ -327,7 +329,8 @@ } /* log the erp chain if fatal error occurred */ - if (era == dasd_era_fatal) { + if ((era == dasd_era_fatal ) && + (cqr != device->init_cqr) ){ log_erp_chain (cqr, 0, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/block/dasd_eckd.c linux-2.5/drivers/s390/block/dasd_eckd.c --- linux-2.5.1/drivers/s390/block/dasd_eckd.c Fri Nov 9 22:05:02 2001 +++ linux-2.5/drivers/s390/block/dasd_eckd.c Thu Dec 27 16:32:31 2001 @@ -585,7 +585,7 @@ /* Free the cqr and cleanup device->sizes */ if ( status != CQR_STATUS_DONE ) { DASD_MESSAGE (KERN_WARNING,device,"%s", - "volume analysis returned fatal error"); + "volume analysis returned unformatted disk"); return -EMEDIUMTYPE; } /* Check Track 0 for Compatible Disk Layout */ @@ -1097,8 +1097,14 @@ ccw->flags |= CCW_FLAG_CC; ccw->cmd_code = locate4k_set ? rw_cmd : dasd_eckd_cdl_cmd (device, recid, req->cmd); - ccw->count = locate4k_set ? byt_per_blk : - dasd_eckd_cdl_reclen (device, recid); + ccw->count = byt_per_blk; + if (!locate4k_set) { + ccw->count = dasd_eckd_cdl_reclen (device,recid); + if (ccw->count < byt_per_blk) { + memset (bh->b_data + size + ccw->count, + 0xE5, byt_per_blk - ccw->count); + } + } if (dasd_set_normalized_cda (ccw, __pa (bh->b_data+size), rw_cp, device)) { goto clear_rw_cp; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/block/dasd_int.h linux-2.5/drivers/s390/block/dasd_int.h --- linux-2.5.1/drivers/s390/block/dasd_int.h Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/s390/block/dasd_int.h Mon Jan 7 19:10:17 2002 @@ -88,7 +88,6 @@ major:D_MAJOR, \ major_name:D_NAME, \ minor_shift:D_PARTN_BITS, \ - max_p:1 << D_PARTN_BITS, \ max_nr:D_PER_MAJOR, \ nr_real:D_PER_MAJOR, static inline struct request * @@ -111,7 +110,6 @@ major:D_MAJOR, \ major_name:D_NAME, \ minor_shift:D_PARTN_BITS, \ - max_p:1 << D_PARTN_BITS, \ nr_real:D_PER_MAJOR, \ fops:&dasd_device_operations, static inline struct request * @@ -259,7 +257,6 @@ typedef int (*dasd_info_fn_t) (struct dasd_device_t *, dasd_information_t *); typedef int (*dasd_use_count_fn_t) (int); - /* * the dasd_discipline_t is * sth like a table of virtual functions, if you think of dasd_eckd @@ -364,6 +361,7 @@ void dasd_schedule_bh (dasd_device_t *); int dasd_sleep_on_req(ccw_req_t*); int dasd_set_normalized_cda ( ccw1_t * cp, unsigned long address, ccw_req_t* request, dasd_device_t* device ); +dasd_device_t * dasd_device_from_kdev (kdev_t kdev); extern debug_info_t *dasd_debug_area; extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/char/con3215.c linux-2.5/drivers/s390/char/con3215.c --- linux-2.5.1/drivers/s390/char/con3215.c Wed Jul 25 21:12:02 2001 +++ linux-2.5/drivers/s390/char/con3215.c Sun Dec 30 13:55:22 2001 @@ -1145,7 +1145,9 @@ tty3215_driver.table = tty3215_table; tty3215_driver.termios = tty3215_termios; tty3215_driver.termios_locked = tty3215_termios_locked; - +#ifdef CONFIG_TN3215_CONSOLE + tty3215_driver.console = &con3215; +#endif tty3215_driver.open = tty3215_open; tty3215_driver.close = tty3215_close; tty3215_driver.write = tty3215_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/char/tuball.c linux-2.5/drivers/s390/char/tuball.c --- linux-2.5.1/drivers/s390/char/tuball.c Thu Oct 11 16:43:29 2001 +++ linux-2.5/drivers/s390/char/tuball.c Thu Dec 27 15:56:12 2001 @@ -84,7 +84,6 @@ tub3270_con_write, /* write */ NULL, /* read */ tub3270_con_device, /* device */ - NULL, /* wait_key */ tub3270_con_unblank, /* unblank */ NULL, /* setup */ CON_PRINTBUFFER, /* flags */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/char/tubtty.c linux-2.5/drivers/s390/char/tubtty.c --- linux-2.5.1/drivers/s390/char/tubtty.c Thu Oct 11 16:43:29 2001 +++ linux-2.5/drivers/s390/char/tubtty.c Sun Dec 30 13:55:22 2001 @@ -53,6 +53,7 @@ struct tty_struct *tty3270_table[TUBMAXMINS]; struct termios *tty3270_termios[TUBMAXMINS]; struct termios *tty3270_termios_locked[TUBMAXMINS]; +extern struct console tub3270_con; #ifdef CONFIG_TN3270_CONSOLE int con3270_major = -1; struct tty_driver con3270_driver; @@ -94,7 +95,9 @@ td->table = tty3270_table; td->termios = tty3270_termios; td->termios_locked = tty3270_termios_locked; - +#ifdef CONFIG_TN3270_CONSOLE + td->console = &tub3270_con; +#endif td->open = tty3270_open; td->close = tty3270_close; td->write = tty3270_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/misc/chandev.c linux-2.5/drivers/s390/misc/chandev.c --- linux-2.5.1/drivers/s390/misc/chandev.c Fri Nov 9 22:05:02 2001 +++ linux-2.5/drivers/s390/misc/chandev.c Thu Dec 27 16:32:31 2001 @@ -1057,6 +1057,9 @@ chandev_add_model(chandev_type_osad,0x3088,0x62,-1,-1,0,default_msck_bits,FALSE,FALSE); /* claw */ chandev_add_model(chandev_type_claw,0x3088,0x61,-1,-1,0,default_msck_bits,FALSE,FALSE); + + /* ficon attached ctc */ + chandev_add_model(chandev_type_escon,0x3088,0x1E,-1,-1,0,default_msck_bits,FALSE,FALSE); } @@ -3092,7 +3095,7 @@ chandevs_detected=TRUE; if(pass) { - chandev_printf(chan_exit,"0x%04x 0x%04x 0x%02x 0x%04x 0x%02x 0x%04x 0x%02x 0x%02x 0x%016Lx %-5s %-5s\n", + chandev_printf(chan_exit,"0x%04x 0x%04x 0x%02x 0x%04x 0x%02x 0x%04x 0x%02x 0x%02x 0x%016Lx %-5s%-5s\n", curr_irq,curr_devinfo.devno, ( curr_force ? curr_force->chan_type : ( curr_model ? curr_model->chan_type : diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/net/ctcmain.c linux-2.5/drivers/s390/net/ctcmain.c --- linux-2.5.1/drivers/s390/net/ctcmain.c Thu Oct 11 16:43:29 2001 +++ linux-2.5/drivers/s390/net/ctcmain.c Thu Dec 27 16:32:31 2001 @@ -1,5 +1,5 @@ /* - * $Id: ctcmain.c,v 1.51 2001/09/24 10:38:02 mschwide Exp $ + * $Id: ctcmain.c,v 1.55 2001/12/03 14:28:45 felfert Exp $ * * CTC / ESCON network driver * @@ -35,7 +35,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.51 $ + * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.55 $ * */ @@ -96,7 +96,9 @@ #ifdef MODULE MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver"); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12)) MODULE_LICENSE("GPL"); +#endif #ifndef CTC_CHANDEV MODULE_PARM(ctc, "s"); MODULE_PARM_DESC(ctc, @@ -368,7 +370,7 @@ static __inline__ void ctc_clear_busy(net_device *dev) { clear_bit(0, &(((ctc_priv *)dev->priv)->tbusy)); - netif_start_queue(dev); + netif_wake_queue(dev); } static __inline__ int ctc_test_and_set_busy(net_device *dev) @@ -385,7 +387,7 @@ */ static void print_banner(void) { static int printed = 0; - char vbuf[] = "$Revision: 1.51 $"; + char vbuf[] = "$Revision: 1.55 $"; char *version = vbuf; if (printed) @@ -396,7 +398,16 @@ *p = '\0'; } else version = " ??? "; - printk(KERN_INFO "CTC driver Version%s initialized\n", version); + printk(KERN_INFO + "CTC driver Version%swith" +#ifndef CTC_CHANDEV + "out" +#endif + " CHANDEV support" +#ifdef DEBUG + " (DEBUG-VERSION, " __DATE__ __TIME__ ")" +#endif + " initialized\n", version); printed = 1; } @@ -754,12 +765,13 @@ pskb->protocol = ntohs(header->type); header->length -= LL_HEADER_LENGTH; if ((header->length == 0) || - (header->length > skb_tailroom(pskb))) { + (header->length > skb_tailroom(pskb)) || + (header->length > len)) { printk(KERN_WARNING "%s Illegal packet size %d " - "received (MTU=%d), " + "received (MTU=%d blocklen=%d), " "dropping\n", dev->name, header->length, - dev->mtu); + dev->mtu, len); #ifdef DEBUG ctc_dump_skb(pskb, -6); #endif @@ -929,7 +941,8 @@ if (ch->trans_skb != NULL) dev_kfree_skb(ch->trans_skb); clear_normalized_cda(&ch->ccw[1]); - ch->trans_skb = dev_alloc_skb(ch->max_bufsize); + ch->trans_skb = __dev_alloc_skb(ch->max_bufsize, + GFP_ATOMIC|GFP_DMA); if (ch->trans_skb == NULL) { if (warn) printk(KERN_WARNING @@ -1026,7 +1039,6 @@ ch->prof.maxmulti = ch->collect_len + 2; if (ch->prof.maxcqueue < skb_queue_len(&ch->collect_queue)) ch->prof.maxcqueue = skb_queue_len(&ch->collect_queue); - ch->ccw[1].count = ch->collect_len + 2; *((__u16 *)skb_put(ch->trans_skb, 2)) = ch->collect_len + 2; i = 0; while ((skb = skb_dequeue(&ch->collect_queue))) { @@ -1039,11 +1051,10 @@ i++; } ch->collect_len = 0; + spin_unlock(&ch->collect_lock); + ch->ccw[1].count = ch->trans_skb->len; fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); ch->prof.send_stamp = xtime; -#ifdef DEBUG - printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda); -#endif rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0); ch->prof.doios_multi++; if (rc != 0) { @@ -1052,10 +1063,11 @@ fsm_deltimer(&ch->timer); ccw_check_return_code(ch, rc); } - } else + } else { + spin_unlock(&ch->collect_lock); fsm_newstate(fi, CH_STATE_TXIDLE); + } ctc_clear_busy(dev); - spin_unlock(&ch->collect_lock); } /** @@ -1146,9 +1158,6 @@ if (ctc_checkalloc_buffer(ch, 1)) return; ch->ccw[1].count = ch->max_bufsize; -#ifdef DEBUG - printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda); -#endif rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0); if (rc != 0) ccw_check_return_code(ch, rc); @@ -1203,9 +1212,6 @@ *((__u16 *)ch->trans_skb->data) = CTC_INITIAL_BLOCKLEN; ch->ccw[1].count = 2; /* Transfer only length */ -#ifdef DEBUG - printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda); -#endif fsm_newstate(fi, (CHANNEL_DIRECTION(ch->flags) == READ) ? CH_STATE_RXINIT : CH_STATE_TXINIT); rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0); @@ -1254,9 +1260,6 @@ return; ch->ccw[1].count = ch->max_bufsize; fsm_newstate(fi, CH_STATE_RXIDLE); -#ifdef DEBUG - printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda); -#endif rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0); if (rc != 0) { fsm_newstate(fi, CH_STATE_RXINIT); @@ -1716,9 +1719,6 @@ fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch); if (event == CH_EVENT_TIMER) s390irq_spin_lock_irqsave(ch->irq, saveflags); -#ifdef DEBUG - printk(KERN_DEBUG "ccw[4].cda = %08x\n", ch->ccw[4].cda); -#endif rc = do_IO(ch->irq, &ch->ccw[3], (intparm_t)ch, 0xff, 0); if (event == CH_EVENT_TIMER) s390irq_spin_unlock_irqrestore(ch->irq, @@ -2479,6 +2479,8 @@ } else { __u16 block_len; int ccw_idx; + struct sk_buff *nskb; + unsigned long hi; /** * Protect skb against beeing free'd by upper @@ -2493,6 +2495,28 @@ LL_HEADER_LENGTH); block_len = skb->len + 2; *((__u16 *)skb_push(skb, 2)) = block_len; + + /** + * IDAL support in CTC is broken, so we have to + * care about skb's above 2G ourselves. + */ + hi = ((unsigned long)skb->tail + LL_HEADER_LENGTH) >> 31; + if (hi) { + nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); + if (!nskb) { + atomic_dec(&skb->users); + skb_pull(skb, LL_HEADER_LENGTH + 2); + return -ENOMEM; + } else { + memcpy(skb_put(nskb, skb->len), + skb->data, skb->len); + atomic_inc(&nskb->users); + atomic_dec(&skb->users); + dev_kfree_skb_irq(skb); + skb = nskb; + } + } + ch->ccw[4].count = block_len; if (set_normalized_cda(&ch->ccw[4], virt_to_phys(skb->data))) { /** @@ -2505,6 +2529,7 @@ * Remove our header. It gets added * again on retransmit. */ + atomic_dec(&skb->users); skb_pull(skb, LL_HEADER_LENGTH + 2); return -EBUSY; } @@ -2522,18 +2547,11 @@ ccw_idx = 3; } ch->retry = 0; -#ifdef DEBUG - ctc_dump_skb(skb, 0); -#endif fsm_newstate(ch->fsm, CH_STATE_TX); fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); s390irq_spin_lock_irqsave(ch->irq, saveflags); ch->prof.send_stamp = xtime; -#ifdef DEBUG - printk(KERN_DEBUG "ccw[%d].cda = %08x\n", ccw_idx+1, - ch->ccw[ccw_idx+1].cda); -#endif rc = do_IO(ch->irq, &ch->ccw[ccw_idx], (intparm_t)ch, 0xff, 0); s390irq_spin_unlock_irqrestore(ch->irq, saveflags); if (ccw_idx == 3) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/net/fsm.h linux-2.5/drivers/s390/net/fsm.h --- linux-2.5.1/drivers/s390/net/fsm.h Wed Jul 25 21:12:02 2001 +++ linux-2.5/drivers/s390/net/fsm.h Thu Dec 27 16:32:31 2001 @@ -1,4 +1,4 @@ -/* $Id: fsm.h,v 1.3 2001/06/18 16:49:19 felfert Exp $ +/* $Id: fsm.h,v 1.4 2001/09/24 10:38:02 mschwide Exp $ */ #ifndef _FSM_H_ #define _FSM_H_ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/net/iucv.c linux-2.5/drivers/s390/net/iucv.c --- linux-2.5.1/drivers/s390/net/iucv.c Thu Oct 11 16:43:29 2001 +++ linux-2.5/drivers/s390/net/iucv.c Thu Dec 27 16:32:31 2001 @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * IUCV network driver @@ -478,7 +478,7 @@ b2f0(__u32 code, void *parm) { iucv_debug("iparml before b2f0 call:"); - iucv_dumpit(parm, sizeof(iucv_param.param)); + iucv_dumpit(parm, sizeof(iucv_param)); asm volatile ( "LRA 1,0(%1)\n\t" @@ -490,7 +490,7 @@ ); iucv_debug("iparml after b2f0 call:"); - iucv_dumpit(parm, sizeof(iucv_param.param)); + iucv_dumpit(parm, sizeof(iucv_param)); return (unsigned long)*((__u8 *)(parm + 3)); } @@ -2126,7 +2126,7 @@ iucv_sever (int_buf->ippathid, no_listener); iucv_debug("add_pathid failed, rc = %d", - (int)add_pathid_result); + rc); } else { interrupt = h->interrupt_table; if (interrupt->ConnectionPending) { @@ -2150,8 +2150,8 @@ h->pgm_data); else iucv_debug("ConnectionComplete not called"); - } - + } else + iucv_sever(int_buf->ippathid, no_listener); break; case 0x03: /* connection severed */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/net/netiucv.c linux-2.5/drivers/s390/net/netiucv.c --- linux-2.5.1/drivers/s390/net/netiucv.c Thu Oct 11 16:43:29 2001 +++ linux-2.5/drivers/s390/net/netiucv.c Thu Dec 27 16:32:31 2001 @@ -1,5 +1,5 @@ /* - * $Id: netiucv.c,v 1.12 2001/09/24 10:38:02 mschwide Exp $ + * $Id: netiucv.c,v 1.16 2001/12/03 14:28:45 felfert Exp $ * * IUCV network driver * @@ -28,7 +28,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV network driver $Revision: 1.12 $ + * RELEASE-TAG: IUCV network driver $Revision: 1.16 $ * */ @@ -189,7 +189,7 @@ static __inline__ void netiucv_clear_busy(net_device *dev) { clear_bit(0, &(((netiucv_priv *)dev->priv)->tbusy)); - netif_start_queue(dev); + netif_wake_queue(dev); } static __inline__ int netiucv_test_and_set_busy(net_device *dev) @@ -548,7 +548,7 @@ header->next -= NETIUCV_HDRLEN; if (skb_tailroom(pskb) < header->next) { printk(KERN_WARNING - "%s: Ilegal next field in iucv header: %d > %d\n", + "%s: Illegal next field in iucv header: %d > %d\n", dev->name, header->next, skb_tailroom(pskb)); return; } @@ -618,7 +618,8 @@ iucv_connection *conn = ev->conn; iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data; netiucv_priv *privptr = NULL; - struct sk_buff *skb = (struct sk_buff *)eib->ipmsgtag; + /* Shut up, gcc! skb is always below 2G. */ + struct sk_buff *skb = (struct sk_buff *)(unsigned long)eib->ipmsgtag; __u32 txbytes = 0; __u32 txpackets = 0; __u32 stat_maxcq = 0; @@ -638,10 +639,9 @@ (skb->len - NETIUCV_HDRLEN - NETIUCV_HDRLEN); } dev_kfree_skb_any(skb); - } else { - conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head; - conn->tx_buff->len = 0; } + conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head; + conn->tx_buff->len = 0; spin_lock_irqsave(&conn->collect_lock, saveflags); while ((skb = skb_dequeue(&conn->collect_queue))) { header.next = conn->tx_buff->len + skb->len + NETIUCV_HDRLEN; @@ -768,7 +768,8 @@ case CONN_STATE_TX: printk(KERN_INFO "%s: Remote dropped connection\n", netdev->name); - iucv_unregister_program(conn->handle); + if (conn->handle) + iucv_unregister_program(conn->handle); conn->handle = 0; fsm_newstate(fi, CONN_STATE_STOPPED); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); @@ -881,7 +882,8 @@ #endif fsm_newstate(fi, CONN_STATE_STOPPED); netiucv_purge_skb_queue(&conn->collect_queue); - iucv_unregister_program(conn->handle); + if (conn->handle) + iucv_unregister_program(conn->handle); conn->handle = 0; fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); } @@ -1127,7 +1129,10 @@ fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, CONN_EVENT_TIMER, conn); conn->prof.send_stamp = xtime; - rc = iucv_send(conn->pathid, NULL, 0, 0, (__u32)nskb, 0, + + rc = iucv_send(conn->pathid, NULL, 0, 0, + /* Shut up, gcc! nskb is always below 2G. */ + (__u32)(((unsigned long)nskb)&0xffffffff), 0, nskb->data, nskb->len); conn->prof.doios_single++; conn->prof.txlen += skb->len; @@ -1167,6 +1172,7 @@ static int netiucv_open(net_device *dev) { MOD_INC_USE_COUNT; + SET_DEVICE_START(dev, 1); fsm_event(((netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START, dev); return 0; } @@ -1573,9 +1579,7 @@ if (file->f_pos == 0) { p += sprintf(p, "Device FSM state: %s\n", fsm_getstate_str(privptr->fsm)); - p += sprintf(p, "RX channel FSM state: %s\n", - fsm_getstate_str(privptr->conn->fsm)); - p += sprintf(p, "TX channel FSM state: %s\n", + p += sprintf(p, "Connection FSM state: %s\n", fsm_getstate_str(privptr->conn->fsm)); p += sprintf(p, "Max. TX buffer used: %ld\n", privptr->conn->prof.maxmulti); @@ -1970,7 +1974,6 @@ dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = NETIUCV_QUEUELEN_DEFAULT; - SET_DEVICE_START(dev, 1); dev_init_buffers(dev); dev->flags = IFF_POINTOPOINT | IFF_NOARP; return dev; @@ -2002,7 +2005,7 @@ static void netiucv_banner(void) { - char vbuf[] = "$Revision: 1.12 $"; + char vbuf[] = "$Revision: 1.16 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { @@ -2118,5 +2121,7 @@ #ifdef MODULE module_init(netiucv_init); module_exit(netiucv_exit); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12)) MODULE_LICENSE("GPL"); +#endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/s390io.c linux-2.5/drivers/s390/s390io.c --- linux-2.5.1/drivers/s390/s390io.c Thu Nov 22 18:41:14 2001 +++ linux-2.5/drivers/s390/s390io.c Thu Dec 27 16:32:31 2001 @@ -6,6 +6,7 @@ * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, * IBM Corporation * Author(s): Ingo Adlung (adlung@de.ibm.com) + * Cornelia Huck (cohuck@de.ibm.com) * ChangeLog: 01/07/2001 Blacklist cleanup (djbarrow@de.ibm.com,barrow_dj@yahoo.com) * 01/04/2001 Holger Smolinski (smolinsk@de.ibm.com) * Fixed lost interrupts and do_adapter_IO @@ -24,6 +25,9 @@ * xx/xx/xxxx some bugfixes & cleanups * 08/02/2001 Cornelia Huck not already known devices can be blacklisted * by piping to /proc/cio_ignore + * 09/xx/2001 couple more fixes + * 10/29/2001 Cornelia Huck Blacklisting reworked again + * 10/29/2001 Cornelia Huck improved utilization of debug feature */ #include <linux/module.h> @@ -108,7 +112,9 @@ static void s390_process_subchannels( void); static void s390_device_recognition_all( void); static void s390_device_recognition_irq( int irq); +#ifdef CONFIG_PROC_FS static void s390_redo_validation(void); +#endif static int s390_validate_subchannel( int irq, int enable); static int s390_SenseID( int irq, senseid_t *sid, __u8 lpm); static int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid); @@ -117,7 +123,9 @@ static int enable_subchannel( unsigned int irq); static int disable_subchannel( unsigned int irq); +#ifdef CONFIG_PROC_FS static int chan_proc_init( void ); +#endif static inline void do_adapter_IO( __u32 intparm ); @@ -131,108 +139,68 @@ asmlinkage void do_IRQ( struct pt_regs regs ); +#ifdef CONFIG_PROC_FS #define MAX_CIO_PROCFS_ENTRIES 0x300 /* magic number; we want to have some room to spare */ int cio_procfs_device_create(int devno); int cio_procfs_device_remove(int devno); int cio_procfs_device_purge(void); +#endif int cio_notoper_msg = 1; +#ifdef CONFIG_PROC_FS int cio_proc_devinfo = 0; /* switch off the /proc/deviceinfo/ stuff by default until problems are dealt with */ +#endif unsigned long s390_irq_count[NR_CPUS]; /* trace how many irqs have occured per cpu... */ int cio_count_irqs = 1; /* toggle use here... */ /* * "Blacklisting" of certain devices: - * Device numbers given in the commandline as blacklist=... won't be known to Linux + * Device numbers given in the commandline as cio_ignore=... 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 + * 10/23/01 reworked to get rid of lists */ -typedef struct dev_blacklist_range_t { - struct dev_blacklist_range_t *next; /* next range in list */ - unsigned int from; /* beginning of range */ - unsigned int to; /* end of range */ - int kmalloced; +static unsigned long bl_dev[2048] = {0,}; -} dev_blacklist_range_t; - -static dev_blacklist_range_t *dev_blacklist_range_head = NULL; /* Anchor for list of ranges */ -static dev_blacklist_range_t *dev_blacklist_unused_head = NULL; - static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED; -static int nr_blacklisted_ranges = 0; - -/* Handling of the blacklist ranges */ - -static inline void blacklist_range_destroy( dev_blacklist_range_t *range,int locked ) -{ - long flags; - - if(!locked) - spin_lock_irqsave( &blacklist_lock, flags ); - if(!remove_from_list((list **)&dev_blacklist_range_head,(list *)range)) - BUG(); - nr_blacklisted_ranges--; - if(range->kmalloced) - kfree(range); - else - add_to_list((list **)&dev_blacklist_unused_head,(list *)range); - if(!locked) - spin_unlock_irqrestore( &blacklist_lock, flags ); -} - - +static int highest_ignored = 0; +static int nr_ignored = 0; /* * Function: blacklist_range_add - * Creates a range from the specified arguments and appends it to the list of - * blacklisted devices + * Blacklist the devices from-to */ -static inline dev_blacklist_range_t *blacklist_range_add( int from, int to,int locked) +static inline void blacklist_range_add( int from, int to,int locked) { - dev_blacklist_range_t *range = NULL; unsigned long flags; + int i; if (to && (from>to)) { printk(KERN_WARNING "Invalid blacklist range %x to %x, skipping\n", from, to); - return NULL; + return; } if(!locked) spin_lock_irqsave( &blacklist_lock, flags ); - if(dev_blacklist_unused_head) - range=(dev_blacklist_range_t *) - remove_listhead((list **)&dev_blacklist_unused_head); - else if (init_IRQ_complete) { - if((range = ( dev_blacklist_range_t *) - kmalloc( sizeof( dev_blacklist_range_t ), GFP_KERNEL))) - range->kmalloced=1; - } else { - if((range = ( dev_blacklist_range_t *) - alloc_bootmem( sizeof( dev_blacklist_range_t ) ))) - range->kmalloced=0; - } - if (range) - { - add_to_list((list **)&dev_blacklist_range_head,(list *)range); - range->from = from; - if (to == 0) { /* only a single device is given */ - range->to = from; - } else { - range->to = to; - } - nr_blacklisted_ranges++; + + if (!to) + to = from; + for (i=from;i<=to;i++) { + set_bit(i,&bl_dev); + nr_ignored++; } + + if (to>=highest_ignored) + highest_ignored = to; + if(!locked) spin_unlock_irqrestore( &blacklist_lock, flags ); - return range; } /* @@ -242,14 +210,19 @@ static inline void blacklist_range_remove( int from, int to ) { - dev_blacklist_range_t *temp; long flags; + int i; spin_lock_irqsave( &blacklist_lock, flags ); - for ( temp = dev_blacklist_range_head; - (temp->from != from) && (temp->to != to); - temp = temp->next ); - blacklist_range_destroy( temp,1 ); + + for (i=from;i<=to;i++) { + clear_bit(i,&bl_dev); + nr_ignored--; + } + + if (to == highest_ignored) + for (highest_ignored=from;(highest_ignored>0) && (!test_bit(highest_ignored,&bl_dev));highest_ignored--); + spin_unlock_irqrestore( &blacklist_lock, flags ); } @@ -257,12 +230,12 @@ /* * Variable to hold the blacklisted devices given by the parameter line - * blacklist=... + * cio_ignore=... */ char *blacklist[256] = {NULL, }; /* - * Get the blacklist=... items from the parameter line + * Get the cio_ignore=... items from the parameter line */ static void blacklist_split_parm_string (char *str) @@ -282,7 +255,7 @@ } blacklist[count] = alloc_bootmem (len * sizeof (char) ); if (blacklist == NULL) { - printk (KERN_WARNING "can't store blacklist= parameter no %d\n", count + 1); + printk (KERN_WARNING "can't store cio_ignore= parameter no %d\n", count + 1); break; } memset (blacklist[count], 0, len * sizeof (char)); @@ -319,7 +292,7 @@ /* * Function: blacklist_parse - * Parse the parameters given to blacklist=... + * Parse the parameters given to cio_ignore=... * Add the blacklisted devices to the blacklist chain */ @@ -338,11 +311,9 @@ temp++; to = blacklist_strtoul( temp, &temp ); } - if (!blacklist_range_add( from, to,0 )) { - printk( KERN_WARNING "Blacklisting range from %X to %X failed!\n", from, to); - } + blacklist_range_add( from, to, 0 ); #ifdef CONFIG_DEBUG_IO - printk( "Blacklisted range from %X to %X\n", from, to ); + printk( KERN_INFO "Blacklisted range from %X to %X\n", from, to ); #endif str++; } @@ -356,7 +327,7 @@ void __init blacklist_init( void ) { #ifdef CONFIG_DEBUG_IO - printk( "Reading blacklist...\n"); + printk( KERN_DEBUG "Reading blacklist...\n"); #endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 6, @@ -383,7 +354,7 @@ { int dummy; #ifdef CONFIG_DEBUG_IO - printk( "Reading blacklist parameters...\n" ); + printk( KERN_DEBUG "Reading blacklist parameters...\n" ); #endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 6, @@ -406,24 +377,14 @@ static inline int is_blacklisted( int devno ) { - dev_blacklist_range_t *temp; long flags; int retval=0; - if (dev_blacklist_range_head == NULL) { - /* no blacklist */ - return 0; - } - spin_lock_irqsave( &blacklist_lock, flags ); - temp = dev_blacklist_range_head; - while (temp) { - if ((temp->from <= devno) && (temp->to >= devno)) { - retval=1; /* Deviceno is blacklisted */ - break; - } - temp = temp->next; - } + + if (test_bit(devno,&bl_dev)) + retval=1; + spin_unlock_irqrestore( &blacklist_lock, flags ); return retval; } @@ -435,17 +396,20 @@ void blacklist_free_all_ranges(void) { - dev_blacklist_range_t *tmp = dev_blacklist_range_head; unsigned long flags; + int i; spin_lock_irqsave( &blacklist_lock, flags ); - while (tmp) { - blacklist_range_destroy(tmp,1); - tmp = dev_blacklist_range_head; - } + + for (i=0;i<=highest_ignored;i++) + clear_bit(i,&bl_dev); + highest_ignored = 0; + nr_ignored = 0; + spin_unlock_irqrestore( &blacklist_lock, flags ); } +#ifdef CONFIG_PROC_FS /* * Function: blacklist_parse_proc_parameters * parse the stuff which is piped to /proc/cio_ignore @@ -459,8 +423,6 @@ char *param; int from = 0; int to = 0; - int changed = 0; - dev_blacklist_range_t *range, *temp; long flags; int err = 0; @@ -492,33 +454,9 @@ } else { to = from; } - spin_lock_irqsave( &blacklist_lock, flags ); - range = dev_blacklist_range_head; - while (range != NULL) { - temp = range->next; - if ((from <= range->from) && (to >= range->to)) { - blacklist_range_destroy(range,1); - changed = 1; - } else if ((from <= range->from) && (to>=range->from) && (to < range->to)) { - blacklist_range_add(to+1, range->to,1); - blacklist_range_destroy(range,1); - changed = 1; - } else if ((from > range->from) && (from<=range->to) && (to >= range->to)) { - blacklist_range_add(range->from, from-1,1); - blacklist_range_destroy(range,1); - changed = 1; - } else if ((from > range->from) && (to < range->to)) { - blacklist_range_add(range->from, from-1,1); - blacklist_range_add(to+1, range->to,1); - blacklist_range_destroy(range,1); - changed = 1; - } - range = temp; - } - spin_unlock_irqrestore( &blacklist_lock, flags ); + blacklist_range_remove( from, to ); kfree(param); } - if (changed) s390_redo_validation(); } } else if (strstr(tmp, "add ")) { @@ -567,12 +505,6 @@ } } - /* - * Note: We allow for overlapping ranges here, - * since the user might specify overlapping ranges - * and we walk through all ranges when freeing anyway. - */ - if (!err) blacklist_range_add(from, to, 1); @@ -581,11 +513,11 @@ } } else { - printk("cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n"); - printk("or 'add <devno-range>,<devno-range>,...'\n"); + printk( KERN_WARNING "cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n"); + printk( KERN_WARNING "or 'add <devno-range>,<devno-range>,...'\n"); } } - +#endif /* End of blacklist handling */ @@ -642,7 +574,7 @@ } else { - printk( "cio_setup : invalid cio_msg parameter '%s'", parm); + printk( KERN_ERR "cio_setup : invalid cio_msg parameter '%s'", parm); } /* endif */ @@ -658,7 +590,7 @@ } else if (!strcmp(parm, "no")) { cio_notoper_msg = 0; } else { - printk("cio_notoper_setup: invalid cio_notoper_msg parameter '%s'", parm); + printk( KERN_ERR "cio_notoper_setup: invalid cio_notoper_msg parameter '%s'", parm); } return 1; @@ -666,6 +598,7 @@ __setup("cio_notoper_msg=", cio_notoper_setup); +#ifdef CONFIG_PROC_FS static int __init cio_proc_devinfo_setup(char *parm) { if (!strcmp(parm, "yes")) { @@ -673,13 +606,14 @@ } else if (!strcmp(parm, "no")) { cio_proc_devinfo = 0; } else { - printk("cio_proc_devinfo_setup: invalid parameter '%s'\n",parm); + printk( KERN_ERR "cio_proc_devinfo_setup: invalid parameter '%s'\n",parm); } return 1; } __setup("cio_proc_devinfo=", cio_proc_devinfo_setup); +#endif /* * register for adapter interrupts @@ -695,6 +629,7 @@ int s390_register_adapter_interrupt( adapter_int_handler_t handler ) { int ret = 0; + char dbf_txt[15]; if (cio_debug_initialized) debug_text_event(cio_debug_trace_id, 4, "rgaint"); @@ -710,6 +645,11 @@ spin_unlock( &adapter_lock ); + if (cio_debug_initialized) { + sprintf(dbf_txt,"ret:%d",ret); + debug_text_event(cio_debug_trace_id, 4, dbf_txt); + } + return( ret); } @@ -717,6 +657,7 @@ int s390_unregister_adapter_interrupt( adapter_int_handler_t handler ) { int ret = 0; + char dbf_txt[15]; if (cio_debug_initialized) debug_text_event(cio_debug_trace_id, 4, "urgaint"); @@ -732,6 +673,11 @@ spin_unlock( &adapter_lock ); + if (cio_debug_initialized) { + sprintf(dbf_txt,"ret:%d",ret); + debug_text_event(cio_debug_trace_id, 4, dbf_txt); + } + return( ret); } @@ -777,8 +723,7 @@ if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "reqsp"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "reqsp%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -835,6 +780,9 @@ ioinfo[irq]->nopfunc = not_oper_handler; } + if (cio_debug_initialized) + debug_int_event(cio_debug_trace_id, 4, retval); + return retval; } @@ -868,18 +816,13 @@ unsigned long flags; int ret; - unsigned int count = 0; char dbf_txt[15]; if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA ) - { return; - } /* endif */ - if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 2, "free"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "free%x", irq); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } @@ -887,10 +830,7 @@ #ifdef CONFIG_KERNEL_DEBUG if ( irq != cons_dev ) - { - printk("Trying to free IRQ%d\n",irq); - - } /* endif */ + printk( KERN_DEBUG "Trying to free IRQ%d\n",irq); #endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 2, "Trying to free IRQ %d\n", irq); @@ -899,10 +839,8 @@ * disable the device and reset all IRQ info if * the IRQ is actually owned by the handler ... */ - if ( ioinfo[irq]->ui.flags.ready ) - { - if ( dev_id == ioinfo[irq]->irq_desc.dev_id ) - { + if ( ioinfo[irq]->ui.flags.ready ) { + if ( dev_id == ioinfo[irq]->irq_desc.dev_id ) { /* start deregister */ ioinfo[irq]->ui.flags.unready = 1; @@ -915,15 +853,9 @@ 0xC8C1D3E3, DOIO_WAIT_FOR_INTERRUPT ); - do - { ret = disable_subchannel( irq); - count++; - - if ( ret == -EBUSY ) - { - int iret; + if ( ret == -EBUSY ) { /* * kill it ! @@ -932,45 +864,31 @@ * an async request, twice halt, then * clear. */ - if ( count < 2 ) - { - iret = halt_IO( irq, + ret = halt_IO( irq, 0xC8C1D3E3, DOIO_WAIT_FOR_INTERRUPT ); - if ( iret == -EBUSY ) - { + if ( ret == -EBUSY ) { halt_IO( irq, 0xC8C1D3E3, 0); s390irq_spin_unlock_irqrestore( irq, flags); udelay( 200000 ); /* 200 ms */ s390irq_spin_lock_irqsave( irq, flags); } /* endif */ - } - else - { - iret = clear_IO( irq, - 0x40C3D3D9, - DOIO_WAIT_FOR_INTERRUPT ); + + ret = disable_subchannel(irq); + + if (ret == -EBUSY) { - if ( iret == -EBUSY ) - { - clear_IO( irq, 0xC8C1D3E3, 0); + clear_IO( irq, 0x40C3D3D9,0 ); s390irq_spin_unlock_irqrestore( irq, flags); udelay( 1000000 ); /* 1000 ms */ s390irq_spin_lock_irqsave( irq, flags); - } /* endif */ - - } /* endif */ - - if ( count == 2 ) - { /* give it a very last try ... */ disable_subchannel( irq); - if ( ioinfo[irq]->ui.flags.busy ) - { + if ( ioinfo[irq]->ui.flags.busy ) { printk( KERN_CRIT"free_irq(%04X) " "- device %04X busy, retry " "count exceeded\n", @@ -983,39 +901,30 @@ } /* endif */ - break; /* sigh, let's give up ... */ - } /* endif */ } /* endif */ - } while ( ret == -EBUSY ); - ioinfo[irq]->ui.flags.ready = 0; ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ ioinfo[irq]->nopfunc = NULL; s390irq_spin_unlock_irqrestore( irq, flags); - } - else - { + } else { s390irq_spin_unlock_irqrestore( irq, flags); - printk( "free_irq(%04X) : error, " + printk( KERN_ERR "free_irq(%04X) : error, " "dev_id does not match !\n", irq); if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, "free_irq(%04X) : error, dev_id does not match !\n", irq); } /* endif */ - - } - else - { + } else { s390irq_spin_unlock_irqrestore( irq, flags); - printk( "free_irq(%04X) : error, " + printk( KERN_ERR "free_irq(%04X) : error, " "no action block ... !\n", irq); if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, @@ -1040,8 +949,7 @@ return -ENODEV; if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "disirq"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "disirq%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -1051,6 +959,9 @@ synchronize_irq(); + if (cio_debug_initialized) + debug_int_event(cio_debug_trace_id, 4, ret); + return( ret); } @@ -1066,8 +977,7 @@ return -ENODEV; if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "enirq"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "enirq%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -1075,6 +985,9 @@ ret = enable_subchannel(irq); s390irq_spin_unlock_irqrestore(irq, flags); + if (cio_debug_initialized) + debug_int_event(cio_debug_trace_id, 4, ret); + return(ret); } @@ -1091,8 +1004,7 @@ SANITY_CHECK(irq); if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 2, "ensch"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "ensch%x", irq); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } @@ -1168,6 +1080,11 @@ } /* endif */ + if (cio_debug_initialized) { + sprintf(dbf_txt,"ret:%d",ret); + debug_text_event(cio_debug_trace_id, 2, dbf_txt); + } + return( ret ); } @@ -1195,8 +1112,7 @@ else { if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 2, "dissch"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "dissch%x", irq); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } @@ -1274,6 +1190,11 @@ } /* endif */ + if (cio_debug_initialized) { + sprintf(dbf_txt, "ret:%d",ret); + debug_text_event(cio_debug_trace_id, 2, dbf_txt); + } + return( ret); } @@ -1364,8 +1285,7 @@ } /* endif */ if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "stIO"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "stIO%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -1427,6 +1347,11 @@ */ ccode = ssch( irq, &(ioinfo[irq]->orb) ); + if (cio_debug_initialized) { + sprintf(dbf_txt, "ccode:%d", ccode); + debug_text_event(cio_debug_trace_id, 4, dbf_txt); + } + switch ( ccode ) { case 0: @@ -1849,8 +1774,7 @@ } /* endif */ if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "doIO"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "doIO%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -1908,8 +1832,7 @@ SANITY_CHECK(irq); if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "resIO"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "resIO%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -1922,6 +1845,11 @@ ccode = rsch( irq); + if (cio_debug_initialized) { + sprintf(dbf_txt, "ccode:%d",ccode); + debug_text_event(cio_debug_trace_id, 4, dbf_txt); + } + switch (ccode) { case 0 : break; @@ -1988,21 +1916,10 @@ { ret = 0; } -#if 0 - /* - * We don't allow for halt_io with a sync do_IO() requests pending. - */ - else if ( ioinfo[irq]->ui.flags.syncio - && (flag & DOIO_WAIT_FOR_INTERRUPT)) - { - ret = -EBUSY; - } -#endif else { if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 2, "haltIO"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "haltIO%x", irq); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } /* @@ -2028,6 +1945,11 @@ */ ccode = hsch( irq ); + if (cio_debug_initialized) { + sprintf(dbf_txt, "ccode:%d",ccode); + debug_text_event(cio_debug_trace_id, 2, dbf_txt); + } + switch ( ccode ) { case 0: @@ -2253,22 +2175,10 @@ { ret = 0; } -#if 0 - /* - * We don't allow for clear_io with a sync do_IO() requests pending. - * Concurrent I/O is possible in SMP environments only, but the - * sync. I/O request can be gated to one CPU at a time only. - */ - else if ( ioinfo[irq]->ui.flags.syncio ) - { - ret = -EBUSY; - } -#endif else { if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 2, "clearIO"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "clearIO%x", irq); debug_text_event(cio_debug_trace_id, 2, dbf_txt); } /* @@ -2294,6 +2204,11 @@ */ ccode = csch( irq ); + if (cio_debug_initialized) { + sprintf(dbf_txt, "ccode:%d",ccode); + debug_text_event(cio_debug_trace_id, 2, dbf_txt); + } + switch ( ccode ) { case 0: @@ -2548,10 +2463,8 @@ } - if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 3, "procIRQ"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "procIRQ%x", irq); debug_text_event(cio_debug_trace_id, 3, dbf_txt); } @@ -2612,6 +2525,11 @@ */ ccode = tsch( irq, &(dp->ii.irb) ); + if (cio_debug_initialized) { + sprintf(dbf_txt, "ccode:%d", ccode); + debug_text_event(cio_debug_trace_id, 3, dbf_txt); + } + // // We must only accumulate the status if the device is busy already // @@ -2675,7 +2593,7 @@ #ifdef CONFIG_DEBUG_IO if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " + printk( KERN_DEBUG "s390_process_IRQ( %04X ) : " "residual count from irb after tsch() %d\n", irq, dp->rescnt ); #endif @@ -2698,7 +2616,7 @@ | SCHN_STAT_INTF_CTRL_CHK ))) { if (irq != cons_dev) - printk( "Channel-Check or Interface-Control-Check " + printk( KERN_WARNING "Channel-Check or Interface-Control-Check " "received\n" " ... device %04X on subchannel %04X, dev_stat " ": %02X sch_stat : %02X\n", @@ -2748,7 +2666,7 @@ #ifdef CONFIG_DEBUG_IO if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " + printk( KERN_DEBUG "s390_process_IRQ( %04X ) : " "concurrent sense bytes avail %d\n", irq, dp->scnt ); #endif @@ -2800,10 +2718,9 @@ ioinfo[irq]->stctl |= stctl; - ending_status = ( stctl & SCSW_STCTL_SEC_STATUS ) - || ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND) ) - || ( (fctl == SCSW_FCTL_HALT_FUNC) && (stctl == SCSW_STCTL_STATUS_PEND) ) - || ( (fctl == SCSW_FCTL_CLEAR_FUNC) && (stctl == SCSW_STCTL_STATUS_PEND) ); + ending_status = ( stctl & SCSW_STCTL_SEC_STATUS ) + || ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND) ) + || ( stctl == SCSW_STCTL_STATUS_PEND); /* * Check for unsolicited interrupts - for debug purposes only @@ -2821,7 +2738,7 @@ { #ifdef CONFIG_DEBUG_IO if (irq != cons_dev) - printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n" + printk( KERN_INFO "Unsolicited interrupt received for device %04X on subchannel %04X\n" " ... device status : %02X subchannel status : %02X\n", dp->devno, irq, @@ -2998,7 +2915,7 @@ #ifdef CONFIG_DEBUG_IO if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " + printk( KERN_DEBUG "s390_process_IRQ( %04X ) : " "BASIC SENSE bytes avail %d\n", irq, sense_count ); #endif @@ -3274,8 +3191,7 @@ else { if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "scons"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "scons%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -3336,8 +3252,7 @@ else { if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "rcons"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "rcons%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -3393,8 +3308,7 @@ { if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "wcons"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "wcons%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -3456,8 +3370,7 @@ char dbf_txt[15]; if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "enisc"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "enisc%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -3573,8 +3486,7 @@ char dbf_txt[15]; if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "disisc"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "disisc%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -3973,7 +3885,7 @@ if ( error ) { - printk( "DIAG X'210' for " + printk( KERN_ERR "DIAG X'210' for " "device %04X returned " "(cc = %d): vdev class : %02X, " "vdev type : %04X \n ... rdev class : %02X, rdev type : %04X, rdev model: %02X\n", @@ -4054,8 +3966,7 @@ } /* endif */ if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "rddevch"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "rddevch%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -4194,8 +4105,7 @@ } /* endif */ if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "rdconf"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "rdconf%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -4637,8 +4547,7 @@ char dbf_txt[15]; if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "devrec"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "devrec%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -4779,10 +4688,12 @@ } } +#ifdef CONFIG_PROC_FS if (cio_proc_devinfo) if (irq < MAX_CIO_PROCFS_ENTRIES) { cio_procfs_device_create(ioinfo[irq]->devno); } +#endif } } irq++; @@ -4811,7 +4722,7 @@ highest_subchannel = (--irq); - printk( "Highest subchannel number detected (hex) : %04X\n", + printk( KERN_INFO "Highest subchannel number detected (hex) : %04X\n", highest_subchannel); if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, @@ -4837,8 +4748,7 @@ char dbf_txt[15]; if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "valsch"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "valsch%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -4876,7 +4786,7 @@ */ if ( p_schib->pmcw.st ) { - printk( "Subchannel %04X reports " + printk( KERN_INFO "Subchannel %04X reports " "non-I/O subchannel type %04X\n", irq, p_schib->pmcw.st); @@ -4898,7 +4808,7 @@ * there is no device and return ENODEV. */ #ifdef CONFIG_DEBUG_IO - printk( "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev ); + printk( KERN_DEBUG "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev ); #endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, @@ -5109,7 +5019,7 @@ if ( ccode2 != 0 ) { - printk( " ... msch() (2) failed with CC = %X\n", + printk( KERN_ERR " ... msch() (2) failed with CC = %X\n", ccode2 ); if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, @@ -5128,7 +5038,7 @@ } else { - printk( " ... msch() (1) failed with CC = %X\n", + printk( KERN_ERR " ... msch() (1) failed with CC = %X\n", ccode2); if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 0, @@ -5148,7 +5058,7 @@ if ( (ccode2 != 0) && (ccode2 != 3) && (!retry) ) { - printk( " ... msch() retry count for " + printk( KERN_ERR " ... msch() retry count for " "subchannel %04X exceeded, CC = %d\n", irq, ccode2); @@ -5226,8 +5136,7 @@ } /* endif */ if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "snsID"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "snsID%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -5344,7 +5253,7 @@ if ( pdevstat->flag & DEVSTAT_STATUS_PENDING ) { #ifdef CONFIG_DEBUG_IO - printk( "SenseID : device %04X on " + printk( KERN_DEBUG "SenseID : device %04X on " "Subchannel %04X " "reports pending status, " "retry : %d\n", @@ -5363,7 +5272,7 @@ retry); } /* endif */ - if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL ) + else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL ) { /* * if the device doesn't support the SenseID @@ -5373,7 +5282,7 @@ & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ) ) { #ifdef CONFIG_DEBUG_IO - printk( "SenseID : device %04X on " + printk( KERN_ERR "SenseID : device %04X on " "Subchannel %04X " "reports cmd reject or " "intervention required\n", @@ -5394,7 +5303,7 @@ else { #ifdef CONFIG_DEBUG_IO - printk( "SenseID : UC on " + printk( KERN_WARNING "SenseID : UC on " "dev %04X, " "retry %d, " "lpum %02X, " @@ -5449,7 +5358,7 @@ || ( irq_ret == -ENODEV ) ) { #ifdef CONFIG_DEBUG_IO - printk( "SenseID : path %02X for " + printk( KERN_ERR "SenseID : path %02X for " "device %04X on " "subchannel %04X " "is 'not operational'\n", @@ -5479,7 +5388,7 @@ DEVSTAT_STATUS_PENDING ) ) { #ifdef CONFIG_DEBUG_IO - printk( "SenseID : start_IO() for " + printk( KERN_INFO "SenseID : start_IO() for " "device %04X on " "subchannel %04X " "returns %d, retry %d, " @@ -5628,7 +5537,7 @@ * consider the device "not operational". */ #ifdef CONFIG_DEBUG_IO - printk( "SenseID : unknown device %04X on subchannel %04X\n", + printk( KERN_WARNING "SenseID : unknown device %04X on subchannel %04X\n", ioinfo[irq]->schib.pmcw.dev, irq); #endif @@ -5732,8 +5641,7 @@ char dbf_txt[15]; if (cio_debug_initialized) { - debug_text_event(cio_debug_trace_id, 4, "dpver"); - sprintf(dbf_txt, "%x", irq); + sprintf(dbf_txt, "dpver%x", irq); debug_text_event(cio_debug_trace_id, 4, dbf_txt); } @@ -5842,7 +5750,7 @@ ioinfo[irq]->ui.flags.pgid_supp = 0; #ifdef CONFIG_DEBUG_IO - printk( "PathVerification(%04X) " + printk( KERN_WARNING "PathVerification(%04X) " "- Device %04X doesn't " " support path grouping\n", irq, @@ -5861,7 +5769,7 @@ else if ( ret == -EIO ) { #ifdef CONFIG_DEBUG_IO - printk("PathVerification(%04X) - I/O error " + printk( KERN_ERR "PathVerification(%04X) - I/O error " "on device %04X\n", irq, ioinfo[irq]->schib.pmcw.dev); #endif @@ -5876,7 +5784,7 @@ } else { #ifdef CONFIG_DEBUG_IO - printk( "PathVerification(%04X) " + printk( KERN_ERR "PathVerification(%04X) " "- Unexpected error on device %04X\n", irq, ioinfo[irq]->schib.pmcw.dev); @@ -5914,6 +5822,7 @@ devstat_t devstat; /* required by request_irq() */ devstat_t *pdevstat = &devstat; unsigned long flags; + char dbf_txt[15]; int irq_ret = 0; /* return code */ @@ -5929,6 +5838,11 @@ } /* endif */ + if (cio_debug_initialized) { + sprintf(dbf_txt,"SPID%x",irq); + debug_text_event(cio_debug_trace_id, 4, dbf_txt); + } + if ( !ioinfo[irq]->ui.flags.ready ) { /* @@ -5966,7 +5880,7 @@ } /* endif */ - spid_ccw[0].cmd_code = 0x5B; /* suspend multipath reconnect */ + spid_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN; spid_ccw[0].cda = 0; spid_ccw[0].count = 0; spid_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; @@ -5999,7 +5913,7 @@ if ( pdevstat->flag & DEVSTAT_STATUS_PENDING ) { #ifdef CONFIG_DEBUG_IO - printk( "SPID - Device %04X " + printk( KERN_DEBUG "SPID - Device %04X " "on Subchannel %04X " "reports pending status, " "retry : %d\n", @@ -6037,6 +5951,18 @@ { if ( mpath ) { + /* + * We now try single path mode. + * Note we must not issue the suspend + * multipath reconnect, or we will get + * a command reject by tapes. + */ + + spid_ccw[0].cmd_code = CCW_CMD_SET_PGID; + spid_ccw[0].cda = (__u32)virt_to_phys( pgid ); + spid_ccw[0].count = sizeof( pgid_t); + spid_ccw[0].flags = CCW_FLAG_SLI; + pgid->inf.fc = SPID_FUNC_SINGLE_PATH | SPID_FUNC_ESTABLISH; mpath = 0; @@ -6053,7 +5979,7 @@ else { #ifdef CONFIG_DEBUG_IO - printk( "SPID - device %04X," + printk( KERN_WARNING "SPID - device %04X," " unit check," " retry %d, cnt %02d," " sns :" @@ -6101,7 +6027,7 @@ /* don't issue warnings during startup unless requested*/ if (init_IRQ_complete || cio_notoper_msg) { - printk( "SPID - Device %04X " + printk( KERN_WARNING "SPID - Device %04X " "on Subchannel %04X " "became 'not operational'\n", ioinfo[irq]->schib.pmcw.dev, @@ -6171,6 +6097,7 @@ ccw1_t *snid_ccw; /* ccw area for SNID command */ devstat_t devstat; /* required by request_irq() */ devstat_t *pdevstat = &devstat; + char dbf_txt[15]; int irq_ret = 0; /* return code */ int retry = 5; /* retry count */ @@ -6185,6 +6112,11 @@ } /* endif */ + if (cio_debug_initialized) { + sprintf(dbf_txt,"SNID%x",irq); + debug_text_event(cio_debug_trace_id, 4, dbf_txt); + } + if ( !ioinfo[irq]->ui.flags.ready ) { /* @@ -6261,7 +6193,7 @@ else { #ifdef CONFIG_DEBUG_IO - printk( "SNID - device %04X," + printk( KERN_WARNING "SNID - device %04X," " unit check," " flag %04X, " " retry %d, cnt %02d," @@ -6310,7 +6242,7 @@ { /* don't issue warnings during startup unless requested*/ if (init_IRQ_complete || cio_notoper_msg) { - printk( "SNID - Device %04X " + printk( KERN_WARNING "SNID - Device %04X " "on Subchannel %04X " "became 'not operational'\n", ioinfo[irq]->schib.pmcw.dev, @@ -6341,7 +6273,7 @@ if ( pdevstat->flag & DEVSTAT_STATUS_PENDING ) { #ifdef CONFIG_DEBUG_IO - printk( "SNID - Device %04X " + printk( KERN_INFO "SNID - Device %04X " "on Subchannel %04X " "reports pending status, " "retry : %d\n", @@ -6361,7 +6293,7 @@ } /* endif */ - printk( "SNID - device %04X," + printk( KERN_WARNING "SNID - device %04X," " start_io() reports rc : %d, retrying ...\n", ioinfo[irq]->schib.pmcw.dev, irq_ret); @@ -6425,7 +6357,7 @@ int lock = 0; #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : starting ...\n"); + printk( KERN_DEBUG "do_crw_pending : starting ...\n"); #endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_crw_id, 2, @@ -6440,7 +6372,7 @@ irq = pcrwe->crw.rsid; #ifdef CONFIG_DEBUG_CRW - printk( KERN_INFO"do_crw_pending : source is " + printk( KERN_NOTICE"do_crw_pending : source is " "subchannel %04X\n", irq); #endif if (cio_debug_initialized) @@ -6465,7 +6397,7 @@ } /* endif */ #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : subchannel validation - start ...\n"); + printk( KERN_DEBUG "do_crw_pending : subchannel validation - start ...\n"); #endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_crw_id, 4, @@ -6476,7 +6408,7 @@ highest_subchannel = irq; #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : subchannel validation - done\n"); + printk( KERN_DEBUG "do_crw_pending : subchannel validation - done\n"); #endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_crw_id, 4, @@ -6496,7 +6428,7 @@ if ( ioinfo[irq] != INVALID_STORAGE_AREA ) { #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : ioinfo at " + printk( KERN_DEBUG "do_crw_pending : ioinfo at " #ifdef CONFIG_ARCH_S390X "%08lX\n", (unsigned long)ioinfo[irq]); @@ -6523,10 +6455,11 @@ if ( ioinfo[irq]->ui.flags.oper == 0 ) { not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc; - +#ifdef CONFIG_PROC_FS /* remove procfs entry */ if (cio_proc_devinfo) cio_procfs_device_remove(dev_no); +#endif /* * If the device has gone * call not oper handler @@ -6543,7 +6476,7 @@ else { #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : device " + printk( KERN_DEBUG "do_crw_pending : device " "recognition - start ...\n"); #endif if (cio_debug_initialized) @@ -6552,7 +6485,7 @@ s390_device_recognition_irq( irq ); #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : device " + printk( KERN_DEBUG "do_crw_pending : device " "recognition - done\n"); #endif if (cio_debug_initialized) @@ -6573,12 +6506,13 @@ pdevreg->oper_func( irq, pdevreg ); } /* endif */ - +#ifdef CONFIG_PROC_FS /* add new procfs entry */ if (cio_proc_devinfo) if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) { cio_procfs_device_create(ioinfo[irq]->devno); } +#endif } /* * ... it is and was operational, but @@ -6586,23 +6520,26 @@ */ else if ((ioinfo[irq]->devno != dev_no) && ( ioinfo[irq]->nopfunc != NULL )) { +#ifdef CONFIG_PROC_FS int devno_old = ioinfo[irq]->devno; +#endif ioinfo[irq]->nopfunc( irq, DEVSTAT_REVALIDATE ); - +#ifdef CONFIG_PROC_FS /* remove old entry, add new */ if (cio_proc_devinfo) { cio_procfs_device_remove(devno_old); cio_procfs_device_create(ioinfo[irq]->devno); } +#endif } /* endif */ } /* endif */ - +#ifdef CONFIG_PROC_FS /* get rid of dead procfs entries */ if (cio_proc_devinfo) cio_procfs_device_purge(); - +#endif } /* endif */ break; @@ -6610,7 +6547,7 @@ case CRW_RSC_MONITOR : #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : source is " + printk( KERN_NOTICE "do_crw_pending : source is " "monitoring facility\n"); #endif if (cio_debug_initialized) @@ -6623,7 +6560,7 @@ chpid = pcrwe->crw.rsid; #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : source is " + printk( KERN_NOTICE "do_crw_pending : source is " "channel path %02X\n", chpid); #endif if (cio_debug_initialized) @@ -6634,7 +6571,7 @@ case CRW_RSC_CONFIG : #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : source is " + printk( KERN_NOTICE "do_crw_pending : source is " "configuration-alert facility\n"); #endif if (cio_debug_initialized) @@ -6645,7 +6582,7 @@ case CRW_RSC_CSS : #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : source is " + printk( KERN_NOTICE "do_crw_pending : source is " "channel subsystem\n"); #endif if (cio_debug_initialized) @@ -6656,7 +6593,7 @@ default : #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : unknown source\n"); + printk( KERN_NOTICE "do_crw_pending : unknown source\n"); #endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_crw_id, 2, @@ -6670,7 +6607,7 @@ } /* endwhile */ #ifdef CONFIG_DEBUG_CRW - printk( "do_crw_pending : done\n"); + printk( KERN_DEBUG "do_crw_pending : done\n"); #endif if (cio_debug_initialized) debug_sprintf_event(cio_debug_crw_id, 2, @@ -6715,7 +6652,7 @@ { int ret = 0; - cio_debug_msg_id = debug_register("cio_msg",2,4,16*sizeof(long)); + cio_debug_msg_id = debug_register("cio_msg",4,4,16*sizeof(long)); if (cio_debug_msg_id != NULL) { debug_register_view(cio_debug_msg_id, &debug_sprintf_view); #ifdef CONFIG_DEBUG_IO @@ -6756,6 +6693,7 @@ __initcall(cio_debug_init); +#ifdef CONFIG_PROC_FS /* * Display info on subchannels in /proc/subchannels. * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01. @@ -7163,19 +7101,19 @@ entry->cio_chpid_entry = create_proc_entry( "chpids", S_IFREG|S_IRUGO, entry->cio_device_entry); entry->cio_chpid_entry->proc_fops = &cio_chpid_entry_file_ops; } else { - printk("Error, could not allocate procfs structure!\n"); + printk( KERN_WARNING "Error, could not allocate procfs structure!\n"); remove_proc_entry(buf, cio_procfs_deviceinfo_root); kfree(entry); rc = -ENOMEM; } } else { - printk("Error, could not allocate procfs structure!\n"); + printk( KERN_WARNING "Error, could not allocate procfs structure!\n"); kfree(entry); rc = -ENOMEM; } } else { - printk("Error, could not allocate procfs structure!\n"); + printk( KERN_WARNING "Error, could not allocate procfs structure!\n"); rc = -ENOMEM; } return rc; @@ -7288,15 +7226,14 @@ */ static struct proc_dir_entry *cio_ignore_proc_entry; - static int cio_ignore_proc_open(struct inode *inode, struct file *file) { int rc = 0; int size = 1; int len = 0; tempinfo_t *info; - dev_blacklist_range_t *tmp; long flags; + int i, j; info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t)); if (info == NULL) { @@ -7304,7 +7241,7 @@ rc = -ENOMEM; } else { file->private_data = (void *) info; - size += nr_blacklisted_ranges * 32; + size += nr_ignored * 6; info->data = (char *) vmalloc(size); if (size && info->data == NULL) { printk( KERN_WARNING "No memory available for data\n"); @@ -7312,13 +7249,15 @@ rc = -ENOMEM; } else { spin_lock_irqsave( &blacklist_lock, flags ); - tmp = dev_blacklist_range_head; - while (tmp) { - len += sprintf(info->data+len, "%04x ", tmp->from); - if (tmp->to != tmp->from) - len += sprintf(info->data+len, "- %04x", tmp->to); + for (i=0;i<=highest_ignored;i++) + if (test_bit(i,&bl_dev)) { + len += sprintf(info->data+len, "%04x ", i); + for (j=i;(j<=highest_ignored) && (test_bit(j,&bl_dev));j++); + j--; + if (i != j) + len += sprintf(info->data+len, "- %04x", j); len += sprintf(info->data+len, "\n"); - tmp = tmp->next; + i=j; } spin_unlock_irqrestore( &blacklist_lock, flags ); info->len = len; @@ -7370,7 +7309,7 @@ } buffer[user_len]='\0'; #ifdef CIO_DEBUG_IO - printk ("/proc/cio_ignore: '%s'\n", buffer); + printk ( KERN_DEBUG "/proc/cio_ignore: '%s'\n", buffer); #endif /* CIO_DEBUG_IO */ if (cio_debug_initialized) debug_sprintf_event(cio_debug_msg_id, 2, "/proc/cio_ignore: '%s'\n",buffer); @@ -7491,6 +7430,7 @@ __initcall(cio_irq_proc_init); /* end of procfs stuff */ +#endif schib_t *s390_get_schib( int irq ) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/s390/sysinfo.c linux-2.5/drivers/s390/sysinfo.c --- linux-2.5.1/drivers/s390/sysinfo.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/s390/sysinfo.c Thu Dec 27 16:32:31 2001 @@ -0,0 +1,354 @@ +/* + * drivers/s390/sysinfo.c + * + * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com) + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/proc_fs.h> +#include <linux/init.h> +#include <asm/ebcdic.h> + +struct sysinfo_1_1_1 +{ + char reserved_0[32]; + char manufacturer[16]; + char type[4]; + char reserved_1[12]; + char model[16]; + char sequence[16]; + char plant[4]; +}; + +struct sysinfo_1_2_1 +{ + char reserved_0[80]; + char sequence[16]; + char plant[4]; + char reserved_1[2]; + unsigned short cpu_address; +}; + +struct sysinfo_1_2_2 +{ + char reserved_0[32]; + unsigned int capability; + unsigned short cpus_total; + unsigned short cpus_configured; + unsigned short cpus_standby; + unsigned short cpus_reserved; + unsigned short adjustment[0]; +}; + +struct sysinfo_2_2_1 +{ + char reserved_0[80]; + char sequence[16]; + char plant[4]; + unsigned short cpu_id; + unsigned short cpu_address; +}; + +struct sysinfo_2_2_2 +{ + char reserved_0[32]; + unsigned short lpar_number; + char reserved_1; + unsigned char characteristics; + #define LPAR_CHAR_DEDICATED (1 << 7) + #define LPAR_CHAR_SHARED (1 << 6) + #define LPAR_CHAR_LIMITED (1 << 5) + unsigned short cpus_total; + unsigned short cpus_configured; + unsigned short cpus_standby; + unsigned short cpus_reserved; + char name[8]; + unsigned int caf; + char reserved_2[16]; + unsigned short cpus_dedicated; + unsigned short cpus_shared; +}; + +struct sysinfo_3_2_2 +{ + char reserved_0[31]; + unsigned char count; + struct + { + char reserved_0[4]; + unsigned short cpus_total; + unsigned short cpus_configured; + unsigned short cpus_standby; + unsigned short cpus_reserved; + char name[8]; + unsigned int caf; + char cpi[16]; + char reserved_1[24]; + + } vm[8]; +}; + +union s390_sysinfo +{ + struct sysinfo_1_1_1 sysinfo_1_1_1; + struct sysinfo_1_2_1 sysinfo_1_2_1; + struct sysinfo_1_2_2 sysinfo_1_2_2; + struct sysinfo_2_2_1 sysinfo_2_2_1; + struct sysinfo_2_2_2 sysinfo_2_2_2; + struct sysinfo_3_2_2 sysinfo_3_2_2; +}; + +static inline int stsi (void *sysinfo, + int fc, int sel1, int sel2) +{ + int cc, retv; + +#ifndef CONFIG_ARCH_S390X + __asm__ __volatile__ ( "lr\t0,%2\n" + "\tlr\t1,%3\n" + "\tstsi\t0(%4)\n" + "0:\tipm\t%0\n" + "\tsrl\t%0,28\n" + "1:lr\t%1,0\n" + ".section .fixup,\"ax\"\n" + "2:\tlhi\t%0,3\n" + "\tbras\t1,3f\n" + "\t.long 1b\n" + "3:\tl\t1,0(1)\n" + "\tbr\t1\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + "\t.align 4\n" + "\t.long 0b,2b\n" + ".previous\n" + : "=d" (cc), "=d" (retv) + : "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo) + : "cc", "memory", "0", "1" ); +#else + __asm__ __volatile__ ( "lr\t0,%2\n" + "lr\t1,%3\n" + "\tstsi\t0(%4)\n" + "0:\tipm\t%0\n" + "\tsrl\t%0,28\n" + "1:lr\t%1,0\n" + ".section .fixup,\"ax\"\n" + "2:\tlhi\t%0,3\n" + "\tjg\t1b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + "\t.align 8\n" + "\t.quad 0b,2b\n" + ".previous\n" + : "=d" (cc), "=d" (retv) + : "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo) + : "cc", "memory", "0", "1" ); +#endif + + return cc? -1 : retv; +} + +static inline int stsi_0 (void) +{ + int rc = stsi (NULL, 0, 0, 0); + return rc == -1 ? rc : (((unsigned int)rc) >> 28); +} + +static inline int stsi_1_1_1 (struct sysinfo_1_1_1 *info) +{ + int rc = stsi (info, 1, 1, 1); + if (rc != -1) + { + EBCASC (info->manufacturer, sizeof(info->manufacturer)); + EBCASC (info->type, sizeof(info->type)); + EBCASC (info->model, sizeof(info->model)); + EBCASC (info->sequence, sizeof(info->sequence)); + EBCASC (info->plant, sizeof(info->plant)); + } + return rc == -1 ? rc : 0; +} + +static inline int stsi_1_2_1 (struct sysinfo_1_2_1 *info) +{ + int rc = stsi (info, 1, 2, 1); + if (rc != -1) + { + EBCASC (info->sequence, sizeof(info->sequence)); + EBCASC (info->plant, sizeof(info->plant)); + } + return rc == -1 ? rc : 0; +} + +static inline int stsi_1_2_2 (struct sysinfo_1_2_2 *info) +{ + int rc = stsi (info, 1, 2, 2); + return rc == -1 ? rc : 0; +} + +static inline int stsi_2_2_1 (struct sysinfo_2_2_1 *info) +{ + int rc = stsi (info, 2, 2, 1); + if (rc != -1) + { + EBCASC (info->sequence, sizeof(info->sequence)); + EBCASC (info->plant, sizeof(info->plant)); + } + return rc == -1 ? rc : 0; +} + +static inline int stsi_2_2_2 (struct sysinfo_2_2_2 *info) +{ + int rc = stsi (info, 2, 2, 2); + if (rc != -1) + { + EBCASC (info->name, sizeof(info->name)); + } + return rc == -1 ? rc : 0; +} + +static inline int stsi_3_2_2 (struct sysinfo_3_2_2 *info) +{ + int rc = stsi (info, 3, 2, 2); + if (rc != -1) + { + int i; + for (i = 0; i < info->count; i++) + { + EBCASC (info->vm[i].name, sizeof(info->vm[i].name)); + EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi)); + } + } + return rc == -1 ? rc : 0; +} + + +static int proc_read_sysinfo(char *page, char **start, + off_t off, int count, + int *eof, void *data) +{ + unsigned long info_page = get_free_page (GFP_KERNEL); + union s390_sysinfo *info = (union s390_sysinfo *) info_page; + int len = 0; + int level; + int i; + + if (!info) + return 0; + + level = stsi_0 (); + + if (level < 1) + goto out; + if (stsi_1_1_1 (&info->sysinfo_1_1_1)) + goto out; + + len += sprintf (page+len, "Manufacturer: %-16.16s\n", + info->sysinfo_1_1_1.manufacturer); + len += sprintf (page+len, "Type: %-4.4s\n", + info->sysinfo_1_1_1.type); + len += sprintf (page+len, "Model: %-16.16s\n", + info->sysinfo_1_1_1.model); + len += sprintf (page+len, "Sequence Code: %-16.16s\n", + info->sysinfo_1_1_1.sequence); + len += sprintf (page+len, "Plant: %-4.4s\n", + info->sysinfo_1_1_1.plant); + + if (stsi_1_2_2 (&info->sysinfo_1_2_2)) + goto out; + + len += sprintf (page+len, "\n"); + len += sprintf (page+len, "CPUs Total: %d\n", + info->sysinfo_1_2_2.cpus_total); + len += sprintf (page+len, "CPUs Configured: %d\n", + info->sysinfo_1_2_2.cpus_configured); + len += sprintf (page+len, "CPUs Standby: %d\n", + info->sysinfo_1_2_2.cpus_standby); + len += sprintf (page+len, "CPUs Reserved: %d\n", + info->sysinfo_1_2_2.cpus_reserved); + + len += sprintf (page+len, "Capability: %d\n", + info->sysinfo_1_2_2.capability); + + for (i = 2; i <= info->sysinfo_1_2_2.cpus_total; i++) + len += sprintf (page+len, "Adjustment %02d-way: %d\n", + i, info->sysinfo_1_2_2.adjustment[i-2]); + + if (level < 2) + goto out; + if (stsi_2_2_2 (&info->sysinfo_2_2_2)) + goto out; + + len += sprintf (page+len, "\n"); + len += sprintf (page+len, "LPAR Number: %d\n", + info->sysinfo_2_2_2.lpar_number); + + len += sprintf (page+len, "LPAR Characteristics: "); + if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_DEDICATED) + len += sprintf (page+len, "Dedicated "); + if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_SHARED) + len += sprintf (page+len, "Shared "); + if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_LIMITED) + len += sprintf (page+len, "Limited "); + len += sprintf (page+len, "\n"); + + len += sprintf (page+len, "LPAR Name: %-8.8s\n", + info->sysinfo_2_2_2.name); + + len += sprintf (page+len, "LPAR Adjustment: %d\n", + info->sysinfo_2_2_2.caf); + + len += sprintf (page+len, "LPAR CPUs Total: %d\n", + info->sysinfo_2_2_2.cpus_total); + len += sprintf (page+len, "LPAR CPUs Configured: %d\n", + info->sysinfo_2_2_2.cpus_configured); + len += sprintf (page+len, "LPAR CPUs Standby: %d\n", + info->sysinfo_2_2_2.cpus_standby); + len += sprintf (page+len, "LPAR CPUs Reserved: %d\n", + info->sysinfo_2_2_2.cpus_reserved); + len += sprintf (page+len, "LPAR CPUs Dedicated: %d\n", + info->sysinfo_2_2_2.cpus_dedicated); + len += sprintf (page+len, "LPAR CPUs Shared: %d\n", + info->sysinfo_2_2_2.cpus_shared); + + if (level < 3) + goto out; + if (stsi_3_2_2 (&info->sysinfo_3_2_2)) + goto out; + + for (i = 0; i < info->sysinfo_3_2_2.count; i++) + { + len += sprintf (page+len, "\n"); + len += sprintf (page+len, "VM%02d Name: %-8.8s\n", + i, info->sysinfo_3_2_2.vm[i].name); + len += sprintf (page+len, "VM%02d Control Program: %-16.16s\n", + i, info->sysinfo_3_2_2.vm[i].cpi); + + len += sprintf (page+len, "VM%02d Adjustment: %d\n", + i, info->sysinfo_3_2_2.vm[i].caf); + + len += sprintf (page+len, "VM%02d CPUs Total: %d\n", + i, info->sysinfo_3_2_2.vm[i].cpus_total); + len += sprintf (page+len, "VM%02d CPUs Configured: %d\n", + i, info->sysinfo_3_2_2.vm[i].cpus_configured); + len += sprintf (page+len, "VM%02d CPUs Standby: %d\n", + i, info->sysinfo_3_2_2.vm[i].cpus_standby); + len += sprintf (page+len, "VM%02d CPUs Reserved: %d\n", + i, info->sysinfo_3_2_2.vm[i].cpus_reserved); + } + +out: + free_page (info_page); + return len; +} + +static __init int create_proc_sysinfo(void) +{ + create_proc_read_entry ("sysinfo", 0444, NULL, + proc_read_sysinfo, NULL); + return 0; +} + +__initcall(create_proc_sysinfo); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sbus/char/aurora.c linux-2.5/drivers/sbus/char/aurora.c --- linux-2.5.1/drivers/sbus/char/aurora.c Tue Oct 30 23:08:11 2001 +++ linux-2.5/drivers/sbus/char/aurora.c Sun Dec 30 21:17:30 2001 @@ -66,7 +66,6 @@ #include <asm/irq.h> #include <asm/oplib.h> #include <asm/system.h> -#include <asm/segment.h> #include <asm/bitops.h> #include <asm/kdebug.h> #include <asm/sbus.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sbus/char/bpp.c linux-2.5/drivers/sbus/char/bpp.c --- linux-2.5.1/drivers/sbus/char/bpp.c Thu Oct 11 16:43:29 2001 +++ linux-2.5/drivers/sbus/char/bpp.c Sun Dec 30 21:17:30 2001 @@ -28,7 +28,6 @@ #if defined(__i386__) # include <asm/system.h> -# include <asm/segment.h> #endif #if defined(__sparc__) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sbus/char/sab82532.c linux-2.5/drivers/sbus/char/sab82532.c --- linux-2.5.1/drivers/sbus/char/sab82532.c Wed Oct 17 21:16:39 2001 +++ linux-2.5/drivers/sbus/char/sab82532.c Sun Dec 30 13:55:22 2001 @@ -361,10 +361,6 @@ writeb(SAB82532_CMDR_RMC, &info->regs->w.cmdr); } -#ifdef CONFIG_SERIAL_CONSOLE - if (info->is_console) - wake_up(&keypress_wait); -#endif if (!tty) return; @@ -2255,7 +2251,9 @@ serial_driver.table = sab82532_table; serial_driver.termios = sab82532_termios; serial_driver.termios_locked = sab82532_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sab82532_console; +#endif serial_driver.open = sab82532_open; serial_driver.close = sab82532_close; serial_driver.write = sab82532_write; @@ -2541,13 +2539,6 @@ sab82532_tec_wait(info); } -static int -sab82532_console_wait_key(struct console *con) -{ - sleep_on(&keypress_wait); - return 0; -} - static kdev_t sab82532_console_device(struct console *con) { @@ -2622,7 +2613,6 @@ name: "ttyS", write: sab82532_console_write, device: sab82532_console_device, - wait_key: sab82532_console_wait_key, setup: sab82532_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sbus/char/su.c linux-2.5/drivers/sbus/char/su.c --- linux-2.5.1/drivers/sbus/char/su.c Tue Nov 13 17:16:05 2001 +++ linux-2.5/drivers/sbus/char/su.c Sun Dec 30 13:55:22 2001 @@ -2506,7 +2506,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = su_open; serial_driver.close = su_close; serial_driver.write = su_write; @@ -2854,40 +2856,6 @@ su_outb(info, UART_IER, ier); } -/* - * Receive character from the serial port - */ -static int -serial_console_wait_key(struct console *co) -{ - struct su_struct *info; - int ier; - int lsr; - int c; - - info = su_table + co->index; - - /* - * First save the IER then disable the interrupts so - * that the real driver for the port does not get the - * character. - */ - ier = su_inb(info, UART_IER); - su_outb(info, UART_IER, 0x00); - - do { - lsr = su_inb(info, UART_LSR); - } while (!(lsr & UART_LSR_DR)); - c = su_inb(info, UART_RX); - - /* - * Restore the interrupts - */ - su_outb(info, UART_IER, ier); - - return c; -} - static kdev_t serial_console_device(struct console *c) { @@ -3013,7 +2981,6 @@ name: "ttyS", write: serial_console_write, device: serial_console_device, - wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sbus/char/sunkbd.c linux-2.5/drivers/sbus/char/sunkbd.c --- linux-2.5.1/drivers/sbus/char/sunkbd.c Mon Sep 17 04:22:50 2001 +++ linux-2.5/drivers/sbus/char/sunkbd.c Thu Dec 27 15:56:12 2001 @@ -82,16 +82,6 @@ struct l1a_kbd_state l1a_state; -#ifndef CONFIG_PCI -DECLARE_WAIT_QUEUE_HEAD(keypress_wait); -#endif - -int keyboard_wait_for_keypress(struct console *co) -{ - sleep_on(&keypress_wait); - return 0; -} - static spinlock_t sunkbd_lock = SPIN_LOCK_UNLOCKED; /* @@ -629,7 +619,6 @@ static void put_queue(int ch) { - wake_up(&keypress_wait); if (tty) { tty_insert_flip_char(tty, ch, 0); con_schedule_flip(tty); @@ -638,7 +627,6 @@ static void puts_queue(char *cp) { - wake_up(&keypress_wait); if (!tty) return; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sbus/char/zs.c linux-2.5/drivers/sbus/char/zs.c --- linux-2.5.1/drivers/sbus/char/zs.c Tue Oct 30 23:08:11 2001 +++ linux-2.5/drivers/sbus/char/zs.c Sun Dec 30 13:55:22 2001 @@ -532,8 +532,6 @@ /* Continue execution... */ return; } - /* It is a 'keyboard interrupt' ;-) */ - wake_up(&keypress_wait); } #ifndef __sparc_v9__ /* Look for kgdb 'stop' character, consult the gdb @@ -2427,7 +2425,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &zs_console; +#endif serial_driver.open = zs_open; serial_driver.close = zs_close; serial_driver.write = zs_write; @@ -2761,13 +2761,6 @@ #endif } -static int -zs_console_wait_key(struct console *con) -{ - sleep_on(&keypress_wait); - return 0; -} - static kdev_t zs_console_device(struct console *con) { return MKDEV(TTY_MAJOR, 64 + con->index); @@ -2845,7 +2838,6 @@ name: "ttyS", write: zs_console_write, device: zs_console_device, - wait_key: zs_console_wait_key, setup: zs_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/3w-xxxx.c linux-2.5/drivers/scsi/3w-xxxx.c --- linux-2.5.1/drivers/scsi/3w-xxxx.c Fri Nov 9 22:05:02 2001 +++ linux-2.5/drivers/scsi/3w-xxxx.c Tue Jan 8 01:17:10 2002 @@ -6,7 +6,7 @@ Arnaldo Carvalho de Melo <acme@conectiva.com.br> Brad Strand <linux@3ware.com> - Copyright (C) 1999-2001 3ware Inc. + Copyright (C) 1999-2002 3ware Inc. Kernel compatablity By: Andre Hedrick <andre@suse.com> Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> @@ -106,6 +106,19 @@ Add entire aen code string list. 1.02.00.010 - Cleanup queueing code, fix jbod thoughput. Fix get_param for specific units. + 1.02.00.011 - Fix bug in tw_aen_complete() where aen's could be lost. + Fix tw_aen_drain_queue() to display useful info at init. + Set tw_host->max_id for 12 port cards. + Add ioctl support for raw command packet post from userspace + with sglist fragments (parameter and io). + 1.02.00.012 - Fix read capacity to under report by 1 sector to fix get + last sector ioctl. + 1.02.00.013 - Fix bug where more AEN codes weren't coming out during + driver initialization. + Improved handling of PCI aborts. + 1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost. + Increase timeout in tw_aen_drain_queue() to 30 seconds. + 1.02.00.015 - Re-write raw command post with data ioctl method. */ #include <linux/module.h> @@ -114,7 +127,6 @@ MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver"); MODULE_LICENSE("GPL"); - #include <linux/kernel.h> #include <linux/pci.h> #include <linux/time.h> @@ -149,11 +161,11 @@ /* Notifier block to get a notify on system shutdown/halt/reboot */ static struct notifier_block tw_notifier = { - tw_halt, NULL, 0 + tw_halt, NULL, 0 }; /* Globals */ -char *tw_driver_version="1.02.00.010"; +char *tw_driver_version="1.02.00.015"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -164,6 +176,7 @@ { TW_Param *param; unsigned short aen; + int error = 0; dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n"); if (tw_dev->alignment_virtual_address[request_id] == NULL) { @@ -182,12 +195,15 @@ if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8); } else { - printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]); + if (aen != 0x0) + printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]); } - } else + } else { printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen); + } } - tw_dev->aen_count++; + if (aen != 0x0) + tw_dev->aen_count++; /* Now queue the code */ tw_dev->aen_queue[tw_dev->aen_tail] = aen; @@ -203,8 +219,18 @@ tw_dev->aen_head = tw_dev->aen_head + 1; } } - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); + + if (aen != TW_AEN_QUEUE_EMPTY) { + error = tw_aen_read_queue(tw_dev, request_id); + if (error) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no); + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + } + } else { + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + } return 0; } /* End tw_aen_complete() */ @@ -235,10 +261,11 @@ status_reg_addr = tw_dev->registers.status_reg_addr; response_que_addr = tw_dev->registers.response_que_addr; - if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) { + if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 30)) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count); return 1; } + tw_clear_attention_interrupt(tw_dev); /* Initialize command packet */ if (tw_dev->command_packet_virtual_address[request_id] == NULL) { @@ -286,7 +313,7 @@ do { /* Post command packet */ outl(command_que_value, command_que_addr); - + /* Now poll for completion */ for (i=0;i<imax;i++) { mdelay(5); @@ -324,7 +351,7 @@ queue = 0; switch (aen_code) { case TW_AEN_QUEUE_EMPTY: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_EMPTY.\n"); + dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); if (first_reset != 1) { continue; } else { @@ -332,51 +359,28 @@ } break; case TW_AEN_SOFT_RESET: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_SOFT_RESET.\n"); if (first_reset == 0) { first_reset = 1; } else { + printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); + tw_dev->aen_count++; queue = 1; } break; - case TW_AEN_DEGRADED_MIRROR: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_DEGRADED_MIRROR.\n"); - queue = 1; - break; - case TW_AEN_CONTROLLER_ERROR: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_CONTROLLER_ERROR.\n"); - queue = 1; - break; - case TW_AEN_REBUILD_FAIL: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_FAIL.\n"); - queue = 1; - break; - case TW_AEN_REBUILD_DONE: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_DONE.\n"); - queue = 1; - break; - case TW_AEN_QUEUE_FULL: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_FULL.\n"); - queue = 1; - break; - case TW_AEN_APORT_TIMEOUT: - printk(KERN_WARNING "3w-xxxx: Received drive timeout AEN on port %d, check drive and drive cables.\n", aen >> 8); - queue = 1; - break; - case TW_AEN_DRIVE_ERROR: - printk(KERN_WARNING "3w-xxxx: Received drive error AEN on port %d, check/replace cabling, or possible bad drive.\n", aen >> 8); - queue = 1; - break; - case TW_AEN_SMART_FAIL: - printk(KERN_WARNING "3w-xxxx: Received S.M.A.R.T. threshold AEN on port %d, check drive/cooling, or possible bad drive.\n", aen >> 8); - queue = 1; - break; - case TW_AEN_SBUF_FAIL: - printk(KERN_WARNING "3w-xxxx: Received SBUF integrity check failure AEN, reseat card or bad card.\n"); - queue = 1; - break; default: - dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unknown AEN code 0x%x.\n", aen_code); + if (aen == 0x0ff) { + printk(KERN_WARNING "3w-xxxx: AEN: AEN queue overflow.\n"); + } else { + if ((aen & 0x0ff) < TW_AEN_STRING_MAX) { + if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { + printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8); + } else { + printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); + } + } else + printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen); + } + tw_dev->aen_count++; queue = 1; } @@ -619,6 +623,11 @@ case TW_STATUS_MICROCONTROLLER_ERROR: printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n"); break; + case TW_STATUS_PCI_ABORT: + printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n"); + outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr); + pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT); + break; } } /* End tw_decode_bits() */ @@ -689,11 +698,22 @@ u32 control_reg_value, control_reg_addr; control_reg_addr = tw_dev->registers.control_reg_addr; + control_reg_value = (TW_CONTROL_ENABLE_INTERRUPTS | + TW_CONTROL_UNMASK_RESPONSE_INTERRUPT); + outl(control_reg_value, control_reg_addr); +} /* End tw_enable_interrupts() */ + +/* This function will enable interrupts on the controller */ +void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev) +{ + u32 control_reg_value, control_reg_addr; + + control_reg_addr = tw_dev->registers.control_reg_addr; control_reg_value = (TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT | TW_CONTROL_ENABLE_INTERRUPTS); outl(control_reg_value, control_reg_addr); -} /* End tw_enable_interrupts() */ +} /* End tw_enable_and_clear_interrupts() */ /* This function will find and initialize all cards */ int tw_findcards(Scsi_Host_Template *tw_host) @@ -761,14 +781,14 @@ error = tw_aen_drain_queue(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards); tries++; continue; } /* Check for controller errors */ if (tw_check_errors(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", numcards); tries++; continue; } @@ -776,7 +796,7 @@ /* Empty the response queue */ error = tw_empty_response_que(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards); tries++; continue; } @@ -786,7 +806,7 @@ } if (tries >= TW_MAX_RESET_TRIES) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", numcards); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; @@ -816,7 +836,7 @@ error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", numcards); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); @@ -841,13 +861,16 @@ /* Register the card with the kernel SCSI layer */ host = scsi_register(tw_host, sizeof(TW_Device_Extension)); if (host == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards-1); + printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; } + /* Set max target id's */ + host->max_id = TW_MAX_UNITS; + /* Set max sectors per io */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) host->max_sectors = TW_MAX_SECTORS; @@ -872,7 +895,7 @@ tw_device_extension_count = numcards; tw_dev2->host = host; } else { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1); + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards); scsi_unregister(host); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); @@ -1052,6 +1075,7 @@ tw_dev->state[i] = TW_S_INITIAL; tw_dev->ioctl_size[i] = 0; tw_dev->aen_queue[i] = 0; + tw_dev->ioctl_data[i] = NULL; } for (i=0;i<TW_MAX_UNITS;i++) { @@ -1330,7 +1354,7 @@ if (tw_dev->tw_pci_dev->irq == irq) { spin_lock(&tw_dev->tw_lock); - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt()\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n"); /* Read the registers */ status_reg_addr = tw_dev->registers.status_reg_addr; @@ -1453,18 +1477,21 @@ tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); } - if (error) { + if (error == 1) { /* Tell scsi layer there was an error */ dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n"); tw_dev->srb[request_id]->result = (DID_RESET << 16); - } else { + } + if (error == 0) { /* Tell scsi layer command was a success */ tw_dev->srb[request_id]->result = (DID_OK << 16); } - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - tw_dev->posted_request_count--; - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + if (error != 2) { + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + tw_dev->posted_request_count--; + tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + } status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); @@ -1477,19 +1504,21 @@ } spin_unlock_irqrestore(&io_request_lock, flags); clear_bit(TW_IN_INTR, &tw_dev->flags); -} /* End tw_interrupt() */ +} /* End tw_interrupt() */ /* This function handles ioctls from userspace to the driver */ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id) { unsigned char opcode; - int bufflen; + int bufflen, error = 0; TW_Param *param; - TW_Command *command_packet; + TW_Command *command_packet, *command_save; u32 param_value; TW_Ioctl *ioctl = NULL; TW_Passthru *passthru = NULL; - int tw_aen_code; + int tw_aen_code, i, use_sg; + char *data_ptr; + int total_bytes = 0; ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; if (ioctl == NULL) { @@ -1610,6 +1639,159 @@ printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n"); return 1; } + case TW_CMD_PACKET_WITH_DATA: + dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n"); + command_save = (TW_Command *)tw_dev->alignment_virtual_address[request_id]; + if (command_save == NULL) { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad alignment virtual address.\n", tw_dev->host->host_no); + return 1; + } + if (ioctl->data != NULL) { + /* Copy down the command packet */ + memcpy(command_packet, ioctl->data, sizeof(TW_Command)); + memcpy(command_save, ioctl->data, sizeof(TW_Command)); + command_packet->request_id = request_id; + + /* Now deal with the two possible sglists */ + if (command_packet->byte0.sgl_offset == 2) { + use_sg = command_packet->size - 3; + for (i=0;i<use_sg;i++) + total_bytes+=command_packet->byte8.param.sgl[i].length; + tw_dev->ioctl_data[request_id] = kmalloc(total_bytes, GFP_ATOMIC); + if (!tw_dev->ioctl_data[request_id]) { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id); + return 1; + } + + /* Copy param sglist into the kernel */ + data_ptr = tw_dev->ioctl_data[request_id]; + for (i=0;i<use_sg;i++) { + if ((u32 *)command_packet->byte8.param.sgl[i].address != NULL) { + error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length); + if (error) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no); + goto tw_ioctl_bail; + } + } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no); + tw_dev->srb[request_id]->result = (DID_RESET << 16); + goto tw_ioctl_bail; + } + data_ptr+=command_packet->byte8.param.sgl[i].length; + } + command_packet->size = 4; + command_packet->byte8.param.sgl[0].address = virt_to_bus(tw_dev->ioctl_data[request_id]); + command_packet->byte8.param.sgl[0].length = total_bytes; + } + if (command_packet->byte0.sgl_offset == 3) { + use_sg = command_packet->size - 4; + for (i=0;i<use_sg;i++) + total_bytes+=command_packet->byte8.io.sgl[i].length; + tw_dev->ioctl_data[request_id] = kmalloc(total_bytes, GFP_ATOMIC); + if (!tw_dev->ioctl_data[request_id]) { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id); + return 1; + } + if (command_packet->byte0.opcode == TW_OP_WRITE) { + /* Copy io sglist into the kernel */ + data_ptr = tw_dev->ioctl_data[request_id]; + for (i=0;i<use_sg;i++) { + if ((u32 *)command_packet->byte8.io.sgl[i].address != NULL) { + error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length); + if (error) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no); + goto tw_ioctl_bail; + } + } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no); + tw_dev->srb[request_id]->result = (DID_RESET << 16); + goto tw_ioctl_bail; + } + data_ptr+=command_packet->byte8.io.sgl[i].length; + } + } + command_packet->size = 5; + command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->ioctl_data[request_id]); + command_packet->byte8.io.sgl[0].length = total_bytes; + } + + spin_unlock_irq(&io_request_lock); + spin_unlock_irq(&tw_dev->tw_lock); + + /* Finally post the command packet */ + tw_post_command_packet(tw_dev, request_id); + + mdelay(TW_IOCTL_WAIT_TIME); + spin_lock_irq(&tw_dev->tw_lock); + spin_lock_irq(&io_request_lock); + + if (signal_pending(current)) { + dprintk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Signal pending, aborting ioctl().\n", tw_dev->host->host_no); + tw_dev->srb[request_id]->result = (DID_OK << 16); + goto tw_ioctl_bail; + } + + tw_dev->srb[request_id]->result = (DID_OK << 16); + /* Now copy up the param or io sglist to userspace */ + if (command_packet->byte0.sgl_offset == 2) { + use_sg = command_save->size - 3; + data_ptr = phys_to_virt(command_packet->byte8.param.sgl[0].address); + for (i=0;i<use_sg;i++) { + if ((u32 *)command_save->byte8.param.sgl[i].address != NULL) { + error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length); + if (error) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no); + goto tw_ioctl_bail; + } + dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.param.sgl[i].length, current->pid); + data_ptr+=command_save->byte8.param.sgl[i].length; + } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no); + tw_dev->srb[request_id]->result = (DID_RESET << 16); + goto tw_ioctl_bail; + } + } + } + if (command_packet->byte0.sgl_offset == 3) { + use_sg = command_save->size - 4; + if (command_packet->byte0.opcode == TW_OP_READ) { + data_ptr = phys_to_virt(command_packet->byte8.io.sgl[0].address); + for(i=0;i<use_sg;i++) { + if ((u32 *)command_save->byte8.io.sgl[i].address != NULL) { + error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length); + if (error) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no); + goto tw_ioctl_bail; + } + dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.io.sgl[i].length, current->pid); + data_ptr+=command_save->byte8.io.sgl[i].length; + } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no); + tw_dev->srb[request_id]->result = (DID_RESET << 16); + goto tw_ioctl_bail; + } + } + } + } + + tw_ioctl_bail: + + /* Free up sglist memory */ + if (tw_dev->ioctl_data[request_id]) + kfree(tw_dev->ioctl_data[request_id]); + else + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n", tw_dev->host->host_no); + + /* Now complete the io */ + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + tw_dev->posted_request_count--; + tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + return 0; + } else { + printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n"); + return 1; + } default: printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode); tw_dev->state[request_id] = TW_S_COMPLETED; @@ -1653,6 +1835,7 @@ TW_Param *param; TW_Ioctl *ioctl = NULL; TW_Passthru *passthru = NULL; + TW_Command *command_packet; ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n"); @@ -1661,6 +1844,13 @@ printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n"); return 1; } + + command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; + if (command_packet == NULL) { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl_complete(): Bad command packet virtual address.\n", tw_dev->host->host_no); + return 1; + } + dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen); ioctl = (TW_Ioctl *)buff; @@ -1669,6 +1859,9 @@ passthru = (TW_Passthru *)ioctl->data; memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512); break; + case TW_CMD_PACKET_WITH_DATA: + dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n"); + return 2; /* Special case for isr to not complete io */ default: memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; @@ -1819,7 +2012,7 @@ error = tw_aen_drain_queue(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Card not responding, retrying.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no); tries++; continue; } @@ -1855,7 +2048,7 @@ } /* Re-enable interrupts */ - tw_enable_interrupts(tw_dev); + tw_enable_and_clear_interrupts(tw_dev); return 0; } /* End tw_reset_sequence() */ @@ -2381,6 +2574,9 @@ capacity = (param_data[3] << 24) | (param_data[2] << 16) | (param_data[1] << 8) | param_data[0]; + /* Subtract one sector to fix get last sector ioctl */ + capacity -= 1; + dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity); /* Number of LBA's */ @@ -2671,7 +2867,7 @@ } /* Re-enable interrupts */ - tw_enable_interrupts(tw_dev); + tw_enable_and_clear_interrupts(tw_dev); return 0; } /* End tw_shutdown_device() */ @@ -2719,7 +2915,7 @@ int id = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n"); - + /* Obtain next free request_id */ do { if (tw_dev->free_head == tw_dev->free_wrap) { @@ -2749,7 +2945,6 @@ } /* End tw_unmask_command_interrupt() */ /* Now get things going */ - static Scsi_Host_Template driver_template = TWXXXX; #include "scsi_module.c" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/3w-xxxx.h linux-2.5/drivers/scsi/3w-xxxx.h --- linux-2.5.1/drivers/scsi/3w-xxxx.h Wed Nov 28 18:22:27 2001 +++ linux-2.5/drivers/scsi/3w-xxxx.h Tue Jan 8 01:17:10 2002 @@ -6,7 +6,7 @@ Arnaldo Carvalho de Melo <acme@conectiva.com.br> Brad Strand <linux@3ware.com> - Copyright (C) 1999-2001 3ware Inc. + Copyright (C) 1999-2002 3ware Inc. Kernel compatablity By: Andre Hedrick <andre@suse.com> Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> @@ -62,7 +62,7 @@ static char *tw_aen_string[] = { "AEN queue empty", // 0x000 "Soft reset occurred", // 0x001 - "Mirorr degraded: Unit #", // 0x002 + "Unit degraded: Unit #", // 0x002 "Controller error", // 0x003 "Rebuild failed: Unit #", // 0x004 "Rebuild complete: Unit #", // 0x005 @@ -90,10 +90,12 @@ "DCB unsupported version: Port #", // 0x028 "Verify started: Unit #", // 0x029 "Verify failed: Port #", // 0x02A - "Verify complete: Unit #" // 0x02B + "Verify complete: Unit #", // 0x02B + "Overwrote bad sector during rebuild: Port #", //0x2C + "Encountered bad sector during rebuild: Port #" //0x2D }; -#define TW_AEN_STRING_MAX 0x02C +#define TW_AEN_STRING_MAX 0x02E /* Control register bit definitions */ #define TW_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000 @@ -108,6 +110,7 @@ #define TW_CONTROL_DISABLE_INTERRUPTS 0x00000040 #define TW_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020 #define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000 +#define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000 /* Status register bit definitions */ #define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000 @@ -140,6 +143,7 @@ #define TW_DEVICE_ID2 (0x1001) /* 7000 series controller */ #define TW_NUMDEVICES 2 #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100 +#define TW_PCI_CLEAR_PCI_ABORT 0x2000 /* Command packet opcodes */ #define TW_OP_NOP 0x0 @@ -153,6 +157,7 @@ #define TW_OP_AEN_LISTEN 0x1c #define TW_CMD_PACKET 0x1d #define TW_ATA_PASSTHRU 0x1e +#define TW_CMD_PACKET_WITH_DATA 0x1f /* Asynchronous Event Notification (AEN) Codes */ #define TW_AEN_QUEUE_EMPTY 0x0000 @@ -197,6 +202,7 @@ #define TW_MAX_SECTORS 128 #endif #define TW_AEN_WAIT_TIME 1000 +#define TW_IOCTL_WAIT_TIME (1 * HZ) /* 1 second */ /* Macros */ #define TW_STATUS_ERRORS(x) \ @@ -381,6 +387,7 @@ unsigned char aen_head; unsigned char aen_tail; long flags; /* long req'd for set_bit --RR */ + char *ioctl_data[TW_Q_LENGTH]; } TW_Device_Extension; /* Function prototypes */ @@ -397,6 +404,7 @@ void tw_disable_interrupts(TW_Device_Extension *tw_dev); int tw_empty_response_que(TW_Device_Extension *tw_dev); void tw_enable_interrupts(TW_Device_Extension *tw_dev); +void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev); int tw_findcards(Scsi_Host_Template *tw_host); void tw_free_device_extension(TW_Device_Extension *tw_dev); int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/53c700.c linux-2.5/drivers/scsi/53c700.c --- linux-2.5.1/drivers/scsi/53c700.c Wed Nov 28 18:22:27 2001 +++ linux-2.5/drivers/scsi/53c700.c Fri Jan 4 17:05:20 2002 @@ -51,6 +51,14 @@ /* CHANGELOG * + * Version 2.7 + * + * Fixed scripts problem which caused certain devices (notably CDRWs) + * to hang on initial INQUIRY. Updated NCR_700_readl/writel to use + * __raw_readl/writel for parisc compatibility (Thomas + * Bogendoerfer). Added missing SCp->request_bufflen initialisation + * for sense requests (Ryan Bradetich). + * * Version 2.6 * * Following test of the 64 bit parisc kernel by Richard Hirst, @@ -96,7 +104,7 @@ * Initial modularisation from the D700. See NCR_D700.c for the rest of * the changelog. * */ -#define NCR_700_VERSION "2.6" +#define NCR_700_VERSION "2.7" #include <linux/config.h> #include <linux/version.h> @@ -1048,6 +1056,7 @@ slot->pCmd, SCp->cmd_len, PCI_DMA_TODEVICE); + SCp->request_bufflen = sizeof(SCp->sense_buffer); slot->dma_handle = pci_map_single(hostdata->pci_dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), PCI_DMA_FROMDEVICE); slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer)); slot->SG[0].pAddr = bS_to_host(slot->dma_handle); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/53c700.h linux-2.5/drivers/scsi/53c700.h --- linux-2.5.1/drivers/scsi/53c700.h Thu Oct 11 16:43:29 2001 +++ linux-2.5/drivers/scsi/53c700.h Mon Jan 7 21:57:11 2002 @@ -210,7 +210,7 @@ struct NCR_700_Host_Parameters { /* These must be filled in by the calling driver */ int clock; /* board clock speed in MHz */ - __u32 base; /* the base for the port (copied to host) */ + unsigned long base; /* the base for the port (copied to host) */ struct pci_dev *pci_dev; __u32 dmode_extra; /* adjustable bus settings */ __u32 differential:1; /* if we are differential */ @@ -503,7 +503,7 @@ static inline __u32 NCR_700_readl(struct Scsi_Host *host, __u32 reg) { - __u32 value = readl(host->base + reg); + __u32 value = __raw_readl(host->base + reg); const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; #if 1 @@ -536,7 +536,7 @@ BUG(); #endif - writel(bS_to_host(value), host->base + reg); + __raw_writel(bS_to_host(value), host->base + reg); } #elif defined(CONFIG_53C700_IO_MAPPED) static inline __u8 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/53c700.scr linux-2.5/drivers/scsi/53c700.scr --- linux-2.5.1/drivers/scsi/53c700.scr Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/scsi/53c700.scr Fri Jan 4 17:05:20 2002 @@ -242,7 +242,7 @@ SendIdentifyMsg: CALL SendMessage - JUMP SendCommand + CLEAR ATN IgnoreMsgBeforeCommand: CLEAR ACK diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/BusLogic.c linux-2.5/drivers/scsi/BusLogic.c --- linux-2.5.1/drivers/scsi/BusLogic.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/BusLogic.c Thu Dec 27 22:10:28 2001 @@ -4106,7 +4106,7 @@ BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Disk->device->host->hostdata; BIOS_DiskParameters_T *DiskParameters = (BIOS_DiskParameters_T *) Parameters; - struct buffer_head *BufferHead; + unsigned char *buf; if (HostAdapter->ExtendedTranslationEnabled && Disk->capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */) { @@ -4128,20 +4128,16 @@ } DiskParameters->Cylinders = Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors); - /* - Attempt to read the first 1024 bytes from the disk device. - */ - BufferHead = bread(MKDEV(MAJOR(Device), MINOR(Device) & ~0x0F), 0, 1024); - if (BufferHead == NULL) return 0; + buf = scsi_bios_ptable(Device); + if (buf == NULL) return 0; /* If the boot sector partition table flag is valid, search for a partition table entry whose end_head matches one of the standard BusLogic geometry translations (64/32, 128/32, or 255/63). */ - if (*(unsigned short *) (BufferHead->b_data + 0x1FE) == 0xAA55) + if (*(unsigned short *) (buf+64) == 0xAA55) { - PartitionTable_T *FirstPartitionEntry = - (PartitionTable_T *) (BufferHead->b_data + 0x1BE); + PartitionTable_T *FirstPartitionEntry = (PartitionTable_T *) buf; PartitionTable_T *PartitionEntry = FirstPartitionEntry; int SavedCylinders = DiskParameters->Cylinders, PartitionNumber; unsigned char PartitionEntryEndHead, PartitionEntryEndSector; @@ -4195,7 +4191,7 @@ DiskParameters->Heads, DiskParameters->Sectors); } } - brelse(BufferHead); + kfree(buf); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/BusLogic.h linux-2.5/drivers/scsi/BusLogic.h --- linux-2.5.1/drivers/scsi/BusLogic.h Fri Jul 20 04:07:57 2001 +++ linux-2.5/drivers/scsi/BusLogic.h Mon Jan 7 21:46:36 2002 @@ -1531,7 +1531,7 @@ void BusLogic_AcquireHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter, ProcessorFlags_T *ProcessorFlags) { - spin_lock_irqsave(&io_request_lock, *ProcessorFlags); + spin_lock_irqsave(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags); } @@ -1544,7 +1544,7 @@ void BusLogic_ReleaseHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter, ProcessorFlags_T *ProcessorFlags) { - spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags); + spin_unlock_irqrestore(HostAdapter->SCSI_Host->host_lock, *ProcessorFlags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/Config.in linux-2.5/drivers/scsi/Config.in --- linux-2.5.1/drivers/scsi/Config.in Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/scsi/Config.in Thu Jan 10 22:41:07 2002 @@ -46,6 +46,9 @@ dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'Adaptec AACRAID support (EXPERIMENTAL)' CONFIG_SCSI_AACRAID $CONFIG_SCSI $CONFIG_PCI +fi source drivers/scsi/aic7xxx/Config.in if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI @@ -207,7 +210,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI fi -if [ "$CONFIG_PPC" = "y" ]; then +if [ "$CONFIG_ALL_PPC" = "y" ]; then dep_tristate 'MESH (Power Mac internal SCSI) support' CONFIG_SCSI_MESH $CONFIG_SCSI if [ "$CONFIG_SCSI_MESH" != "n" ]; then int ' maximum synchronous transfer rate (MB/s) (0 = async)' CONFIG_SCSI_MESH_SYNC_RATE 5 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/Makefile linux-2.5/drivers/scsi/Makefile --- linux-2.5.1/drivers/scsi/Makefile Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/scsi/Makefile Mon Dec 17 01:03:06 2001 @@ -25,6 +25,7 @@ mod-subdirs := pcmcia ../acorn/scsi +subdir-$(CONFIG_SCSI_AACRAID) += aacraid subdir-$(CONFIG_SCSI_AIC7XXX) += aic7xxx subdir-$(CONFIG_PCMCIA) += pcmcia @@ -64,6 +65,9 @@ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o obj-$(CONFIG_SCSI_AHA1740) += aha1740.o +ifeq ($(CONFIG_SCSI_AACRAID),y) + obj-$(CONFIG_SCSI_AACRAID) += aacraid/aacraid.o +endif ifeq ($(CONFIG_SCSI_AIC7XXX),y) obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx_drv.o endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/NCR5380.c linux-2.5/drivers/scsi/NCR5380.c --- linux-2.5.1/drivers/scsi/NCR5380.c Sat Feb 17 00:02:36 2001 +++ linux-2.5/drivers/scsi/NCR5380.c Thu Dec 27 15:14:59 2001 @@ -83,8 +83,6 @@ * basically, transfer size needs to be reduced by one * and the last byte read as is done with PSEUDO_DMA. * - * 3. Test USLEEP code - * * 4. Test SCSI-II tagged queueing (I have no devices which support * tagged queueing) * @@ -110,6 +108,12 @@ #define READ_OVERRUNS #endif +#ifdef BOARD_REQUIRES_NO_DELAY +#define io_recovery_delay(x) +#else +#define io_recovery_delay(x) udelay(x) +#endif + /* * Design * Issues : @@ -192,9 +196,8 @@ * phase goes through the various phases as instructed by the target. * if the target goes into MSG IN and sends a DISCONNECT message, * the command structure is placed into the per instance disconnected - * queue, and NCR5380_main tries to find more work. If USLEEP - * was defined, and the target is idle for too long, the system - * will try to sleep. + * queue, and NCR5380_main tries to find more work. If the target is + * idle for too long, the system will try to sleep. * * If a command has disconnected, eventually an interrupt will trigger, * calling NCR5380_intr() which will in turn call NCR5380_reselect @@ -244,21 +247,14 @@ * rely on phase mismatch and EOP interrupts to determine end * of phase. * - * SCSI2 - if defined, SCSI-2 tagged queuing is used where possible - * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You * only really want to use this if you're having a problem with * dropped characters during high speed communications, and even * then, you're going to be better off twiddling with transfersize * in the high level code. * - * USLEEP - if defined, on devices that aren't disconnecting from the - * bus, we will go to sleep so that the CPU can get real work done - * when we run a command that won't complete immediately. - * - * Defaults for these will be provided if USLEEP is defined, although - * the user may want to adjust these to allocate CPU resources to - * the SCSI driver or "real" code. + * Defaults for these will be provided although the user may want to adjust + * these to allocate CPU resources to the SCSI driver or "real" code. * * USLEEP_SLEEP - amount of time, in jiffies, to sleep * @@ -322,18 +318,13 @@ static void do_reset(struct Scsi_Host *host); static struct Scsi_Host *first_instance = NULL; static Scsi_Host_Template *the_template = NULL; - -#ifdef USLEEP -struct timer_list usleep_timer; -#endif +static struct timer_list usleep_timer; /* - * Function : void initialize_SCp(Scsi_Cmnd *cmd) + * initialize_SCp - init the scsi pointer field + * @cmd: command block to set up * - * Purpose : initialize the saved data pointers for cmd to point to the - * start of the buffer. - * - * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. + * Set up the internal fields in the SCSI command. */ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd) @@ -362,88 +353,49 @@ static struct { unsigned char mask; const char *name; -} signals[] = { { - - SR_DBP, "PARITY" -}, { - SR_RST, "RST" -}, { - SR_BSY, "BSY" -}, -{ - SR_REQ, "REQ" -}, { - SR_MSG, "MSG" -}, { - SR_CD, "CD" -}, { - SR_IO, "IO" -}, -{ - SR_SEL, "SEL" -}, { - 0, NULL -} -}, - -basrs[] = { { - BASR_ATN, "ATN" -}, { - BASR_ACK, "ACK" -}, { - 0, NULL -} -}, - -icrs[] = { { - ICR_ASSERT_RST, "ASSERT RST" -}, { - ICR_ASSERT_ACK, "ASSERT ACK" -}, -{ - ICR_ASSERT_BSY, "ASSERT BSY" -}, { - ICR_ASSERT_SEL, "ASSERT SEL" -}, -{ - ICR_ASSERT_ATN, "ASSERT ATN" -}, { - ICR_ASSERT_DATA, "ASSERT DATA" -}, -{ - 0, NULL -} -}, - -mrs[] = { { - MR_BLOCK_DMA_MODE, "MODE BLOCK DMA" -}, { - MR_TARGET, "MODE TARGET" -}, -{ - MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK" -}, { - MR_ENABLE_PAR_INTR, - "MODE PARITY INTR" -}, { - MR_MONITOR_BSY, "MODE MONITOR BSY" -}, -{ - MR_DMA_MODE, "MODE DMA" -}, { - MR_ARBITRATE, "MODE ARBITRATION" -}, -{ - 0, NULL -} +} signals[] = { + {SR_DBP, "PARITY"}, + {SR_RST, "RST"}, + {SR_BSY, "BSY"}, + {SR_REQ, "REQ"}, + {SR_MSG, "MSG"}, + {SR_CD, "CD"}, + {SR_IO, "IO"}, + {SR_SEL, "SEL"}, + {0, NULL} +}, +basrs[] = { + {BASR_ATN, "ATN"}, + {BASR_ACK, "ACK"}, + {0, NULL} +}, +icrs[] = { + {ICR_ASSERT_RST, "ASSERT RST"}, + {ICR_ASSERT_ACK, "ASSERT ACK"}, + {ICR_ASSERT_BSY, "ASSERT BSY"}, + {ICR_ASSERT_SEL, "ASSERT SEL"}, + {ICR_ASSERT_ATN, "ASSERT ATN"}, + {ICR_ASSERT_DATA, "ASSERT DATA"}, + {0, NULL} +}, +mrs[] = { + {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, + {MR_TARGET, "MODE TARGET"}, + {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, + {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, + {MR_MONITOR_BSY, "MODE MONITOR BSY"}, + {MR_DMA_MODE, "MODE DMA"}, + {MR_ARBITRATE, "MODE ARBITRATION"}, + {0, NULL} }; -/* - * Function : void NCR5380_print(struct Scsi_Host *instance) +/** + * NCR5380_print - print scsi bus signals + * @instance: adapter state to dump * - * Purpose : print the SCSI bus signals for debugging purposes + * Print the SCSI bus signals for debugging purposes * - * Input : instance - which NCR5380 + * Locks: none */ static void NCR5380_print(struct Scsi_Host *instance) @@ -452,6 +404,7 @@ unsigned long flags; unsigned char status, data, basr, mr, icr, i; NCR5380_setup(instance); + /* FIXME - this needs proper locking */ save_flags(flags); cli(); data = NCR5380_read(CURRENT_SCSI_DATA_REG); @@ -483,32 +436,22 @@ unsigned char value; const char *name; } phases[] = { - - { - PHASE_DATAOUT, "DATAOUT" - }, { - PHASE_DATAIN, "DATAIN" - }, { - PHASE_CMDOUT, "CMDOUT" - }, - { - PHASE_STATIN, "STATIN" - }, { - PHASE_MSGOUT, "MSGOUT" - }, { - PHASE_MSGIN, "MSGIN" - }, - { - PHASE_UNKNOWN, "UNKNOWN" - } + {PHASE_DATAOUT, "DATAOUT"}, + {PHASE_DATAIN, "DATAIN"}, + {PHASE_CMDOUT, "CMDOUT"}, + {PHASE_STATIN, "STATIN"}, + {PHASE_MSGOUT, "MSGOUT"}, + {PHASE_MSGIN, "MSGIN"}, + {PHASE_UNKNOWN, "UNKNOWN"} }; /* - * Function : void NCR5380_print_phase(struct Scsi_Host *instance) + * NCR5380_print_phase - show SCSI phase + * @instance: adapter to dump * - * Purpose : print the current SCSI phase for debugging purposes + * Print the current SCSI phase for debugging purposes * - * Input : instance - which NCR5380 + * Locks: none */ static void NCR5380_print_phase(struct Scsi_Host *instance) @@ -520,11 +463,9 @@ status = NCR5380_read(STATUS_REG); if (!(status & SR_REQ)) - printk("scsi%d : REQ not asserted, phase unknown.\n", - instance->host_no); + printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no); else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i); + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); printk("scsi%d : phase %s\n", instance->host_no, phases[i].name); } } @@ -549,7 +490,7 @@ * conditions are possible. */ -static volatile int main_running = 0; +static unsigned long main_running = 0; /* * Function : run_main(void) @@ -563,14 +504,10 @@ static __inline__ void run_main(void) { - if (!main_running) { - main_running = 1; + if (!test_and_set_bit(0, &main_running)) NCR5380_main(); - } } -#ifdef USLEEP - /* * These need tweaking, and would probably work best as per-device * flags initialized differently for disk, tape, cd, etc devices. @@ -621,63 +558,67 @@ static int should_disconnect(unsigned char cmd) { switch (cmd) { - case READ_6: - case WRITE_6: - case SEEK_6: - case READ_10: - case WRITE_10: - case SEEK_10: - return DISCONNECT_TIME_TO_DATA; - case FORMAT_UNIT: - case SEARCH_HIGH: - case SEARCH_LOW: - case SEARCH_EQUAL: - return DISCONNECT_LONG; - default: - return DISCONNECT_NONE; + case READ_6: + case WRITE_6: + case SEEK_6: + case READ_10: + case WRITE_10: + case SEEK_10: + return DISCONNECT_TIME_TO_DATA; + case FORMAT_UNIT: + case SEARCH_HIGH: + case SEARCH_LOW: + case SEARCH_EQUAL: + return DISCONNECT_LONG; + default: + return DISCONNECT_NONE; } } /* * Assumes instance->time_expires has been set in higher level code. + * + * Locks: Caller must hold io_request_lock */ static int NCR5380_set_timer(struct Scsi_Host *instance) { - unsigned long flags; struct Scsi_Host *tmp, **prev; - save_flags(flags); - cli(); if (((struct NCR5380_hostdata *) (instance->hostdata))->next_timer) { - restore_flags(flags); return -1; } - for (prev = &expires_first, tmp = expires_first; tmp; - prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), - tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer) - if (((struct NCR5380_hostdata *)instance->hostdata)->time_expires < - ((struct NCR5380_hostdata *)tmp->hostdata)->time_expires) + for (prev = &expires_first, tmp = expires_first; tmp; prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer) + if (((struct NCR5380_hostdata *) instance->hostdata)->time_expires < ((struct NCR5380_hostdata *) tmp->hostdata)->time_expires) break; ((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp; *prev = instance; - + mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires); - restore_flags(flags); return 0; } -/* Doing something about unwanted reentrancy here might be useful */ -void NCR5380_timer_fn(unsigned long surplus_to_requirements) +/** + * NCR5380_timer_fn - handle polled timeouts + * @unused: unused + * + * Walk the list of controllers, find which controllers have exceeded + * their expiry timeout and then schedule the processing co-routine to + * do the real work. + * + * Doing something about unwanted reentrancy here might be useful + * + * Locks: disables irqs, takes and frees io_request_lock + */ + +static void NCR5380_timer_fn(unsigned long unused) { - unsigned long flags; struct Scsi_Host *instance; - save_flags(flags); - cli(); - for (; expires_first && - time_before_eq(((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires, jiffies); ) - { + + spin_lock_irq(&io_request_lock); + + for (; expires_first && time_before_eq(((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires, jiffies);) { instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer; ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL; ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires = 0; @@ -685,90 +626,91 @@ } del_timer(&usleep_timer); - if (expires_first) - { - usleep_timer.expires = ((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires; + if (expires_first) { + usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires; add_timer(&usleep_timer); } - restore_flags(flags); - - spin_lock_irqsave(&io_request_lock, flags); run_main(); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irq(&io_request_lock); } -#endif /* def USLEEP */ +/** + * NCR5380_all_init - global setup + * + * Set up the global values and timers needed by the NCR5380 driver + */ + static inline void NCR5380_all_init(void) { static int done = 0; if (!done) { -#if (NDEBUG & NDEBUG_INIT) - printk("scsi : NCR5380_all_init()\n"); -#endif + dprintk(NDEBUG_INIT, ("scsi : NCR5380_all_init()\n")); done = 1; -#ifdef USLEEP init_timer(&usleep_timer); usleep_timer.function = NCR5380_timer_fn; -#endif } } -#ifdef AUTOPROBE_IRQ -/* - * Function : int NCR5380_probe_irq (struct Scsi_Host *instance, int possible) - * - * Purpose : autoprobe for the IRQ line used by the NCR5380. - * - * Inputs : instance - pointer to this instance of the NCR5380 driver, - * possible - bitmask of permissible interrupts. - * - * Returns : number of the IRQ selected, IRQ_NONE if no interrupt fired. - * - * XXX no effort is made to deal with spurious interrupts. - */ - static int probe_irq __initdata = 0; +/** + * probe_intr - helper for IRQ autoprobe + * @irq: interrupt number + * @dev_id: unused + * @regs: unused + * + * Set a flag to indicate the IRQ in question was received. This is + * used by the IRQ probe code. + */ + static void __init probe_intr(int irq, void *dev_id, struct pt_regs *regs) { probe_irq = irq; } +/** + * NCR5380_probe_irq - find the IRQ of an NCR5380 + * @instance: NCR5380 controller + * @possible: bitmask of ISA IRQ lines + * + * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ + * and then looking to see what interrupt actually turned up. + * + * Locks: none, irqs must be enabled on entry + */ + static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible) { NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; unsigned long timeout; int trying_irqs, i, mask; NCR5380_setup(instance); for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1) - if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) - == 0)) + if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) == 0)) trying_irqs |= mask; timeout = jiffies + (250 * HZ / 1000); probe_irq = IRQ_NONE; -/* - * A interrupt is triggered whenever BSY = false, SEL = true - * and a bit set in the SELECT_ENABLE_REG is asserted on the - * SCSI bus. - * - * Note that the bus is only driven when the phase control signals - * (I/O, C/D, and MSG) match those in the TCR, so we must reset that - * to zero. - */ + /* + * A interrupt is triggered whenever BSY = false, SEL = true + * and a bit set in the SELECT_ENABLE_REG is asserted on the + * SCSI bus. + * + * Note that the bus is only driven when the phase control signals + * (I/O, C/D, and MSG) match those in the TCR, so we must reset that + * to zero. + */ NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_SEL); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); - while (probe_irq == IRQ_NONE && time_before(jiffies,timeout)) + while (probe_irq == IRQ_NONE && time_before(jiffies, timeout)) barrier(); NCR5380_write(SELECT_ENABLE_REG, 0); @@ -780,15 +722,16 @@ return probe_irq; } -#endif /* AUTOPROBE_IRQ */ -/* - * Function : void NCR58380_print_options (struct Scsi_Host *instance) +/** + * NCR58380_print_options - show options + * @instance: unused for now + * + * Called by probe code indicating the NCR5380 driver options that + * were selected. At some point this will switch to runtime options + * read from the adapter in question * - * Purpose : called by probe code indicating the NCR5380 driver - * options that were selected. - * - * Inputs : instance, pointer to this instance. Unused. + * Locks: none */ static void __init NCR5380_print_options(struct Scsi_Host *instance) @@ -815,29 +758,25 @@ #ifdef PSEUDO_DMA " PSEUDO DMA" #endif -#ifdef SCSI2 - " SCSI-2" -#endif #ifdef UNSAFE " UNSAFE " #endif ); -#ifdef USLEEP printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP); -#endif printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) { printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE); } } -/* - * Function : void NCR5380_print_status (struct Scsi_Host *instance) +/** + * NCR5380_print_status - dump controller info + * @instance: controller to dump * - * Purpose : print commands in the various queues, called from - * NCR5380_abort and NCR5380_debug to aid debugging. + * Print commands in the various queues, called from NCR5380_abort + * and NCR5380_debug to aid debugging. * - * Inputs : instance, pointer to this instance. + * Locks: called functions disable irqs, missing queue lock in proc call */ static void NCR5380_print_status(struct Scsi_Host *instance) @@ -846,16 +785,12 @@ char *start; int len; - printk("NCR5380 : coroutine is%s running.\n", - main_running ? "" : "n't"); + printk("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); -#ifdef NDEBUG - NCR5380_print(instance); - NCR5380_print_phase(instance); -#endif + NCR5380_dprint(NDEBUG_ANY, instance); + NCR5380_dprint_phase(NDEBUG_ANY, instance); - len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), - instance->host_no, 0); + len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), instance->host_no, 0); pr_bfr[len] = 0; printk("\n%s\n", pr_bfr); } @@ -886,18 +821,14 @@ #ifndef NCR5380_proc_info static #endif -int NCR5380_proc_info( - char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { - unsigned long flags; char *pos = buffer; struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; Scsi_Cmnd *ptr; - for (instance = first_instance; instance && - instance->host_no != hostno; instance = instance->next); + for (instance = first_instance; instance && instance->host_no != hostno; instance = instance->next); if (!instance) return (-ESRCH); hostdata = (struct NCR5380_hostdata *) instance->hostdata; @@ -935,32 +866,27 @@ SPRINTF("IRQ: %d.\n", instance->irq); #ifdef DTC_PUBLIC_RELEASE - SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", - dtc_wmaxi, dtc_maxi); + SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", dtc_wmaxi, dtc_maxi); #endif #ifdef PAS16_PUBLIC_RELEASE - SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", - pas_wmaxi, pas_maxi); + SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", pas_wmaxi, pas_maxi); #endif - save_flags(flags); - cli(); + spin_lock_irq(&io_request_lock); SPRINTF("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); if (!hostdata->connected) SPRINTF("scsi%d: no currently connected command\n", instance->host_no); else - pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, - pos, buffer, length); + pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, pos, buffer, length); SPRINTF("scsi%d: issue_queue\n", instance->host_no); - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); SPRINTF("scsi%d: disconnected_queue\n", instance->host_no); - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - restore_flags(flags); + spin_unlock_irq(&io_request_lock); + *start = buffer; if (pos - buffer < offset) return 0; @@ -972,16 +898,14 @@ static char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length) { - SPRINTF("scsi%d : destination target %d, lun %d\n", - cmd->host->host_no, cmd->target, cmd->lun); + SPRINTF("scsi%d : destination target %d, lun %d\n", cmd->host->host_no, cmd->target, cmd->lun); SPRINTF(" command = "); pos = lprint_command(cmd->cmnd, pos, buffer, length); return (pos); } static -char *lprint_command(unsigned char *command, - char *pos, char *buffer, int length) +char *lprint_command(unsigned char *command, char *pos, char *buffer, int length) { int i, s; pos = lprint_opcode(command[0], pos, buffer, length); @@ -999,17 +923,18 @@ } -/* - * Function : void NCR5380_init (struct Scsi_Host *instance, flags) +/** + * NCR5380_init - initialise an NCR5380 + * @instance: adapter to configure + * @flags: control flags * - * Purpose : initializes *instance and corresponding 5380 chip, + * Initializes *instance and corresponding 5380 chip, * with flags OR'd into the initial flags value. * - * Inputs : instance - instantiation of the 5380 driver. - * - * Notes : I assume that the host, hostno, and id bits have been + * Notes : I assume that the host, hostno, and id bits have been * set correctly. I don't care about the irq and other fields. - * + * + * Locks: interrupts must be enabled when we are called */ static void __init NCR5380_init(struct Scsi_Host *instance, int flags) @@ -1017,9 +942,10 @@ NCR5380_local_declare(); int i, pass; unsigned long timeout; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; + if(in_interrupt()) + printk(KERN_ERR "NCR5380_init called with interrupts off!\n"); /* * On NCR53C400 boards, NCR5380 registers are mapped 8 past * the base address. @@ -1031,7 +957,6 @@ #endif NCR5380_setup(instance); - NCR5380_all_init(); hostdata->aborted = 0; @@ -1070,17 +995,13 @@ the_template = instance->hostt; first_instance = instance; } -#ifdef USLEEP hostdata->time_expires = 0; hostdata->next_timer = NULL; -#endif #ifndef AUTOSENSE if ((instance->cmd_per_lun > 1) || instance->can_queue > 1) - ) - printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n" - " without AUTOSENSE option, contingent allegiance conditions may\n" - " be incorrectly cleared.\n", instance->host_no); + printk(KERN_WARNING "scsi%d : WARNING : support for multiple outstanding commands enabled\n" " without AUTOSENSE option, contingent allegiance conditions may\n" + " be incorrectly cleared.\n", instance->host_no); #endif /* def AUTOSENSE */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); @@ -1106,50 +1027,40 @@ * failing, do a hard reset of the SCSI bus */ - for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && - pass <= 6; ++pass) { + for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) { switch (pass) { case 1: case 3: case 5: - printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", - instance->host_no); + printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no); timeout = jiffies + 5 * HZ; - while (time_before(jiffies,timeout) && (NCR5380_read(STATUS_REG) & SR_BSY)); + while (time_before(jiffies, timeout) && (NCR5380_read(STATUS_REG) & SR_BSY)); break; case 2: - printk("scsi%d: bus busy, attempting abort\n", - instance->host_no); + printk("scsi%d: bus busy, attempting abort\n", instance->host_no); do_abort(instance); break; case 4: - printk("scsi%d: bus busy, attempting reset\n", - instance->host_no); + printk("scsi%d: bus busy, attempting reset\n", instance->host_no); do_reset(instance); break; case 6: - printk("scsi%d: bus locked solid or invalid override\n", - instance->host_no); + printk("scsi%d: bus locked solid or invalid override\n", instance->host_no); } } } -/* - * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, - * void (*done)(Scsi_Cmnd *)) - * - * Purpose : enqueues a SCSI command +/** + * NCR5380_queue_command - queue a command + * @cmd: SCSI command + * @done: completion handler * - * Inputs : cmd - SCSI command, done - function called on completion, with - * a pointer to the command descriptor. - * - * Returns : 0 - * - * Side effects : * cmd is added to the per instance issue_queue, with minor * twiddling done to the host specific fields of cmd. If the * main coroutine is not running, it is restarted. * + * Locks: io_request lock held by caller. Called functions drop and + * retake this lock. Called functions take dma lock. */ /* Only make static if a wrapper function is used */ @@ -1158,16 +1069,14 @@ #endif int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { struct Scsi_Host *instance = cmd->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; Scsi_Cmnd *tmp; #if (NDEBUG & NDEBUG_NO_WRITE) switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", - instance->host_no); + case WRITE_6: + case WRITE_10: + printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", instance->host_no); cmd->result = (DID_ERROR << 16); done(cmd); return 0; @@ -1175,31 +1084,22 @@ #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ #ifdef NCR5380_STATS -#if 0 - if (!hostdata->connected && !hostdata->issue_queue && - !hostdata->disconnected_queue) { - hostdata->timebase = jiffies; - } -#endif -#ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) -#endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); hostdata->bytes_write[cmd->target] += cmd->request_bufflen; hostdata->pendingw++; break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); hostdata->bytes_read[cmd->target] += cmd->request_bufflen; hostdata->pendingr++; break; - } + } #endif /* @@ -1209,10 +1109,8 @@ cmd->host_scribble = NULL; cmd->scsi_done = done; - cmd->result = 0; - /* * Insert the cmd into the issue queue. Note that REQUEST SENSE * commands are added to the head of the queue since any command will @@ -1225,31 +1123,28 @@ cmd->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = cmd; } else { - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; - tmp = (Scsi_Cmnd *) tmp->host_scribble); + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble); LIST(cmd, tmp); tmp->host_scribble = (unsigned char *) cmd; } -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command added to %s of queue\n", instance->host_no, - (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail")); -/* Run the coroutine if it isn't already running. */ + /* Run the coroutine if it isn't already running. */ run_main(); return 0; } -/* - * Function : NCR5380_main (void) +/** + * NCR5380_main - NCR state machines * - * Purpose : NCR5380_main is a coroutine that runs as long as more work can + * NCR5380_main is a coroutine that runs as long as more work can * be done on the NCR5380 host adapters in a system. Both * NCR5380_queue_command() and NCR5380_intr() will try to start it * in case it is not running. * - * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should - * reenable them. This prevents reentrancy and kernel stack overflow. + * Locks; The caller must hold the io_request_lock. The lock will still be + * held on return but may be dropped while running. Called functions take + * the DMA lock. */ static void NCR5380_main(void) { @@ -1257,7 +1152,6 @@ struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; int done; - unsigned long flags; /* * We run (with interrupts disabled) until we're sure that none of @@ -1271,43 +1165,22 @@ * this should prevent any race conditions. */ - spin_unlock_irq(&io_request_lock); - - save_flags(flags); - do { - cli(); /* Freeze request queues */ + /* Lock held here */ done = 1; - for (instance = first_instance; instance && - instance->hostt == the_template; instance = instance->next) { - hostdata = (struct NCR5380_hostdata *) instance->hostdata; - cli(); -#ifdef USLEEP + for (instance = first_instance; instance && instance->hostt == the_template; instance = instance->next) { + hostdata = (struct NCR5380_hostdata *) instance->hostdata; + /* Lock held here */ if (!hostdata->connected && !hostdata->selecting) { -#else - if (!hostdata->connected) { -#endif -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : not connected\n", instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : not connected\n", instance->host_no)); /* * Search through the issue_queue for a command destined * for a target that's not busy. */ -#if (NDEBUG & NDEBUG_LISTS) - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp && (tmp != prev); prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble); - /*printk("%p ", tmp); */ - if ((tmp == prev) && tmp) - printk(" LOOP\n"); /* else printk("\n"); */ -#endif - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, - prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) - tmp->host_scribble) { - -#if (NDEBUG & NDEBUG_LISTS) + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) + { if (prev != tmp) - printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun); -#endif + dprintk(NDEBUG_LISTS, ("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun)); /* When we find one, remove it from the issue queue. */ if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) { if (prev) { @@ -1319,8 +1192,6 @@ } tmp->host_scribble = NULL; - /* reenable interrupts after finding one */ - restore_flags(flags); /* * Attempt to establish an I_T_L nexus here. @@ -1328,10 +1199,7 @@ * On failure, we must add the command back to the * issue queue so we can keep trying. */ -#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) - printk("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", - instance->host_no, tmp->target, tmp->lun); -#endif + dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", instance->host_no, tmp->target, tmp->lun)); /* * A successful selection is defined as one that @@ -1343,105 +1211,81 @@ * and see if we can do an information transfer, * with failures we will restart. */ -#ifdef USLEEP - hostdata->selecting = 0; /* RvC: have to preset this - to indicate a new command is being performed */ -#endif + hostdata->selecting = 0; + /* RvC: have to preset this to indicate a new command is being performed */ if (!NCR5380_select(instance, tmp, - /* - * REQUEST SENSE commands are issued without tagged - * queueing, even on SCSI-II devices because the - * contingent allegiance condition exists for the - * entire unit. - */ - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : - TAG_NEXT)) { + /* + * REQUEST SENSE commands are issued without tagged + * queueing, even on SCSI-II devices because the + * contingent allegiance condition exists for the + * entire unit. + */ + (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { break; } else { - cli(); LIST(tmp, hostdata->issue_queue); - tmp->host_scribble = (unsigned char *) - hostdata->issue_queue; + tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; done = 0; - restore_flags(flags); -#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) - printk("scsi%d : main(): select() failed, returned to issue_queue\n", - instance->host_no); -#endif + dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no)); } + /* lock held here still */ } /* if target/lun is not busy */ } /* for */ + /* exited locked */ } /* if (!hostdata->connected) */ -#ifdef USLEEP - if (hostdata->selecting) - { - tmp = (Scsi_Cmnd *)hostdata->selecting; - if (!NCR5380_select(instance, tmp, - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) - { + if (hostdata->selecting) { + tmp = (Scsi_Cmnd *) hostdata->selecting; + /* Selection will drop and retake the lock */ + if (!NCR5380_select(instance, tmp, (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { /* Ok ?? */ - } - else - { + } else { /* RvC: device failed, so we wait a long time - this is needed for Mustek scanners, that - do not respond to commands immediately - after a scan */ - printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", - instance->host_no, tmp->target); - cli(); + this is needed for Mustek scanners, that + do not respond to commands immediately + after a scan */ + printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->target); + //spin_lock_irq(&io_request_lock); LIST(tmp, hostdata->issue_queue); tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; - restore_flags(flags); + //spin_unlock_irq(&io_request_lock); hostdata->time_expires = jiffies + USLEEP_WAITLONG; - NCR5380_set_timer (instance); + NCR5380_set_timer(instance); } - } /* if hostdata->selecting */ -#endif + } /* if hostdata->selecting */ if (hostdata->connected #ifdef REAL_DMA && !hostdata->dmalen #endif -#ifdef USLEEP && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies)) -#endif ) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : main() : performing information transfer\n", - instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : main() : performing information transfer\n", instance->host_no)); NCR5380_information_transfer(instance); -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : main() : done set false\n", instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : main() : done set false\n", instance->host_no)); done = 0; } else break; } /* for instance */ } while (!done); - spin_lock_irq(&io_request_lock); - /* cli();*/ - main_running = 0; + /* Exit lock held */ + clear_bit(0, &main_running); } #ifndef DONT_USE_INTR #include <linux/blk.h> #include <linux/spinlock.h> -/* - * Function : void NCR5380_intr (int irq) - * - * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses +/** + * NCR5380_intr - generic NCR5380 irq handler + * + * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses * from the disconnected queue, and restarting NCR5380_main() * as required. * - * Inputs : int irq, irq that caused this interrupt. - * + * Locks: caller must hold the io_request lock. */ static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { @@ -1449,17 +1293,12 @@ struct Scsi_Host *instance; int done; unsigned char basr; - unsigned long flags; - save_flags(flags); - cli(); -#if (NDEBUG & NDEBUG_INTR) - printk("scsi : NCR5380 irq %d triggered\n", irq); -#endif + dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq)); + do { done = 1; - for (instance = first_instance; instance && (instance->hostt == - the_template); instance = instance->next) + for (instance = first_instance; instance && (instance->hostt == the_template); instance = instance->next) if (instance->irq == irq) { /* Look for pending interrupts */ @@ -1467,34 +1306,19 @@ basr = NCR5380_read(BUS_AND_STATUS_REG); /* XXX dispatch to appropriate routine if found and done=0 */ if (basr & BASR_IRQ) { -#if (NDEBUG & NDEBUG_INTR) - NCR5380_print(instance); -#endif - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == - (SR_SEL | SR_IO)) { + NCR5380_dprint(NDEBUG_INTR, instance); + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { done = 0; - restore_flags(flags); -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : SEL interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : SEL interrupt\n", instance->host_no)); NCR5380_reselect(instance); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else if (basr & BASR_PARITY_ERROR) { -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : PARITY interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : PARITY interrupt\n", instance->host_no)); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : RESET interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : RESET interrupt\n", instance->host_no)); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else { -/* - * XXX the rest of the interrupt conditions should *only* occur during a - * DMA transfer, which I haven't gotten around to fixing yet. - */ - #if defined(REAL_DMA) /* * We should only get PHASE MISMATCH and EOP interrupts @@ -1502,14 +1326,11 @@ * the current setting of the MODE register. */ - if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & - BASR_END_DMA_TRANSFER) || - !(basr & BASR_PHASE_MATCH))) { + if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) { int transfered; if (!hostdata->connected) - panic("scsi%d : received end of DMA interrupt with no connected cmd\n", - instance->hostno); + panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno); transfered = (hostdata->dmalen - NCR5380_dma_residual(instance)); hostdata->connected->SCp.this_residual -= transferred; @@ -1522,15 +1343,13 @@ unsigned long timeout = jiffies + NCR_TIMEOUT; spin_unlock_irq(&io_request_lock); - while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK - && time_before(jiffies, timeout)); + while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK && time_before(jiffies, timeout)); spin_lock_irq(&io_request_lock); - - if (time_after_eq(jiffies, timeout) ) - printk("scsi%d: timeout at NCR5380.c:%d\n", - host->host_no, __LINE__); + + if (time_after_eq(jiffies, timeout)) + printk("scsi%d: timeout at NCR5380.c:%d\n", host->host_no, __LINE__); } -#else /* NCR_TIMEOUT */ +#else /* NCR_TIMEOUT */ while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); #endif @@ -1538,9 +1357,7 @@ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); } #else -#if (NDEBUG & NDEBUG_INTR) - printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); -#endif + dprintk(NDEBUG_INTR, ("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG))); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); #endif } @@ -1551,6 +1368,17 @@ } while (!done); } +/** + * do_NCR5380_intr + * @irq: interrupt number + * @dev_id: device info + * @regs: registers (unused) + * + * Takes the io_request_lock and invokes the generic NCR5380 interrupt + * handler code + * + * Locks: takes and releases the io_request lock + */ static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; @@ -1559,32 +1387,38 @@ NCR5380_intr(irq, dev_id, regs); spin_unlock_irqrestore(&io_request_lock, flags); } - #endif + +/** + * collect_stats - collect stats on a scsi command + * @hostdata: adapter + * @cmd: command being issued + * + * Update the statistical data by parsing the command in question + */ + +static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) +{ #ifdef NCR5380_STATS -static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { -#ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) -#endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen; */ - hostdata->pendingw--; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen; */ - hostdata->pendingr--; - break; - } -} + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); + hostdata->pendingw--; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); + hostdata->pendingr--; + break; + } #endif +} + + /* * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, * int tag); @@ -1614,55 +1448,44 @@ * * If failed (no target) : cmd->scsi_done() will be called, and the * cmd->result host byte set to DID_BAD_TARGET. + * + * Locks: caller holds io_request_lock */ -static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) { + +static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) +{ NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; unsigned char tmp[3], phase; unsigned char *data; int len; unsigned long timeout; - unsigned long flags; -#ifdef USLEEP unsigned char value; -#endif - NCR5380_setup(instance); -#ifdef USLEEP - - if (hostdata->selecting) - { + if (hostdata->selecting) { goto part2; /* RvC: sorry prof. Dijkstra, but it keeps the rest of the code nearly the same */ } -#endif - hostdata->restart_select = 0; -#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) - NCR5380_print(instance); - printk("scsi%d : starting arbitration, id = %d\n", instance->host_no, - instance->this_id); -#endif - save_flags(flags); - cli(); + hostdata->restart_select = 0; + + NCR5380_dprint(NDEBUG_ARBITRATION, instance); + dprintk(NDEBUG_ARBITRATION, ("scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id)); /* * Set the phase bits to 0, otherwise the NCR5380 won't drive the * data bus during SELECTION. */ - NCR5380_write(TARGET_COMMAND_REG, 0); - + NCR5380_write(TARGET_COMMAND_REG, 0); /* * Start arbitration. */ - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(MODE_REG, MR_ARBITRATE); - - restore_flags(flags); + NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); + NCR5380_write(MODE_REG, MR_ARBITRATE); /* Wait for arbitration logic to complete */ #if NCR_TIMEOUT @@ -1672,11 +1495,11 @@ spin_unlock_irq(&io_request_lock); while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && time_before(jiffies,timeout)); + && time_before(jiffies, timeout)); spin_lock_irq(&io_request_lock); - - if (time_after_eq(jiffies,timeout)) { + + if (time_after_eq(jiffies, timeout)) { printk("scsi: arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -1687,11 +1510,7 @@ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)); #endif -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : arbitration complete\n", instance->host_no); -/* Avoid GCC 2.4.5 asm needs to many reloads error */ - __asm__("nop"); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : arbitration complete\n", instance->host_no)); /* * The arbitration delay is 2.2us, but this is a minimum and there is @@ -1700,34 +1519,25 @@ * */ - udelay(3); + udelay(3); /* Check for lost arbitration */ - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { NCR5380_write(MODE_REG, MR_BASE); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", - instance->host_no); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no)); return -1; } NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL); if (!(hostdata->flags & FLAG_DTC3181E) && - /* RvC: DTC3181E has some trouble with this - * so we simply removed it. Seems to work with - * only Mustek scanner attached - */ - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) - { + /* RvC: DTC3181E has some trouble with this + * so we simply removed it. Seems to work with + * only Mustek scanner attached + */ + (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", - instance->host_no); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no)); return -1; } /* @@ -1737,10 +1547,7 @@ udelay(2); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : won arbitration\n", instance->host_no); -#endif - + dprintk(NDEBUG_ARBITRATION, ("scsi%d : won arbitration\n", instance->host_no)); /* * Now that we have won arbitration, start Selection process, asserting @@ -1755,8 +1562,7 @@ * phase immediately after selection. */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); NCR5380_write(MODE_REG, MR_BASE); /* @@ -1772,8 +1578,7 @@ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ /* Reset BSY */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); /* * Something weird happens when we cease to drive BSY - looks @@ -1794,9 +1599,7 @@ udelay(1); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : selecting target %d\n", instance->host_no, cmd->target); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : selecting target %d\n", instance->host_no, cmd->target)); /* * The SCSI specification calls for a 250 ms timeout for the actual @@ -1811,40 +1614,30 @@ * and it's detecting as true. Sigh. */ -#ifdef USLEEP - hostdata->select_time = 0; /* we count the clock ticks at which we polled */ + hostdata->select_time = 0; /* we count the clock ticks at which we polled */ hostdata->selecting = cmd; part2: - /* RvC: here we enter after a sleeping period, or immediately after - execution of part 1 - we poll only once ech clock tick */ + /* RvC: here we enter after a sleeping period, or immediately after + execution of part 1 + we poll only once ech clock tick */ value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO); - if (!value && (hostdata->select_time < 25)) - { + if (!value && (hostdata->select_time < 25)) { /* RvC: we still must wait for a device response */ - hostdata->select_time++; /* after 25 ticks the device has failed */ + hostdata->select_time++; /* after 25 ticks the device has failed */ hostdata->time_expires = jiffies + 1; NCR5380_set_timer(instance); return 0; /* RvC: we return here with hostdata->selecting set, to go to sleep */ } - hostdata->selecting = 0; /* clear this pointer, because we passed the - waiting period */ -#else - spin_unlock_irq(&io_request_lock); - while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & - (SR_BSY | SR_IO))); - spin_lock_irq(&io_request_lock); -#endif - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == - (SR_SEL | SR_IO)) { + hostdata->selecting = 0; /* clear this pointer, because we passed the + waiting period */ + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_reselect(instance); - printk("scsi%d : reselection after won arbitration?\n", - instance->host_no); + printk("scsi%d : reselection after won arbitration?\n", instance->host_no); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } @@ -1864,22 +1657,15 @@ printk("scsi%d : weirdness\n", instance->host_no); if (hostdata->restart_select) printk("\trestart select\n"); -#if (NDEBUG & NDEBUG_SELECTION) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_SELECTION, instance); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } cmd->result = DID_BAD_TARGET << 16; -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : target did not respond within 250ms\n", - instance->host_no); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : target did not respond within 250ms\n", instance->host_no)); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return 0; } @@ -1908,7 +1694,7 @@ spin_unlock_irq(&io_request_lock); while (!(NCR5380_read(STATUS_REG) & SR_REQ) && time_before(jiffies, timeout)); spin_lock_irq(&io_request_lock); - + if (time_after_eq(jiffies, timeout)) { printk("scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -1919,47 +1705,20 @@ while (!(NCR5380_read(STATUS_REG) & SR_REQ)); #endif /* def NCR_TIMEOUT */ -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", - instance->host_no, cmd->target); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->target)); tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun); -#ifdef SCSI2 - if (cmd->device->tagged_queue && (tag != TAG_NONE)) { - tmp[1] = SIMPLE_QUEUE_TAG; - if (tag == TAG_NEXT) { - /* 0 is TAG_NONE, used to imply no tag for this command */ - if (cmd->device->current_tag == 0) - cmd->device->current_tag = 1; - - cmd->tag = cmd->device->current_tag; - cmd->device->current_tag++; - } else - cmd->tag = (unsigned char) tag; - - tmp[2] = cmd->tag; - hostdata->last_message = SIMPLE_QUEUE_TAG; - len = 3; - } else -#endif /* def SCSI2 */ - { - len = 1; - cmd->tag = 0; - } + + len = 1; + cmd->tag = 0; /* Send message(s) */ data = tmp; phase = PHASE_MSGOUT; NCR5380_transfer_pio(instance, &phase, &len, &data); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : nexus established.\n", instance->host_no); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : nexus established.\n", instance->host_no)); /* XXX need to handle errors here */ hostdata->connected = cmd; -#ifdef SCSI2 - if (!cmd->device->tagged_queue) -#endif - hostdata->busy[cmd->target] |= (1 << cmd->lun); + hostdata->busy[cmd->target] |= (1 << cmd->lun); initialize_SCp(cmd); @@ -1992,27 +1751,22 @@ * counts, we will always do a pseudo DMA or DMA transfer. */ -static int NCR5380_transfer_pio(struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data) { +static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { NCR5380_local_declare(); - register unsigned char p = *phase, tmp; - register int c = *count; - register unsigned char *d = *data; -#ifdef USLEEP + unsigned char p = *phase, tmp; + int c = *count; + unsigned char *d = *data; /* - * RvC: some administrative data to process polling time + * RvC: some administrative data to process polling time */ int break_allowed = 0; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; -#endif NCR5380_setup(instance); -#if (NDEBUG & NDEBUG_PIO) if (!(p & SR_IO)) - printk("scsi%d : pio write %d bytes\n", instance->host_no, c); + dprintk(NDEBUG_PIO, ("scsi%d : pio write %d bytes\n", instance->host_no, c)); else - printk("scsi%d : pio read %d bytes\n", instance->host_no, c); -#endif + dprintk(NDEBUG_PIO, ("scsi%d : pio read %d bytes\n", instance->host_no, c)); /* * The NCR5380 chip will only drive the SCSI bus when the @@ -2022,56 +1776,42 @@ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); -#ifdef USLEEP /* RvC: don't know if this is necessary, but other SCSI I/O is short - * so breaks are not necessary there + * so breaks are not necessary there */ - if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) - { + if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) { break_allowed = 1; } -#endif - - do { /* * Wait for assertion of REQ, after which the phase bits will be * valid */ -#ifdef USLEEP /* RvC: we simply poll once, after that we stop temporarily - * and let the device buffer fill up - * if breaking is not allowed, we keep polling as long as needed + * and let the device buffer fill up + * if breaking is not allowed, we keep polling as long as needed */ - while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && - !break_allowed ); - if (!(tmp & SR_REQ)) - { + while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed); + if (!(tmp & SR_REQ)) { /* timeout condition */ hostdata->time_expires = jiffies + USLEEP_SLEEP; - NCR5380_set_timer (instance); + NCR5380_set_timer(instance); break; } -#else - while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) ); -#endif -#if (NDEBUG & NDEBUG_HANDSHAKE) - printk("scsi%d : REQ detected\n", instance->host_no); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : REQ detected\n", instance->host_no)); /* Check for phase mismatch */ if ((tmp & PHASE_MASK) != p) { -#if (NDEBUG & NDEBUG_PIO) - printk("scsi%d : phase mismatch\n", instance->host_no); - NCR5380_print_phase(instance); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : phase mismatch\n", instance->host_no)); + NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance); break; } - /* Do actual transfer from SCSI bus to / from memory */ if (!(p & SR_IO)) - NCR5380_write(OUTPUT_DATA_REG, *d); + /* Do actual transfer from SCSI bus to / from memory */ + if (!(p & SR_IO)) + NCR5380_write(OUTPUT_DATA_REG, *d); else *d = NCR5380_read(CURRENT_SCSI_DATA_REG); @@ -2086,34 +1826,22 @@ if (!(p & SR_IO)) { if (!((p & SR_MSG) && c > 1)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA); -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); + NCR5380_dprint(NDEBUG_PIO, instance); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK); } else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN); -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN); + NCR5380_dprint(NDEBUG_PIO, instance); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); } } else { -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_PIO, instance); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); } while (NCR5380_read(STATUS_REG) & SR_REQ); -#if (NDEBUG & NDEBUG_HANDSHAKE) - printk("scsi%d : req false, handshake complete\n", instance->host_no); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : req false, handshake complete\n", instance->host_no)); /* * We have several special cases to consider during REQ/ACK handshaking : @@ -2134,9 +1862,7 @@ } } while (--c); -#if (NDEBUG & NDEBUG_PIO) - printk("scsi%d : residual %d\n", instance->host_no, c); -#endif + dprintk(NDEBUG_PIO, ("scsi%d : residual %d\n", instance->host_no, c)); *count = c; *data = d; @@ -2152,36 +1878,46 @@ return -1; } +/** + * do_reset - issue a reset command + * @host: adapter to reset + * + * Issue a reset sequence to the NCR5380 and try and get the bus + * back into sane shape. + * + * Locks: caller holds io_request lock + */ + static void do_reset(struct Scsi_Host *host) { - unsigned long flags; - NCR5380_local_declare(); - NCR5380_setup(host); + NCR5380_local_declare(); + NCR5380_setup(host); + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); + udelay(25); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +} + +/* + * Function : do_abort (Scsi_Host *host) + * + * Purpose : abort the currently established nexus. Should only be + * called from a routine which can drop into a + * + * Returns : 0 on success, -1 on failure. + * + * Locks: io_request lock held by caller + */ - save_flags(flags); - cli(); - NCR5380_write(TARGET_COMMAND_REG, - PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); - udelay(25); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - restore_flags(flags); -} /* - - * Function : do_abort (Scsi_Host *host) - * - * Purpose : abort the currently established nexus. Should only be - * called from a routine which can drop into a - * - * Returns : 0 on success, -1 on failure. - */ static int do_abort(struct Scsi_Host *host) { +static int do_abort(struct Scsi_Host *host) { NCR5380_local_declare(); unsigned char tmp, *msgptr, phase; int len; - NCR5380_setup(host); + NCR5380_setup(host); /* Request message out phase */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); /* * Wait for the target to indicate a valid phase by asserting @@ -2195,11 +1931,10 @@ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); while (NCR5380_read(STATUS_REG) & SR_REQ); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); } @@ -2235,54 +1970,46 @@ * * Also, *phase, *count, *data are modified in place. * + * Locks: io_request lock held by caller */ -static int NCR5380_transfer_dma(struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data) { +static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { NCR5380_local_declare(); register int c = *count; register unsigned char p = *phase; register unsigned char *d = *data; unsigned char tmp; -#if defined(PSEUDO_DMA) && !defined(UNSAFE) - unsigned long flags; -#endif int foo; #if defined(REAL_DMA_POLL) int cnt, toPIO; unsigned char saved_data = 0, overrun = 0, residue; #endif - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - NCR5380_setup(instance); + NCR5380_setup(instance); if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { *phase = tmp; return -1; } #if defined(REAL_DMA) || defined(REAL_DMA_POLL) -#ifdef READ_OVERRUNS - if (p & SR_IO) { c -= 2; } -#endif -#if (NDEBUG & NDEBUG_DMA) -printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", - instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : - "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d); +#ifdef READ_OVERRUNS + if (p & SR_IO) { + c -= 2; + } #endif -hostdata->dma_len = (p & SR_IO) ? -NCR5380_dma_read_setup(instance, d, c) : -NCR5380_dma_write_setup(instance, d, c); + dprintk(NDEBUG_DMA, ("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d)); + hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); #endif -NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); #ifdef REAL_DMA -NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); #elif defined(REAL_DMA_POLL) -NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); #else /* * Note : on my sample board, watch-dog timeouts occurred when interrupts @@ -2290,58 +2017,38 @@ * before the setting of DMA mode to after transfer of the last byte. */ -#if defined(PSEUDO_DMA) && !defined(UNSAFE) -save_flags(flags); -cli(); +#if defined(PSEUDO_DMA) && defined(UNSAFE) + spin_unlock_irq(&io_request_lock); #endif /* KLL May need eop and parity in 53c400 */ -if (hostdata->flags & FLAG_NCR53C400) - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK - | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE - | MR_MONITOR_BSY); -else - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); + if (hostdata->flags & FLAG_NCR53C400) + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE | MR_MONITOR_BSY); + else + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); #endif /* def REAL_DMA */ -#if (NDEBUG & NDEBUG_DMA) & 0 -printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)); -#endif + dprintk(NDEBUG_DMA, ("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG))); -/* - * FOO stuff. For some UNAPPARENT reason, I'm getting - * watchdog timers fired on bootup for NO APPARENT REASON, meaning it's - * probably a timing problem. - * - * Since this is the only place I have back-to-back writes, perhaps this - * is the problem? - */ + /* + * On the PAS16 at least I/O recovery delays are not needed here. + * Everyone else seems to want them. + */ -if (p & SR_IO) -{ -#ifndef FOO -udelay(1); -#endif -NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); -} else { -#ifndef FOO - udelay(1); -#endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); -#ifndef FOO - udelay(1); -#endif - NCR5380_write(START_DMA_SEND_REG, 0); -#ifndef FOO - udelay(1); -#endif -} + if (p & SR_IO) { + io_recovery_delay(1); + NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); + } else { + io_recovery_delay(1); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); + io_recovery_delay(1); + NCR5380_write(START_DMA_SEND_REG, 0); + io_recovery_delay(1); + } #if defined(REAL_DMA_POLL) -do { - tmp = NCR5380_read(BUS_AND_STATUS_REG); -} while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | - - BASR_END_DMA_TRANSFER))); + do { + tmp = NCR5380_read(BUS_AND_STATUS_REG); + } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER))); /* At this point, either we've completed DMA, or we have a phase mismatch, @@ -2379,172 +2086,128 @@ request. */ -if (p & SR_IO) { + if (p & SR_IO) { #ifdef READ_OVERRUNS - udelay(10); - if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == - (BASR_PHASE_MATCH | BASR_ACK))) { - saved_data = NCR5380_read(INPUT_DATA_REGISTER); - overrun = 1; - } + udelay(10); + if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK))) { + saved_data = NCR5380_read(INPUT_DATA_REGISTER); + overrun = 1; + } #endif -} else { - int limit = 100; - while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || - (NCR5380_read(STATUS_REG) & SR_REQ)) { - if (!(tmp & BASR_PHASE_MATCH)) - break; - if (--limit < 0) - break; + } else { + int limit = 100; + while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) { + if (!(tmp & BASR_PHASE_MATCH)) + break; + if (--limit < 0) + break; + } } -} + dprintk(NDEBUG_DMA, ("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG))); -#if (NDEBUG & NDEBUG_DMA) -printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", - instance->host_no, tmp, NCR5380_read(STATUS_REG)); -#endif + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); -NCR5380_write(MODE_REG, MR_BASE); -NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -residue = NCR5380_dma_residual(instance); -c -= residue; -*count -= c; -*data += c; -*phase = NCR5380_read(STATUS_REG) & PHASE_MASK; + residue = NCR5380_dma_residual(instance); + c -= residue; + *count -= c; + *data += c; + *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; #ifdef READ_OVERRUNS -if (*phase == p && (p & SR_IO) && residue == 0) -{ -if (overrun) { -#if (NDEBUG & NDEBUG_DMA) - printk("Got an input overrun, using saved byte\n"); -#endif - **data = saved_data; - *data += 1; - *count -= 1; - cnt = toPIO = 1; -} else { - printk("No overrun??\n"); - cnt = toPIO = 2; -} -#if (NDEBUG & NDEBUG_DMA) -printk("Doing %d-byte PIO to 0x%X\n", cnt, *data); -#endif -NCR5380_transfer_pio(instance, phase, &cnt, data); -*count -= toPIO - cnt; -} + if (*phase == p && (p & SR_IO) && residue == 0) { + if (overrun) { + dprintk(NDEBUG_DMA, ("Got an input overrun, using saved byte\n")); + **data = saved_data; + *data += 1; + *count -= 1; + cnt = toPIO = 1; + } else { + printk("No overrun??\n"); + cnt = toPIO = 2; + } + dprintk(NDEBUG_DMA, ("Doing %d-byte PIO to 0x%X\n", cnt, *data)); + NCR5380_transfer_pio(instance, phase, &cnt, data); + *count -= toPIO - cnt; + } #endif -#if (NDEBUG & NDEBUG_DMA) -printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", - *data, *count, *(*data + *count - 1), *(*data + *count)); -#endif -return 0; + dprintk(NDEBUG_DMA, ("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count))); + return 0; #elif defined(REAL_DMA) -return 0; + return 0; #else /* defined(REAL_DMA_POLL) */ -if (p & SR_IO) { + if (p & SR_IO) { #ifdef DMA_WORKS_RIGHT - foo = NCR5380_pread(instance, d, c); + foo = NCR5380_pread(instance, d, c); #else - int diff = 1; - if (hostdata->flags & FLAG_NCR53C400) { - diff = 0; - } - if (!(foo = NCR5380_pread(instance, d, c - diff))) { - /* - * We can't disable DMA mode after successfully transferring - * what we plan to be the last byte, since that would open up - * a race condition where if the target asserted REQ before - * we got the DMA mode reset, the NCR5380 would have latched - * an additional byte into the INPUT DATA register and we'd - * have dropped it. - * - * The workaround was to transfer one fewer bytes than we - * intended to with the pseudo-DMA read function, wait for - * the chip to latch the last byte, read it, and then disable - * pseudo-DMA mode. - * - * After REQ is asserted, the NCR5380 asserts DRQ and ACK. - * REQ is deasserted when ACK is asserted, and not reasserted - * until ACK goes false. Since the NCR5380 won't lower ACK - * until DACK is asserted, which won't happen unless we twiddle - * the DMA port or we take the NCR5380 out of DMA mode, we - * can guarantee that we won't handshake another extra - * byte. - */ + int diff = 1; + if (hostdata->flags & FLAG_NCR53C400) { + diff = 0; + } + if (!(foo = NCR5380_pread(instance, d, c - diff))) { + /* + * We can't disable DMA mode after successfully transferring + * what we plan to be the last byte, since that would open up + * a race condition where if the target asserted REQ before + * we got the DMA mode reset, the NCR5380 would have latched + * an additional byte into the INPUT DATA register and we'd + * have dropped it. + * + * The workaround was to transfer one fewer bytes than we + * intended to with the pseudo-DMA read function, wait for + * the chip to latch the last byte, read it, and then disable + * pseudo-DMA mode. + * + * After REQ is asserted, the NCR5380 asserts DRQ and ACK. + * REQ is deasserted when ACK is asserted, and not reasserted + * until ACK goes false. Since the NCR5380 won't lower ACK + * until DACK is asserted, which won't happen unless we twiddle + * the DMA port or we take the NCR5380 out of DMA mode, we + * can guarantee that we won't handshake another extra + * byte. + */ - if (!(hostdata->flags & FLAG_NCR53C400)) { - while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); - /* Wait for clean handshake */ - while (NCR5380_read(STATUS_REG) & SR_REQ); - d[c - 1] = NCR5380_read(INPUT_DATA_REG); + if (!(hostdata->flags & FLAG_NCR53C400)) { + while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); + /* Wait for clean handshake */ + while (NCR5380_read(STATUS_REG) & SR_REQ); + d[c - 1] = NCR5380_read(INPUT_DATA_REG); + } } - } #endif -} else { + } else { #ifdef DMA_WORKS_RIGHT - foo = NCR5380_pwrite(instance, d, c); + foo = NCR5380_pwrite(instance, d, c); #else - int timeout; -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("About to pwrite %d bytes\n", c); -#endif - if (!(foo = NCR5380_pwrite(instance, d, c))) { - /* - * Wait for the last byte to be sent. If REQ is being asserted for - * the byte we're interested, we'll ACK it and it will go false. - */ - if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { - timeout = 20000; -#if 1 -#if 1 - while (!(NCR5380_read(BUS_AND_STATUS_REG) & - BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & - BASR_PHASE_MATCH)); -#else - if (NCR5380_read(STATUS_REG) & SR_REQ) { - for (; timeout && - !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); - --timeout); - for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ); - --timeout); - } -#endif - - -#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) - if (!timeout) - printk("scsi%d : timed out on last byte\n", - instance->host_no); -#endif - - - if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { - hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; - if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { - hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; -#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) - printk("scsi%d : last bit sent works\n", - instance->host_no); -#endif + int timeout; + dprintk(NDEBUG_C400_PWRITE, ("About to pwrite %d bytes\n", c)); + if (!(foo = NCR5380_pwrite(instance, d, c))) { + /* + * Wait for the last byte to be sent. If REQ is being asserted for + * the byte we're interested, we'll ACK it and it will go false. + */ + if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { + timeout = 20000; + while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)); + + if (!timeout) + dprintk(NDEBUG_LAST_BYTE_SENT, ("scsi%d : timed out on last byte\n", instance->host_no)); + + if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { + hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; + if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { + hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; + dprintk(NDEBUG_LAST_WRITE_SENT, ("scsi%d : last bit sent works\n", instance->host_no)); + } } + } else { + dprintk(NDEBUG_C400_PWRITE, ("Waiting for LASTBYTE\n")); + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); + dprintk(NDEBUG_C400_PWRITE, ("Got LASTBYTE\n")); } - } else { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("Waiting for LASTBYTE\n"); -#endif - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("Got LASTBYTE\n"); -#endif - } -#else - udelay(5); -#endif } #endif } @@ -2552,13 +2215,9 @@ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: Checking for IRQ\n"); -#endif + dprintk(NDEBUG_C400_PWRITE, ("53C400w: Checking for IRQ\n")); if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got it, reading reset interrupt reg\n"); -#endif + dprintk(NDEBUG_C400_PWRITE, ("53C400w: got it, reading reset interrupt reg\n")); NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else { printk("53C400w: IRQ NOT THERE!\n"); @@ -2567,11 +2226,8 @@ *data = d + c; *count = 0; *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; -#if 0 - NCR5380_print_phase(instance); -#endif -#if defined(PSEUDO_DMA) && !defined(UNSAFE) - restore_flags(flags); +#if defined(PSEUDO_DMA) && defined(UNSAFE) + spin_lock_irq(&io_request_lock); #endif /* defined(REAL_DMA_POLL) */ return foo; #endif /* def REAL_DMA */ @@ -2593,12 +2249,13 @@ * * XXX Note : we need to watch for bus free or a reset condition here * to recover from an unexpected bus free condition. + * + * Locks: io_request_lock held by caller */ static void NCR5380_information_transfer(struct Scsi_Host *instance) { NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata; unsigned char msgout = NOP; int sink = 0; int len; @@ -2608,10 +2265,8 @@ unsigned char *data; unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; -#ifdef USLEEP /* RvC: we need to set the end of the polling time */ unsigned long poll_time = jiffies + USLEEP_POLL; -#endif NCR5380_setup(instance); @@ -2622,27 +2277,22 @@ phase = (tmp & PHASE_MASK); if (phase != old_phase) { old_phase = phase; -#if (NDEBUG & NDEBUG_INFORMATION) - NCR5380_print_phase(instance); -#endif + NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); } if (sink && (phase != PHASE_MSGOUT)) { NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); while (NCR5380_read(STATUS_REG) & SR_REQ); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); sink = 0; continue; } switch (phase) { - case PHASE_DATAIN: - case PHASE_DATAOUT: + case PHASE_DATAIN: + case PHASE_DATAOUT: #if (NDEBUG & NDEBUG_NO_DATAOUT) - printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", - instance->host_no); + printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no); sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; @@ -2659,11 +2309,7 @@ --cmd->SCp.buffers_residual; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = cmd->SCp.buffer->address; -#if (NDEBUG & NDEBUG_INFORMATION) - printk("scsi%d : %d bytes and %d buffers left\n", - instance->host_no, cmd->SCp.this_residual, - cmd->SCp.buffers_residual); -#endif + dprintk(NDEBUG_INFORMATION, ("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); } /* * The preferred transfer method is going to be @@ -2684,9 +2330,7 @@ * We supplement these 2 if's with the flag. */ #ifdef NCR5380_dma_xfer_len - if (!cmd->device->borken && - !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && - (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) { + if (!cmd->device->borken && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) { #else transfersize = cmd->transfersize; @@ -2695,27 +2339,21 @@ transfersize = 512; #endif /* LIMIT_TRANSFERSIZE */ - if (!cmd->device->borken && transfersize && - !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && - cmd->SCp.this_residual && !(cmd->SCp.this_residual % - transfersize)) { + if (!cmd->device->borken && transfersize && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && cmd->SCp.this_residual && !(cmd->SCp.this_residual % transfersize)) { /* Limit transfers to 32K, for xx400 & xx406 * pseudoDMA that transfers in 128 bytes blocks. */ if (transfersize > 32 * 1024) transfersize = 32 * 1024; #endif len = transfersize; - if (NCR5380_transfer_dma(instance, &phase, - &len, (unsigned char **) &cmd->SCp.ptr)) { + if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) { /* * If the watchdog timer fires, all future accesses to this * device will use the polled-IO. */ - printk("scsi%d : switching target %d lun %d to slow handshake\n", - instance->host_no, cmd->target, cmd->lun); + printk("scsi%d : switching target %d lun %d to slow handshake\n", instance->host_no, cmd->target, cmd->lun); cmd->device->borken = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; @@ -2725,12 +2363,11 @@ cmd->SCp.this_residual -= transfersize - len; } else #endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */ - NCR5380_transfer_pio(instance, &phase, - (int *) &cmd->SCp.this_residual, (unsigned char **) - &cmd->SCp.ptr); + NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **) + &cmd->SCp.ptr); break; - case PHASE_MSGIN: - len = 1; + case PHASE_MSGIN: + len = 1; data = &tmp; NCR5380_transfer_pio(instance, &phase, &len, &data); cmd->SCp.Message = tmp; @@ -2747,24 +2384,18 @@ * next_link, done() is called as with unlinked commands. */ #ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -#if (NDEBUG & NDEBUG_LINKED) - printk("scsi%d : target %d lun %d linked command complete.\n", - instance->host_no, cmd->target, cmd->lun); -#endif + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked command complete.\n", instance->host_no, cmd->target, cmd->lun)); /* * Sanity check : A linked command should only terminate with * one of these messages if there are more linked commands * available. */ - if (!cmd->next_link) { - printk("scsi%d : target %d lun %d linked command complete, no next_link\n" - instance->host_no, cmd->target, cmd->lun); + printk("scsi%d : target %d lun %d linked command complete, no next_link\n" instance->host_no, cmd->target, cmd->lun); sink = 1; do_abort(instance); return; @@ -2773,27 +2404,19 @@ /* The next command is still part of this process */ cmd->next_link->tag = cmd->tag; cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); -#if (NDEBUG & NDEBUG_LINKED) - printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", - instance->host_no, cmd->target, cmd->lun); -#endif -#ifdef NCR5380_STATS + dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", instance->host_no, cmd->target, cmd->lun)); collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); cmd = hostdata->connected; break; #endif /* def LINKED */ - case ABORT: - case COMMAND_COMPLETE: + case ABORT: + case COMMAND_COMPLETE: /* Accept message by clearing ACK */ - sink = 1; + sink = 1; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); hostdata->connected = NULL; -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command for target %d, lun %d completed\n", - instance->host_no, cmd->target, cmd->lun); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d, lun %d completed\n", instance->host_no, cmd->target, cmd->lun)); hostdata->busy[cmd->target] &= ~(1 << cmd->lun); /* @@ -2818,13 +2441,8 @@ cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); #ifdef AUTOSENSE - if ((cmd->cmnd[0] != REQUEST_SENSE) && - (cmd->SCp.Status == CHECK_CONDITION)) { - unsigned long flags; -#if (NDEBUG & NDEBUG_AUTOSENSE) - printk("scsi%d : performing request sense\n", - instance->host_no); -#endif + if ((cmd->cmnd[0] != REQUEST_SENSE) && (cmd->SCp.Status == CHECK_CONDITION)) { + dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no)); cmd->cmnd[0] = REQUEST_SENSE; cmd->cmnd[1] &= 0xe0; cmd->cmnd[2] = 0; @@ -2837,21 +2455,14 @@ cmd->SCp.ptr = (char *) cmd->sense_buffer; cmd->SCp.this_residual = sizeof(cmd->sense_buffer); - save_flags(flags); - cli(); LIST(cmd, hostdata->issue_queue); cmd->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = (Scsi_Cmnd *) cmd; - restore_flags(flags); -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no)); } else { #endif /* def AUTOSENSE */ -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); } @@ -2865,37 +2476,29 @@ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) barrier(); return; - case MESSAGE_REJECT: + case MESSAGE_REJECT: /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); switch (hostdata->last_message) { - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - cmd->device->tagged_queue = 0; + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + cmd->device->tagged_queue = 0; hostdata->busy[cmd->target] |= (1 << cmd->lun); break; - default: - break; + default: + break; } - case DISCONNECT: { - unsigned long flags; + case DISCONNECT:{ /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); cmd->device->disconnect = 1; - save_flags(flags); - cli(); LIST(cmd, hostdata->disconnected_queue); cmd->host_scribble = (unsigned char *) hostdata->disconnected_queue; hostdata->connected = NULL; hostdata->disconnected_queue = cmd; - restore_flags(flags); -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command for target %d lun %d was moved from connected to" - " the disconnected_queue\n", instance->host_no, - cmd->target, cmd->lun); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d lun %d was moved from connected to" " the disconnected_queue\n", instance->host_no, cmd->target, cmd->lun)); /* * Restore phase bits to 0 so an interrupted selection, * arbitration can resume. @@ -2907,9 +2510,6 @@ /* Wait for bus free to avoid nasty timeouts */ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) barrier(); -#if 0 - NCR5380_print_status(instance); -#endif return; } /* @@ -2922,12 +2522,12 @@ * disconnecting, and we have to break spec to remain * compatible. */ - case SAVE_POINTERS: - case RESTORE_POINTERS: + case SAVE_POINTERS: + case RESTORE_POINTERS: /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); break; - case EXTENDED_MESSAGE: + case EXTENDED_MESSAGE: /* * Extended messages are sent in the following format : * Byte @@ -2940,28 +2540,19 @@ * Start the extended message buffer with the EXTENDED_MESSAGE * byte, since print_msg() wants the whole thing. */ - extended_msg[0] = EXTENDED_MESSAGE; + extended_msg[0] = EXTENDED_MESSAGE; /* Accept first byte by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : receiving extended message\n", - instance->host_no); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : receiving extended message\n", instance->host_no)); len = 2; data = extended_msg + 1; phase = PHASE_MSGIN; NCR5380_transfer_pio(instance, &phase, &len, &data); -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : length=%d, code=0x%02x\n", - instance->host_no, (int) extended_msg[1], - (int) extended_msg[2]); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2])); - if (!len && extended_msg[1] <= - (sizeof(extended_msg) - 1)) { + if (!len && extended_msg[1] <= (sizeof(extended_msg) - 1)) { /* Accept third byte by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); len = extended_msg[1] - 1; @@ -2969,26 +2560,20 @@ phase = PHASE_MSGIN; NCR5380_transfer_pio(instance, &phase, &len, &data); - -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : message received, residual %d\n", - instance->host_no, len); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : message received, residual %d\n", instance->host_no, len)); switch (extended_msg[2]) { - case EXTENDED_SDTR: - case EXTENDED_WDTR: - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - tmp = 0; + case EXTENDED_SDTR: + case EXTENDED_WDTR: + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + tmp = 0; } } else if (len) { - printk("scsi%d: error receiving extended message\n", - instance->host_no); + printk("scsi%d: error receiving extended message\n", instance->host_no); tmp = 0; } else { - printk("scsi%d: extended message code %02x length %d is too long\n", - instance->host_no, extended_msg[2], extended_msg[1]); + printk("scsi%d: extended message code %02x length %d is too long\n", instance->host_no, extended_msg[2], extended_msg[1]); tmp = 0; } /* Fall through to reject message */ @@ -2997,26 +2582,23 @@ * If we get something weird that we aren't expecting, * reject it. */ - default: - if (!tmp) { + default: + if (!tmp) { printk("scsi%d: rejecting message ", instance->host_no); print_msg(extended_msg); printk("\n"); } else if (tmp != EXTENDED_MESSAGE) - printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", - instance->host_no, tmp, cmd->target, cmd->lun); + printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", instance->host_no, tmp, cmd->target, cmd->lun); else - printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n", - instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun); + printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n", instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun); msgout = MESSAGE_REJECT; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); break; } /* switch (tmp) */ break; - case PHASE_MSGOUT: - len = 1; + case PHASE_MSGOUT: + len = 1; data = &msgout; hostdata->last_message = msgout; NCR5380_transfer_pio(instance, &phase, &len, &data); @@ -3024,69 +2606,50 @@ hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->connected = NULL; cmd->result = DID_ERROR << 16; -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return; } msgout = NOP; break; - case PHASE_CMDOUT: - len = cmd->cmd_len; + case PHASE_CMDOUT: + len = cmd->cmd_len; data = cmd->cmnd; /* * XXX for performance reasons, on machines with a * PSEUDO-DMA architecture we should probably * use the dma transfer function. */ - NCR5380_transfer_pio(instance, &phase, &len, - &data); -#ifdef USLEEP - if (!cmd->device->disconnect && - should_disconnect(cmd->cmnd[0])) - { + NCR5380_transfer_pio(instance, &phase, &len, &data); + if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) { hostdata->time_expires = jiffies + USLEEP_SLEEP; -#if (NDEBUG & NDEBUG_USLEEP) - printk("scsi%d : issued command, sleeping until %ul\n", instance->host_no, - hostdata->time_expires); -#endif + dprintk(NDEBUG_USLEEP, ("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); NCR5380_set_timer(instance); return; } -#endif /* def USLEEP */ break; - case PHASE_STATIN: - len = 1; + case PHASE_STATIN: + len = 1; data = &tmp; NCR5380_transfer_pio(instance, &phase, &len, &data); cmd->SCp.Status = tmp; break; - default: - printk("scsi%d : unknown phase\n", instance->host_no); -#ifdef NDEBUG - NCR5380_print(instance); -#endif + default: + printk("scsi%d : unknown phase\n", instance->host_no); + NCR5380_dprint(NDEBUG_ALL, instance); } /* switch(phase) */ } /* if (tmp * SR_REQ) */ -#ifdef USLEEP - else - { + else { /* RvC: go to sleep if polling time expired */ - if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) - { + if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) { hostdata->time_expires = jiffies + USLEEP_SLEEP; -#if (NDEBUG & NDEBUG_USLEEP) - printk("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, - hostdata->time_expires); -#endif + dprintk(NDEBUG_USLEEP, ("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); NCR5380_set_timer(instance); return; } } -#endif } /* while (1) */ } @@ -3099,9 +2662,9 @@ * * Inputs : instance - this instance of the NCR5380. * + * Locks: io_request_lock held by caller */ - static void NCR5380_reselect(struct Scsi_Host *instance) { NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) @@ -3109,28 +2672,22 @@ unsigned char target_mask; unsigned char lun, phase; int len; -#ifdef SCSI2 - unsigned char tag; -#endif unsigned char msg[3]; unsigned char *data; Scsi_Cmnd *tmp = NULL, *prev; int abort = 0; - NCR5380_setup(instance); + NCR5380_setup(instance); /* * Disable arbitration, etc. since the host adapter obviously * lost, and tell an interrupted NCR5380_select() to restart. */ - NCR5380_write(MODE_REG, MR_BASE); - hostdata->restart_select = 1; - - target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + NCR5380_write(MODE_REG, MR_BASE); + hostdata->restart_select = 1; -#if (NDEBUG & NDEBUG_RESELECTION) - printk("scsi%d : reselect\n", instance->host_no); -#endif + target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + dprintk(NDEBUG_SELECTION, ("scsi%d : reselect\n", instance->host_no)); /* * At this point, we have detected that our SCSI ID is on the bus, @@ -3141,10 +2698,10 @@ * signal. */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); while (NCR5380_read(STATUS_REG) & SR_SEL); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); /* * Wait for target to go into MSGIN. @@ -3152,15 +2709,13 @@ while (!(NCR5380_read(STATUS_REG) & SR_REQ)); - len = 1; - data = msg; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - + len = 1; + data = msg; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); if (!msg[0] & 0x80) { - printk("scsi%d : expecting IDENTIFY message, got ", - instance->host_no); + printk("scsi%d : expecting IDENTIFY message, got ", instance->host_no); print_msg(msg); abort = 1; } else { @@ -3174,22 +2729,14 @@ * nexuses so we can chose to do additional data transfer. */ -#ifdef SCSI2 -#error "SCSI-II tagged queueing is not supported yet" -#endif - /* * Find the command corresponding to the I_T_L or I_T_L_Q nexus we * just reestablished, and remove it from the disconnected queue. */ - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; - tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun) -#ifdef SCSI2 - && (tag == tmp->tag) -#endif ) { if (prev) { REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble); @@ -3202,13 +2749,7 @@ break; } if (!tmp) { -#ifdef SCSI2 - printk("scsi%d : warning : target bitmask %02x lun %d tag %d not in disconnect_queue.\n", - instance->host_no, target_mask, lun, tag); -#else - printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", - instance->host_no, target_mask, lun); -#endif + printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun); /* * Since we have an established nexus that we can't do anything with, * we must abort it. @@ -3221,10 +2762,7 @@ do_abort(instance); } else { hostdata->connected = tmp; -#if (NDEBUG & NDEBUG_RESELECTION) - printk("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", - instance->host_no, tmp->target, tmp->lun, tmp->tag); -#endif + dprintk(NDEBUG_RESELECTION, ("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", instance->host_no, tmp->target, tmp->lun, tmp->tag)); } } @@ -3243,8 +2781,7 @@ #ifdef REAL_DMA static void NCR5380_dma_complete(NCR5380_instance * instance) { NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata * - instance->hostdata); + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata * instance->hostdata); int transferred; NCR5380_setup(instance); @@ -3287,10 +2824,12 @@ * * Returns : 0 - success, -1 on failure. * - * XXX - there is no way to abort the command that is currently - * connected, you have to wait for it to complete. If this is - * a problem, we could implement longjmp() / setjmp(), setjmp() - * called where the loop started in NCR5380_main(). + * XXX - there is no way to abort the command that is currently + * connected, you have to wait for it to complete. If this is + * a problem, we could implement longjmp() / setjmp(), setjmp() + * called where the loop started in NCR5380_main(). + * + * Locks: io_request_lock held by caller */ #ifndef NCR5380_abort @@ -3298,10 +2837,8 @@ #endif int NCR5380_abort(Scsi_Cmnd * cmd) { NCR5380_local_declare(); - unsigned long flags; struct Scsi_Host *instance = cmd->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; Scsi_Cmnd *tmp, **prev; printk("scsi%d : aborting command\n", instance->host_no); @@ -3314,15 +2851,10 @@ NCR5380_print_status(instance); - save_flags(flags); - cli(); NCR5380_setup(instance); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort called\n", instance->host_no); - printk(" basr 0x%X, sr 0x%X\n", - NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort called\n", instance->host_no)); + dprintk(NDEBUG_ABORT, (" basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG))); #if 0 /* @@ -3332,9 +2864,7 @@ */ if (hostdata->connected == cmd) { -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : aborting connected command\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : aborting connected command\n", instance->host_no)); hostdata->aborted = 1; /* * We should perform BSY checking, and make sure we haven't slipped @@ -3361,24 +2891,15 @@ * Case 2 : If the command hasn't been issued yet, we simply remove it * from the issue queue. */ -#if (NDEBUG & NDEBUG_ABORT) /* KLL */ - printk("scsi%d : abort going into loop.\n", instance->host_no); -#endif - for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), - tmp = (Scsi_Cmnd *) hostdata->issue_queue; - tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = - (Scsi_Cmnd *) tmp->host_scribble) + dprintk(NDEBUG_ABORT, ("scsi%d : abort going into loop.\n", instance->host_no)); + for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { REMOVE(5, *prev, tmp, tmp->host_scribble); (*prev) = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort removed command from issue queue.\n", - instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no)); tmp->done(tmp); return SCSI_ABORT_SUCCESS; } @@ -3400,10 +2921,7 @@ */ if (hostdata->connected) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort failed, command connected.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort failed, command connected.\n", instance->host_no)); return SCSI_ABORT_NOT_RUNNING; } /* @@ -3431,34 +2949,22 @@ * it from the disconnected queue. */ - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; - tmp = (Scsi_Cmnd *) tmp->host_scribble) + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : aborting disconnected command.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : aborting disconnected command.\n", instance->host_no)); if (NCR5380_select(instance, cmd, (int) cmd->tag)) return SCSI_ABORT_BUSY; - -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : nexus reestablished.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : nexus reestablished.\n", instance->host_no)); do_abort(instance); - cli(); - for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), - tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; - tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = - (Scsi_Cmnd *) tmp->host_scribble) + for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { REMOVE(5, *prev, tmp, tmp->host_scribble); *prev = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); tmp->done(tmp); return SCSI_ABORT_SUCCESS; } @@ -3472,10 +2978,7 @@ * so we won't panic, but we will notify the user in case something really * broke. */ - - restore_flags(flags); - printk("scsi%d : warning : SCSI command probably completed successfully\n" - " before abortion\n", instance->host_no); + printk("scsi%d : warning : SCSI command probably completed successfully\n" " before abortion\n", instance->host_no); return SCSI_ABORT_NOT_RUNNING; } @@ -3487,6 +2990,7 @@ * * Returns : SCSI_RESET_WAKEUP * + * Locks: io_request_lock held by caller */ #ifndef NCR5380_reset diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/NCR5380.h linux-2.5/drivers/scsi/NCR5380.h --- linux-2.5.1/drivers/scsi/NCR5380.h Tue Feb 13 21:15:04 2001 +++ linux-2.5/drivers/scsi/NCR5380.h Thu Dec 13 16:32:36 2001 @@ -55,6 +55,8 @@ #define NDEBUG_C400_PWRITE 0x200000 #define NDEBUG_LISTS 0x400000 +#define NDEBUG_ANY 0xFFFFFFFFUL + /* * The contents of the OUTPUT DATA register are asserted on the bus when * either arbitration is occurring or the phase-indicating signals ( @@ -62,8 +64,8 @@ * bit in the INITIATOR COMMAND register is set. */ -#define OUTPUT_DATA_REG 0 /* wo DATA lines on SCSI bus */ -#define CURRENT_SCSI_DATA_REG 0 /* ro same */ +#define OUTPUT_DATA_REG 0 /* wo DATA lines on SCSI bus */ +#define CURRENT_SCSI_DATA_REG 0 /* ro same */ #define INITIATOR_COMMAND_REG 1 /* rw */ #define ICR_ASSERT_RST 0x80 /* rw Set to assert RST */ @@ -91,10 +93,10 @@ */ #define MR_BLOCK_DMA_MODE 0x80 /* rw block mode DMA */ #define MR_TARGET 0x40 /* rw target mode */ -#define MR_ENABLE_PAR_CHECK 0x20 /* rw enable parity checking */ +#define MR_ENABLE_PAR_CHECK 0x20 /* rw enable parity checking */ #define MR_ENABLE_PAR_INTR 0x10 /* rw enable bad parity interrupt */ #define MR_ENABLE_EOP_INTR 0x08 /* rw enable eop interrupt */ -#define MR_MONITOR_BSY 0x04 /* rw enable int on unexpected bsy fail */ +#define MR_MONITOR_BSY 0x04 /* rw enable int on unexpected bsy fail */ #define MR_DMA_MODE 0x02 /* rw DMA / pseudo DMA mode */ #define MR_ARBITRATE 0x01 /* rw start arbitration */ @@ -116,7 +118,7 @@ * Note : a set bit indicates an active signal, driven by us or another * device. */ -#define SR_RST 0x80 +#define SR_RST 0x80 #define SR_BSY 0x40 #define SR_REQ 0x20 #define SR_MSG 0x10 @@ -159,17 +161,17 @@ /* Write any value to this register to start an ini mode DMA receive */ #define START_DMA_INITIATOR_RECEIVE_REG 7 /* wo */ -#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8 /* rw */ +#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8 /* rw */ -#define CSR_RESET 0x80 /* wo Resets 53c400 */ -#define CSR_53C80_REG 0x80 /* ro 5380 registers busy */ -#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ -#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ -#define CSR_53C80_INTR 0x10 /* rw Enable 53c80 interrupts */ -#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ -#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Is Host buffer ready */ -#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer read */ -#define CSR_GATED_53C80_IRQ 0x01 /* ro Last block xferred */ +#define CSR_RESET 0x80 /* wo Resets 53c400 */ +#define CSR_53C80_REG 0x80 /* ro 5380 registers busy */ +#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ +#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ +#define CSR_53C80_INTR 0x10 /* rw Enable 53c80 interrupts */ +#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ +#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Is Host buffer ready */ +#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer read */ +#define CSR_GATED_53C80_IRQ 0x01 /* ro Last block xferred */ #if 0 #define CSR_BASE CSR_SCSI_BUFF_INTR | CSR_53C80_INTR @@ -178,13 +180,13 @@ #endif /* Number of 128-byte blocks to be transferred */ -#define C400_BLOCK_COUNTER_REG NCR53C400_register_offset-7 /* rw */ +#define C400_BLOCK_COUNTER_REG NCR53C400_register_offset-7 /* rw */ /* Resume transfer after disconnect */ -#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6 /* wo */ +#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6 /* wo */ /* Access to host buffer stack */ -#define C400_HOST_BUFFER NCR53C400_register_offset-4 /* rw */ +#define C400_HOST_BUFFER NCR53C400_register_offset-4 /* rw */ /* Note : PHASE_* macros are based on the values of the STATUS register */ @@ -203,8 +205,8 @@ * the target register so we can get phase mismatch interrupts on DMA * transfers. */ - -#define PHASE_SR_TO_TCR(phase) ((phase) >> 2) + +#define PHASE_SR_TO_TCR(phase) ((phase) >> 2) /* * The internal should_disconnect() function returns these based on the @@ -220,7 +222,7 @@ * These are "special" values for the tag parameter passed to NCR5380_select. */ -#define TAG_NEXT -1 /* Use next free tag */ +#define TAG_NEXT -1 /* Use next free tag */ #define TAG_NONE -2 /* * Establish I_T_L nexus instead of I_T_L_Q * even on SCSI-II devices. @@ -235,7 +237,7 @@ #define DMA_NONE 255 #define IRQ_AUTO 254 #define DMA_AUTO 254 -#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */ +#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */ #define FLAG_HAS_LAST_BYTE_SENT 1 /* NCR53c81 or better */ #define FLAG_CHECK_LAST_BYTE_SENT 2 /* Only test once */ @@ -245,134 +247,188 @@ #ifndef ASM struct NCR5380_hostdata { - NCR5380_implementation_fields; /* implementation specific */ - unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */ - unsigned char targets_present; /* targets we have connected + NCR5380_implementation_fields; /* implementation specific */ + unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */ + unsigned char targets_present; /* targets we have connected to, so we can call a select failure a retryable condition */ - volatile unsigned char busy[8]; /* index = target, bit = lun */ + volatile unsigned char busy[8]; /* index = target, bit = lun */ #if defined(REAL_DMA) || defined(REAL_DMA_POLL) - volatile int dma_len; /* requested length of DMA */ + volatile int dma_len; /* requested length of DMA */ #endif - volatile unsigned char last_message; /* last message OUT */ - volatile Scsi_Cmnd *connected; /* currently connected command */ - volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */ - volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */ - volatile int restart_select; /* we have disconnected, + volatile unsigned char last_message; /* last message OUT */ + volatile Scsi_Cmnd *connected; /* currently connected command */ + volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */ + volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */ + volatile int restart_select; /* we have disconnected, used to restart NCR5380_select() */ - volatile unsigned aborted:1; /* flag, says aborted */ - int flags; -#ifdef USLEEP - unsigned long time_expires; /* in jiffies, set prior to sleeping */ - struct Scsi_Host *next_timer; - int select_time; /* timer in select for target response */ - volatile Scsi_Cmnd *selecting; -#endif + volatile unsigned aborted:1; /* flag, says aborted */ + int flags; + unsigned long time_expires; /* in jiffies, set prior to sleeping */ + struct Scsi_Host *next_timer; + int select_time; /* timer in select for target response */ + volatile Scsi_Cmnd *selecting; #ifdef NCR5380_STATS - unsigned timebase; /* Base for time calcs */ - long time_read[8]; /* time to do reads */ - long time_write[8]; /* time to do writes */ - unsigned long bytes_read[8]; /* bytes read */ - unsigned long bytes_write[8]; /* bytes written */ - unsigned pendingr; - unsigned pendingw; + unsigned timebase; /* Base for time calcs */ + long time_read[8]; /* time to do reads */ + long time_write[8]; /* time to do writes */ + unsigned long bytes_read[8]; /* bytes read */ + unsigned long bytes_write[8]; /* bytes written */ + unsigned pendingr; + unsigned pendingw; #endif }; #ifdef __KERNEL__ -static struct Scsi_Host *first_instance; /* linked list of 5380's */ +static struct Scsi_Host *first_instance; /* linked list of 5380's */ + +#define dprintk(a,b) do {} while(0) +#define NCR5380_dprint(a,b) do {} while(0) +#define NCR5380_dprint_phase(a,b) do {} while(0) #if defined(AUTOPROBE_IRQ) -static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible); +static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible); #endif -static void NCR5380_init (struct Scsi_Host *instance, int flags); -static void NCR5380_information_transfer (struct Scsi_Host *instance); +static void NCR5380_init(struct Scsi_Host *instance, int flags); +static void NCR5380_information_transfer(struct Scsi_Host *instance); #ifndef DONT_USE_INTR -static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs); -static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs); +static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs); +static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs); #endif -static void NCR5380_main (void); -static void NCR5380_print_options (struct Scsi_Host *instance); -static void NCR5380_print_phase (struct Scsi_Host *instance); -static void NCR5380_print (struct Scsi_Host *instance); +static void NCR5380_main(void); +static void NCR5380_print_options(struct Scsi_Host *instance); +static void NCR5380_print_phase(struct Scsi_Host *instance); +static void NCR5380_print(struct Scsi_Host *instance); #ifndef NCR5380_abort static #endif -int NCR5380_abort (Scsi_Cmnd *cmd); +int NCR5380_abort(Scsi_Cmnd * cmd); #ifndef NCR5380_reset static #endif -int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags); +int NCR5380_reset(Scsi_Cmnd * cmd, unsigned int reset_flags); #ifndef NCR5380_queue_command -static +static #endif -int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); +int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); -static void NCR5380_reselect (struct Scsi_Host *instance); -static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag); +static void NCR5380_reselect(struct Scsi_Host *instance); +static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag); #if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL) -static int NCR5380_transfer_dma (struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data); +static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); #endif -static int NCR5380_transfer_pio (struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data); +static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); #if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) #if defined(i386) || defined(__alpha__) -static __inline__ int NCR5380_pc_dma_setup (struct Scsi_Host *instance, - unsigned char *ptr, unsigned int count, unsigned char mode) { - unsigned limit; - unsigned long bus_addr = virt_to_bus(ptr); - - if (instance->dma_channel <=3) { - if (count > 65536) - count = 65536; - limit = 65536 - (bus_addr & 0xFFFF); - } else { - if (count > 65536 * 2) - count = 65536 * 2; - limit = 65536* 2 - (bus_addr & 0x1FFFF); - } - - if (count > limit) count = limit; - - if ((count & 1) || (bus_addr & 1)) - panic ("scsi%d : attempted unaligned DMA transfer\n", instance->host_no); - cli(); - disable_dma(instance->dma_channel); - clear_dma_ff(instance->dma_channel); - set_dma_addr(instance->dma_channel, bus_addr); - set_dma_count(instance->dma_channel, count); - set_dma_mode(instance->dma_channel, mode); - enable_dma(instance->dma_channel); - sti(); - return count; +/** + * NCR5380_pc_dma_setup - setup ISA DMA + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * @mode: DMA controller mode to use + * + * Program the DMA controller ready to perform an ISA DMA transfer + * on this chip. + * + * Locks: takes and releases the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_setup(struct Scsi_Host *instance, unsigned char *ptr, unsigned int count, unsigned char mode) +{ + unsigned limit; + unsigned long bus_addr = virt_to_bus(ptr); + unsigned long flags; + + if (instance->dma_channel <= 3) { + if (count > 65536) + count = 65536; + limit = 65536 - (bus_addr & 0xFFFF); + } else { + if (count > 65536 * 2) + count = 65536 * 2; + limit = 65536 * 2 - (bus_addr & 0x1FFFF); + } + + if (count > limit) + count = limit; + + if ((count & 1) || (bus_addr & 1)) + panic("scsi%d : attempted unaligned DMA transfer\n", instance->host_no); + + flags=claim_dma_lock(); + disable_dma(instance->dma_channel); + clear_dma_ff(instance->dma_channel); + set_dma_addr(instance->dma_channel, bus_addr); + set_dma_count(instance->dma_channel, count); + set_dma_mode(instance->dma_channel, mode); + enable_dma(instance->dma_channel); + release_dma_lock(flags); + + return count; } -static __inline__ int NCR5380_pc_dma_write_setup (struct Scsi_Host *instance, - unsigned char *src, unsigned int count) { - return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_WRITE); +/** + * NCR5380_pc_dma_write_setup - setup ISA DMA write + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * + * Program the DMA controller ready to perform an ISA DMA write to the + * SCSI controller. + * + * Locks: called routines take and release the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_write_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count) +{ + return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_WRITE); } -static __inline__ int NCR5380_pc_dma_read_setup (struct Scsi_Host *instance, - unsigned char *src, unsigned int count) { - return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_READ); +/** + * NCR5380_pc_dma_read_setup - setup ISA DMA read + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * + * Program the DMA controller ready to perform an ISA DMA read from the + * SCSI controller. + * + * Locks: called routines take and release the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_read_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count) +{ + return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_READ); } -static __inline__ int NCR5380_pc_dma_residual (struct Scsi_Host *instance) { - register int tmp; - cli(); - clear_dma_ff(instance->dma_channel); - tmp = get_dma_residue(instance->dma_channel); - sti(); - return tmp; +/** + * NCR5380_pc_dma_residual - return bytes left + * @instance: adapter + * + * Reports the number of bytes left over after the DMA was terminated. + * + * Locks: takes and releases the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_residual(struct Scsi_Host *instance) +{ + unsigned long flags; + int tmp; + + flags = claim_dma_lock(); + clear_dma_ff(instance->dma_channel); + tmp = get_dma_residue(instance->dma_channel); + release_dma_lock(flags); + + return tmp; } -#endif /* defined(i386) || defined(__alpha__) */ -#endif /* defined(REAL_DMA) */ -#endif /* __KERNEL__ */ -#endif /* ndef ASM */ -#endif /* NCR5380_H */ +#endif /* defined(i386) || defined(__alpha__) */ +#endif /* defined(REAL_DMA) */ +#endif /* __KERNEL__ */ +#endif /* ndef ASM */ +#endif /* NCR5380_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/NCR_D700.c linux-2.5/drivers/scsi/NCR_D700.c --- linux-2.5.1/drivers/scsi/NCR_D700.c Sun Sep 9 18:58:36 2001 +++ linux-2.5/drivers/scsi/NCR_D700.c Fri Jan 4 17:05:20 2002 @@ -36,6 +36,10 @@ /* CHANGELOG * + * Version 2.2 + * + * Added mca_set_adapter_name(). + * * Version 2.1 * * Modularise the driver into a Board piece (this file) and a chip @@ -86,7 +90,7 @@ * disconnections and reselections are being processed correctly. * */ -#define NCR_D700_VERSION "2.1" +#define NCR_D700_VERSION "2.2" #include <linux/config.h> #include <linux/version.h> @@ -299,6 +303,7 @@ continue; } found++; + mca_set_adapter_name(slot, "NCR D700 SCSI Adapter (version " NCR_D700_VERSION ")"); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/Makefile linux-2.5/drivers/scsi/aacraid/Makefile --- linux-2.5.1/drivers/scsi/aacraid/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/Makefile Thu Dec 13 16:32:36 2001 @@ -0,0 +1,16 @@ + +EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi + + +O_TARGET := dummy.o + +list-multi := aacraid.o +aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \ + dpcsup.o rx.o sap1sup.o + +obj-$(CONFIG_SCSI_AACRAID) += aacraid.o + +include $(TOPDIR)/Rules.make + +aacraid.o: $(aacraid-objs) + $(LD) -r -o $@ $(aacraid-objs) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/README linux-2.5/drivers/scsi/aacraid/README --- linux-2.5.1/drivers/scsi/aacraid/README Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/README Thu Dec 13 16:32:36 2001 @@ -0,0 +1,41 @@ +AACRAID Driver for Linux (take two) + +Introduction +------------------------- +The aacraid driver adds support for Adaptec (http://www.adaptec.com) +OEM based RAID controllers. This is a major rewrite from the original +Adaptec supplied driver. It has signficantly cleaned up both the code +and the running binary size (the module is less than half the size of +the original). + +This driver is experimental. + +Supported Cards/Chipsets +------------------------- + Dell Computer Corporation PERC 2 Quad Channel + Dell Computer Corporation PERC 2/Si + Dell Computer Corporation PERC 3/Si + Dell Computer Corporation PERC 3/Di + HP NetRAID-4M + +Probably Supported Devices +------------------------- + Any and All Adaptec branded AAC964/5400 series raid controllers. + +People +------------------------- +Alan Cox <alan@redhat.com> +Christoph Hellwig <hch@caldera.de> (small cleanups/fixes) +Matt Domsch <matt_domsch@dell.com> (revision ioctl, adapter messages) + +Original Driver +------------------------- +Adaptec Unix OEM Product Group + +Mailing List +------------------------- +None currently. Also note this is very different to Brian's original driver +so don't expect him to support it. + +Original by Brian Boerner February 2001 +Rewritten by Alan Cox, November 2001 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/TODO linux-2.5/drivers/scsi/aacraid/TODO --- linux-2.5.1/drivers/scsi/aacraid/TODO Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/TODO Thu Dec 13 16:32:36 2001 @@ -0,0 +1,4 @@ +o Testing +o More testing +o Feature request: display the firmware/bios/etc revisions in the + /proc info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/aachba.c linux-2.5/drivers/scsi/aacraid/aachba.c --- linux-2.5.1/drivers/scsi/aacraid/aachba.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/aachba.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,1155 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/completion.h> +#include <asm/semaphore.h> +#include <asm/uaccess.h> +#define MAJOR_NR SCSI_DISK0_MAJOR /* For DEVICE_NR() */ +#include <linux/blk.h> +#include "scsi.h" +#include "hosts.h" +#include "sd.h" + +#include "aacraid.h" + +/* SCSI Commands */ +#define SS_TEST 0x00 /* Test unit ready */ +#define SS_REZERO 0x01 /* Rezero unit */ +#define SS_REQSEN 0x03 /* Request Sense */ +#define SS_REASGN 0x07 /* Reassign blocks */ +#define SS_READ 0x08 /* Read 6 */ +#define SS_WRITE 0x0A /* Write 6 */ +#define SS_INQUIR 0x12 /* inquiry */ +#define SS_ST_SP 0x1B /* Start/Stop unit */ +#define SS_LOCK 0x1E /* prevent/allow medium removal */ +#define SS_RESERV 0x16 /* Reserve */ +#define SS_RELES 0x17 /* Release */ +#define SS_MODESEN 0x1A /* Mode Sense 6 */ +#define SS_RDCAP 0x25 /* Read Capacity */ +#define SM_READ 0x28 /* Read 10 */ +#define SM_WRITE 0x2A /* Write 10 */ +#define SS_SEEK 0x2B /* Seek */ + +/* values for inqd_pdt: Peripheral device type in plain English */ +#define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */ +#define INQD_PDT_PROC 0x03 /* Processor device */ +#define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */ +#define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */ +#define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */ +#define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */ + +#define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */ +#define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask */ + +#define TARGET_LUN_TO_CONTAINER(target, lun) (((lun) << 4) | target) +#define CONTAINER_TO_TARGET(cont) ((cont) & 0xf) +#define CONTAINER_TO_LUN(cont) ((cont) >> 4) + +#define MAX_FIB_DATA (sizeof(struct hw_fib) - sizeof(FIB_HEADER)) + +#define MAX_DRIVER_SG_SEGMENT_COUNT 17 + +/* + * Sense keys + */ +#define SENKEY_NO_SENSE 0x00 +#define SENKEY_UNDEFINED 0x01 +#define SENKEY_NOT_READY 0x02 +#define SENKEY_MEDIUM_ERR 0x03 +#define SENKEY_HW_ERR 0x04 +#define SENKEY_ILLEGAL 0x05 +#define SENKEY_ATTENTION 0x06 +#define SENKEY_PROTECTED 0x07 +#define SENKEY_BLANK 0x08 +#define SENKEY_V_UNIQUE 0x09 +#define SENKEY_CPY_ABORT 0x0A +#define SENKEY_ABORT 0x0B +#define SENKEY_EQUAL 0x0C +#define SENKEY_VOL_OVERFLOW 0x0D +#define SENKEY_MISCOMP 0x0E +#define SENKEY_RESERVED 0x0F + +/* + * Sense codes + */ + +#define SENCODE_NO_SENSE 0x00 +#define SENCODE_END_OF_DATA 0x00 +#define SENCODE_BECOMING_READY 0x04 +#define SENCODE_INIT_CMD_REQUIRED 0x04 +#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A +#define SENCODE_INVALID_COMMAND 0x20 +#define SENCODE_LBA_OUT_OF_RANGE 0x21 +#define SENCODE_INVALID_CDB_FIELD 0x24 +#define SENCODE_LUN_NOT_SUPPORTED 0x25 +#define SENCODE_INVALID_PARAM_FIELD 0x26 +#define SENCODE_PARAM_NOT_SUPPORTED 0x26 +#define SENCODE_PARAM_VALUE_INVALID 0x26 +#define SENCODE_RESET_OCCURRED 0x29 +#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E +#define SENCODE_INQUIRY_DATA_CHANGED 0x3F +#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 +#define SENCODE_DIAGNOSTIC_FAILURE 0x40 +#define SENCODE_INTERNAL_TARGET_FAILURE 0x44 +#define SENCODE_INVALID_MESSAGE_ERROR 0x49 +#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c +#define SENCODE_OVERLAPPED_COMMAND 0x4E + +/* + * Additional sense codes + */ + +#define ASENCODE_NO_SENSE 0x00 +#define ASENCODE_END_OF_DATA 0x05 +#define ASENCODE_BECOMING_READY 0x01 +#define ASENCODE_INIT_CMD_REQUIRED 0x02 +#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 +#define ASENCODE_INVALID_COMMAND 0x00 +#define ASENCODE_LBA_OUT_OF_RANGE 0x00 +#define ASENCODE_INVALID_CDB_FIELD 0x00 +#define ASENCODE_LUN_NOT_SUPPORTED 0x00 +#define ASENCODE_INVALID_PARAM_FIELD 0x00 +#define ASENCODE_PARAM_NOT_SUPPORTED 0x01 +#define ASENCODE_PARAM_VALUE_INVALID 0x02 +#define ASENCODE_RESET_OCCURRED 0x00 +#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 +#define ASENCODE_INQUIRY_DATA_CHANGED 0x03 +#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 +#define ASENCODE_DIAGNOSTIC_FAILURE 0x80 +#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 +#define ASENCODE_INVALID_MESSAGE_ERROR 0x00 +#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 +#define ASENCODE_OVERLAPPED_COMMAND 0x00 + +#define BYTE0(x) (unsigned char)(x) +#define BYTE1(x) (unsigned char)((x) >> 8) +#define BYTE2(x) (unsigned char)((x) >> 16) +#define BYTE3(x) (unsigned char)((x) >> 24) + +/*------------------------------------------------------------------------------ + * S T R U C T S / T Y P E D E F S + *----------------------------------------------------------------------------*/ +/* SCSI inquiry data */ +struct inquiry_data { + u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ + u8 inqd_dtq; /* RMB | Device Type Qualifier */ + u8 inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ + u8 inqd_rdf; /* AENC | TrmIOP | Response data format */ + u8 inqd_len; /* Additional length (n-4) */ + u8 inqd_pad1[2];/* Reserved - must be zero */ + u8 inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ + u8 inqd_vid[8]; /* Vendor ID */ + u8 inqd_pid[16];/* Product ID */ + u8 inqd_prl[4]; /* Product Revision Level */ +}; + +struct sense_data { + u8 error_code; /* 70h (current errors), 71h(deferred errors) */ + u8 valid:1; /* A valid bit of one indicates that the information */ + /* field contains valid information as defined in the + * SCSI-2 Standard. + */ + u8 segment_number; /* Only used for COPY, COMPARE, or COPY AND VERIFY Commands */ + u8 sense_key:4; /* Sense Key */ + u8 reserved:1; + u8 ILI:1; /* Incorrect Length Indicator */ + u8 EOM:1; /* End Of Medium - reserved for random access devices */ + u8 filemark:1; /* Filemark - reserved for random access devices */ + + u8 information[4]; /* for direct-access devices, contains the unsigned + * logical block address or residue associated with + * the sense key + */ + u8 add_sense_len; /* number of additional sense bytes to follow this field */ + u8 cmnd_info[4]; /* not used */ + u8 ASC; /* Additional Sense Code */ + u8 ASCQ; /* Additional Sense Code Qualifier */ + u8 FRUC; /* Field Replaceable Unit Code - not used */ + u8 bit_ptr:3; /* indicates which byte of the CDB or parameter data + * was in error + */ + u8 BPV:1; /* bit pointer valid (BPV): 1- indicates that + * the bit_ptr field has valid value + */ + u8 reserved2:2; + u8 CD:1; /* command data bit: 1- illegal parameter in CDB. + * 0- illegal parameter in data. + */ + u8 SKSV:1; + u8 field_ptr[2]; /* byte of the CDB or parameter data in error */ +}; + +/* + * M O D U L E G L O B A L S + */ + +static struct fsa_scsi_hba *fsa_dev[MAXIMUM_NUM_ADAPTERS]; /* SCSI Device Instance Pointers */ +static struct sense_data sense_data[MAXIMUM_NUM_CONTAINERS]; +static void get_sd_devname(int disknum, char *buffer); + +/** + * aac_get_containers - list containers + * @common: adapter to probe + * + * Make a list of all containers on this controller + */ +int aac_get_containers(struct aac_dev *dev) +{ + struct fsa_scsi_hba *fsa_dev_ptr; + int index, status = 0; + struct aac_query_mount *dinfo; + struct aac_mount *dresp; + struct fib * fibptr; + unsigned instance; + + fsa_dev_ptr = &(dev->fsa_dev); + instance = dev->scsi_host_ptr->unique_id; + + if (!(fibptr = fib_alloc(dev))) + return -ENOMEM; + + for (index = 0; index < MAXIMUM_NUM_CONTAINERS; index++) { + fib_init(fibptr); + dinfo = (struct aac_query_mount *) fib_data(fibptr); + + dinfo->command = cpu_to_le32(VM_NameServe); + dinfo->count = cpu_to_le32(index); + dinfo->type = cpu_to_le32(FT_FILESYS); + + status = fib_send(ContainerCommand, + fibptr, + sizeof (struct aac_query_mount), + FsaNormal, + 1, 1, + NULL, NULL); + if (status < 0 ) { + printk(KERN_WARNING "ProbeContainers: SendFIB failed.\n"); + break; + } + dresp = (struct aac_mount *)fib_data(fibptr); + + if ((le32_to_cpu(dresp->status) == ST_OK) && + (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) { + fsa_dev_ptr->valid[index] = 1; + fsa_dev_ptr->type[index] = le32_to_cpu(dresp->mnt[0].vol); + fsa_dev_ptr->size[index] = le32_to_cpu(dresp->mnt[0].capacity); + if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) + fsa_dev_ptr->ro[index] = 1; + } + fib_complete(fibptr); + /* + * If there are no more containers, then stop asking. + */ + if ((index + 1) >= le32_to_cpu(dresp->count)) + break; + } + fib_free(fibptr); + fsa_dev[instance] = fsa_dev_ptr; + return status; +} + +/** + * probe_container - query a logical volume + * @dev: device to query + * @cid: container identifier + * + * Queries the controller about the given volume. The volume information + * is updated in the struct fsa_scsi_hba structure rather than returned. + */ + +static int probe_container(struct aac_dev *dev, int cid) +{ + struct fsa_scsi_hba *fsa_dev_ptr; + int status; + struct aac_query_mount *dinfo; + struct aac_mount *dresp; + struct fib * fibptr; + unsigned instance; + + fsa_dev_ptr = &(dev->fsa_dev); + instance = dev->scsi_host_ptr->unique_id; + + if (!(fibptr = fib_alloc(dev))) + return -ENOMEM; + + fib_init(fibptr); + + dinfo = (struct aac_query_mount *)fib_data(fibptr); + + dinfo->command = cpu_to_le32(VM_NameServe); + dinfo->count = cpu_to_le32(cid); + dinfo->type = cpu_to_le32(FT_FILESYS); + + status = fib_send(ContainerCommand, + fibptr, + sizeof(struct aac_query_mount), + FsaNormal, + 1, 1, + NULL, NULL); + if (status < 0) { + printk(KERN_WARNING "aacraid: probe_containers query failed.\n"); + goto error; + } + + dresp = (struct aac_mount *) fib_data(fibptr); + + if ((le32_to_cpu(dresp->status) == ST_OK) && + (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) { + fsa_dev_ptr->valid[cid] = 1; + fsa_dev_ptr->type[cid] = le32_to_cpu(dresp->mnt[0].vol); + fsa_dev_ptr->size[cid] = le32_to_cpu(dresp->mnt[0].capacity); + if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) + fsa_dev_ptr->ro[cid] = 1; + } + +error: + fib_complete(fibptr); + fib_free(fibptr); + + return status; +} + +/* Local Structure to set SCSI inquiry data strings */ +struct scsi_inq { + char vid[8]; /* Vendor ID */ + char pid[16]; /* Product ID */ + char prl[4]; /* Product Revision Level */ +}; + +/** + * InqStrCopy - string merge + * @a: string to copy from + * @b: string to copy to + * + * Copy a String from one location to another + * without copying \0 + */ + +static void inqstrcpy(char *a, char *b) +{ + + while(*a != (char)0) + *b++ = *a++; +} + +static char *container_types[] = { + "None", + "Volume", + "Mirror", + "Stripe", + "RAID5", + "SSRW", + "SSRO", + "Morph", + "Legacy", + "RAID4", + "RAID10", + "RAID00", + "V-MIRRORS", + "PSEUDO R4", + "RAID50", + "Unknown" +}; + + + +/* Function: setinqstr + * + * Arguments: [1] pointer to void [1] int + * + * Purpose: Sets SCSI inquiry data strings for vendor, product + * and revision level. Allows strings to be set in platform dependant + * files instead of in OS dependant driver source. + */ + +static void setinqstr(int devtype, void *data, int tindex) +{ + struct scsi_inq *str; + char *findit; + struct aac_driver_ident *mp; + extern struct aac_driver_ident aac_drivers[]; /* HACK FIXME */ + + mp = &aac_drivers[devtype]; + + str = (struct scsi_inq *)(data); /* cast data to scsi inq block */ + + inqstrcpy (mp->vname, str->vid); + inqstrcpy (mp->model, str->pid); /* last six chars reserved for vol type */ + + findit = str->pid; + + for ( ; *findit != ' '; findit++); /* walk till we find a space then incr by 1 */ + findit++; + + if (tindex < (sizeof(container_types)/sizeof(char *))){ + inqstrcpy (container_types[tindex], findit); + } + inqstrcpy ("0001", str->prl); +} + +void set_sense(char *sense_buf, u8 sense_key, u8 sense_code, + u8 a_sense_code, u8 incorrect_length, + u8 bit_pointer, unsigned field_pointer, + unsigned long residue) +{ + sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */ + sense_buf[1] = 0; /* Segment number, always zero */ + + if (incorrect_length) { + sense_buf[2] = sense_key | 0x20; /* Set the ILI bit | sense key */ + sense_buf[3] = BYTE3(residue); + sense_buf[4] = BYTE2(residue); + sense_buf[5] = BYTE1(residue); + sense_buf[6] = BYTE0(residue); + } else + sense_buf[2] = sense_key; /* Sense key */ + + if (sense_key == SENKEY_ILLEGAL) + sense_buf[7] = 10; /* Additional sense length */ + else + sense_buf[7] = 6; /* Additional sense length */ + + sense_buf[12] = sense_code; /* Additional sense code */ + sense_buf[13] = a_sense_code; /* Additional sense code qualifier */ + if (sense_key == SENKEY_ILLEGAL) { + sense_buf[15] = 0; + + if (sense_code == SENCODE_INVALID_PARAM_FIELD) + sense_buf[15] = 0x80; /* Std sense key specific field */ + /* Illegal parameter is in the parameter block */ + + if (sense_code == SENCODE_INVALID_CDB_FIELD) + sense_buf[15] = 0xc0; /* Std sense key specific field */ + /* Illegal parameter is in the CDB block */ + sense_buf[15] |= bit_pointer; + sense_buf[16] = field_pointer >> 8; /* MSB */ + sense_buf[17] = field_pointer; /* LSB */ + } +} + +static void aac_io_done(Scsi_Cmnd * scsicmd) +{ + unsigned long cpu_flags; + spin_lock_irqsave(&io_request_lock, cpu_flags); + scsicmd->scsi_done(scsicmd); + spin_unlock_irqrestore(&io_request_lock, cpu_flags); +} + +static void __aac_io_done(Scsi_Cmnd * scsicmd) +{ + scsicmd->scsi_done(scsicmd); +} + +static void read_callback(void *context, struct fib * fibptr) +{ + struct aac_dev *dev; + struct aac_read_reply *readreply; + Scsi_Cmnd *scsicmd; + unsigned long lba; + int cid; + + scsicmd = (Scsi_Cmnd *) context; + + dev = (struct aac_dev *)scsicmd->host->hostdata; + cid =TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun); + + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %ld, t = %ld.\n", smp_processor_id(), lba, jiffies)); + + if (fibptr == NULL) + BUG(); + + if(scsicmd->use_sg) + pci_unmap_sg(dev->pdev, + (struct scatterlist *)scsicmd->buffer, + scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + else if(scsicmd->request_bufflen) + pci_unmap_single(dev->pdev, (dma_addr_t)(long)scsicmd->SCp.ptr, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + readreply = (struct aac_read_reply *)fib_data(fibptr); + if (le32_to_cpu(readreply->status) == ST_OK) + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else { + printk(KERN_WARNING "read_callback: read failed, status = %d\n", readreply->status); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_HW_ERR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); + } + fib_complete(fibptr); + fib_free(fibptr); + + aac_io_done(scsicmd); +} + +static void write_callback(void *context, struct fib * fibptr) +{ + struct aac_dev *dev; + struct aac_write_reply *writereply; + Scsi_Cmnd *scsicmd; + unsigned long lba; + int cid; + + scsicmd = (Scsi_Cmnd *) context; + dev = (struct aac_dev *)scsicmd->host->hostdata; + cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun); + + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %ld, t = %ld.\n", smp_processor_id(), lba, jiffies)); + if (fibptr == NULL) + BUG(); + + if(scsicmd->use_sg) + pci_unmap_sg(dev->pdev, + (struct scatterlist *)scsicmd->buffer, + scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + else if(scsicmd->request_bufflen) + pci_unmap_single(dev->pdev, (dma_addr_t)(long)scsicmd->SCp.ptr, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + + writereply = (struct aac_write_reply *) fib_data(fibptr); + if (le32_to_cpu(writereply->status) == ST_OK) + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else { + printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_HW_ERR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); + } + + fib_complete(fibptr); + fib_free(fibptr); + aac_io_done(scsicmd); +} + +int aac_read(Scsi_Cmnd * scsicmd, int cid) +{ + unsigned long lba; + unsigned long count; + unsigned long byte_count = 0; + int status; + + struct aac_read *readcmd; + u16 fibsize; + struct aac_dev *dev; + struct fib * cmd_fibcontext; + + dev = (struct aac_dev *)scsicmd->host->hostdata; + /* + * Get block address and transfer length + */ + if (scsicmd->cmnd[0] == SS_READ) /* 6 byte command */ + { + dprintk((KERN_DEBUG "aachba: received a read(6) command on target %d.\n", cid)); + + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + count = scsicmd->cmnd[4]; + + if (count == 0) + count = 256; + } else { + dprintk((KERN_DEBUG "aachba: received a read(10) command on target %d.\n", cid)); + + lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; + count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; + } + dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %lu, t = %ld.\n", smp_processor_id(), lba, jiffies)); + /* + * Alocate and initialize a Fib + */ + if (!(cmd_fibcontext = fib_alloc(dev))) { + scsicmd->result = DID_ERROR << 16; + aac_io_done(scsicmd); + return (-1); + } + + fib_init(cmd_fibcontext); + + readcmd = (struct aac_read *) fib_data(cmd_fibcontext); + readcmd->command = cpu_to_le32(VM_CtBlockRead); + readcmd->cid = cpu_to_le32(cid); + readcmd->block = cpu_to_le32(lba); + readcmd->count = cpu_to_le32(count * 512); + readcmd->sg.count = cpu_to_le32(1); + + if (count * 512 > (64 * 1024)) + BUG(); + /* + * Build Scatter/Gather list + */ + if (scsicmd->use_sg) /* use scatter/gather list */ + { + struct scatterlist *sg; + int i; + int sg_count; + + sg = (struct scatterlist *) scsicmd->request_buffer; + + sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + + byte_count = 0; + + for (i = 0; i < sg_count; i++) { + readcmd->sg.sg[i].addr = cpu_to_le32(sg_dma_address(sg)); + readcmd->sg.sg[i].count = cpu_to_le32(sg_dma_len(sg)); + byte_count += sg->length; + if (sg->length > (64 * 1024)) + BUG(); + sg++; + } + readcmd->sg.count = cpu_to_le32(sg_count); + + if (sg_count > MAX_DRIVER_SG_SEGMENT_COUNT) + BUG(); + } + else if(scsicmd->request_bufflen) + { + dma_addr_t addr; + addr = pci_map_single(dev->pdev, scsicmd->request_buffer, + scsicmd->request_bufflen, scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + scsicmd->SCp.ptr = (void *)(long)addr; + readcmd->sg.sg[0].addr = cpu_to_le32(addr); + readcmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen); + + byte_count = scsicmd->request_bufflen; + + if (byte_count > (64 * 1024)) + BUG(); + } + if (byte_count != readcmd->count) + BUG(); + /* + * Now send the Fib to the adapter + */ + fibsize = sizeof(struct aac_read) + ((readcmd->sg.count - 1) * sizeof (struct sgentry)); + status = fib_send(ContainerCommand, + cmd_fibcontext, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) read_callback, + (void *) scsicmd); + /* + * Check that the command queued to the controller + */ + if (status == -EINPROGRESS) + return 0; + + printk(KERN_WARNING "aac_read: fib_send failed with status: %d.\n", status); + /* + * For some reason, the Fib didn't queue, return QUEUE_FULL + */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL; + aac_io_done(scsicmd); + fib_complete(cmd_fibcontext); + fib_free(cmd_fibcontext); + return -1; +} + +static int aac_write(Scsi_Cmnd * scsicmd, int cid) +{ + unsigned long lba; + unsigned long count; + unsigned long byte_count = 0; + int status; + struct aac_write *writecmd; + u16 fibsize; + struct aac_dev *dev; + struct fib * cmd_fibcontext; + + dev = (struct aac_dev *)scsicmd->host->hostdata; + /* + * Get block address and transfer length + */ + if (scsicmd->cmnd[0] == SS_WRITE) /* 6 byte command */ + { + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + count = scsicmd->cmnd[4]; + if (count == 0) + count = 256; + } else { + dprintk((KERN_DEBUG "aachba: received a write(10) command on target %d.\n", cid)); + lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; + count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; + } + dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %lu, t = %ld.\n", smp_processor_id(), lba, jiffies)); + /* + * Allocate and initialize a Fib then setup a BlockWrite command + */ + if (!(cmd_fibcontext = fib_alloc(dev))) { + scsicmd->result = DID_ERROR << 16; + aac_io_done(scsicmd); + return -1; + } + fib_init(cmd_fibcontext); + + writecmd = (struct aac_write *) fib_data(cmd_fibcontext); + writecmd->command = cpu_to_le32(VM_CtBlockWrite); + writecmd->cid = cpu_to_le32(cid); + writecmd->block = cpu_to_le32(lba); + writecmd->count = cpu_to_le32(count * 512); + writecmd->sg.count = cpu_to_le32(1); + /* FIXME: why isnt ->stable setup */ + + if (count * 512 > (64 * 1024)) { + BUG(); + } + /* + * Build Scatter/Gather list + */ + if (scsicmd->use_sg) + { + struct scatterlist *sg; + int i; + int sg_count; + + sg = (struct scatterlist *) scsicmd->request_buffer; + + sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + + byte_count = 0; + + for (i = 0; i < scsicmd->use_sg; i++) { + writecmd->sg.sg[i].addr = cpu_to_le32(sg_dma_address(sg)); + writecmd->sg.sg[i].count = cpu_to_le32(sg_dma_len(sg)); + byte_count += sg->length; + + if (sg->length > (64 * 1024)) + BUG(); + sg++; + } + writecmd->sg.count = cpu_to_le32(sg_count); + + if (sg_count > MAX_DRIVER_SG_SEGMENT_COUNT) + BUG(); + } + else if(scsicmd->request_bufflen) + { + dma_addr_t addr; + addr = pci_map_single(dev->pdev, + scsicmd->request_buffer, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + writecmd->sg.sg[0].addr = cpu_to_le32(addr); + writecmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen); + scsicmd->SCp.ptr = (void *)(long)addr; + byte_count = scsicmd->request_bufflen; + + if (byte_count > (64 * 1024)) + BUG(); + } + if (byte_count != writecmd->count) + BUG(); + /* + * Now send the Fib to the adapter + */ + fibsize = sizeof (struct aac_write) + ((writecmd->sg.count - 1) * sizeof (struct sgentry)); + + status = fib_send(ContainerCommand, + cmd_fibcontext, + fibsize, FsaNormal, + 0, 1, + (fib_callback) write_callback, + (void *) scsicmd); + /* + * Check that the command queued to the controller + */ + if (status == -EINPROGRESS) + return 0; + + printk(KERN_WARNING "aac_write: fib_send failed with status: %d\n", status); + /* + * For some reason, the Fib didn't queue, return QUEUE_FULL + */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL; + aac_io_done(scsicmd); + + fib_complete(cmd_fibcontext); + fib_free(cmd_fibcontext); + return -1; +} + + +/** + * aac_scsi_cmd() - Process SCSI command + * @scsicmd: SCSI command block + * @wait: 1 if the user wants to await completion + * + * Emulate a SCSI command and queue the required request for the + * aacraid firmware. + */ + +int aac_scsi_cmd(Scsi_Cmnd * scsicmd) +{ + int cid = 0; + struct fsa_scsi_hba *fsa_dev_ptr; + int cardtype; + int ret; + struct aac_dev *dev = (struct aac_dev *)scsicmd->host->hostdata; + + cardtype = dev->cardtype; + + fsa_dev_ptr = fsa_dev[scsicmd->host->unique_id]; + + /* + * If the bus, target or lun is out of range, return fail + * Test does not apply to ID 16, the pseudo id for the controller + * itself. + */ + if (scsicmd->target != scsicmd->host->this_id) { + if ((scsicmd->channel > 0) ||(scsicmd->target > 15) || (scsicmd->lun > 7)) + { + dprintk((KERN_DEBUG "The bus, target or lun is out of range = %d, %d, %d.\n", + scsicmd->channel, scsicmd->target, scsicmd->lun)); + scsicmd->result = DID_BAD_TARGET << 16; + __aac_io_done(scsicmd); + return -1; + } + cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun); + /* + * If the target container doesn't exist, it may have + * been newly created + */ + if (fsa_dev_ptr->valid[cid] == 0) { + switch (scsicmd->cmnd[0]) { + case SS_INQUIR: + case SS_RDCAP: + case SS_TEST: + spin_unlock_irq(&io_request_lock); + probe_container(dev, cid); + spin_lock_irq(&io_request_lock); + default: + break; + } + } + /* + * If the target container still doesn't exist, + * return failure + */ + if (fsa_dev_ptr->valid[cid] == 0) { + scsicmd->result = DID_BAD_TARGET << 16; + __aac_io_done(scsicmd); + return -1; + } + } + else if ((scsicmd->cmnd[0] != SS_INQUIR) && /* only INQUIRY & TUR cmnd supported for controller */ + (scsicmd->cmnd[0] != SS_TEST)) + { + /* + * Command aimed at the controller + */ + dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0])); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_ILLEGAL, + SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); + __aac_io_done(scsicmd); + return -1; + } + /* Handle commands here that don't really require going out to the adapter */ + switch (scsicmd->cmnd[0]) + { + case SS_INQUIR: + { + struct inquiry_data *inq_data_ptr; + + dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->target)); + inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer; + memset(inq_data_ptr, 0, sizeof (struct inquiry_data)); + + inq_data_ptr->inqd_ver = 2; /* claim compliance to SCSI-2 */ + inq_data_ptr->inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */ + inq_data_ptr->inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ + inq_data_ptr->inqd_len = 31; + + /* + * Set the Vendor, Product, and Revision Level + * see: <vendor>.c i.e. aac.c + */ + setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]); + if (scsicmd->target == scsicmd->host->this_id) + inq_data_ptr->inqd_pdt = INQD_PDT_PROC; /* Processor device */ + else + inq_data_ptr->inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return 0; + } + case SS_RDCAP: + { + int capacity; + char *cp; + + dprintk((KERN_DEBUG "READ CAPACITY command.\n")); + capacity = fsa_dev_ptr->size[cid] - 1; + cp = scsicmd->request_buffer; + cp[0] = (capacity >> 24) & 0xff; + cp[1] = (capacity >> 16) & 0xff; + cp[2] = (capacity >> 8) & 0xff; + cp[3] = (capacity >> 0) & 0xff; + cp[4] = 0; + cp[5] = 0; + cp[6] = 2; + cp[7] = 0; + + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + + return 0; + } + + case SS_MODESEN: + { + char *mode_buf; + + dprintk((KERN_DEBUG "MODE SENSE command.\n")); + mode_buf = scsicmd->request_buffer; + mode_buf[0] = 0; /* Mode data length (MSB) */ + mode_buf[1] = 6; /* Mode data length (LSB) */ + mode_buf[2] = 0; /* Medium type - default */ + mode_buf[3] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */ + mode_buf[4] = 0; /* reserved */ + mode_buf[5] = 0; /* reserved */ + mode_buf[6] = 0; /* Block descriptor length (MSB) */ + mode_buf[7] = 0; /* Block descriptor length (LSB) */ + + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + + return 0; + } + case SS_REQSEN: + dprintk((KERN_DEBUG "REQUEST SENSE command.\n")); + memcpy(scsicmd->sense_buffer, &sense_data[cid], sizeof (struct sense_data)); + memset(&sense_data[cid], 0, sizeof (struct sense_data)); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return (0); + + case SS_LOCK: + dprintk((KERN_DEBUG "LOCK command.\n")); + if (scsicmd->cmnd[4]) + fsa_dev_ptr->locked[cid] = 1; + else + fsa_dev_ptr->locked[cid] = 0; + + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return 0; + /* + * These commands are all No-Ops + */ + case SS_TEST: + case SS_RESERV: + case SS_RELES: + case SS_REZERO: + case SS_REASGN: + case SS_SEEK: + case SS_ST_SP: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return (0); + } + + switch (scsicmd->cmnd[0]) + { + case SS_READ: + case SM_READ: + /* + * Hack to keep track of ordinal number of the device that + * corresponds to a container. Needed to convert + * containers to /dev/sd device names + */ + + spin_unlock_irq(&io_request_lock); + fsa_dev_ptr->devno[cid] = DEVICE_NR(scsicmd->request.rq_dev); + ret = aac_read(scsicmd, cid); + spin_lock_irq(&io_request_lock); + return ret; + + case SS_WRITE: + case SM_WRITE: + spin_unlock_irq(&io_request_lock); + ret = aac_write(scsicmd, cid); + spin_lock_irq(&io_request_lock); + return ret; + default: + /* + * Unhandled commands + */ + printk(KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); + __aac_io_done(scsicmd); + return -1; + } +} + +static int query_disk(struct aac_dev *dev, void *arg) +{ + struct aac_query_disk qd; + struct fsa_scsi_hba *fsa_dev_ptr; + + fsa_dev_ptr = &(dev->fsa_dev); + if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk))) + return -EFAULT; + if (qd.cnum == -1) + qd.cnum = TARGET_LUN_TO_CONTAINER(qd.target, qd.lun); + else if ((qd.bus == -1) && (qd.target == -1) && (qd.lun == -1)) + { + if (qd.cnum < 0 || qd.cnum > MAXIMUM_NUM_CONTAINERS) + return -EINVAL; + qd.instance = dev->scsi_host_ptr->host_no; + qd.bus = 0; + qd.target = CONTAINER_TO_TARGET(qd.cnum); + qd.lun = CONTAINER_TO_LUN(qd.cnum); + } + else return -EINVAL; + + qd.valid = fsa_dev_ptr->valid[qd.cnum]; + qd.locked = fsa_dev_ptr->locked[qd.cnum]; + qd.deleted = fsa_dev_ptr->deleted[qd.cnum]; + + if (fsa_dev_ptr->devno[qd.cnum] == -1) + qd.unmapped = 1; + else + qd.unmapped = 0; + + get_sd_devname(fsa_dev_ptr->devno[qd.cnum], qd.name); + + if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk))) + return -EFAULT; + return 0; +} + +static void get_sd_devname(int disknum, char *buffer) +{ + if (disknum < 0) { + sprintf(buffer, "%s", ""); + return; + } + + if (disknum < 26) + sprintf(buffer, "sd%c", 'a' + disknum); + else { + unsigned int min1; + unsigned int min2; + /* + * For larger numbers of disks, we need to go to a new + * naming scheme. + */ + min1 = disknum / 26; + min2 = disknum % 26; + sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); + } +} + +static int force_delete_disk(struct aac_dev *dev, void *arg) +{ + struct aac_delete_disk dd; + struct fsa_scsi_hba *fsa_dev_ptr; + + fsa_dev_ptr = &(dev->fsa_dev); + + if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) + return -EFAULT; + + if (dd.cnum > MAXIMUM_NUM_CONTAINERS) + return -EINVAL; + /* + * Mark this container as being deleted. + */ + fsa_dev_ptr->deleted[dd.cnum] = 1; + /* + * Mark the container as no longer valid + */ + fsa_dev_ptr->valid[dd.cnum] = 0; + return 0; +} + +static int delete_disk(struct aac_dev *dev, void *arg) +{ + struct aac_delete_disk dd; + struct fsa_scsi_hba *fsa_dev_ptr; + + fsa_dev_ptr = &(dev->fsa_dev); + + if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) + return -EFAULT; + + if (dd.cnum > MAXIMUM_NUM_CONTAINERS) + return -EINVAL; + /* + * If the container is locked, it can not be deleted by the API. + */ + if (fsa_dev_ptr->locked[dd.cnum]) + return -EBUSY; + else { + /* + * Mark the container as no longer being valid. + */ + fsa_dev_ptr->valid[dd.cnum] = 0; + fsa_dev_ptr->devno[dd.cnum] = -1; + return 0; + } +} + +int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg) +{ + switch (cmd) { + case FSACTL_QUERY_DISK: + return query_disk(dev, arg); + case FSACTL_DELETE_DISK: + return delete_disk(dev, arg); + case FSACTL_FORCE_DELETE_DISK: + return force_delete_disk(dev, arg); + case 2131: + return aac_get_containers(dev); + default: + return -ENOTTY; + } +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/aacraid.h linux-2.5/drivers/scsi/aacraid/aacraid.h --- linux-2.5.1/drivers/scsi/aacraid/aacraid.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/aacraid.h Mon Jan 14 22:39:45 2002 @@ -0,0 +1,1208 @@ +#define dprintk(x) + +#define AAC_NUM_FIB 128 +#define AAC_NUM_IO_FIB 116 + +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ + +struct diskparm +{ + int heads; + int sectors; + int cylinders; +}; + + +/* + * DON'T CHANGE THE ORDER, this is set by the firmware + */ + +#define CT_NONE 0 +#define CT_VOLUME 1 +#define CT_MIRROR 2 +#define CT_STRIPE 3 +#define CT_RAID5 4 +#define CT_SSRW 5 +#define CT_SSRO 6 +#define CT_MORPH 7 +#define CT_PASSTHRU 8 +#define CT_RAID4 9 +#define CT_RAID10 10 /* stripe of mirror */ +#define CT_RAID00 11 /* stripe of stripe */ +#define CT_VOLUME_OF_MIRRORS 12 /* volume of mirror */ +#define CT_PSEUDO_RAID 13 /* really raid4 */ +#define CT_LAST_VOLUME_TYPE 14 + +/* + * Types of objects addressable in some fashion by the client. + * This is a superset of those objects handled just by the filesystem + * and includes "raw" objects that an administrator would use to + * configure containers and filesystems. + */ + +#define FT_REG 1 /* regular file */ +#define FT_DIR 2 /* directory */ +#define FT_BLK 3 /* "block" device - reserved */ +#define FT_CHR 4 /* "character special" device - reserved */ +#define FT_LNK 5 /* symbolic link */ +#define FT_SOCK 6 /* socket */ +#define FT_FIFO 7 /* fifo */ +#define FT_FILESYS 8 /* ADAPTEC's "FSA"(tm) filesystem */ +#define FT_DRIVE 9 /* physical disk - addressable in scsi by bus/target/lun */ +#define FT_SLICE 10 /* virtual disk - raw volume - slice */ +#define FT_PARTITION 11 /* FSA partition - carved out of a slice - building block for containers */ +#define FT_VOLUME 12 /* Container - Volume Set */ +#define FT_STRIPE 13 /* Container - Stripe Set */ +#define FT_MIRROR 14 /* Container - Mirror Set */ +#define FT_RAID5 15 /* Container - Raid 5 Set */ +#define FT_DATABASE 16 /* Storage object with "foreign" content manager */ + +/* + * Host side memory scatter gather list + * Used by the adapter for read, write, and readdirplus operations + */ + +struct sgentry { + u32 addr; /* 32-bit Base address. */ + u32 count; /* Length. */ +}; + +/* + * SGMAP + * + * This is the SGMAP structure for all commands that use + * 32-bit addressing. + * + * Note that the upper 16 bits of SgCount are used as flags. + * Only the lower 16 bits of SgCount are actually used as the + * SG element count. + */ + +struct sgmap { + u32 count; + struct sgentry sg[1]; +}; + +struct creation_info +{ + u8 buildnum; /* e.g., 588 */ + u8 usec; /* e.g., 588 */ + u8 via; /* e.g., 1 = FSU, + * 2 = API + */ + u8 year; /* e.g., 1997 = 97 */ + u32 date; /* + * unsigned Month :4; // 1 - 12 + * unsigned Day :6; // 1 - 32 + * unsigned Hour :6; // 0 - 23 + * unsigned Minute :6; // 0 - 60 + * unsigned Second :6; // 0 - 60 + */ + u64 serial; /* e.g., 0x1DEADB0BFAFAF001 */ +}; + + +/* + * Define all the constants needed for the communication interface + */ + +/* + * Define how many queue entries each queue will have and the total + * number of entries for the entire communication interface. Also define + * how many queues we support. + * + * This has to match the controller + */ + +#define NUMBER_OF_COMM_QUEUES 8 // 4 command; 4 response +#define HOST_HIGH_CMD_ENTRIES 4 +#define HOST_NORM_CMD_ENTRIES 8 +#define ADAP_HIGH_CMD_ENTRIES 4 +#define ADAP_NORM_CMD_ENTRIES 512 +#define HOST_HIGH_RESP_ENTRIES 4 +#define HOST_NORM_RESP_ENTRIES 512 +#define ADAP_HIGH_RESP_ENTRIES 4 +#define ADAP_NORM_RESP_ENTRIES 8 + +#define TOTAL_QUEUE_ENTRIES \ + (HOST_NORM_CMD_ENTRIES + HOST_HIGH_CMD_ENTRIES + ADAP_NORM_CMD_ENTRIES + ADAP_HIGH_CMD_ENTRIES + \ + HOST_NORM_RESP_ENTRIES + HOST_HIGH_RESP_ENTRIES + ADAP_NORM_RESP_ENTRIES + ADAP_HIGH_RESP_ENTRIES) + + +/* + * Set the queues on a 16 byte alignment + */ + +#define QUEUE_ALIGNMENT 16 + +/* + * The queue headers define the Communication Region queues. These + * are physically contiguous and accessible by both the adapter and the + * host. Even though all queue headers are in the same contiguous block + * they will be represented as individual units in the data structures. + */ + +struct aac_entry { + u32 size; /* Size in bytes of the Fib which this QE points to */ + u32 addr; /* Receiver addressable address of the FIB (low 32 address bits) */ +}; + +/* + * The adapter assumes the ProducerIndex and ConsumerIndex are grouped + * adjacently and in that order. + */ + +struct aac_qhdr { + u64 header_addr; /* Address to hand the adapter to access to this queue head */ + u32 *producer; /* The producer index for this queue (host address) */ + u32 *consumer; /* The consumer index for this queue (host address) */ +}; + +/* + * Define all the events which the adapter would like to notify + * the host of. + */ + +#define HostNormCmdQue 1 /* Change in host normal priority command queue */ +#define HostHighCmdQue 2 /* Change in host high priority command queue */ +#define HostNormRespQue 3 /* Change in host normal priority response queue */ +#define HostHighRespQue 4 /* Change in host high priority response queue */ +#define AdapNormRespNotFull 5 +#define AdapHighRespNotFull 6 +#define AdapNormCmdNotFull 7 +#define AdapHighCmdNotFull 8 +#define SynchCommandComplete 9 +#define AdapInternalError 0xfe /* The adapter detected an internal error shutting down */ + +/* + * Define all the events the host wishes to notify the + * adapter of. The first four values much match the Qid the + * corresponding queue. + */ + +#define AdapNormCmdQue 2 +#define AdapHighCmdQue 3 +#define AdapNormRespQue 6 +#define AdapHighRespQue 7 +#define HostShutdown 8 +#define HostPowerFail 9 +#define FatalCommError 10 +#define HostNormRespNotFull 11 +#define HostHighRespNotFull 12 +#define HostNormCmdNotFull 13 +#define HostHighCmdNotFull 14 +#define FastIo 15 +#define AdapPrintfDone 16 + +/* + * Define all the queues that the adapter and host use to communicate + * Number them to match the physical queue layout. + */ + +enum aac_queue_types { + HostNormCmdQueue = 0, /* Adapter to host normal priority command traffic */ + HostHighCmdQueue, /* Adapter to host high priority command traffic */ + AdapNormCmdQueue, /* Host to adapter normal priority command traffic */ + AdapHighCmdQueue, /* Host to adapter high priority command traffic */ + HostNormRespQueue, /* Adapter to host normal priority response traffic */ + HostHighRespQueue, /* Adapter to host high priority response traffic */ + AdapNormRespQueue, /* Host to adapter normal priority response traffic */ + AdapHighRespQueue /* Host to adapter high priority response traffic */ +}; + +/* + * Assign type values to the FSA communication data structures + */ + +#define FIB_MAGIC 0x0001 + +/* + * Define the priority levels the FSA communication routines support. + */ + +#define FsaNormal 1 +#define FsaHigh 2 + +// +// Define the FIB. The FIB is the where all the requested data and +// command information are put to the application on the FSA adapter. +// + +struct aac_fibhdr { + u32 XferState; // Current transfer state for this CCB + u16 Command; // Routing information for the destination + u8 StructType; // Type FIB + u8 Flags; // Flags for FIB + u16 Size; // Size of this FIB in bytes + u16 SenderSize; // Size of the FIB in the sender (for response sizing) + u32 SenderFibAddress; // Host defined data in the FIB + u32 ReceiverFibAddress; // Logical address of this FIB for the adapter + u32 SenderData; // Place holder for the sender to store data + union { + struct { + u32 _ReceiverTimeStart; // Timestamp for receipt of fib + u32 _ReceiverTimeDone; // Timestamp for completion of fib + } _s; + struct list_head _FibLinks; // Used to link Adapter Initiated Fibs on the host + } _u; +}; + +#define FibLinks _u._FibLinks + +#define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(struct aac_fibhdr)) + + +struct hw_fib { + struct aac_fibhdr header; + u8 data[FIB_DATA_SIZE_IN_BYTES]; // Command specific data +}; + +/* + * FIB commands + */ + +#define TestCommandResponse 1 +#define TestAdapterCommand 2 +/* + * Lowlevel and comm commands + */ +#define LastTestCommand 100 +#define ReinitHostNormCommandQueue 101 +#define ReinitHostHighCommandQueue 102 +#define ReinitHostHighRespQueue 103 +#define ReinitHostNormRespQueue 104 +#define ReinitAdapNormCommandQueue 105 +#define ReinitAdapHighCommandQueue 107 +#define ReinitAdapHighRespQueue 108 +#define ReinitAdapNormRespQueue 109 +#define InterfaceShutdown 110 +#define DmaCommandFib 120 +#define StartProfile 121 +#define TermProfile 122 +#define SpeedTest 123 +#define TakeABreakPt 124 +#define RequestPerfData 125 +#define SetInterruptDefTimer 126 +#define SetInterruptDefCount 127 +#define GetInterruptDefStatus 128 +#define LastCommCommand 129 +/* + * Filesystem commands + */ +#define NuFileSystem 300 +#define UFS 301 +#define HostFileSystem 302 +#define LastFileSystemCommand 303 +/* + * Container Commands + */ +#define ContainerCommand 500 +#define ContainerCommand64 501 +/* + * Cluster Commands + */ +#define ClusterCommand 550 +/* + * Scsi Port commands (scsi passthrough) + */ +#define ScsiPortCommand 600 +/* + * Misc house keeping and generic adapter initiated commands + */ +#define AifRequest 700 +#define CheckRevision 701 +#define FsaHostShutdown 702 +#define RequestAdapterInfo 703 +#define IsAdapterPaused 704 +#define SendHostTime 705 +#define LastMiscCommand 706 + +// +// Commands that will target the failover level on the FSA adapter +// + +enum fib_xfer_state { + HostOwned = (1<<0), + AdapterOwned = (1<<1), + FibInitialized = (1<<2), + FibEmpty = (1<<3), + AllocatedFromPool = (1<<4), + SentFromHost = (1<<5), + SentFromAdapter = (1<<6), + ResponseExpected = (1<<7), + NoResponseExpected = (1<<8), + AdapterProcessed = (1<<9), + HostProcessed = (1<<10), + HighPriority = (1<<11), + NormalPriority = (1<<12), + Async = (1<<13), + AsyncIo = (1<<13), // rpbfix: remove with new regime + PageFileIo = (1<<14), // rpbfix: remove with new regime + ShutdownRequest = (1<<15), + LazyWrite = (1<<16), // rpbfix: remove with new regime + AdapterMicroFib = (1<<17), + BIOSFibPath = (1<<18), + FastResponseCapable = (1<<19), + ApiFib = (1<<20) // Its an API Fib. +}; + +/* + * The following defines needs to be updated any time there is an + * incompatible change made to the aac_init structure. + */ + +#define ADAPTER_INIT_STRUCT_REVISION 3 + +struct aac_init +{ + u32 InitStructRevision; + u32 MiniPortRevision; + u32 fsrev; + u32 CommHeaderAddress; + u32 FastIoCommAreaAddress; + u32 AdapterFibsPhysicalAddress; + u32 AdapterFibsVirtualAddress; + u32 AdapterFibsSize; + u32 AdapterFibAlign; + u32 printfbuf; + u32 printfbufsiz; + u32 HostPhysMemPages; // number of 4k pages of host physical memory + u32 HostElapsedSeconds; // number of seconds since 1970. +}; + +enum aac_log_level { + LOG_INIT = 10, + LOG_INFORMATIONAL = 20, + LOG_WARNING = 30, + LOG_LOW_ERROR = 40, + LOG_MEDIUM_ERROR = 50, + LOG_HIGH_ERROR = 60, + LOG_PANIC = 70, + LOG_DEBUG = 80, + LOG_WINDBG_PRINT = 90 +}; + +#define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT 0x030b +#define FSAFS_NTC_FIB_CONTEXT 0x030c + +struct aac_dev; + +struct adapter_ops +{ + void (*adapter_interrupt)(struct aac_dev *dev); + void (*adapter_notify)(struct aac_dev *dev, u32 event); + void (*adapter_enable_int)(struct aac_dev *dev, u32 event); + void (*adapter_disable_int)(struct aac_dev *dev, u32 event); +}; + +/* + * Define which interrupt handler needs to be installed + */ + +struct aac_driver_ident +{ + u16 vendor; + u16 device; + u16 subsystem_vendor; + u16 subsystem_device; + int (*init)(struct aac_dev *dev, unsigned long num); + char * name; + char * vname; + char * model; +}; + +/* + * The adapter interface specs all queues to be located in the same + * physically contigous block. The host structure that defines the + * commuication queues will assume they are each a seperate physically + * contigous memory region that will support them all being one big + * contigous block. + * There is a command and response queue for each level and direction of + * commuication. These regions are accessed by both the host and adapter. + */ + +struct aac_queue { + u64 logical; /* This is the address we give the adapter */ + struct aac_entry *base; /* This is the system virtual address */ + struct aac_qhdr headers; /* A pointer to the producer and consumer queue headers for this queue */ + u32 entries; /* Number of queue entries on this queue */ + wait_queue_head_t qfull; /* Event to wait on if the queue is full */ + wait_queue_head_t cmdready; /* Indicates there is a Command ready from the adapter on this queue. */ + /* This is only valid for adapter to host command queues. */ + spinlock_t *lock; /* Spinlock for this queue must take this lock before accessing the lock */ + spinlock_t lockdata; /* Actual lock (used only on one side of the lock) */ + unsigned long SavedIrql; /* Previous IRQL when the spin lock is taken */ + u32 padding; /* Padding - FIXME - can remove I believe */ + struct list_head cmdq; /* A queue of FIBs which need to be prcessed by the FS thread. This is */ + /* only valid for command queues which receive entries from the adapter. */ + struct list_head pendingq; /* A queue of outstanding fib's to the adapter. */ + unsigned long numpending; /* Number of entries on outstanding queue. */ + struct aac_dev * dev; /* Back pointer to adapter structure */ +}; + +/* + * Message queues. The order here is important, see also the + * queue type ordering + */ + +struct aac_queue_block +{ + struct aac_queue queue[8]; +}; + +/* + * SaP1 Message Unit Registers + */ + +struct sa_drawbridge_CSR { + // Offset | Name + u32 reserved[10]; // 00h-27h | Reserved + u8 LUT_Offset; // 28h | Looup Table Offset + u8 reserved1[3]; // 29h-2bh | Reserved + u32 LUT_Data; // 2ch | Looup Table Data + u32 reserved2[26]; // 30h-97h | Reserved + u16 PRICLEARIRQ; // 98h | Primary Clear Irq + u16 SECCLEARIRQ; // 9ah | Secondary Clear Irq + u16 PRISETIRQ; // 9ch | Primary Set Irq + u16 SECSETIRQ; // 9eh | Secondary Set Irq + u16 PRICLEARIRQMASK; // a0h | Primary Clear Irq Mask + u16 SECCLEARIRQMASK; // a2h | Secondary Clear Irq Mask + u16 PRISETIRQMASK; // a4h | Primary Set Irq Mask + u16 SECSETIRQMASK; // a6h | Secondary Set Irq Mask + u32 MAILBOX0; // a8h | Scratchpad 0 + u32 MAILBOX1; // ach | Scratchpad 1 + u32 MAILBOX2; // b0h | Scratchpad 2 + u32 MAILBOX3; // b4h | Scratchpad 3 + u32 MAILBOX4; // b8h | Scratchpad 4 + u32 MAILBOX5; // bch | Scratchpad 5 + u32 MAILBOX6; // c0h | Scratchpad 6 + u32 MAILBOX7; // c4h | Scratchpad 7 + + u32 ROM_Setup_Data; // c8h | Rom Setup and Data + u32 ROM_Control_Addr; // cch | Rom Control and Address + + u32 reserved3[12]; // d0h-ffh | reserved + u32 LUT[64]; // 100h-1ffh| Lookup Table Entries + + // + // TO DO + // need to add DMA, I2O, UART, etc registers form 80h to 364h + // + +}; + +#define Mailbox0 SaDbCSR.MAILBOX0 +#define Mailbox1 SaDbCSR.MAILBOX1 +#define Mailbox2 SaDbCSR.MAILBOX2 +#define Mailbox3 SaDbCSR.MAILBOX3 +#define Mailbox4 SaDbCSR.MAILBOX4 +#define Mailbox5 SaDbCSR.MAILBOX5 +#define Mailbox7 SaDbCSR.MAILBOX7 + +#define DoorbellReg_p SaDbCSR.PRISETIRQ +#define DoorbellReg_s SaDbCSR.SECSETIRQ +#define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ + + +#define DOORBELL_0 cpu_to_le16(0x0001) +#define DOORBELL_1 cpu_to_le16(0x0002) +#define DOORBELL_2 cpu_to_le16(0x0004) +#define DOORBELL_3 cpu_to_le16(0x0008) +#define DOORBELL_4 cpu_to_le16(0x0010) +#define DOORBELL_5 cpu_to_le16(0x0020) +#define DOORBELL_6 cpu_to_le16(0x0040) + + +#define PrintfReady DOORBELL_5 +#define PrintfDone DOORBELL_5 + +struct sa_registers { + struct sa_drawbridge_CSR SaDbCSR; /* 98h - c4h */ +}; + + +#define Sa_MINIPORT_REVISION 1 + +#define sa_readw(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) +#define sa_readl(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) +#define sa_writew(AEP, CSR, value) writew(value, &((AEP)->regs.sa->CSR)) +#define sa_writel(AEP, CSR, value) writel(value, &((AEP)->regs.sa->CSR)) + +/* + * Rx Message Unit Registers + */ + +struct rx_mu_registers { + // Local | PCI* | Name + // | | + u32 ARSR; // 1300h | 00h | APIC Register Select Register + u32 reserved0; // 1304h | 04h | Reserved + u32 AWR; // 1308h | 08h | APIC Window Register + u32 reserved1; // 130Ch | 0Ch | Reserved + u32 IMRx[2]; // 1310h | 10h | Inbound Message Registers + u32 OMRx[2]; // 1318h | 18h | Outbound Message Registers + u32 IDR; // 1320h | 20h | Inbound Doorbell Register + u32 IISR; // 1324h | 24h | Inbound Interrupt Status Register + u32 IIMR; // 1328h | 28h | Inbound Interrupt Mask Register + u32 ODR; // 132Ch | 2Ch | Outbound Doorbell Register + u32 OISR; // 1330h | 30h | Outbound Interrupt Status Register + u32 OIMR; // 1334h | 34h | Outbound Interrupt Mask Register + // * Must access through ATU Inbound Translation Window +}; + +struct rx_inbound { + u32 Mailbox[8]; +}; + +#define InboundMailbox0 IndexRegs.Mailbox[0] +#define InboundMailbox1 IndexRegs.Mailbox[1] +#define InboundMailbox2 IndexRegs.Mailbox[2] +#define InboundMailbox3 IndexRegs.Mailbox[3] +#define InboundMailbox4 IndexRegs.Mailbox[4] + +#define INBOUNDDOORBELL_0 cpu_to_le32(0x00000001) +#define INBOUNDDOORBELL_1 cpu_to_le32(0x00000002) +#define INBOUNDDOORBELL_2 cpu_to_le32(0x00000004) +#define INBOUNDDOORBELL_3 cpu_to_le32(0x00000008) +#define INBOUNDDOORBELL_4 cpu_to_le32(0x00000010) +#define INBOUNDDOORBELL_5 cpu_to_le32(0x00000020) +#define INBOUNDDOORBELL_6 cpu_to_le32(0x00000040) + +#define OUTBOUNDDOORBELL_0 cpu_to_le32(0x00000001) +#define OUTBOUNDDOORBELL_1 cpu_to_le32(0x00000002) +#define OUTBOUNDDOORBELL_2 cpu_to_le32(0x00000004) +#define OUTBOUNDDOORBELL_3 cpu_to_le32(0x00000008) +#define OUTBOUNDDOORBELL_4 cpu_to_le32(0x00000010) + +#define InboundDoorbellReg MUnit.IDR +#define OutboundDoorbellReg MUnit.ODR + +struct rx_registers { + struct rx_mu_registers MUnit; // 1300h - 1334h + u32 reserved1[6]; // 1338h - 134ch + struct rx_inbound IndexRegs; +}; + +#define rx_readb(AEP, CSR) readb(&((AEP)->regs.rx->CSR)) +#define rx_readl(AEP, CSR) readl(&((AEP)->regs.rx->CSR)) +#define rx_writeb(AEP, CSR, value) writeb(value, &((AEP)->regs.rx->CSR)) +#define rx_writel(AEP, CSR, value) writel(value, &((AEP)->regs.rx->CSR)) + +struct fib; + +typedef void (*fib_callback)(void *ctxt, struct fib *fibctx); + +struct aac_fib_context { + s16 type; // used for verification of structure + s16 size; + u32 jiffies; // used for cleanup + struct list_head next; // used to link context's into a linked list + struct semaphore wait_sem; // this is used to wait for the next fib to arrive. + int wait; // Set to true when thread is in WaitForSingleObject + unsigned long count; // total number of FIBs on FibList + struct list_head fibs; +}; + +#define MAXIMUM_NUM_CONTAINERS 64 // 4 Luns * 16 Targets +#define MAXIMUM_NUM_ADAPTERS 8 + +struct fsa_scsi_hba { + unsigned long size[MAXIMUM_NUM_CONTAINERS]; + unsigned long type[MAXIMUM_NUM_CONTAINERS]; + unsigned char valid[MAXIMUM_NUM_CONTAINERS]; + unsigned char ro[MAXIMUM_NUM_CONTAINERS]; + unsigned char locked[MAXIMUM_NUM_CONTAINERS]; + unsigned char deleted[MAXIMUM_NUM_CONTAINERS]; + long devno[MAXIMUM_NUM_CONTAINERS]; +}; + +struct fib { + void *next; /* this is used by the allocator */ + s16 type; + s16 size; + /* + * The Adapter that this I/O is destined for. + */ + struct aac_dev *dev; + u64 logicaladdr; /* 64 bit */ + /* + * This is the event the sendfib routine will wait on if the + * caller did not pass one and this is synch io. + */ + struct semaphore event_wait; + spinlock_t event_lock; + + unsigned long done; /* gets set to 1 when fib is complete */ + fib_callback callback; + void *callback_data; + unsigned long flags; + /* + * The following is used to put this fib context onto the + * Outstanding I/O queue. + */ + struct list_head queue; + + void *data; + struct hw_fib *fib; /* Actual shared object */ +}; + +struct aac_dev +{ + struct aac_dev *next; + const char *name; + int id; + + u16 irq_mask; + /* + * Map for 128 fib objects (64k) + */ + dma_addr_t hw_fib_pa; + struct hw_fib *hw_fib_va; + /* + * Fib Headers + */ + struct fib fibs[AAC_NUM_FIB]; + struct fib *free_fib; + struct fib *timeout_fib; + spinlock_t fib_lock; + + struct aac_queue_block *queues; + /* + * The user API will use an IOCTL to register itself to receive + * FIBs from the adapter. The following list is used to keep + * track of all the threads that have requested these FIBs. The + * mutex is used to synchronize access to all data associated + * with the adapter fibs. + */ + struct list_head fib_list; + + struct adapter_ops a_ops; + unsigned long fsrev; /* Main driver's revision number */ + + struct aac_init *init; /* Holds initialization info to communicate with adapter */ + void * init_pa; /* Holds physical address of the init struct */ + + struct pci_dev *pdev; /* Our PCI interface */ + void * printfbuf; /* pointer to buffer used for printf's from the adapter */ + void * comm_addr; /* Base address of Comm area */ + dma_addr_t comm_phys; /* Physical Address of Comm area */ + size_t comm_size; + + struct Scsi_Host *scsi_host_ptr; + struct fsa_scsi_hba fsa_dev; + int thread_pid; + int cardtype; + + /* + * The following is the device specific extension. + */ + union + { + struct sa_registers *sa; + struct rx_registers *rx; + } regs; + /* + * The following is the number of the individual adapter + */ + long devnum; + int aif_thread; + struct completion aif_completion; +}; + +#define AllocateAndMapFibSpace(dev, MapFibContext) \ + dev->a_ops.AllocateAndMapFibSpace(dev, MapFibContext) + +#define UnmapAndFreeFibSpace(dev, MapFibContext) \ + dev->a_ops.UnmapAndFreeFibSpace(dev, MapFibContext) + +#define aac_adapter_interrupt(dev) \ + dev->a_ops.adapter_interrupt(dev) + +#define aac_adapter_notify(dev, event) \ + dev->a_ops.adapter_notify(dev, event) + +#define aac_adapter_enable_int(dev, event) \ + dev->a_ops.adapter_enable_int(dev, event) + +#define aac_adapter_disable_int(dev, event) \ + dev->a_ops.adapter_disable_int(dev, event) + + + +#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001) + +/* + * Define the command values + */ + +#define Null 0 +#define GetAttributes 1 +#define SetAttributes 2 +#define Lookup 3 +#define ReadLink 4 +#define Read 5 +#define Write 6 +#define Create 7 +#define MakeDirectory 8 +#define SymbolicLink 9 +#define MakeNode 10 +#define Removex 11 +#define RemoveDirectoryx 12 +#define Rename 13 +#define Link 14 +#define ReadDirectory 15 +#define ReadDirectoryPlus 16 +#define FileSystemStatus 17 +#define FileSystemInfo 18 +#define PathConfigure 19 +#define Commit 20 +#define Mount 21 +#define UnMount 22 +#define Newfs 23 +#define FsCheck 24 +#define FsSync 25 +#define SimReadWrite 26 +#define SetFileSystemStatus 27 +#define BlockRead 28 +#define BlockWrite 29 +#define NvramIoctl 30 +#define FsSyncWait 31 +#define ClearArchiveBit 32 +#define SetAcl 33 +#define GetAcl 34 +#define AssignAcl 35 +#define FaultInsertion 36 /* Fault Insertion Command */ +#define CrazyCache 37 /* Crazycache */ + +#define MAX_FSACOMMAND_NUM 38 + + +/* + * Define the status returns. These are very unixlike although + * most are not in fact used + */ + +#define ST_OK 0 +#define ST_PERM 1 +#define ST_NOENT 2 +#define ST_IO 5 +#define ST_NXIO 6 +#define ST_E2BIG 7 +#define ST_ACCES 13 +#define ST_EXIST 17 +#define ST_XDEV 18 +#define ST_NODEV 19 +#define ST_NOTDIR 20 +#define ST_ISDIR 21 +#define ST_INVAL 22 +#define ST_FBIG 27 +#define ST_NOSPC 28 +#define ST_ROFS 30 +#define ST_MLINK 31 +#define ST_WOULDBLOCK 35 +#define ST_NAMETOOLONG 63 +#define ST_NOTEMPTY 66 +#define ST_DQUOT 69 +#define ST_STALE 70 +#define ST_REMOTE 71 +#define ST_BADHANDLE 10001 +#define ST_NOT_SYNC 10002 +#define ST_BAD_COOKIE 10003 +#define ST_NOTSUPP 10004 +#define ST_TOOSMALL 10005 +#define ST_SERVERFAULT 10006 +#define ST_BADTYPE 10007 +#define ST_JUKEBOX 10008 +#define ST_NOTMOUNTED 10009 +#define ST_MAINTMODE 10010 +#define ST_STALEACL 10011 + +/* + * On writes how does the client want the data written. + */ + +#define CACHE_CSTABLE 1 +#define CACHE_UNSTABLE 2 + +/* + * Lets the client know at which level the data was commited on + * a write request + */ + +#define CMFILE_SYNCH_NVRAM 1 +#define CMDATA_SYNCH_NVRAM 2 +#define CMFILE_SYNCH 3 +#define CMDATA_SYNCH 4 +#define CMUNSTABLE 5 + +struct aac_read +{ + u32 command; + u32 cid; + u32 block; + u32 count; + struct sgmap sg; // Must be last in struct because it is variable +}; + +struct aac_read_reply +{ + u32 status; + u32 count; +}; + +struct aac_write +{ + u32 command; + u32 cid; + u32 block; + u32 count; + u32 stable; + struct sgmap sg; // Must be last in struct because it is variable +}; + +struct aac_write_reply +{ + u32 status; + u32 count; + u32 committed; +}; + + +/* + * Object-Server / Volume-Manager Dispatch Classes + */ + +#define VM_Null 0 +#define VM_NameServe 1 +#define VM_ContainerConfig 2 +#define VM_Ioctl 3 +#define VM_FilesystemIoctl 4 +#define VM_CloseAll 5 +#define VM_CtBlockRead 6 +#define VM_CtBlockWrite 7 +#define VM_SliceBlockRead 8 /* raw access to configured "storage objects" */ +#define VM_SliceBlockWrite 9 +#define VM_DriveBlockRead 10 /* raw access to physical devices */ +#define VM_DriveBlockWrite 11 +#define VM_EnclosureMgt 12 /* enclosure management */ +#define VM_Unused 13 /* used to be diskset management */ +#define VM_CtBlockVerify 14 +#define VM_CtPerf 15 /* performance test */ +#define VM_CtBlockRead64 16 +#define VM_CtBlockWrite64 17 +#define VM_CtBlockVerify64 18 + +#define MAX_VMCOMMAND_NUM 19 /* used for sizing stats array - leave last */ + +/* + * Descriptive information (eg, vital stats) + * that a content manager might report. The + * FileArray filesystem component is one example + * of a content manager. Raw mode might be + * another. + */ + +struct aac_fsinfo { + u32 fsTotalSize; /* Consumed by fs, incl. metadata */ + u32 fsBlockSize; + u32 fsFragSize; + u32 fsMaxExtendSize; + u32 fsSpaceUnits; + u32 fsMaxNumFiles; + u32 fsNumFreeFiles; + u32 fsInodeDensity; +}; /* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */ + +union aac_contentinfo { + struct aac_fsinfo filesys; /* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */ +}; + +/* + * Query for "mountable" objects, ie, objects that are typically + * associated with a drive letter on the client (host) side. + */ + +struct aac_mntent { + u32 oid; + char name[16]; // if applicable + struct creation_info create_info; // if applicable + u32 capacity; + u32 vol; // substrate structure + u32 obj; // FT_FILESYS, FT_DATABASE, etc. + u32 state; // unready for mounting, readonly, etc. + union aac_contentinfo fileinfo; // Info specific to content manager (eg, filesystem) + u32 altoid; // != oid <==> snapshot or broken mirror exists +}; + +#define FSCS_READONLY 0x0002 /* possible result of broken mirror */ + +struct aac_query_mount { + u32 command; + u32 type; + u32 count; +}; + +struct aac_mount { + u32 status; + u32 type; /* should be same as that requested */ + u32 count; + struct aac_mntent mnt[1]; +}; + +/* + * The following command is sent to shut down each container. + */ + +struct aac_close { + u32 command; + u32 cid; +}; + +struct aac_query_disk +{ + s32 cnum; + s32 bus; + s32 target; + s32 lun; + u32 valid; + u32 locked; + u32 deleted; + s32 instance; + s8 name[10]; + u32 unmapped; +}; + +struct aac_delete_disk { + u32 disknum; + u32 cnum; +}; + +struct fib_ioctl +{ + char *fibctx; + int wait; + char *fib; +}; + +struct revision +{ + int compat; + unsigned long version; + unsigned long build; +}; + +/* + * Ugly - non Linux like ioctl coding for back compat. + */ + +#define CTL_CODE(function, method) ( \ + (4<< 16) | ((function) << 2) | (method) \ +) + +/* + * Define the method codes for how buffers are passed for I/O and FS + * controls + */ + +#define METHOD_BUFFERED 0 +#define METHOD_NEITHER 3 + +/* + * Filesystem ioctls + */ + +#define FSACTL_SENDFIB CTL_CODE(2050, METHOD_BUFFERED) +#define FSACTL_DELETE_DISK 0x163 +#define FSACTL_QUERY_DISK 0x173 +#define FSACTL_OPEN_GET_ADAPTER_FIB CTL_CODE(2100, METHOD_BUFFERED) +#define FSACTL_GET_NEXT_ADAPTER_FIB CTL_CODE(2101, METHOD_BUFFERED) +#define FSACTL_CLOSE_GET_ADAPTER_FIB CTL_CODE(2102, METHOD_BUFFERED) +#define FSACTL_MINIPORT_REV_CHECK CTL_CODE(2107, METHOD_BUFFERED) +#define FSACTL_FORCE_DELETE_DISK CTL_CODE(2120, METHOD_NEITHER) + +struct aac_common +{ + /* + * If this value is set to 1 then interrupt moderation will occur + * in the base commuication support. + */ + unsigned long irq_mod; + int peak_fibs; + int zero_fibs; + unsigned long fib_timeouts; + /* + * Statistical counters in debug mode + */ +#ifdef DBG + unsigned long FibsSent; + unsigned long FibRecved; + unsigned long NoResponseSent; + unsigned long NoResponseRecved; + unsigned long AsyncSent; + unsigned long AsyncRecved; + unsigned long NormalSent; + unsigned long NormalRecved; +#endif +}; + +extern struct aac_common aac_config; + + +/* + * The following macro is used when sending and receiving FIBs. It is + * only used for debugging. + */ + +#if DBG +#define FIB_COUNTER_INCREMENT(counter) (counter)++ +#else +#define FIB_COUNTER_INCREMENT(counter) +#endif + +/* + * Adapter direct commands + */ + +#define BREAKPOINT_REQUEST 0x00000004 +#define INIT_STRUCT_BASE_ADDRESS 0x00000005 +#define SEND_SYNCHRONOUS_FIB 0x0000000c + +/* + * Adapter Status Register + * + * Phase Staus mailbox is 32bits: + * <31:16> = Phase Status + * <15:0> = Phase + * + * The adapter reports is present state through the phase. Only + * a single phase should be ever be set. Each phase can have multiple + * phase status bits to provide more detailed information about the + * state of the board. Care should be taken to ensure that any phase + * status bits that are set when changing the phase are also valid + * for the new phase or be cleared out. Adapter software (monitor, + * iflash, kernel) is responsible for properly maintining the phase + * status mailbox when it is running. + * + * MONKER_API Phases + * + * Phases are bit oriented. It is NOT valid to have multiple bits set + */ + +#define SELF_TEST_FAILED cpu_to_le32(0x00000004) +#define KERNEL_UP_AND_RUNNING cpu_to_le32(0x00000080) +#define KERNEL_PANIC cpu_to_le32(0x00000100) + +/* + * Doorbell bit defines + */ + +#define DoorBellPrintfDone cpu_to_le32(1<<5) // Host -> Adapter +#define DoorBellAdapterNormCmdReady cpu_to_le32(1<<1) // Adapter -> Host +#define DoorBellAdapterNormRespReady cpu_to_le32(1<<2) // Adapter -> Host +#define DoorBellAdapterNormCmdNotFull cpu_to_le32(1<<3) // Adapter -> Host +#define DoorBellAdapterNormRespNotFull cpu_to_le32(1<<4) // Adapter -> Host +#define DoorBellPrintfReady cpu_to_le32(1<<5) // Adapter -> Host + +/* + * For FIB communication, we need all of the following things + * to send back to the user. + */ + +#define AifCmdEventNotify 1 /* Notify of event */ +#define AifCmdJobProgress 2 /* Progress report */ +#define AifCmdAPIReport 3 /* Report from other user of API */ +#define AifCmdDriverNotify 4 /* Notify host driver of event */ +#define AifReqJobList 100 /* Gets back complete job list */ +#define AifReqJobsForCtr 101 /* Gets back jobs for specific container */ +#define AifReqJobsForScsi 102 /* Gets back jobs for specific SCSI device */ +#define AifReqJobReport 103 /* Gets back a specific job report or list of them */ +#define AifReqTerminateJob 104 /* Terminates job */ +#define AifReqSuspendJob 105 /* Suspends a job */ +#define AifReqResumeJob 106 /* Resumes a job */ +#define AifReqSendAPIReport 107 /* API generic report requests */ +#define AifReqAPIJobStart 108 /* Start a job from the API */ +#define AifReqAPIJobUpdate 109 /* Update a job report from the API */ +#define AifReqAPIJobFinish 110 /* Finish a job from the API */ + +/* + * Adapter Initiated FIB command structures. Start with the adapter + * initiated FIBs that really come from the adapter, and get responded + * to by the host. + */ + +struct aac_aifcmd { + u32 command; /* Tell host what type of notify this is */ + u32 seqnum; /* To allow ordering of reports (if necessary) */ + u8 data[1]; /* Undefined length (from kernel viewpoint) */ +}; + +/* + * Adapter Information Block + * + * This is returned by the RequestAdapterInfo block + */ + +struct aac_adapter_info +{ + u32 platform; + u32 cpu; + u32 subcpu; + u32 clock; + u32 execmem; + u32 buffermem; + u32 totalmem; + u32 kernelrev; + u32 kernelbuild; + u32 monitorrev; + u32 monitorbuild; + u32 hwrev; + u32 hwbuild; + u32 biosrev; + u32 biosbuild; + u32 clustering; + u32 clustermask; + u64 serial; + u32 battery; + u32 options; + u32 OEM; +}; + +static inline u32 fib2addr(struct hw_fib *hw) +{ + return (u32)hw; +} + +static inline struct hw_fib *addr2fib(u32 addr) +{ + return (struct hw_fib *)addr; +} + +const char *aac_driverinfo(struct Scsi_Host *); +struct fib *fib_alloc(struct aac_dev *dev); +int fib_setup(struct aac_dev *dev); +void fib_map_free(struct aac_dev *dev); +void fib_free(struct fib * context); +void fib_init(struct fib * context); +void fib_dealloc(struct fib * context); +void aac_printf(struct aac_dev *dev, u32 val); +int fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt); +int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry); +int aac_consumer_avail(struct aac_dev * dev, struct aac_queue * q); +void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum); +int fib_complete(struct fib * context); +#define fib_data(fibctx) ((void *)(fibctx)->fib->data) +int aac_detach(struct aac_dev *dev); +struct aac_dev *aac_init_adapter(struct aac_dev *dev); +int aac_get_containers(struct aac_dev *dev); +int aac_scsi_cmd(Scsi_Cmnd *scsi_cmnd_ptr); +int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg); +int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg); +int aac_rx_init(struct aac_dev *dev, unsigned long devNumber); +int aac_sa_init(struct aac_dev *dev, unsigned long devNumber); +unsigned int aac_response_normal(struct aac_queue * q); +unsigned int aac_command_normal(struct aac_queue * q); +int aac_command_thread(struct aac_dev * dev); +int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx); +int fib_adapter_complete(struct fib * fibptr, unsigned short size); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/commctrl.c linux-2.5/drivers/scsi/aacraid/commctrl.c --- linux-2.5.1/drivers/scsi/aacraid/commctrl.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/commctrl.c Thu Dec 13 16:32:36 2001 @@ -0,0 +1,410 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commctrl.c + * + * Abstract: Contains all routines for control of the AFA comm layer + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/completion.h> +#include <linux/blk.h> +#include <asm/semaphore.h> +#include <asm/uaccess.h> +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +/** + * ioctl_send_fib - send a FIB from userspace + * @dev: adapter is being processed + * @arg: arguments to the ioctl call + * + * This routine sends a fib to the adapter on behalf of a user level + * program. + */ + +static int ioctl_send_fib(struct aac_dev * dev, void *arg) +{ + struct hw_fib * kfib; + struct fib *fibptr; + + fibptr = fib_alloc(dev); + if(fibptr == NULL) + return -ENOMEM; + + kfib = fibptr->fib; + /* + * First copy in the header so that we can check the size field. + */ + if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) { + fib_free(fibptr); + return -EFAULT; + } + /* + * Since we copy based on the fib header size, make sure that we + * will not overrun the buffer when we copy the memory. Return + * an error if we would. + */ + if(le32_to_cpu(kfib->header.Size) > sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) { + fib_free(fibptr); + return -EINVAL; + } + + if (copy_from_user((void *) kfib, arg, le32_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr))) { + fib_free(fibptr); + return -EFAULT; + } + + if (kfib->header.Command == cpu_to_le32(TakeABreakPt)) { + aac_adapter_interrupt(dev); + /* + * Since we didn't really send a fib, zero out the state to allow + * cleanup code not to assert. + */ + kfib->header.XferState = 0; + } else { + if (fib_send(kfib->header.Command, fibptr, le32_to_cpu(kfib->header.Size) , FsaNormal, + 1, 1, NULL, NULL) != 0) + { + fib_free(fibptr); + return -EINVAL; + } + if (fib_complete(fibptr) != 0) { + fib_free(fibptr); + return -EINVAL; + } + } + /* + * Make sure that the size returned by the adapter (which includes + * the header) is less than or equal to the size of a fib, so we + * don't corrupt application data. Then copy that size to the user + * buffer. (Don't try to add the header information again, since it + * was already included by the adapter.) + */ + + if (copy_to_user(arg, (void *)kfib, kfib->header.Size)) { + fib_free(fibptr); + return -EFAULT; + } + fib_free(fibptr); + return 0; +} + +/** + * open_getadapter_fib - Get the next fib + * + * This routine will get the next Fib, if available, from the AdapterFibContext + * passed in from the user. + */ + +static int open_getadapter_fib(struct aac_dev * dev, void *arg) +{ + struct aac_fib_context * fibctx; + int status; + unsigned long flags; + + fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); + if (fibctx == NULL) { + status = -ENOMEM; + } else { + fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; + fibctx->size = sizeof(struct aac_fib_context); + /* + * Initialize the mutex used to wait for the next AIF. + */ + init_MUTEX_LOCKED(&fibctx->wait_sem); + fibctx->wait = 0; + /* + * Initialize the fibs and set the count of fibs on + * the list to 0. + */ + fibctx->count = 0; + INIT_LIST_HEAD(&fibctx->fibs); + fibctx->jiffies = jiffies/HZ; + /* + * Now add this context onto the adapter's + * AdapterFibContext list. + */ + spin_lock_irqsave(&dev->fib_lock, flags); + list_add_tail(&fibctx->next, &dev->fib_list); + spin_unlock_irqrestore(&dev->fib_lock, flags); + if (copy_to_user(arg, &fibctx, sizeof(struct aac_fib_context *))) { + status = -EFAULT; + } else { + status = 0; + } + } + return status; +} + +/** + * next_getadapter_fib - get the next fib + * @dev: adapter to use + * @arg: ioctl argument + * + * This routine will get the next Fib, if available, from the AdapterFibContext + * passed in from the user. + */ + +static int next_getadapter_fib(struct aac_dev * dev, void *arg) +{ + struct fib_ioctl f; + struct aac_fib_context *fibctx, *aifcp; + struct hw_fib * fib; + int status; + struct list_head * entry; + int found; + unsigned long flags; + + if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) + return -EFAULT; + /* + * Extract the AdapterFibContext from the Input parameters. + */ + fibctx = (struct aac_fib_context *) f.fibctx; + + /* + * Verify that the HANDLE passed in was a valid AdapterFibContext + * + * Search the list of AdapterFibContext addresses on the adapter + * to be sure this is a valid address + */ + found = 0; + entry = dev->fib_list.next; + + while(entry != &dev->fib_list) { + aifcp = list_entry(entry, struct aac_fib_context, next); + if(fibctx == aifcp) { /* We found a winner */ + found = 1; + break; + } + entry = entry->next; + } + if (found == 0) + return -EINVAL; + + if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || + (fibctx->size != sizeof(struct aac_fib_context))) + return -EINVAL; + status = 0; + spin_lock_irqsave(&dev->fib_lock, flags); + /* + * If there are no fibs to send back, then either wait or return + * -EAGAIN + */ +return_fib: + if (!list_empty(&fibctx->fibs)) { + struct list_head * entry; + /* + * Pull the next fib from the fibs + */ + entry = fibctx->fibs.next; + list_del(entry); + + fib = list_entry(entry, struct hw_fib, header.FibLinks); + fibctx->count--; + spin_unlock_irqrestore(&dev->fib_lock, flags); + if (copy_to_user(f.fib, fib, sizeof(struct hw_fib))) { + kfree(fib); + return -EFAULT; + } + /* + * Free the space occupied by this copy of the fib. + */ + kfree(fib); + status = 0; + fibctx->jiffies = jiffies/HZ; + } else { + spin_unlock_irqrestore(&dev->fib_lock, flags); + if (f.wait) { + if(down_interruptible(&fibctx->wait_sem) < 0) { + status = -EINTR; + } else { + /* Lock again and retry */ + spin_lock_irqsave(&dev->fib_lock, flags); + goto return_fib; + } + } else { + status = -EAGAIN; + } + } + return status; +} + +int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) +{ + struct hw_fib *fib; + + /* + * First free any FIBs that have not been consumed. + */ + while (!list_empty(&fibctx->fibs)) { + struct list_head * entry; + /* + * Pull the next fib from the fibs + */ + entry = fibctx->fibs.next; + list_del(entry); + fib = list_entry(entry, struct hw_fib, header.FibLinks); + fibctx->count--; + /* + * Free the space occupied by this copy of the fib. + */ + kfree(fib); + } + /* + * Remove the Context from the AdapterFibContext List + */ + list_del(&fibctx->next); + /* + * Invalidate context + */ + fibctx->type = 0; + /* + * Free the space occupied by the Context + */ + kfree(fibctx); + return 0; +} + +/** + * close_getadapter_fib - close down user fib context + * @dev: adapter + * @arg: ioctl arguments + * + * This routine will close down the fibctx passed in from the user. + */ + +static int close_getadapter_fib(struct aac_dev * dev, void *arg) +{ + struct aac_fib_context *fibctx, *aifcp; + int status; + unsigned long flags; + struct list_head * entry; + int found; + + /* + * Extract the fibctx from the input parameters + */ + fibctx = arg; + + /* + * Verify that the HANDLE passed in was a valid AdapterFibContext + * + * Search the list of AdapterFibContext addresses on the adapter + * to be sure this is a valid address + */ + + found = 0; + entry = dev->fib_list.next; + + while(entry != &dev->fib_list) { + aifcp = list_entry(entry, struct aac_fib_context, next); + if(fibctx == aifcp) { /* We found a winner */ + found = 1; + break; + } + entry = entry->next; + } + + if(found == 0) + return 0; /* Already gone */ + + if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || + (fibctx->size != sizeof(struct aac_fib_context))) + return -EINVAL; + spin_lock_irqsave(&dev->fib_lock, flags); + status = aac_close_fib_context(dev, fibctx); + spin_unlock_irqrestore(&dev->fib_lock, flags); + return status; +} + +/** + * check_revision - close down user fib context + * @dev: adapter + * @arg: ioctl arguments + * + * This routine returns the firmware version. + * Under Linux, there have been no version incompatibilities, so this is simple! + */ + +static int check_revision(struct aac_dev *dev, void *arg) +{ + struct revision response; + + response.compat = 1; + response.version = 0x03000400; + response.build = 0x5125; + + if (copy_to_user(arg, &response, sizeof(response))) + return -EFAULT; + return 0; +} + + +int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg) +{ + int status; + + /* + * HBA gets first crack + */ + + status = aac_dev_ioctl(dev, cmd, arg); + if(status != -ENOTTY) + return status; + + switch (cmd) { + case FSACTL_MINIPORT_REV_CHECK: + status = check_revision(dev, arg); + break; + case FSACTL_SENDFIB: + status = ioctl_send_fib(dev, arg); + break; + case FSACTL_OPEN_GET_ADAPTER_FIB: + status = open_getadapter_fib(dev, arg); + break; + case FSACTL_GET_NEXT_ADAPTER_FIB: + status = next_getadapter_fib(dev, arg); + break; + case FSACTL_CLOSE_GET_ADAPTER_FIB: + status = close_getadapter_fib(dev, arg); + break; + default: + status = -ENOTTY; + break; + } + return status; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/comminit.c linux-2.5/drivers/scsi/aacraid/comminit.c --- linux-2.5.1/drivers/scsi/aacraid/comminit.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/comminit.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,332 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comminit.c + * + * Abstract: This supports the initialization of the host adapter commuication interface. + * This is a platform dependent module for the pci cyclone board. + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/blk.h> +#include <asm/semaphore.h> +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +struct aac_common aac_config; + +static struct aac_dev *devices; + +static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign) +{ + unsigned char *base; + unsigned long size, align; + unsigned long fibsize = 4096; + unsigned long printfbufsiz = 256; + struct aac_init *init; + dma_addr_t phys; + + size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz; + + base = pci_alloc_consistent(dev->pdev, size, &phys); + if(base == NULL) + { + printk(KERN_ERR "aacraid: unable to create mapping.\n"); + return 0; + } + dev->comm_addr = (void *)base; + dev->comm_phys = phys; + dev->comm_size = size; + + dev->init = (struct aac_init *)(base + fibsize); + dev->init_pa = (struct aac_init *)(phys + fibsize); + + init = dev->init; + + init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION); + init->MiniPortRevision = cpu_to_le32(Sa_MINIPORT_REVISION); + init->fsrev = cpu_to_le32(dev->fsrev); + + /* + * Adapter Fibs are the first thing allocated so that they + * start page aligned + */ + init->AdapterFibsVirtualAddress = cpu_to_le32((long)base); + init->AdapterFibsPhysicalAddress = cpu_to_le32(phys); + init->AdapterFibsSize = cpu_to_le32(fibsize); + init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib)); + + /* + * Increment the base address by the amount already used + */ + base = base + fibsize + sizeof(struct aac_init); + phys = phys + fibsize + sizeof(struct aac_init); + /* + * Align the beginning of Headers to commalign + */ + align = (commalign - ((unsigned long)(base) & (commalign - 1))); + base = base + align; + phys = phys + align; + /* + * Fill in addresses of the Comm Area Headers and Queues + */ + *commaddr = (unsigned long *)base; + init->CommHeaderAddress = cpu_to_le32(phys); + /* + * Increment the base address by the size of the CommArea + */ + base = base + commsize; + phys = phys + commsize; + /* + * Place the Printf buffer area after the Fast I/O comm area. + */ + dev->printfbuf = (void *)base; + init->printfbuf = cpu_to_le32(phys); + init->printfbufsiz = cpu_to_le32(printfbufsiz); + memset(base, 0, printfbufsiz); + return 1; +} + +static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, int qsize) +{ + q->numpending = 0; + q->dev = dev; + INIT_LIST_HEAD(&q->pendingq); + init_waitqueue_head(&q->cmdready); + INIT_LIST_HEAD(&q->cmdq); + init_waitqueue_head(&q->qfull); + spin_lock_init(&q->lockdata); + q->lock = &q->lockdata; + q->headers.producer = mem; + q->headers.consumer = mem+1; + *q->headers.producer = cpu_to_le32(qsize); + *q->headers.consumer = cpu_to_le32(qsize); + q->entries = qsize; +} + +/** + * aac_send_shutdown - shutdown an adapter + * @dev: Adapter to shutdown + * + * This routine will send a VM_CloseAll (shutdown) request to the adapter. + */ + +static int aac_send_shutdown(struct aac_dev * dev) +{ + struct fib * fibctx; + struct aac_close *cmd; + int status; + + fibctx = fib_alloc(dev); + fib_init(fibctx); + + cmd = (struct aac_close *) fib_data(fibctx); + + cmd->command = cpu_to_le32(VM_CloseAll); + cmd->cid = cpu_to_le32(0xffffffff); + + status = fib_send(ContainerCommand, + fibctx, + sizeof(struct aac_close), + FsaNormal, + 1, 1, + NULL, NULL); + + if (status == 0) + fib_complete(fibctx); + fib_free(fibctx); + return status; +} + +/** + * aac_detach - detach adapter + * @detach: adapter to disconnect + * + * Disconnect and shutdown an AAC based adapter, freeing resources + * as we go. + */ + +int aac_detach(struct aac_dev *detach) +{ + struct aac_dev **dev = &devices; + + while(*dev) + { + if(*dev == detach) + { + *dev = detach->next; + aac_send_shutdown(detach); + fib_map_free(detach); + pci_free_consistent(detach->pdev, detach->comm_size, detach->comm_addr, detach->comm_phys); + kfree(detach->queues); + return 1; + } + dev=&((*dev)->next); + } + BUG(); + return 0; +} + +/** + * aac_comm_init - Initialise FSA data structures + * @dev: Adapter to intialise + * + * Initializes the data structures that are required for the FSA commuication + * interface to operate. + * Returns + * 1 - if we were able to init the commuication interface. + * 0 - If there were errors initing. This is a fatal error. + */ + +int aac_comm_init(struct aac_dev * dev) +{ + unsigned long hdrsize = (sizeof(u32) * NUMBER_OF_COMM_QUEUES) * 2; + unsigned long queuesize = sizeof(struct aac_entry) * TOTAL_QUEUE_ENTRIES; + u32 *headers; + struct aac_entry * queues; + unsigned long size; + struct aac_queue_block * comm = dev->queues; + + /* + * Now allocate and initialize the zone structures used as our + * pool of FIB context records. The size of the zone is based + * on the system memory size. We also initialize the mutex used + * to protect the zone. + */ + spin_lock_init(&dev->fib_lock); + + /* + * Allocate the physically contigous space for the commuication + * queue headers. + */ + + size = hdrsize + queuesize; + + if (!aac_alloc_comm(dev, (void * *)&headers, size, QUEUE_ALIGNMENT)) + return -ENOMEM; + + queues = (struct aac_entry *)((unsigned char *)headers + hdrsize); + + /* Adapter to Host normal priority Command queue */ + comm->queue[HostNormCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostNormCmdQueue], headers, HOST_NORM_CMD_ENTRIES); + queues += HOST_NORM_CMD_ENTRIES; + headers += 2; + + /* Adapter to Host high priority command queue */ + comm->queue[HostHighCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostHighCmdQueue], headers, HOST_HIGH_CMD_ENTRIES); + + queues += HOST_HIGH_CMD_ENTRIES; + headers +=2; + + /* Host to adapter normal priority command queue */ + comm->queue[AdapNormCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapNormCmdQueue], headers, ADAP_NORM_CMD_ENTRIES); + + queues += ADAP_NORM_CMD_ENTRIES; + headers += 2; + + /* host to adapter high priority command queue */ + comm->queue[AdapHighCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapHighCmdQueue], headers, ADAP_HIGH_CMD_ENTRIES); + + queues += ADAP_HIGH_CMD_ENTRIES; + headers += 2; + + /* adapter to host normal priority response queue */ + comm->queue[HostNormRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostNormRespQueue], headers, HOST_NORM_RESP_ENTRIES); + + queues += HOST_NORM_RESP_ENTRIES; + headers += 2; + + /* adapter to host high priority response queue */ + comm->queue[HostHighRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostHighRespQueue], headers, HOST_HIGH_RESP_ENTRIES); + + queues += HOST_HIGH_RESP_ENTRIES; + headers += 2; + + /* host to adapter normal priority response queue */ + comm->queue[AdapNormRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapNormRespQueue], headers, ADAP_NORM_RESP_ENTRIES); + + queues += ADAP_NORM_RESP_ENTRIES; + headers += 2; + + /* host to adapter high priority response queue */ + comm->queue[AdapHighRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapHighRespQueue], headers, ADAP_HIGH_RESP_ENTRIES); + + comm->queue[AdapNormCmdQueue].lock = comm->queue[HostNormRespQueue].lock; + comm->queue[AdapHighCmdQueue].lock = comm->queue[HostHighRespQueue].lock; + comm->queue[AdapNormRespQueue].lock = comm->queue[HostNormCmdQueue].lock; + comm->queue[AdapHighRespQueue].lock = comm->queue[HostHighCmdQueue].lock; + + return 0; +} + +struct aac_dev *aac_init_adapter(struct aac_dev *dev) +{ + /* + * Ok now init the communication subsystem + */ + dev->queues = (struct aac_queue_block *) kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL); + if (dev->queues == NULL) { + printk(KERN_ERR "Error could not allocate comm region.\n"); + return NULL; + } + memset(dev->queues, 0, sizeof(struct aac_queue_block)); + + if (aac_comm_init(dev)<0) + return NULL; + /* + * Initialize the list of fibs + */ + if(fib_setup(dev)<0) + return NULL; + + INIT_LIST_HEAD(&dev->fib_list); + spin_lock_init(&dev->fib_lock); + init_completion(&dev->aif_completion); + /* + * Add this adapter in to our dev List. + */ + dev->next = devices; + devices = dev; + return dev; +} + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/commsup.c linux-2.5/drivers/scsi/aacraid/commsup.c --- linux-2.5.1/drivers/scsi/aacraid/commsup.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/commsup.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,949 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> + * + * based on the old aacraid driver that is.. + + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commsup.c + * + * Abstract: Contain all routines that are required for FSA host/adapter + * commuication. + * + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/completion.h> +#include <asm/semaphore.h> +#include <linux/blk.h> +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +/** + * fib_map_alloc - allocate the fib objects + * @dev: Adapter to allocate for + * + * Allocate and map the shared PCI space for the FIB blocks used to + * talk to the Adaptec firmware. + */ + +static int fib_map_alloc(struct aac_dev *dev) +{ + if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, &dev->hw_fib_pa))==NULL) + return -ENOMEM; + return 0; +} + +/** + * fib_map_free - free the fib objects + * @dev: Adapter to free + * + * Free the PCI mappings and the memory allocated for FIB blocks + * on this adapter. + */ + +void fib_map_free(struct aac_dev *dev) +{ + pci_free_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, dev->hw_fib_va, dev->hw_fib_pa); +} + +/** + * fib_setup - setup the fibs + * @dev: Adapter to set up + * + * Allocate the PCI space for the fibs, map it and then intialise the + * fib area, the unmapped fib data and also the free list + */ + +int fib_setup(struct aac_dev * dev) +{ + struct fib *fibptr; + struct hw_fib *fib; + dma_addr_t fibpa; + int i; + + if(fib_map_alloc(dev)<0) + return -ENOMEM; + + fib = dev->hw_fib_va; + fibpa = dev->hw_fib_pa; + memset(fib, 0, sizeof(struct hw_fib) * AAC_NUM_FIB); + /* + * Initialise the fibs + */ + for (i = 0, fibptr = &dev->fibs[i]; i < AAC_NUM_FIB; i++, fibptr++) + { + fibptr->dev = dev; + fibptr->fib = fib; + fibptr->data = (void *) fibptr->fib->data; + fibptr->next = fibptr+1; /* Forward chain the fibs */ + init_MUTEX_LOCKED(&fibptr->event_wait); + spin_lock_init(&fibptr->event_lock); + fib->header.XferState = cpu_to_le32(0xffffffff); + fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib)); + fibptr->logicaladdr = (unsigned long) fibpa; + fib = (struct hw_fib *)((unsigned char *)fib + sizeof(struct hw_fib)); + fibpa = fibpa + sizeof(struct hw_fib); + } + /* + * Add the fib chain to the free list + */ + dev->fibs[AAC_NUM_FIB-1].next = NULL; + /* + * Enable this to debug out of queue space + */ + dev->free_fib = &dev->fibs[0]; + return 0; +} + +/** + * fib_alloc - allocate a fib + * @dev: Adapter to allocate the fib for + * + * Allocate a fib from the adapter fib pool. If the pool is empty we + * wait for fibs to become free. + */ + +struct fib * fib_alloc(struct aac_dev *dev) +{ + struct fib * fibptr; + unsigned long flags; + + spin_lock_irqsave(&dev->fib_lock, flags); + fibptr = dev->free_fib; + if(!fibptr) + BUG(); + dev->free_fib = fibptr->next; + spin_unlock_irqrestore(&dev->fib_lock, flags); + /* + * Set the proper node type code and node byte size + */ + fibptr->type = FSAFS_NTC_FIB_CONTEXT; + fibptr->size = sizeof(struct fib); + /* + * Null out fields that depend on being zero at the start of + * each I/O + */ + fibptr->fib->header.XferState = cpu_to_le32(0); + fibptr->callback = NULL; + fibptr->callback_data = NULL; + + return fibptr; +} + +/** + * fib_free - free a fib + * @fibptr: fib to free up + * + * Frees up a fib and places it on the appropriate queue + * (either free or timed out) + */ + +void fib_free(struct fib * fibptr) +{ + unsigned long flags; + + spin_lock_irqsave(&fibptr->dev->fib_lock, flags); + + if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) { + aac_config.fib_timeouts++; + fibptr->next = fibptr->dev->timeout_fib; + fibptr->dev->timeout_fib = fibptr; + } else { + if (fibptr->fib->header.XferState != 0) { + printk(KERN_WARNING "fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", + fibptr, fibptr->fib->header.XferState); + } + fibptr->next = fibptr->dev->free_fib; + fibptr->dev->free_fib = fibptr; + } + spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags); +} + +/** + * fib_init - initialise a fib + * @fibptr: The fib to initialize + * + * Set up the generic fib fields ready for use + */ + +void fib_init(struct fib *fibptr) +{ + struct hw_fib *fib = fibptr->fib; + + fib->header.StructType = FIB_MAGIC; + fib->header.Size = cpu_to_le16(sizeof(struct hw_fib)); + fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable); + fib->header.SenderFibAddress = cpu_to_le32(0); + fib->header.ReceiverFibAddress = cpu_to_le32(0); + fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib)); +} + +/** + * fib_deallocate - deallocate a fib + * @fibptr: fib to deallocate + * + * Will deallocate and return to the free pool the FIB pointed to by the + * caller. + */ + +void fib_dealloc(struct fib * fibptr) +{ + struct hw_fib *fib = fibptr->fib; + if(fib->header.StructType != FIB_MAGIC) + BUG(); + fib->header.XferState = cpu_to_le32(0); +} + +/* + * Commuication primitives define and support the queuing method we use to + * support host to adapter commuication. All queue accesses happen through + * these routines and are the only routines which have a knowledge of the + * how these queues are implemented. + */ + +/** + * aac_get_entry - get a queue entry + * @dev: Adapter + * @qid: Queue Number + * @entry: Entry return + * @index: Index return + * @nonotify: notification control + * + * With a priority the routine returns a queue entry if the queue has free entries. If the queue + * is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is + * returned. + */ + +static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify) +{ + struct aac_queue * q; + + /* + * All of the queues wrap when they reach the end, so we check + * to see if they have reached the end and if they have we just + * set the index back to zero. This is a wrap. You could or off + * the high bits in all updates but this is a bit faster I think. + */ + + q = &dev->queues->queue[qid]; + + *index = le32_to_cpu(*(q->headers.producer)); + if (*index - 2 == le32_to_cpu(*(q->headers.consumer))) + *nonotify = 1; + + if (qid == AdapHighCmdQueue) { + if (*index >= ADAP_HIGH_CMD_ENTRIES) + *index = 0; + } else if (qid == AdapNormCmdQueue) { + if (*index >= ADAP_NORM_CMD_ENTRIES) + *index = 0; /* Wrap to front of the Producer Queue. */ + } + else if (qid == AdapHighRespQueue) + { + if (*index >= ADAP_HIGH_RESP_ENTRIES) + *index = 0; + } + else if (qid == AdapNormRespQueue) + { + if (*index >= ADAP_NORM_RESP_ENTRIES) + *index = 0; /* Wrap to front of the Producer Queue. */ + } + else BUG(); + + if (*index + 1 == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */ + printk(KERN_WARNING "Queue %d full, %ld outstanding.\n", + qid, q->numpending); + return 0; + } else { + *entry = q->base + *index; + return 1; + } +} + +/** + * aac_queue_get - get the next free QE + * @dev: Adapter + * @index: Returned index + * @priority: Priority of fib + * @fib: Fib to associate with the queue entry + * @wait: Wait if queue full + * @fibptr: Driver fib object to go with fib + * @nonotify: Don't notify the adapter + * + * Gets the next free QE off the requested priorty adapter command + * queue and associates the Fib with the QE. The QE represented by + * index is ready to insert on the queue when this routine returns + * success. + */ + +static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * fib, int wait, struct fib * fibptr, unsigned long *nonotify) +{ + struct aac_entry * entry = NULL; + int map = 0; + struct aac_queue * q = &dev->queues->queue[qid]; + + spin_lock_irqsave(q->lock, q->SavedIrql); + + if (qid == AdapHighCmdQueue || qid == AdapNormCmdQueue) + { + /* if no entries wait for some if caller wants to */ + while (!aac_get_entry(dev, qid, &entry, index, nonotify)) + { + printk(KERN_ERR "GetEntries failed\n"); + } + /* + * Setup queue entry with a command, status and fib mapped + */ + entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size)); + map = 1; + } + else if (qid == AdapHighRespQueue || qid == AdapNormRespQueue) + { + while(!aac_get_entry(dev, qid, &entry, index, nonotify)) + { + /* if no entries wait for some if caller wants to */ + } + /* + * Setup queue entry with command, status and fib mapped + */ + entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size)); + entry->addr = cpu_to_le32(fib->header.SenderFibAddress); /* Restore adapters pointer to the FIB */ + fib->header.ReceiverFibAddress = fib->header.SenderFibAddress; /* Let the adapter now where to find its data */ + map = 0; + } + /* + * If MapFib is true than we need to map the Fib and put pointers + * in the queue entry. + */ + if (map) + entry->addr = cpu_to_le32((unsigned long)(fibptr->logicaladdr)); + return 0; +} + + +/** + * aac_insert_entry - insert a queue entry + * @dev: Adapter + * @index: Index of entry to insert + * @qid: Queue number + * @nonotify: Suppress adapter notification + * + * Gets the next free QE off the requested priorty adapter command + * queue and associates the Fib with the QE. The QE represented by + * index is ready to insert on the queue when this routine returns + * success. + */ + +static int aac_insert_entry(struct aac_dev * dev, u32 index, u32 qid, unsigned long nonotify) +{ + struct aac_queue * q = &dev->queues->queue[qid]; + + if(q == NULL) + BUG(); + *(q->headers.producer) = cpu_to_le32(index + 1); + spin_unlock_irqrestore(q->lock, q->SavedIrql); + + if (qid == AdapHighCmdQueue || + qid == AdapNormCmdQueue || + qid == AdapHighRespQueue || + qid == AdapNormRespQueue) + { + if (!nonotify) + aac_adapter_notify(dev, qid); + } + else + printk("Suprise insert!\n"); + return 0; +} + +/* + * Define the highest level of host to adapter communication routines. + * These routines will support host to adapter FS commuication. These + * routines have no knowledge of the commuication method used. This level + * sends and receives FIBs. This level has no knowledge of how these FIBs + * get passed back and forth. + */ + +/** + * fib_send - send a fib to the adapter + * @command: Command to send + * @fibptr: The fib + * @size: Size of fib data area + * @priority: Priority of Fib + * @wait: Async/sync select + * @reply: True if a reply is wanted + * @callback: Called with reply + * @callback_data: Passed to callback + * + * Sends the requested FIB to the adapter and optionally will wait for a + * response FIB. If the caller does not wish to wait for a response than + * an event to wait on must be supplied. This event will be set when a + * response FIB is received from the adapter. + */ + +int fib_send(u16 command, struct fib * fibptr, unsigned long size, int priority, int wait, int reply, fib_callback callback, void * callback_data) +{ + u32 index; + u32 qid; + struct aac_dev * dev = fibptr->dev; + unsigned long nointr = 0; + struct hw_fib * fib = fibptr->fib; + struct aac_queue * q; + unsigned long flags = 0; + + if (!(le32_to_cpu(fib->header.XferState) & HostOwned)) + return -EBUSY; + /* + * There are 5 cases with the wait and reponse requested flags. + * The only invalid cases are if the caller requests to wait and + * does not request a response and if the caller does not want a + * response and the Fibis not allocated from pool. If a response + * is not requesed the Fib will just be deallocaed by the DPC + * routine when the response comes back from the adapter. No + * further processing will be done besides deleting the Fib. We + * will have a debug mode where the adapter can notify the host + * it had a problem and the host can log that fact. + */ + if (wait && !reply) { + return -EINVAL; + } else if (!wait && reply) { + fib->header.XferState |= cpu_to_le32(Async | ResponseExpected); + FIB_COUNTER_INCREMENT(aac_config.AsyncSent); + } else if (!wait && !reply) { + fib->header.XferState |= cpu_to_le32(NoResponseExpected); + FIB_COUNTER_INCREMENT(aac_config.NoResponseSent); + } else if (wait && reply) { + fib->header.XferState |= cpu_to_le32(ResponseExpected); + FIB_COUNTER_INCREMENT(aac_config.NormalSent); + } + /* + * Map the fib into 32bits by using the fib number + */ + fib->header.SenderData = fibptr-&dev->fibs[0]; /* for callback */ + /* + * Set FIB state to indicate where it came from and if we want a + * response from the adapter. Also load the command from the + * caller. + * + * Map the hw fib pointer as a 32bit value + */ + fib->header.SenderFibAddress = fib2addr(fib); + fib->header.Command = cpu_to_le16(command); + fib->header.XferState |= cpu_to_le32(SentFromHost); + fibptr->fib->header.Flags = 0; /* Zero the flags field - its internal only... */ + /* + * Set the size of the Fib we want to send to the adapter + */ + fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size); + if (le16_to_cpu(fib->header.Size) > le16_to_cpu(fib->header.SenderSize)) { + return -EMSGSIZE; + } + /* + * Get a queue entry connect the FIB to it and send an notify + * the adapter a command is ready. + */ + if (priority == FsaHigh) { + fib->header.XferState |= cpu_to_le32(HighPriority); + qid = AdapHighCmdQueue; + } else { + fib->header.XferState |= cpu_to_le32(NormalPriority); + qid = AdapNormCmdQueue; + } + q = &dev->queues->queue[qid]; + + if(wait) + spin_lock_irqsave(&fibptr->event_lock, flags); + if(aac_queue_get( dev, &index, qid, fib, 1, fibptr, &nointr)<0) + return -EWOULDBLOCK; + dprintk((KERN_DEBUG "fib_send: inserting a queue entry at index %d.\n",index)); + dprintk((KERN_DEBUG "Fib contents:.\n")); + dprintk((KERN_DEBUG " Command = %d.\n", fib->header.Command)); + dprintk((KERN_DEBUG " XferState = %x.\n", fib->header.XferState)); + /* + * Fill in the Callback and CallbackContext if we are not + * going to wait. + */ + if (!wait) { + fibptr->callback = callback; + fibptr->callback_data = callback_data; + } + FIB_COUNTER_INCREMENT(aac_config.FibsSent); + list_add_tail(&fibptr->queue, &q->pendingq); + q->numpending++; + + fibptr->done = 0; + + if(aac_insert_entry(dev, index, qid, (nointr & aac_config.irq_mod)) < 0) + return -EWOULDBLOCK; + /* + * If the caller wanted us to wait for response wait now. + */ + + if (wait) { + spin_unlock_irqrestore(&fibptr->event_lock, flags); + down(&fibptr->event_wait); + if(fibptr->done == 0) + BUG(); + + if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) + return -ETIMEDOUT; + else + return 0; + } + /* + * If the user does not want a response than return success otherwise + * return pending + */ + if (reply) + return -EINPROGRESS; + else + return 0; +} + +/** + * aac_consumer_get - get the top of the queue + * @dev: Adapter + * @q: Queue + * @entry: Return entry + * + * Will return a pointer to the entry on the top of the queue requested that + * we are a consumer of, and return the address of the queue entry. It does + * not change the state of the queue. + */ + +int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry) +{ + u32 index; + int status; + + if (*q->headers.producer == *q->headers.consumer) { + status = 0; + } else { + /* + * The consumer index must be wrapped if we have reached + * the end of the queue, else we just use the entry + * pointed to by the header index + */ + if (le32_to_cpu(*q->headers.consumer) >= q->entries) + index = 0; + else + index = le32_to_cpu(*q->headers.consumer); + *entry = q->base + index; + status = 1; + } + return(status); +} + +int aac_consumer_avail(struct aac_dev *dev, struct aac_queue * q) +{ + return (*q->headers.producer != *q->headers.consumer); +} + + +/** + * aac_consumer_free - free consumer entry + * @dev: Adapter + * @q: Queue + * @qid: Queue ident + * + * Frees up the current top of the queue we are a consumer of. If the + * queue was full notify the producer that the queue is no longer full. + */ + +void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid) +{ + int wasfull = 0; + u32 notify; + + if (*q->headers.producer+1 == *q->headers.consumer) + wasfull = 1; + + if (le32_to_cpu(*q->headers.consumer) >= q->entries) + *q->headers.consumer = cpu_to_le32(1); + else + *q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1); + + if (wasfull) { + switch (qid) { + + case HostNormCmdQueue: + notify = HostNormCmdNotFull; + break; + case HostHighCmdQueue: + notify = HostHighCmdNotFull; + break; + case HostNormRespQueue: + notify = HostNormRespNotFull; + break; + case HostHighRespQueue: + notify = HostHighRespNotFull; + break; + default: + BUG(); + return; + } + aac_adapter_notify(dev, notify); + } +} + +/** + * fib_adapter_complete - complete adapter issued fib + * @fibptr: fib to complete + * @size: size of fib + * + * Will do all necessary work to complete a FIB that was sent from + * the adapter. + */ + +int fib_adapter_complete(struct fib * fibptr, unsigned short size) +{ + struct hw_fib * fib = fibptr->fib; + struct aac_dev * dev = fibptr->dev; + unsigned long nointr = 0; + + if (le32_to_cpu(fib->header.XferState) == 0) + return 0; + /* + * If we plan to do anything check the structure type first. + */ + if ( fib->header.StructType != FIB_MAGIC ) { + return -EINVAL; + } + /* + * This block handles the case where the adapter had sent us a + * command and we have finished processing the command. We + * call completeFib when we are done processing the command + * and want to send a response back to the adapter. This will + * send the completed cdb to the adapter. + */ + if (fib->header.XferState & cpu_to_le32(SentFromAdapter)) { + fib->header.XferState |= cpu_to_le32(HostProcessed); + if (fib->header.XferState & cpu_to_le32(HighPriority)) { + u32 index; + if (size) + { + size += sizeof(struct aac_fibhdr); + if (size > le16_to_cpu(fib->header.SenderSize)) + return -EMSGSIZE; + fib->header.Size = cpu_to_le16(size); + } + if(aac_queue_get(dev, &index, AdapHighRespQueue, fib, 1, NULL, &nointr) < 0) { + return -EWOULDBLOCK; + } + if (aac_insert_entry(dev, index, AdapHighRespQueue, (nointr & (int)aac_config.irq_mod)) != 0) { + } + } + else if (fib->header.XferState & NormalPriority) + { + u32 index; + + if (size) { + size += sizeof(struct aac_fibhdr); + if (size > le16_to_cpu(fib->header.SenderSize)) + return -EMSGSIZE; + fib->header.Size = cpu_to_le16(size); + } + if (aac_queue_get(dev, &index, AdapNormRespQueue, fib, 1, NULL, &nointr) < 0) + return -EWOULDBLOCK; + if (aac_insert_entry(dev, index, AdapNormRespQueue, + (nointr & (int)aac_config.irq_mod)) != 0) + { + } + } + } + else + { + printk(KERN_WARNING "fib_complete: Unknown xferstate detected.\n"); + BUG(); + } + return 0; +} + +/** + * fib_complete - fib completion handler + * @fib: FIB to complete + * + * Will do all necessary work to complete a FIB. + */ + +int fib_complete(struct fib * fibptr) +{ + struct hw_fib * fib = fibptr->fib; + + /* + * Check for a fib which has already been completed + */ + + if (fib->header.XferState == cpu_to_le32(0)) + return 0; + /* + * If we plan to do anything check the structure type first. + */ + + if (fib->header.StructType != FIB_MAGIC) + return -EINVAL; + /* + * This block completes a cdb which orginated on the host and we + * just need to deallocate the cdb or reinit it. At this point the + * command is complete that we had sent to the adapter and this + * cdb could be reused. + */ + if((fib->header.XferState & cpu_to_le32(SentFromHost)) && + (fib->header.XferState & cpu_to_le32(AdapterProcessed))) + { + fib_dealloc(fibptr); + } + else if(fib->header.XferState & cpu_to_le32(SentFromHost)) + { + /* + * This handles the case when the host has aborted the I/O + * to the adapter because the adapter is not responding + */ + fib_dealloc(fibptr); + } else if(fib->header.XferState & cpu_to_le32(HostOwned)) { + fib_dealloc(fibptr); + } else { + BUG(); + } + return 0; +} + +/** + * aac_printf - handle printf from firmware + * @dev: Adapter + * @val: Message info + * + * Print a message passed to us by the controller firmware on the + * Adaptec board + */ + +void aac_printf(struct aac_dev *dev, u32 val) +{ + int length = val & 0xffff; + int level = (val >> 16) & 0xffff; + char *cp = dev->printfbuf; + + /* + * The size of the printfbuf is set in port.c + * There is no variable or define for it + */ + if (length > 255) + length = 255; + if (cp[length] != 0) + cp[length] = 0; + if (level == LOG_HIGH_ERROR) + printk(KERN_WARNING "aacraid:%s", cp); + else + printk(KERN_INFO "aacraid:%s", cp); + memset(cp, 0, 256); +} + + +/** + * aac_handle_aif - Handle a message from the firmware + * @dev: Which adapter this fib is from + * @fibptr: Pointer to fibptr from adapter + * + * This routine handles a driver notify fib from the adapter and + * dispatches it to the appropriate routine for handling. + */ + +static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) +{ + struct hw_fib * fib = fibptr->fib; + /* + * Set the status of this FIB to be Invalid parameter. + * + * *(u32 *)fib->data = ST_INVAL; + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib_adapter_complete(fibptr, sizeof(u32)); +} + +/** + * aac_command_thread - command processing thread + * @dev: Adapter to monitor + * + * Waits on the commandready event in it's queue. When the event gets set + * it will pull FIBs off it's queue. It will continue to pull FIBs off + * until the queue is empty. When the queue is empty it will wait for + * more FIBs. + */ + +int aac_command_thread(struct aac_dev * dev) +{ + struct hw_fib *fib, *newfib; + struct fib fibptr; /* for error logging */ + struct aac_queue_block *queues = dev->queues; + struct aac_fib_context *fibctx; + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + + /* + * We can only have one thread per adapter for AIF's. + */ + if (dev->aif_thread) + return -EINVAL; + /* + * Set up the name that will appear in 'ps' + * stored in task_struct.comm[16]. + */ + sprintf(current->comm, "aacraid"); + daemonize(); + /* + * Let the DPC know it has a place to send the AIF's to. + */ + dev->aif_thread = 1; + memset(&fibptr, 0, sizeof(struct fib)); + add_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait); + set_current_state(TASK_INTERRUPTIBLE); + while(1) + { + spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags); + while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) { + struct list_head *entry; + struct aac_aifcmd * aifcmd; + + set_current_state(TASK_RUNNING); + + entry = queues->queue[HostNormCmdQueue].cmdq.next; + list_del(entry); + + spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags); + fib = list_entry(entry, struct hw_fib, header.FibLinks); + /* + * We will process the FIB here or pass it to a + * worker thread that is TBD. We Really can't + * do anything at this point since we don't have + * anything defined for this thread to do. + */ + memset(&fibptr, 0, sizeof(struct fib)); + fibptr.type = FSAFS_NTC_FIB_CONTEXT; + fibptr.size = sizeof( struct fib ); + fibptr.fib = fib; + fibptr.data = fib->data; + fibptr.dev = dev; + /* + * We only handle AifRequest fibs from the adapter. + */ + aifcmd = (struct aac_aifcmd *) fib->data; + if (aifcmd->command == le16_to_cpu(AifCmdDriverNotify)) { + aac_handle_aif(dev, &fibptr); + } else { + /* The u32 here is important and intended. We are using + 32bit wrapping time to fit the adapter field */ + + u32 time_now, time_last; + unsigned long flagv; + + time_now = jiffies/HZ; + + spin_lock_irqsave(&dev->fib_lock, flagv); + entry = dev->fib_list.next; + /* + * For each Context that is on the + * fibctxList, make a copy of the + * fib, and then set the event to wake up the + * thread that is waiting for it. + */ + while (entry != &dev->fib_list) { + /* + * Extract the fibctx + */ + fibctx = list_entry(entry, struct aac_fib_context, next); + /* + * Check if the queue is getting + * backlogged + */ + if (fibctx->count > 20) + { + time_last = fibctx->jiffies; + /* + * Has it been > 2 minutes + * since the last read off + * the queue? + */ + if ((time_now - time_last) > 120) { + entry = entry->next; + aac_close_fib_context(dev, fibctx); + continue; + } + } + /* + * Warning: no sleep allowed while + * holding spinlock + */ + newfib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC); + if (newfib) { + /* + * Make the copy of the FIB + */ + memcpy(newfib, fib, sizeof(struct hw_fib)); + /* + * Put the FIB onto the + * fibctx's fibs + */ + list_add_tail(&newfib->header.FibLinks, &fibctx->fibs); + fibctx->count++; + /* + * Set the event to wake up the + * thread that will waiting. + */ + up(&fibctx->wait_sem); + } else { + printk(KERN_WARNING "aifd: didn't allocate NewFib.\n"); + } + entry = entry->next; + } + /* + * Set the status of this FIB + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib_adapter_complete(&fibptr, sizeof(u32)); + spin_unlock_irqrestore(&dev->fib_lock, flagv); + } + spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags); + } + /* + * There are no more AIF's + */ + spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags); + schedule(); + + if(signal_pending(current)) + break; + set_current_state(TASK_INTERRUPTIBLE); + } + remove_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait); + dev->aif_thread = 0; + complete_and_exit(&dev->aif_completion, 0); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/dpcsup.c linux-2.5/drivers/scsi/aacraid/dpcsup.c --- linux-2.5.1/drivers/scsi/aacraid/dpcsup.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/dpcsup.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,201 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * dpcsup.c + * + * Abstract: All DPC processing routines for the cyclone board occur here. + * + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/completion.h> +#include <linux/blk.h> +#include <asm/semaphore.h> +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +/** + * aac_response_normal - Handle command replies + * @q: Queue to read from + * + * This DPC routine will be run when the adapter interrupts us to let us + * know there is a response on our normal priority queue. We will pull off + * all QE there are and wake up all the waiters before exiting. We will + * take a spinlock out on the queue before operating on it. + */ + +unsigned int aac_response_normal(struct aac_queue * q) +{ + struct aac_dev * dev = q->dev; + struct aac_entry *entry; + struct hw_fib * fib; + struct fib * fibctx; + int consumed = 0; + unsigned long flags; + + spin_lock_irqsave(q->lock, flags); + + /* + * Keep pulling response QEs off the response queue and waking + * up the waiters until there are no more QEs. We then return + * back to the system. If no response was requesed we just + * deallocate the Fib here and continue. + */ + while(aac_consumer_get(dev, q, &entry)) + { + int fast; + + fast = (int) (entry->addr & 0x01); + fib = addr2fib(entry->addr & ~0x01); + aac_consumer_free(dev, q, HostNormRespQueue); + fibctx = &dev->fibs[fib->header.SenderData]; + /* + * Remove this fibctx from the Outstanding I/O queue. + * But only if it has not already been timed out. + * + * If the fib has been timed out already, then just + * continue. The caller has already been notified that + * the fib timed out. + */ + if (!(fibctx->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) { + list_del(&fibctx->queue); + dev->queues->queue[AdapNormCmdQueue].numpending--; + } else { + printk(KERN_WARNING "aacraid: FIB timeout.\n"); + continue; + } + spin_unlock_irqrestore(q->lock, flags); + + if (fast) { + /* + * Doctor the fib + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib->header.XferState |= cpu_to_le32(AdapterProcessed); + } + + FIB_COUNTER_INCREMENT(aac_config.FibRecved); + + if (fib->header.Command == cpu_to_le16(NuFileSystem)) + { + u32 *pstatus = (u32 *)fib->data; + if (*pstatus & cpu_to_le32(0xffff0000)) + *pstatus = cpu_to_le32(ST_OK); + } + if (fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) + { + if (fib->header.XferState & cpu_to_le32(NoResponseExpected)) + FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved); + else + FIB_COUNTER_INCREMENT(aac_config.AsyncRecved); + /* + * NOTE: we cannot touch the fibctx after this + * call, because it may have been deallocated. + */ + fibctx->callback(fibctx->callback_data, fibctx); + } else { + unsigned long flagv; + spin_lock_irqsave(&fibctx->event_lock, flagv); + fibctx->done = 1; + up(&fibctx->event_wait); + spin_unlock_irqrestore(&fibctx->event_lock, flagv); + FIB_COUNTER_INCREMENT(aac_config.NormalRecved); + } + consumed++; + spin_lock_irqsave(q->lock, flags); + } + + if (consumed > aac_config.peak_fibs) + aac_config.peak_fibs = consumed; + if (consumed == 0) + aac_config.zero_fibs++; + + spin_unlock_irqrestore(q->lock, flags); + return 0; +} + + +/** + * aac_command_normal - handle commands + * @q: queue to process + * + * This DPC routine will be queued when the adapter interrupts us to + * let us know there is a command on our normal priority queue. We will + * pull off all QE there are and wake up all the waiters before exiting. + * We will take a spinlock out on the queue before operating on it. + */ + +unsigned int aac_command_normal(struct aac_queue *q) +{ + struct aac_dev * dev = q->dev; + struct aac_entry *entry; + unsigned long flags; + + spin_lock_irqsave(q->lock, flags); + + /* + * Keep pulling response QEs off the response queue and waking + * up the waiters until there are no more QEs. We then return + * back to the system. + */ + while(aac_consumer_get(dev, q, &entry)) + { + struct hw_fib * fib; + fib = addr2fib(entry->addr); + + if (dev->aif_thread) { + list_add_tail(&fib->header.FibLinks, &q->cmdq); + aac_consumer_free(dev, q, HostNormCmdQueue); + wake_up_interruptible(&q->cmdready); + } else { + struct fib fibctx; + aac_consumer_free(dev, q, HostNormCmdQueue); + spin_unlock_irqrestore(q->lock, flags); + memset(&fibctx, 0, sizeof(struct fib)); + fibctx.type = FSAFS_NTC_FIB_CONTEXT; + fibctx.size = sizeof(struct fib); + fibctx.fib = fib; + fibctx.data = fib->data; + fibctx.dev = dev; + /* + * Set the status of this FIB + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib_adapter_complete(&fibctx, sizeof(u32)); + spin_lock_irqsave(q->lock, flags); + } + } + spin_unlock_irqrestore(q->lock, flags); + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/linit.c linux-2.5/drivers/scsi/aacraid/linit.c --- linux-2.5.1/drivers/scsi/aacraid/linit.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/linit.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,691 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * linit.c + * + * Abstract: Linux Driver entry module for Adaptec RAID Array Controller + * + * Provides the following driver entry points: + * aac_detect() + * aac_release() + * aac_queuecommand() + * aac_resetcommand() + * aac_biosparm() + * + */ + +#define AAC_DRIVER_VERSION "0.9.9ac4-rel" +#define AAC_DRIVER_BUILD_DATE __DATE__ + +#include <linux/module.h> +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/completion.h> +#include <asm/semaphore.h> +#include <linux/blk.h> +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" +#include "sd.h" + +#define AAC_DRIVERNAME "aacraid" + +MODULE_AUTHOR("Red Hat Inc and Adaptec OEM RAID Solutions"); +MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, and HP NetRAID-4M devices. http://domsch.com/linux/"); +MODULE_LICENSE("GPL"); + +struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS]; + +static unsigned aac_count = 0; +static int aac_cfg_major = -1; +static int single_command_done = 0; + +/* + * Because of the way Linux names scsi devices, the order in this table has + * become important. Check for on-board Raid first, add-in cards second. + */ + +/* FIXME static */struct aac_driver_ident aac_drivers[] = { + { 0x1028, 0x0001, 0x1028, 0x0001, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 2/Si */ + { 0x1028, 0x0002, 0x1028, 0x0002, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x0003, 0x1028, 0x0003, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Si */ + { 0x1028, 0x0004, 0x1028, 0x00d0, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Si */ + { 0x1028, 0x0002, 0x1028, 0x00d1, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x0002, 0x1028, 0x00d9, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x000a, 0x1028, 0x0106, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x000a, 0x1028, 0x011b, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x000a, 0x1028, 0x0121, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL ", "PERCRAID " }, /* Dell PERC2 "Quad Channel" */ + { 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S " }, /* Adaptec 5400S */ + { 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid", "HP ", "NetRAID-4M " } /* HP NetRAID-4M */ +}; + +#define NUM_AACTYPES (sizeof(aac_drivers) / sizeof(struct aac_driver_ident)) +static int num_aacdrivers = NUM_AACTYPES; + +static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); +static int aac_cfg_open(struct inode * inode, struct file * file); +static int aac_cfg_release(struct inode * inode,struct file * file); + +static struct file_operations aac_cfg_fops = { + owner: THIS_MODULE, + ioctl: aac_cfg_ioctl, + open: aac_cfg_open, + release: aac_cfg_release +}; + +static int aac_detect(Scsi_Host_Template *); +static int aac_release(struct Scsi_Host *); +static int aac_queuecommand(Scsi_Cmnd *, void (*CompletionRoutine)(Scsi_Cmnd *)); +static int aac_command(Scsi_Cmnd *); +static int aac_abortcommand(Scsi_Cmnd *scsi_cmnd_ptr); +static int aac_resetcommand(Scsi_Cmnd *, unsigned int); +static int aac_biosparm(Scsi_Disk *, kdev_t, int *); +static int aac_procinfo(char *, char **, off_t, int, int, int); +static int aac_ioctl(Scsi_Device *, int, void *); + +static void aac_queuedepth(struct Scsi_Host *, Scsi_Device *); + +/** + * aac_detect - Probe for aacraid cards + * @template: SCSI driver template + * + * Probe for AAC Host Adapters initialize, register, and report the + * configuration of each AAC Host Adapter found. + * Returns the number of adapters successfully initialized and + * registered. + * Initializes all data necessary for this particular SCSI driver. + * Notes: + * The detect routine must not call any of the mid level functions + * to queue commands because things are not guaranteed to be set + * up yet. The detect routine can send commands to the host adapter + * as long as the program control will not be passed to scsi.c in + * the processing of the command. Note especially that + * scsi_malloc/scsi_free must not be called. + * + */ + +static int aac_detect(Scsi_Host_Template *template) +{ + int index; + int container; + u16 vendor_id, device_id; + struct Scsi_Host *host_ptr; + struct pci_dev *dev = NULL; + struct aac_dev *aac; + struct fsa_scsi_hba *fsa_dev_ptr; + char *name = NULL; + + printk(KERN_INFO "Red Hat/Adaptec aacraid driver, %s\n", AAC_DRIVER_BUILD_DATE); + + /* setting up the proc directory structure */ + template->proc_name = "aacraid"; + + for( index = 0; index != num_aacdrivers; index++ ) + { + device_id = aac_drivers[index].device; + vendor_id = aac_drivers[index].vendor; + name = aac_drivers[index].name; + dprintk((KERN_DEBUG "Checking %s %x/%x/%x/%x.\n", + name, vendor_id, device_id, + aac_drivers[index].subsystem_vendor, + aac_drivers[index].subsystem_device)); + + dev = NULL; + while((dev = pci_find_device(vendor_id, device_id, dev))) + { + if (pci_enable_device(dev)) + continue; + pci_set_master(dev); + pci_set_dma_mask(dev, 0xFFFFFFFFULL); + + if((dev->subsystem_vendor != aac_drivers[index].subsystem_vendor) || + (dev->subsystem_device != aac_drivers[index].subsystem_device)) + continue; + + dprintk((KERN_DEBUG "%s device detected.\n", name)); + dprintk((KERN_DEBUG "%x/%x/%x/%x.\n", vendor_id, device_id, + aac_drivers[index].subsystem_vendor, aac_drivers[index].subsystem_device)); + /* Increment the host adapter count */ + aac_count++; + /* + * scsi_register() allocates memory for a Scsi_Hosts structure and + * links it into the linked list of host adapters. This linked list + * contains the data for all possible <supported> scsi hosts. + * This is similar to the Scsi_Host_Template, except that we have + * one entry for each actual physical host adapter on the system, + * stored as a linked list. If there are two AAC boards, then we + * will need to make two Scsi_Host entries, but there will be only + * one Scsi_Host_Template entry. The second argument to scsi_register() + * specifies the size of the extra memory we want to hold any device + * specific information. + */ + host_ptr = scsi_register( template, sizeof(struct aac_dev) ); + /* + * These three parameters can be used to allow for wide SCSI + * and for host adapters that support multiple buses. + */ + host_ptr->max_id = 17; + host_ptr->max_lun = 8; + host_ptr->max_channel = 1; + host_ptr->irq = dev->irq; /* Adapter IRQ number */ + /* host_ptr->base = ( char * )(dev->resource[0].start & ~0xff); */ + host_ptr->base = dev->resource[0].start; + scsi_set_pci_device(host_ptr, dev); + dprintk((KERN_DEBUG "Device base address = 0x%lx [0x%lx].\n", host_ptr->base, dev->resource[0].start)); + dprintk((KERN_DEBUG "Device irq = 0x%x.\n", dev->irq)); + /* + * The unique_id field is a unique identifier that must + * be assigned so that we have some way of identifying + * each host adapter properly and uniquely. For hosts + * that do not support more than one card in the + * system, this does not need to be set. It is + * initialized to zero in scsi_register(). This is the + * value returned as aac->id. + */ + host_ptr->unique_id = aac_count - 1; + /* + * This function is called after the device list has + * been built to find the tagged queueing depth + * supported for each device. + */ + host_ptr->select_queue_depths = aac_queuedepth; + aac = (struct aac_dev *)host_ptr->hostdata; + /* attach a pointer back to Scsi_Host */ + aac->scsi_host_ptr = host_ptr; + aac->pdev = dev; + aac->cardtype = index; + aac->name = aac->scsi_host_ptr->hostt->name; + aac->id = aac->scsi_host_ptr->unique_id; + /* Initialize the ordinal number of the device to -1 */ + fsa_dev_ptr = &(aac->fsa_dev); + for( container = 0; container < MAXIMUM_NUM_CONTAINERS; container++ ) + fsa_dev_ptr->devno[container] = -1; + + dprintk((KERN_DEBUG "Initializing Hardware...\n")); + if((*aac_drivers[index].init)(aac , host_ptr->unique_id) != 0) + { + /* device initialization failed */ + printk(KERN_WARNING "aacraid: device initialization failed.\n"); + scsi_unregister(host_ptr); + aac_count--; + } + else + { + dprintk((KERN_DEBUG "%s:%d device initialization successful.\n", name, host_ptr->unique_id)); + aac_get_containers(aac); + aac_devices[aac_count-1] = aac; + } + } + } + + if( aac_count ){ + if((aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops))<0) + printk(KERN_WARNING "aacraid: unable to register \"aac\" device.\n"); + } + + template->present = aac_count; /* # of cards of this type found */ + return aac_count; +} + +/** + * aac_release - release SCSI host resources + * @host_ptr: SCSI host to clean up + * + * Release all resources previously acquired to support a specific Host + * Adapter and unregister the AAC Host Adapter. + * + * BUGS: Does not wait for the thread it kills to die. + */ + +static int aac_release(struct Scsi_Host *host_ptr) +{ + struct aac_dev *dev; + dprintk((KERN_DEBUG "aac_release.\n")); + dev = (struct aac_dev *)host_ptr->hostdata; + /* + * kill any threads we started + */ + kill_proc(dev->thread_pid, SIGKILL, 0); + wait_for_completion(&dev->aif_completion); + /* + * Call the comm layer to detach from this adapter + */ + aac_detach(dev); + /* Check free orderings... */ + /* remove interrupt binding */ + free_irq(host_ptr->irq, dev); + iounmap((void * )dev->regs.sa); + /* unregister adapter */ + scsi_unregister(host_ptr); + /* + * FIXME: This assumes no hot plugging is going on... + */ + if( aac_cfg_major >= 0 ) + { + unregister_chrdev(aac_cfg_major, "aac"); + aac_cfg_major = -1; + } + return 0; +} + +/** + * aac_queuecommand - queue a SCSI command + * @scsi_cmnd_ptr: SCSI command to queue + * @CompletionRoutine: Function to call on command completion + * + * Queues a command for execution by the associated Host Adapter. + */ + +static int aac_queuecommand(Scsi_Cmnd *scsi_cmnd_ptr, void (*CompletionRoutine)(Scsi_Cmnd *)) +{ + int ret; + + scsi_cmnd_ptr->scsi_done = CompletionRoutine; + /* + * aac_scsi_cmd() handles command processing, setting the + * result code and calling completion routine. + */ + if((ret = aac_scsi_cmd(scsi_cmnd_ptr)) != 0) + dprintk((KERN_DEBUG "aac_scsi_cmd failed.\n")); + return ret; +} + + +/** + * aac_done - Callback function for a non-queued command. + * @scsi_cmnd_ptr: SCSI command block to wait for + * + * Sets single_command done to 1. This lets aac_command complete. + * This function is obsolete. + * + * Bugs: Doesn't actually work properly with multiple controllers + */ + +static void aac_done(Scsi_Cmnd * scsi_cmnd_ptr) +{ + single_command_done = 1; +} + +/** + * aac_command - synchronous SCSI command execution + * @scsi_cmnd_ptr: SCSI command to issue + * + * Accepts a single command for execution by the associated Host Adapter. + * Waits until it completes an then returns an int where: + * Byte 0 = SCSI status code + * Byte 1 = SCSI 1 byte message + * Byte 2 = host error return + * Byte 3 = mid level error return + */ + +static int aac_command(Scsi_Cmnd *scsi_cmnd_ptr ) +{ + scsi_cmnd_ptr->scsi_done = aac_done; + dprintk((KERN_DEBUG "aac_command.\n")); + + /* + * aac_scsi_cmd() handles command processing, setting the + * result code and calling completion routine. + */ + single_command_done = 0; + aac_scsi_cmd(scsi_cmnd_ptr); + while(!single_command_done) + rmb(); + return scsi_cmnd_ptr->result; +} + +/** + * aac_abortcommand - Abort command if possible. + * @scsi_cmnd_ptr: SCSI command block to abort + * + * Called when the midlayer wishes to abort a command. We don't support + * this facility, and our firmware looks after life for us. We just + * report the command as busy. + */ + +static int aac_abortcommand(Scsi_Cmnd *scsi_cmnd_ptr ) +{ + return SCSI_ABORT_BUSY; +} + +/** + * aac_resetcommand - Reset command handling + * @scsi_cmnd_ptr: SCSI command block causing the reset + * @reset_flags: Reset hints from the midlayer code + * + * Issue a reset of a SCSI command. We are ourselves not truely a SCSI + * controller and our firmware will do the work for us anyway. Thus this + * is a no-op. We just return SCSI_RESET_PUNT + */ + +static int aac_resetcommand(struct scsi_cmnd *scsi_cmnd_ptr, unsigned int reset_flags ) +{ + return SCSI_RESET_PUNT; +} + +/** + * aac_driverinfo - Returns the host adapter name + * @host_ptr: Scsi host to report on + * + * Returns a static string describing the device in question + */ + +const char *aac_driverinfo(struct Scsi_Host *host_ptr) +{ + struct aac_dev *dev = (struct aac_dev *)host_ptr->hostdata; + return aac_drivers[dev->cardtype].name; +} + +/** + * aac_biosparm - return BIOS parameters for disk + * @disk: SCSI disk object to process + * @device: kdev_t of the disk in question + * @geom: geometry block to fill in + * + * Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk. + * The default disk geometry is 64 heads, 32 sectors, and the appropriate + * number of cylinders so as not to exceed drive capacity. In order for + * disks equal to or larger than 1 GB to be addressable by the BIOS + * without exceeding the BIOS limitation of 1024 cylinders, Extended + * Translation should be enabled. With Extended Translation enabled, + * drives between 1 GB inclusive and 2 GB exclusive are given a disk + * geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive + * are given a disk geometry of 255 heads and 63 sectors. However, if + * the BIOS detects that the Extended Translation setting does not match + * the geometry in the partition table, then the translation inferred + * from the partition table will be used by the BIOS, and a warning may + * be displayed. + */ + +static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom) +{ + struct diskparm *param = (struct diskparm *)geom; + struct buffer_head * buf; + + dprintk((KERN_DEBUG "aac_biosparm.\n")); + + /* + * Assuming extended translation is enabled - #REVISIT# + */ + if( disk->capacity >= 2 * 1024 * 1024 ) /* 1 GB in 512 byte sectors */ + { + if( disk->capacity >= 4 * 1024 * 1024 ) /* 2 GB in 512 byte sectors */ + { + param->heads = 255; + param->sectors = 63; + } + else + { + param->heads = 128; + param->sectors = 32; + } + } + else + { + param->heads = 64; + param->sectors = 32; + } + + param->cylinders = disk->capacity/(param->heads * param->sectors); + + /* + * Read the first 1024 bytes from the disk device + */ + + buf = bread(mk_kdev(major(dev), minor(dev)&~0xf), 0, block_size(dev)); + if(buf == NULL) + return 0; + /* + * If the boot sector partition table is valid, search for a partition + * table entry whose end_head matches one of the standard geometry + * translations ( 64/32, 128/32, 255/63 ). + */ + + if(*(unsigned short *)(buf->b_data + 0x1fe) == cpu_to_le16(0xaa55)) + { + struct partition *first = (struct partition * )(buf->b_data + 0x1be); + struct partition *entry = first; + int saved_cylinders = param->cylinders; + int num; + unsigned char end_head, end_sec; + + for(num = 0; num < 4; num++) + { + end_head = entry->end_head; + end_sec = entry->end_sector & 0x3f; + + if(end_head == 63) + { + param->heads = 64; + param->sectors = 32; + break; + } + else if(end_head == 127) + { + param->heads = 128; + param->sectors = 32; + break; + } + else if(end_head == 254) + { + param->heads = 255; + param->sectors = 63; + break; + } + entry++; + } + + if(num == 4) + { + end_head = first->end_head; + end_sec = first->end_sector & 0x3f; + } + + param->cylinders = disk->capacity / (param->heads * param->sectors); + + if(num < 4 && end_sec == param->sectors) + { + if(param->cylinders != saved_cylinders) + dprintk((KERN_DEBUG "Adopting geometry: heads=%d, sectors=%d from partition table %d.\n", + param->heads, param->sectors, num)); + } + else if(end_head > 0 || end_sec > 0) + { + dprintk((KERN_DEBUG "Strange geometry: heads=%d, sectors=%d in partition table %d.\n", + end_head + 1, end_sec, num)); + dprintk((KERN_DEBUG "Using geometry: heads=%d, sectors=%d.\n", + param->heads, param->sectors)); + } + } + brelse(buf); + return 0; +} + +/** + * aac_queuedepth - compute queue depths + * @host: SCSI host in question + * @dev: SCSI device we are considering + * + * Selects queue depths for each target device based on the host adapter's + * total capacity and the queue depth supported by the target device. + * A queue depth of one automatically disables tagged queueing. + */ + +static void aac_queuedepth(struct Scsi_Host * host, Scsi_Device * dev ) +{ + Scsi_Device * dptr; + + dprintk((KERN_DEBUG "aac_queuedepth.\n")); + dprintk((KERN_DEBUG "Device # Q Depth Online\n")); + dprintk((KERN_DEBUG "---------------------------\n")); + for(dptr = dev; dptr != NULL; dptr = dptr->next) + { + if(dptr->host == host) + { + dptr->queue_depth = 10; + dprintk((KERN_DEBUG " %2d %d %d\n", + dptr->id, dptr->queue_depth, dptr->online)); + } + } +} + +/*------------------------------------------------------------------------------ + aac_ioctl() + + Handle SCSI ioctls + *----------------------------------------------------------------------------*/ +static int aac_ioctl(Scsi_Device * scsi_dev_ptr, int cmd, void * arg) +/*----------------------------------------------------------------------------*/ +{ + struct aac_dev *dev; + dprintk((KERN_DEBUG "aac_ioctl.\n")); + dev = (struct aac_dev *)scsi_dev_ptr->host->hostdata; + return aac_do_ioctl(dev, cmd, arg); +} + +/** + * aac_cfg_open - open a configuration file + * @inode: inode being opened + * @file: file handle attached + * + * Called when the configuration device is opened. Does the needed + * set up on the handle and then returns + * + * Bugs: This needs extending to check a given adapter is present + * so we can support hot plugging, and to ref count adapters. + */ + +static int aac_cfg_open(struct inode * inode, struct file * file ) +{ + unsigned minor_number = minor(inode->i_rdev); + if(minor_number >= aac_count) + return -ENODEV; + return 0; +} + +/** + * aac_cfg_release - close down an AAC config device + * @inode: inode of configuration file + * @file: file handle of configuration file + * + * Called when the last close of the configuration file handle + * is performed. + */ + +static int aac_cfg_release(struct inode * inode, struct file * file ) +{ + return 0; +} + +/** + * aac_cfg_ioctl - AAC configuration request + * @inode: inode of device + * @file: file handle + * @cmd: ioctl command code + * @arg: argument + * + * Handles a configuration ioctl. Currently this involves wrapping it + * up and feeding it into the nasty windowsalike glue layer. + * + * Bugs: Needs locking against parallel ioctls lower down + * Bugs: Needs to handle hot plugging + */ + +static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg ) +{ + struct aac_dev *dev = aac_devices[minor(inode->i_rdev)]; + return aac_do_ioctl(dev, cmd, (void *)arg); +} + +/* + * To use the low level SCSI driver support using the linux kernel loadable + * module interface we should initialize the global variable driver_interface + * (datatype Scsi_Host_Template) and then include the file scsi_module.c. + */ + +static Scsi_Host_Template driver_template = { + module: THIS_MODULE, + name: "AAC", + proc_info: aac_procinfo, + detect: aac_detect, + release: aac_release, + info: aac_driverinfo, + ioctl: aac_ioctl, + command: aac_command, + queuecommand: aac_queuecommand, + abort: aac_abortcommand, + reset: aac_resetcommand, + bios_param: aac_biosparm, + can_queue: AAC_NUM_IO_FIB, + this_id: 16, + sg_tablesize: 16, + max_sectors: 128, + cmd_per_lun: 1, + eh_abort_handler: aac_abortcommand, + use_clustering: ENABLE_CLUSTERING, +}; + +#include "scsi_module.c" + +/** + * aac_procinfo - Implement /proc/scsi/<drivername>/<n> + * @proc_buffer: memory buffer for I/O + * @start_ptr: pointer to first valid data + * @offset: offset into file + * @bytes_available: space left + * @host_no: scsi host ident + * @write: direction of I/O + * + * Used to export driver statistics and other infos to the world outside + * the kernel using the proc file system. Also provides an interface to + * feed the driver with information. + * + * For reads + * - if offset > 0 return 0 + * - if offset == 0 write data to proc_buffer and set the start_ptr to + * beginning of proc_buffer, return the number of characters written. + * For writes + * - writes currently not supported, return 0 + * + * Bugs: Only offset zero is handled + */ + +static int aac_procinfo(char *proc_buffer, char **start_ptr,off_t offset, + int bytes_available, int host_no, int write) +{ + if(write || offset > 0) + return 0; + *start_ptr = proc_buffer; + return sprintf(proc_buffer, "%s %d\n", "Raid Controller, scsi hba number", host_no); +} + +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/rx.c linux-2.5/drivers/scsi/aacraid/rx.c --- linux-2.5.1/drivers/scsi/aacraid/rx.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/rx.c Thu Dec 13 16:32:36 2001 @@ -0,0 +1,413 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * rx.c + * + * Abstract: Hardware miniport for Drawbridge specific hardware functions. + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/blk.h> +#include <linux/delay.h> +#include <linux/completion.h> +#include <asm/semaphore.h> +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +static void aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct aac_dev *dev = dev_id; + unsigned long bellbits; + u8 intstat, mask; + + intstat = rx_readb(dev, MUnit.OISR); + /* + * Read mask and invert because drawbridge is reversed. + * This allows us to only service interrupts that have + * been enabled. + */ + mask = ~(rx_readb(dev, MUnit.OIMR)); + /* Check to see if this is our interrupt. If it isn't just return */ + if (intstat & mask) + { + bellbits = rx_readl(dev, OutboundDoorbellReg); + if (bellbits & DoorBellPrintfReady) + { + aac_printf(dev, le32_to_cpu(rx_readl (dev, IndexRegs.Mailbox[5]))); + rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); + rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); + } + else if (bellbits & DoorBellAdapterNormCmdReady) + { + aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); + } + else if (bellbits & DoorBellAdapterNormRespReady) + { + aac_response_normal(&dev->queues->queue[HostNormRespQueue]); + rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); + } + else if (bellbits & DoorBellAdapterNormCmdNotFull) + { + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); + } + else if (bellbits & DoorBellAdapterNormRespNotFull) + { + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); + } + } +} + +/** + * aac_rx_enable_interrupt - Enable event reporting + * @dev: Adapter + * @event: Event to enable + * + * Enable event reporting from the i960 for a given event. + */ + +static void aac_rx_enable_interrupt(struct aac_dev * dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_1); + break; + + case HostNormRespQue: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_2); + break; + + case AdapNormCmdNotFull: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_3); + break; + + case AdapNormRespNotFull: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_4); + break; + } +} + +/** + * aac_rx_disable_interrupt - Disable event reporting + * @dev: Adapter + * @event: Event to enable + * + * Disable event reporting from the i960 for a given event. + */ + +static void aac_rx_disable_interrupt(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + dev->irq_mask |= (OUTBOUNDDOORBELL_1); + break; + + case HostNormRespQue: + dev->irq_mask |= (OUTBOUNDDOORBELL_2); + break; + + case AdapNormCmdNotFull: + dev->irq_mask |= (OUTBOUNDDOORBELL_3); + break; + + case AdapNormRespNotFull: + dev->irq_mask |= (OUTBOUNDDOORBELL_4); + break; + } +} + +/** + * rx_sync_cmd - send a command and wait + * @dev: Adapter + * @command: Command to execute + * @p1: first parameter + * @ret: adapter status + * + * This routine will send a synchronous comamnd to the adapter and wait + * for its completion. + */ + +static int rx_sync_cmd(struct aac_dev *dev, unsigned long command, unsigned long p1, unsigned long *status) +{ + unsigned long start; + int ok; + /* + * Write the command into Mailbox 0 + */ + rx_writel(dev, InboundMailbox0, cpu_to_le32(command)); + /* + * Write the parameters into Mailboxes 1 - 4 + */ + rx_writel(dev, InboundMailbox1, cpu_to_le32(p1)); + rx_writel(dev, InboundMailbox2, 0); + rx_writel(dev, InboundMailbox3, 0); + rx_writel(dev, InboundMailbox4, 0); + /* + * Clear the synch command doorbell to start on a clean slate. + */ + rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + /* + * Disable doorbell interrupts + */ + rx_writeb(dev, MUnit.OIMR, rx_readb(dev, MUnit.OIMR) | 0x04); + /* + * Force the completion of the mask register write before issuing + * the interrupt. + */ + rx_readb (dev, MUnit.OIMR); + /* + * Signal that there is a new synch command + */ + rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0); + + ok = 0; + start = jiffies; + + /* + * Wait up to 30 seconds + */ + while (time_before(start+30*HZ, jiffies)) + { + udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ + /* + * Mon960 will set doorbell0 bit when it has completed the command. + */ + if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) { + /* + * Clear the doorbell. + */ + rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + ok = 1; + break; + } + /* + * Yield the processor in case we are slow + */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + if (ok != 1) { + /* + * Restore interrupt mask even though we timed out + */ + rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb); + return -ETIMEDOUT; + } + /* + * Pull the synch status from Mailbox 0. + */ + *status = le32_to_cpu(rx_readl(dev, IndexRegs.Mailbox[0])); + /* + * Clear the synch command doorbell. + */ + rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + /* + * Restore interrupt mask + */ + rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb); + return 0; + +} + +/** + * aac_rx_interrupt_adapter - interrupt adapter + * @dev: Adapter + * + * Send an interrupt to the i960 and breakpoint it. + */ + +static void aac_rx_interrupt_adapter(struct aac_dev *dev) +{ + unsigned long ret; + rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret); +} + +/** + * aac_rx_notify_adapter - send an event to the adapter + * @dev: Adapter + * @event: Event to send + * + * Notify the i960 that something it probably cares about has + * happened. + */ + +static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case AdapNormCmdQue: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1); + break; + case HostNormRespNotFull: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4); + break; + case AdapNormRespQue: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2); + break; + case HostNormCmdNotFull: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3); + break; + case HostShutdown: +// rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, &ret); + break; + case FastIo: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6); + break; + case AdapPrintfDone: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5); + break; + default: + BUG(); + break; + } +} + +/** + * aac_rx_start_adapter - activate adapter + * @dev: Adapter + * + * Start up processing on an i960 based AAC adapter + */ + +static void aac_rx_start_adapter(struct aac_dev *dev) +{ + unsigned long status; + struct aac_init *init; + + init = dev->init; + init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ); + /* + * Tell the adapter we are back and up and running so it will scan + * its command queues and enable our interrupts + */ + dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4); + /* + * First clear out all interrupts. Then enable the one's that we + * can handle. + */ + rx_writeb(dev, MUnit.OIMR, 0xff); + rx_writel(dev, MUnit.ODR, 0xffffffff); +// rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK); + rx_writeb(dev, MUnit.OIMR, 0xfb); + + rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (unsigned long) dev->init_pa, &status); +} + +/** + * aac_rx_init - initialize an i960 based AAC card + * @dev: device to configure + * @devnum: adapter number + * + * Allocate and set up resources for the i960 based AAC variants. The + * device_interface in the commregion will be allocated and linked + * to the comm region. + */ + +int aac_rx_init(struct aac_dev *dev, unsigned long num) +{ + unsigned long start; + unsigned long status; + int instance; + const char * name; + + dev->devnum = num; + + instance = dev->id; + name = dev->name; + + /* + * Map in the registers from the adapter. + */ + if((dev->regs.rx = (struct rx_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL) + { + printk(KERN_WARNING "aacraid: unable to map i960.\n" ); + return -1; + } + /* + * Check to see if the board failed any self tests. + */ + if (rx_readl(dev, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) { + printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); + return -1; + } + /* + * Check to see if the board panic'd while booting. + */ + if (rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_PANIC) { + printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance); + return -1; + } + start = jiffies; + /* + * Wait for the adapter to be up and running. Wait up to 30 seconds. + */ + while (!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) + { + if(time_after(jiffies, start+30*HZ)) + { + status = rx_readl(dev, IndexRegs.Mailbox[7]) >> 16; + printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %ld.\n", dev->name, instance, status); + return -1; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) + { + printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance); + return -1; + } + /* + * Fill in the function dispatch table. + */ + dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; + dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt; + dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; + dev->a_ops.adapter_notify = aac_rx_notify_adapter; + + if (aac_init_adapter(dev) == NULL) + return -1; + /* + * Start any kernel threads needed + */ + dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0); + /* + * Tell the adapter that all is configured, and it can start + * accepting requests + */ + aac_rx_start_adapter(dev); + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aacraid/sap1sup.c linux-2.5/drivers/scsi/aacraid/sap1sup.c --- linux-2.5.1/drivers/scsi/aacraid/sap1sup.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/sap1sup.c Thu Dec 13 16:32:36 2001 @@ -0,0 +1,394 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * sap1sup.c + * + * Abstract: Drawbridge specific support functions + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/blk.h> +#include <linux/delay.h> +#include <linux/completion.h> +#include <asm/semaphore.h> +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +static void aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct aac_dev *dev = dev_id; + unsigned short intstat, mask; + + intstat = sa_readw(dev, DoorbellReg_p); + /* + * Read mask and invert because drawbridge is reversed. + * This allows us to only service interrupts that have been enabled. + */ + mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK)); + + /* Check to see if this is our interrupt. If it isn't just return */ + + if (intstat & mask) { + if (intstat & PrintfReady) { + aac_printf(dev, le32_to_cpu(sa_readl(dev, Mailbox5))); + sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */ + sa_writew(dev, DoorbellReg_s, PrintfDone); + } else if (intstat & DOORBELL_1) { // dev -> Host Normal Command Ready + aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); + sa_writew(dev, DoorbellClrReg_p, DOORBELL_1); + } else if (intstat & DOORBELL_2) { // dev -> Host Normal Response Ready + aac_response_normal(&dev->queues->queue[HostNormRespQueue]); + sa_writew(dev, DoorbellClrReg_p, DOORBELL_2); + } else if (intstat & DOORBELL_3) { // dev -> Host Normal Command Not Full + sa_writew(dev, DoorbellClrReg_p, DOORBELL_3); + } else if (intstat & DOORBELL_4) { // dev -> Host Normal Response Not Full + sa_writew(dev, DoorbellClrReg_p, DOORBELL_4); + } + } +} + +/** + * aac_sa_enable_interrupt - enable an interrupt event + * @dev: Which adapter to enable. + * @event: Which adapter event. + * + * This routine will enable the corresponding adapter event to cause an interrupt on + * the host. + */ + +void aac_sa_enable_interrupt(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_1); + break; + + case HostNormRespQue: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_2); + break; + + case AdapNormCmdNotFull: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_3); + break; + + case AdapNormRespNotFull: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_4); + break; + } +} + +/** + * aac_sa_disable_interrupt - disable an interrupt event + * @dev: Which adapter to enable. + * @event: Which adapter event. + * + * This routine will enable the corresponding adapter event to cause an interrupt on + * the host. + */ + +void aac_sa_disable_interrupt (struct aac_dev *dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_1); + break; + + case HostNormRespQue: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_2); + break; + + case AdapNormCmdNotFull: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_3); + break; + + case AdapNormRespNotFull: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_4); + break; + } +} + +/** + * aac_sa_notify_adapter - handle adapter notification + * @dev: Adapter that notification is for + * @event: Event to notidy + * + * Notify the adapter of an event + */ + +void aac_sa_notify_adapter(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case AdapNormCmdQue: + sa_writew(dev, DoorbellReg_s,DOORBELL_1); + break; + case HostNormRespNotFull: + sa_writew(dev, DoorbellReg_s,DOORBELL_4); + break; + case AdapNormRespQue: + sa_writew(dev, DoorbellReg_s,DOORBELL_2); + break; + case HostNormCmdNotFull: + sa_writew(dev, DoorbellReg_s,DOORBELL_3); + break; + case HostShutdown: + //sa_sync_cmd(dev, HOST_CRASHING, 0, &ret); + break; + case FastIo: + sa_writew(dev, DoorbellReg_s,DOORBELL_6); + break; + case AdapPrintfDone: + sa_writew(dev, DoorbellReg_s,DOORBELL_5); + break; + default: + BUG(); + break; + } +} + + +/** + * sa_sync_cmd - send a command and wait + * @dev: Adapter + * @command: Command to execute + * @p1: first parameter + * @ret: adapter status + * + * This routine will send a synchronous comamnd to the adapter and wait + * for its completion. + */ + +static int sa_sync_cmd(struct aac_dev *dev, unsigned long command, unsigned long p1, unsigned long *ret) +{ + unsigned long start; + int ok; + /* + * Write the Command into Mailbox 0 + */ + sa_writel(dev, Mailbox0, cpu_to_le32(command)); + /* + * Write the parameters into Mailboxes 1 - 4 + */ + sa_writel(dev, Mailbox1, cpu_to_le32(p1)); + sa_writel(dev, Mailbox2, 0); + sa_writel(dev, Mailbox3, 0); + sa_writel(dev, Mailbox4, 0); + /* + * Clear the synch command doorbell to start on a clean slate. + */ + sa_writew(dev, DoorbellClrReg_p, DOORBELL_0); + /* + * Signal that there is a new synch command + */ + sa_writew(dev, DoorbellReg_s, DOORBELL_0); + + ok = 0; + start = jiffies; + + while(time_before(jiffies, start+30*HZ)) + { + /* + * Delay 5uS so that the monitor gets access + */ + udelay(5); + /* + * Mon110 will set doorbell0 bit when it has + * completed the command. + */ + if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0) { + ok = 1; + break; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + if (ok != 1) + return -ETIMEDOUT; + /* + * Clear the synch command doorbell. + */ + sa_writew(dev, DoorbellClrReg_p, DOORBELL_0); + /* + * Pull the synch status from Mailbox 0. + */ + *ret = le32_to_cpu(sa_readl(dev, Mailbox0)); + return 0; +} + +/** + * aac_sa_interrupt_adapter - interrupt an adapter + * @dev: Which adapter to enable. + * + * Breakpoint an adapter. + */ + +static void aac_sa_interrupt_adapter (struct aac_dev *dev) +{ + unsigned long ret; + sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret); +} + +/** + * aac_sa_start_adapter - activate adapter + * @dev: Adapter + * + * Start up processing on an ARM based AAC adapter + */ + +static void aac_sa_start_adapter(struct aac_dev *dev) +{ + unsigned long ret; + struct aac_init *init; + /* + * Fill in the remaining pieces of the init. + */ + init = dev->init; + init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ); + + dprintk(("INIT\n")); + /* + * Tell the adapter we are back and up and running so it will scan its command + * queues and enable our interrupts + */ + dev->irq_mask = (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4); + /* + * First clear out all interrupts. Then enable the one's that + * we can handle. + */ + dprintk(("MASK\n")); + sa_writew(dev, SaDbCSR.PRISETIRQMASK, cpu_to_le16(0xffff)); + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4)); + dprintk(("SYNCCMD\n")); + sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (unsigned long) dev->init_pa, &ret); +} + +/** + * aac_sa_init - initialize an ARM based AAC card + * @dev: device to configure + * @devnum: adapter number + * + * Allocate and set up resources for the ARM based AAC variants. The + * device_interface in the commregion will be allocated and linked + * to the comm region. + */ + +int aac_sa_init(struct aac_dev *dev, unsigned long devnum) +{ + unsigned long start; + unsigned long status; + int instance; + const char *name; + + dev->devnum = devnum; + + dprintk(("PREINST\n")); + instance = dev->id; + name = dev->name; + + /* + * Map in the registers from the adapter. + */ + dprintk(("PREMAP\n")); + + if((dev->regs.sa = (struct sa_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL) + { + printk(KERN_WARNING "aacraid: unable to map ARM.\n" ); + return -1; + } + /* + * Check to see if the board failed any self tests. + */ + if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) { + printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance); + return -1; + } + /* + * Check to see if the board panic'd while booting. + */ + if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) { + printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance); + return -1; + } + start = jiffies; + /* + * Wait for the adapter to be up and running. Wait up to 3 minutes. + */ + while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) { + if (time_after(start+180*HZ, jiffies)) { + status = sa_readl(dev, Mailbox7) >> 16; + printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %d.\n", name, instance, le32_to_cpu(status)); + return -1; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + dprintk(("ATIRQ\n")); + if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) { + printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance); + return -1; + } + + /* + * Fill in the function dispatch table. + */ + + dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; + dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt; + dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; + dev->a_ops.adapter_notify = aac_sa_notify_adapter; + + dprintk(("FUNCDONE\n")); + + if(aac_init_adapter(dev) == NULL) + return -1; + + dprintk(("NEWADAPTDONE\n")); + /* + * Start any kernel threads needed + */ + dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0); + /* + * Tell the adapter that all is configure, and it can start + * accepting requests + */ + dprintk(("STARTING\n")); + aac_sa_start_adapter(dev); + dprintk(("STARTED\n")); + return 0; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/advansys.c linux-2.5/drivers/scsi/advansys.c --- linux-2.5.1/drivers/scsi/advansys.c Fri Nov 9 22:05:06 2001 +++ linux-2.5/drivers/scsi/advansys.c Sun Jan 6 19:17:51 2002 @@ -3610,36 +3610,6 @@ #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 #define ASC_FALSE 0 @@ -4084,7 +4054,6 @@ ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */ } eep_config; ulong last_reset; /* Saved last reset time */ - spinlock_t lock; /* Board spinlock */ #ifdef CONFIG_PROC_FS /* /proc/scsi/advansys/[0...] */ char *prtbuf; /* /proc print buffer */ @@ -4604,13 +4573,6 @@ ASC_DBG(1, "advansys_detect: begin\n"); - /* - * 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 ASC_LINUX_KERNEL22 @@ -4837,9 +4799,6 @@ 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. * @@ -5723,13 +5682,6 @@ } } - /* - * 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; } @@ -5893,14 +5845,7 @@ boardp = ASC_BOARDP(shp); ASC_STATS(shp, queuecommand); - /* - * 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. - */ - ASC_UNLOCK_IO_REQUEST_LOCK - - spin_lock_irqsave(&boardp->lock, flags); + spin_lock_irqsave(shp->host_lock, flags); /* * Block new commands while handling a reset or abort request. @@ -5917,7 +5862,7 @@ * handling. */ asc_enqueue(&boardp->done, scp, ASC_BACK); - spin_unlock_irqrestore(&boardp->lock, flags); + spin_unlock_irqrestore(shp->host_lock, flags); return 0; } @@ -5961,15 +5906,7 @@ break; } - spin_unlock_irqrestore(&boardp->lock, flags); - - /* - * 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. - */ - ASC_LOCK_IO_REQUEST_LOCK - + spin_unlock_irqrestore(shp->host_lock, flags); return 0; } @@ -6015,20 +5952,13 @@ /* * Check for re-entrancy. */ - spin_lock_irqsave(&boardp->lock, flags); + spin_lock_irqsave(shp->host_lock, flags); if (boardp->flags & ASC_HOST_IN_RESET) { - spin_unlock_irqrestore(&boardp->lock, flags); + spin_unlock_irqrestore(shp->host_lock, flags); return FAILED; } boardp->flags |= ASC_HOST_IN_RESET; - spin_unlock_irqrestore(&boardp->lock, flags); - - /* - * 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 + spin_unlock_irqrestore(shp->host_lock, flags); if (ASC_NARROW_BOARD(boardp)) { /* @@ -6063,7 +5993,7 @@ /* * Acquire the board lock. */ - spin_lock_irqsave(&boardp->lock, flags); + spin_lock_irqsave(shp->host_lock, flags); } else { /* @@ -6094,7 +6024,7 @@ * Acquire the board lock and ensure all requests completed by the * microcode have been processed by calling AdvISR(). */ - spin_lock_irqsave(&boardp->lock, flags); + spin_lock_irqsave(shp->host_lock, flags); (void) AdvISR(adv_dvc_varp); } @@ -6160,7 +6090,7 @@ boardp->flags &= ~ASC_HOST_IN_RESET; /* Release the board. */ - spin_unlock_irqrestore(&boardp->lock, flags); + spin_unlock_irqrestore(shp->host_lock, flags); /* * Complete all the 'done_scp' requests. @@ -6169,13 +6099,6 @@ asc_scsi_done_list(done_scp); } - /* - * 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 - ASC_DBG1(1, "advansys_reset: ret %d\n", ret); return ret; @@ -6344,10 +6267,11 @@ * AscISR() will call asc_isr_callback(). */ for (i = 0; i < asc_board_count; i++) { - boardp = ASC_BOARDP(asc_host[i]); + struct Scsi_Host *shp = asc_host[i]; + boardp = ASC_BOARDP(shp); ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n", i, (ulong) boardp); - spin_lock_irqsave(&boardp->lock, flags); + spin_lock_irqsave(shp->host_lock, flags); if (ASC_NARROW_BOARD(boardp)) { /* * Narrow Board @@ -6403,7 +6327,7 @@ } } } - spin_unlock_irqrestore(&boardp->lock, flags); + spin_unlock_irqrestore(shp->host_lock, flags); } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aha152x.c linux-2.5/drivers/scsi/aha152x.c --- linux-2.5.1/drivers/scsi/aha152x.c Fri Nov 9 22:05:06 2001 +++ linux-2.5/drivers/scsi/aha152x.c Sun Jan 6 19:17:51 2002 @@ -1349,9 +1349,9 @@ printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO); SETPORT(DMACNTRL0, SWINT|INTEN); - spin_unlock_irq(&io_request_lock); + spin_unlock_irq(shpnt->host_lock); mdelay(1000); - spin_lock_irq(&io_request_lock); + spin_lock_irq(shpnt->host_lock); free_irq(shpnt->irq, shpnt); if (!HOSTDATA(shpnt)->swint) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aha1542.c linux-2.5/drivers/scsi/aha1542.c --- linux-2.5.1/drivers/scsi/aha1542.c Fri Oct 12 22:35:53 2001 +++ linux-2.5/drivers/scsi/aha1542.c Sun Jan 6 19:17:51 2002 @@ -67,10 +67,10 @@ int nseg, int badseg) { - printk(KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx length %d\n", + printk(KERN_CRIT "sgpnt[%d:%d] page %p/0x%lx length %d\n", badseg, nseg, - sgpnt[badseg].address, - SCSI_PA(sgpnt[badseg].address), + page_address(sgpnt[badseg].page) + sgpnt[badseg].offset, + (unsigned long)page_to_bus(sgpnt[badseg].page) + sgpnt[badseg].offset, sgpnt[badseg].length); /* @@ -176,7 +176,7 @@ static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt); static int aha1542_restart(struct Scsi_Host *shost); -static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs); +static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs); static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs); #define aha1542_intr_reset(base) outb(IRST, CONTROL(base)) @@ -419,30 +419,30 @@ static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; + struct Scsi_Host *shost; + + shost = aha_host[irq - 9]; + if (!shost) + panic("Splunge!"); - spin_lock_irqsave(&io_request_lock, flags); - aha1542_intr_handle(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_lock_irqsave(shost->host_lock, flags); + aha1542_intr_handle(shost, dev_id, regs); + spin_unlock_irqrestore(shost->host_lock, flags); } /* A "high" level interrupt handler */ -static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs) +static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs) { void (*my_done) (Scsi_Cmnd *) = NULL; int errstatus, mbi, mbo, mbistatus; int number_serviced; unsigned long flags; - struct Scsi_Host *shost; Scsi_Cmnd *SCtmp; int flag; int needs_restart; struct mailbox *mb; struct ccb *ccb; - shost = aha_host[irq - 9]; - if (!shost) - panic("Splunge!"); - mb = HOSTDATA(shost)->mb; ccb = HOSTDATA(shost)->ccb; @@ -542,7 +542,7 @@ } my_done = SCtmp->scsi_done; if (SCtmp->host_scribble) { - scsi_free(SCtmp->host_scribble, 512); + kfree(SCtmp->host_scribble); SCtmp->host_scribble = 0; } /* Fetch the sense data, and tuck it away, in the required slot. The @@ -703,18 +703,19 @@ #endif int i; ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ - SCpnt->host_scribble = (unsigned char *) scsi_malloc(512); + SCpnt->host_scribble = (unsigned char *) kmalloc(512, GFP_DMA); sgpnt = (struct scatterlist *) SCpnt->request_buffer; cptr = (struct chain *) SCpnt->host_scribble; if (cptr == NULL) panic("aha1542.c: unable to allocate DMA memory\n"); for (i = 0; i < SCpnt->use_sg; i++) { if (sgpnt[i].length == 0 || SCpnt->use_sg > 16 || - (((int) sgpnt[i].address) & 1) || (sgpnt[i].length & 1)) { + (((int) sgpnt[i].offset) & 1) || (sgpnt[i].length & 1)) { unsigned char *ptr; printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i); for (i = 0; i < SCpnt->use_sg; i++) { - printk(KERN_CRIT "%d: %p %d\n", i, sgpnt[i].address, + printk(KERN_CRIT "%d: %p %d\n", i, + page_address(sgpnt[i].page) + sgpnt[i].offset, sgpnt[i].length); }; printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr); @@ -723,8 +724,8 @@ printk("%02x ", ptr[i]); panic("Foooooooood fight!"); }; - any2scsi(cptr[i].dataptr, SCSI_PA(sgpnt[i].address)); - if (SCSI_PA(sgpnt[i].address + sgpnt[i].length - 1) > ISA_DMA_THRESHOLD) + any2scsi(cptr[i].dataptr, page_to_bus(sgpnt[i].page) + sgpnt[i].offset); + if (page_to_bus(sgpnt[i].page) + sgpnt[i].offset + sgpnt[i].length - 1 > ISA_DMA_THRESHOLD) BAD_SG_DMA(SCpnt, sgpnt, SCpnt->use_sg, i); any2scsi(cptr[i].datalen, sgpnt[i].length); }; @@ -1442,7 +1443,7 @@ Scsi_Cmnd *SCtmp; SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; if (SCtmp->host_scribble) { - scsi_free(SCtmp->host_scribble, 512); + kfree(SCtmp->host_scribble); SCtmp->host_scribble = NULL; } HOSTDATA(SCpnt->host)->SCint[i] = NULL; @@ -1474,9 +1475,9 @@ * check for timeout, and if we are doing something like this * we are pretty desperate anyways. */ - spin_unlock_irq(&io_request_lock); + spin_unlock_irq(SCpnt->host->host_lock); scsi_sleep(4 * HZ); - spin_lock_irq(&io_request_lock); + spin_lock_irq(SCpnt->host->host_lock); WAIT(STATUS(SCpnt->host->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF); @@ -1505,7 +1506,7 @@ continue; } if (SCtmp->host_scribble) { - scsi_free(SCtmp->host_scribble, 512); + kfree(SCtmp->host_scribble); SCtmp->host_scribble = NULL; } HOSTDATA(SCpnt->host)->SCint[i] = NULL; @@ -1538,9 +1539,9 @@ * check for timeout, and if we are doing something like this * we are pretty desperate anyways. */ - spin_unlock_irq(&io_request_lock); + spin_unlock_irq(SCpnt->host->host_lock); scsi_sleep(4 * HZ); - spin_lock_irq(&io_request_lock); + spin_lock_irq(SCpnt->host->host_lock); WAIT(STATUS(SCpnt->host->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF); @@ -1574,7 +1575,7 @@ continue; } if (SCtmp->host_scribble) { - scsi_free(SCtmp->host_scribble, 512); + kfree(SCtmp->host_scribble); SCtmp->host_scribble = NULL; } HOSTDATA(SCpnt->host)->SCint[i] = NULL; @@ -1623,7 +1624,7 @@ if (mb[mbi].status) { printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n", SCpnt->host->irq); - aha1542_intr_handle(SCpnt->host->irq, NULL); + aha1542_intr_handle(SCpnt->host, NULL); return 0; } /* OK, no lost interrupt. Try looking to see how many pending commands @@ -1712,7 +1713,7 @@ SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; SCtmp->result = DID_RESET << 16; if (SCtmp->host_scribble) { - scsi_free(SCtmp->host_scribble, 512); + kfree(SCtmp->host_scribble); SCtmp->host_scribble = NULL; } printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target); @@ -1758,7 +1759,7 @@ SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; SCtmp->result = DID_RESET << 16; if (SCtmp->host_scribble) { - scsi_free(SCtmp->host_scribble, 512); + kfree(SCtmp->host_scribble); SCtmp->host_scribble = NULL; } printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aha1740.c linux-2.5/drivers/scsi/aha1740.c --- linux-2.5.1/drivers/scsi/aha1740.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/aha1740.c Sun Jan 6 19:17:51 2002 @@ -213,6 +213,7 @@ /* A "high" level interrupt handler */ void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs) { + struct Scsi_Host *host = aha_host[irq - 9]; void (*my_done)(Scsi_Cmnd *); int errstatus, adapstat; int number_serviced; @@ -221,11 +222,10 @@ unsigned int base; unsigned long flags; - spin_lock_irqsave(&io_request_lock, flags); - - if (!aha_host[irq - 9]) + if (!host) panic("aha1740.c: Irq from unknown host!\n"); - base = aha_host[irq - 9]->io_port; + spin_lock_irqsave(host->host_lock, flags); + base = host->io_port; number_serviced = 0; while(inb(G2STAT(base)) & G2STAT_INTPEND) @@ -299,7 +299,7 @@ number_serviced++; } - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aic7xxx/aic7xxx_linux.c linux-2.5/drivers/scsi/aic7xxx/aic7xxx_linux.c --- linux-2.5.1/drivers/scsi/aic7xxx/aic7xxx_linux.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx_linux.c Thu Jan 3 18:50:09 2002 @@ -1699,6 +1699,7 @@ cmd->request_buffer, cmd->request_bufflen, scsi_to_pci_dma_dir(cmd->sc_data_direction)); + scb->sg_count = 0; scb->sg_count = ahc_linux_map_seg(ahc, scb, sg, addr, cmd->request_bufflen); @@ -2727,15 +2728,15 @@ int ret; int extended; struct ahc_softc *ahc; - struct buffer_head *bh; + unsigned char *buf; ahc = *((struct ahc_softc **)disk->device->host->hostdata); - bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev)); + buf = scsi_bios_ptable(dev); - if (bh) { - ret = scsi_partsize(bh, disk->capacity, + if (buf) { + ret = scsi_partsize(buf, disk->capacity, &geom[2], &geom[0], &geom[1]); - brelse(bh); + kfree(buf); if (ret != -1) return (ret); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aic7xxx/aic7xxx_osm.h linux-2.5/drivers/scsi/aic7xxx/aic7xxx_osm.h --- linux-2.5.1/drivers/scsi/aic7xxx/aic7xxx_osm.h Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx_osm.h Mon Jan 7 21:46:04 2002 @@ -713,20 +713,20 @@ static __inline void ahc_lockinit(struct ahc_softc *ahc) { - spin_lock_init(&ahc->platform_data->host->host_lock); + spin_lock_init(ahc->platform_data->host->host_lock); } static __inline void ahc_lock(struct ahc_softc *ahc, unsigned long *flags) { *flags = 0; - spin_lock_irqsave(&ahc->platform_data->host->host_lock, *flags); + spin_lock_irqsave(ahc->platform_data->host->host_lock, *flags); } static __inline void ahc_unlock(struct ahc_softc *ahc, unsigned long *flags) { - spin_unlock_irqrestore(&ahc->platform_data->host->host_lock, *flags); + spin_unlock_irqrestore(ahc->platform_data->host->host_lock, *flags); } static __inline void @@ -741,7 +741,7 @@ struct Scsi_Host *host = ahc->platform_data->host; *flags = 0; - spin_lock_irqsave(&host->host_lock, *flags); + spin_lock_irqsave(host->host_lock, *flags); } static __inline void @@ -749,7 +749,7 @@ { struct Scsi_Host *host = ahc->platform_data->host; - spin_unlock_irqrestore(&host->host_lock, *flags); + spin_unlock_irqrestore(host->host_lock, *flags); } #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aic7xxx/aicasm/aicdb.h linux-2.5/drivers/scsi/aic7xxx/aicasm/aicdb.h --- linux-2.5.1/drivers/scsi/aic7xxx/aicasm/aicdb.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicdb.h Mon Jan 7 21:43:21 2002 @@ -0,0 +1 @@ +#include <db3/db_185.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/aic7xxx_old.c linux-2.5/drivers/scsi/aic7xxx_old.c --- linux-2.5.1/drivers/scsi/aic7xxx_old.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/scsi/aic7xxx_old.c Sun Jan 6 19:17:51 2002 @@ -4127,7 +4127,7 @@ unsigned long cpu_flags = 0; struct aic7xxx_scb *scb; - spin_lock_irqsave(&p->host->host_lock, cpu_flags); + spin_lock_irqsave(p->host->host_lock, cpu_flags); p->dev_timer_active &= ~(0x01 << MAX_TARGETS); if ( (p->dev_timer_active & (0x01 << p->scsi_id)) && time_after_eq(jiffies, p->dev_expires[p->scsi_id]) ) @@ -4184,7 +4184,7 @@ } aic7xxx_run_waiting_queues(p); - spin_unlock_irqrestore(&p->host->host_lock, cpu_flags); + spin_unlock_irqrestore(p->host->host_lock, cpu_flags); } /*+F************************************************************************* @@ -7011,7 +7011,7 @@ p = (struct aic7xxx_host *)dev_id; if(!p) return; - spin_lock_irqsave(&p->host->host_lock, cpu_flags); + spin_lock_irqsave(p->host->host_lock, cpu_flags); p->flags |= AHC_IN_ISR; do { @@ -7020,7 +7020,7 @@ aic7xxx_done_cmds_complete(p); aic7xxx_run_waiting_queues(p); p->flags &= ~AHC_IN_ISR; - spin_unlock_irqrestore(&p->host->host_lock, cpu_flags); + spin_unlock_irqrestore(p->host->host_lock, cpu_flags); } /*+F************************************************************************* @@ -11148,7 +11148,7 @@ disable_irq(p->irq); aic7xxx_print_card(p); aic7xxx_print_scratch_ram(p); - spin_unlock_irq(&p->host->host_lock); + spin_unlock_irq(p->host->host_lock); for(;;) barrier(); } @@ -11737,15 +11737,15 @@ { int heads, sectors, cylinders, ret; struct aic7xxx_host *p; - struct buffer_head *bh; + unsigned char *buf; p = (struct aic7xxx_host *) disk->device->host->hostdata; - bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev)); + buf = scsi_bios_ptable(dev); - if ( bh ) + if ( buf ) { - ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]); - brelse(bh); + ret = scsi_partsize(buf, disk->capacity, &geom[2], &geom[0], &geom[1]); + kfree(buf); if ( ret != -1 ) return(ret); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/cpqfcTSinit.c linux-2.5/drivers/scsi/cpqfcTSinit.c --- linux-2.5.1/drivers/scsi/cpqfcTSinit.c Mon Dec 10 22:22:21 2001 +++ linux-2.5/drivers/scsi/cpqfcTSinit.c Sun Jan 6 19:17:51 2002 @@ -242,7 +242,7 @@ cpqfcHBAdata->notify_wt = &sem; /* must unlock before kernel_thread(), for it may cause a reschedule. */ - spin_unlock_irq(&HostAdapter->host_lock); + spin_unlock_irq(HostAdapter->host_lock); kernel_thread((int (*)(void *))cpqfcTSWorkerThread, (void *) HostAdapter, 0); /* @@ -250,7 +250,7 @@ */ down (&sem); - spin_lock_irq(&HostAdapter->host_lock); + spin_lock_irq(HostAdapter->host_lock); cpqfcHBAdata->notify_wt = NULL; LEAVE("launch_FC_worker_thread"); @@ -407,7 +407,7 @@ // start our kernel worker thread - spin_lock_irq(&HostAdapter->host_lock); + spin_lock_irq(HostAdapter->host_lock); launch_FCworker_thread(HostAdapter); @@ -447,16 +447,16 @@ unsigned long stop_time; - spin_unlock_irq(&HostAdapter->host_lock); + spin_unlock_irq(HostAdapter->host_lock); stop_time = jiffies + 4*HZ; while ( time_before(jiffies, stop_time) ) schedule(); // (our worker task needs to run) } - spin_lock_irq(&HostAdapter->host_lock); + spin_lock_irq(HostAdapter->host_lock); NumberOfAdapters++; - spin_unlock_irq(&HostAdapter->host_lock); + spin_unlock_irq(HostAdapter->host_lock); } // end of while() } @@ -1596,9 +1596,9 @@ int retval; Scsi_Device *SDpnt = Cmnd->device; // printk(" ENTERING cpqfcTS_eh_device_reset() \n"); - spin_unlock_irq(&Cmnd->host->host_lock); + spin_unlock_irq(Cmnd->host->host_lock); retval = cpqfcTS_TargetDeviceReset( SDpnt, 0); - spin_lock_irq(&Cmnd->host->host_lock); + spin_lock_irq(Cmnd->host->host_lock); return retval; } @@ -1653,7 +1653,7 @@ UCHAR IntPending; ENTER("intr_handler"); - spin_lock_irqsave( &HostAdapter->host_lock, flags); + spin_lock_irqsave(HostAdapter->host_lock, flags); // is this our INT? IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address); @@ -1702,7 +1702,7 @@ } } } - spin_unlock_irqrestore( &HostAdapter->host_lock, flags); + spin_unlock_irqrestore(HostAdapter->host_lock, flags); LEAVE("intr_handler"); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/cpqfcTSworker.c linux-2.5/drivers/scsi/cpqfcTSworker.c --- linux-2.5.1/drivers/scsi/cpqfcTSworker.c Mon Dec 10 22:15:19 2001 +++ linux-2.5/drivers/scsi/cpqfcTSworker.c Sun Jan 6 19:17:51 2002 @@ -159,7 +159,6 @@ #ifdef PCI_KERNEL_TRACE PTACHYON fcChip = &cpqfcHBAdata->fcChip; #endif - struct fs_struct *fs; DECLARE_MUTEX_LOCKED(fcQueReady); DECLARE_MUTEX_LOCKED(fcTYOBcomplete); DECLARE_MUTEX_LOCKED(TachFrozen); @@ -168,33 +167,7 @@ ENTER("WorkerThread"); lock_kernel(); - /* - * If we were started as result of loading a module, close all of the - * user space pages. We don't need them, and if we didn't close them - * they would be locked into memory. - */ - exit_mm(current); - - current->session = 1; - current->pgrp = 1; - - /* Become as one with the init task */ - - exit_fs(current); /* current->fs->count--; */ - fs = init_task.fs; - // Some kernels compiled for SMP, while actually running - // on a uniproc machine, will return NULL for this call - if( !fs) - { - printk(" cpqfcTS FATAL: fs is NULL! Is this an SMP kernel on uniproc machine?\n "); - } - - else - { - current->fs = fs; - atomic_inc(&fs->count); - } - + daemonize(); siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); @@ -227,7 +200,7 @@ PCI_TRACE( 0x90) // first, take the IO lock so the SCSI upper layers can't call // into our _quecommand function (this also disables INTs) - spin_lock_irqsave( &HostAdapter->host_lock, flags); // STOP _que function + spin_lock_irqsave(HostAdapter->host_lock, flags); // STOP _que function PCI_TRACE( 0x90) CPQ_SPINLOCK_HBA( cpqfcHBAdata) @@ -241,7 +214,7 @@ PCI_TRACE( 0x90) // release the IO lock (and re-enable interrupts) - spin_unlock_irqrestore( &HostAdapter->host_lock, flags); + spin_unlock_irqrestore(HostAdapter->host_lock, flags); // disable OUR HBA interrupt (keep them off as much as possible // during error recovery) @@ -3078,7 +3051,7 @@ goto Skip; // STOP _que function - spin_lock_irqsave( &cpqfcHBAdata->HostAdapter->host_lock, flags); + spin_lock_irqsave(cpqfcHBAdata->HostAdapter->host_lock, flags); PCI_TRACE( 0xA8) @@ -3086,7 +3059,7 @@ cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing // release the IO lock (and re-enable interrupts) - spin_unlock_irqrestore( &cpqfcHBAdata->HostAdapter->host_lock, flags); + spin_unlock_irqrestore(cpqfcHBAdata->HostAdapter->host_lock, flags); // Ensure no contention from _quecommand or Worker process CPQ_SPINLOCK_HBA( cpqfcHBAdata) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/dpt_i2o.c linux-2.5/drivers/scsi/dpt_i2o.c --- linux-2.5.1/drivers/scsi/dpt_i2o.c Wed Nov 28 18:22:27 2001 +++ linux-2.5/drivers/scsi/dpt_i2o.c Sun Jan 6 19:17:51 2002 @@ -1157,17 +1157,13 @@ msg[2] |= 0x80000000 | ((u32)wait_data->id); timeout *= HZ; if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){ - if(!timeout){ - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&io_request_lock); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(pHba->host->host_lock); + if (!timeout) schedule(); - spin_lock_irq(&io_request_lock); - } else { - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&io_request_lock); + else schedule_timeout(timeout*HZ); - spin_lock_irq(&io_request_lock); - } + spin_lock_irq(pHba->host->host_lock); } wq_write_lock_irq(&adpt_wq_i2o_post.lock); __remove_wait_queue(&adpt_wq_i2o_post, &wait); @@ -1560,7 +1556,7 @@ //TODO check for root access // - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); if (minor >= hba_count) { return -ENXIO; } @@ -1591,7 +1587,7 @@ int minor; adpt_hba* pHba; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); if (minor >= hba_count) { return -ENXIO; } @@ -1705,7 +1701,7 @@ } do { - spin_lock_irqsave(&io_request_lock, flags); + spin_lock_irqsave(pHba->host->host_lock, flags); // This state stops any new commands from enterring the // controller while processing the ioctl // pHba->state |= DPTI_STATE_IOCTL; @@ -1713,7 +1709,7 @@ // the queue empties and stops. We need a way to restart the queue rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER); // pHba->state &= ~DPTI_STATE_IOCTL; - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irqrestore(pHba->host->host_lock, flags); } while(rcode == -ETIMEDOUT); if(rcode){ @@ -1887,7 +1883,7 @@ adpt_hba* pHba; ulong flags; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); if (minor >= DPTI_MAX_HBA){ return -ENXIO; } @@ -1951,9 +1947,9 @@ break; } case I2ORESETCMD: - spin_lock_irqsave(&io_request_lock, flags); + spin_lock_irqsave(pHba->host->host_lock, flags); adpt_hba_reset(pHba); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irqrestore(pHba->host->host_lock, flags); break; case I2ORESCANCMD: adpt_rescan(pHba); @@ -1989,19 +1985,18 @@ static void adpt_isr(int irq, void *dev_id, struct pt_regs *regs) { Scsi_Cmnd* cmd; - adpt_hba* pHba=NULL; + adpt_hba* pHba = dev_id; u32 m; ulong reply; u32 status=0; u32 context; ulong flags = 0; - pHba = dev_id; if (pHba == NULL ){ printk(KERN_WARNING"adpt_isr: NULL dev_id\n"); return; } - spin_lock_irqsave(&io_request_lock, flags); + spin_lock_irqsave(pHba->host->host_lock, flags); while( readl(pHba->irq_mask) & I2O_INTERRUPT_PENDING_B) { m = readl(pHba->reply_port); if(m == EMPTY_QUEUE){ @@ -2011,8 +2006,7 @@ if(m == EMPTY_QUEUE){ // This really should not happen printk(KERN_ERR"dpti: Could not get reply frame\n"); - spin_unlock_irqrestore(&io_request_lock,flags); - return; + goto out; } } reply = (ulong)bus_to_virt(m); @@ -2067,9 +2061,7 @@ wmb(); rmb(); } - spin_unlock_irqrestore(&io_request_lock, flags); - return; - +out: spin_unlock_irqrestore(pHba->host->host_lock, flags); } static s32 adpt_scsi_to_i2o(adpt_hba* pHba, Scsi_Cmnd* cmd, struct adpt_device* d) @@ -2342,18 +2334,14 @@ s32 rcode; ulong flags; - spin_lock_irqsave(&io_request_lock, flags); - if ((rcode=adpt_i2o_lct_get(pHba)) < 0){ - spin_unlock_irqrestore(&io_request_lock, flags); - return rcode; - } - - if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0){ - spin_unlock_irqrestore(&io_request_lock, flags); - return rcode; - } - spin_unlock_irqrestore(&io_request_lock, flags); - return 0; + spin_lock_irqsave(pHba->host->host_lock, flags); + if ((rcode=adpt_i2o_lct_get(pHba)) < 0) + goto out; + if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0) + goto out; + rcode = 0; +out: spin_unlock_irqrestore(pHba->host->host_lock, flags); + return rcode; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/dtc.c linux-2.5/drivers/scsi/dtc.c --- linux-2.5.1/drivers/scsi/dtc.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/dtc.c Thu Dec 13 16:32:36 2001 @@ -1,13 +1,11 @@ - #define AUTOSENSE #define PSEUDO_DMA #define DONT_USE_INTR -#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */ +#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */ #define xNDEBUG (NDEBUG_INTR+NDEBUG_RESELECTION+\ NDEBUG_SELECTION+NDEBUG_ARBITRATION) #define DMA_WORKS_RIGHT - /* * DTC 3180/3280 driver, by * Ray Van Tassle rayvt@comm.mot.com @@ -65,6 +63,7 @@ 6 = yellow 7 = white */ + #if 0 #define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);} #else @@ -102,336 +101,318 @@ */ /* - */ + */ /* Offset from DTC_5380_OFFSET */ #define DTC_CONTROL_REG 0x100 /* rw */ #define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ #define CSR_DIR_READ 0x40 /* rw direction, 1 = read 0 = write */ -#define CSR_RESET 0x80 /* wo Resets 53c400 */ -#define CSR_5380_REG 0x80 /* ro 5380 registers can be accessed */ -#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ -#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ -#define CSR_5380_INTR 0x10 /* rw Enable 5380 interrupts */ -#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ -#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Host buffer not ready */ -#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer ready */ -#define CSR_GATED_5380_IRQ 0x01 /* ro Last block xferred */ +#define CSR_RESET 0x80 /* wo Resets 53c400 */ +#define CSR_5380_REG 0x80 /* ro 5380 registers can be accessed */ +#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ +#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ +#define CSR_5380_INTR 0x10 /* rw Enable 5380 interrupts */ +#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ +#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Host buffer not ready */ +#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer ready */ +#define CSR_GATED_5380_IRQ 0x01 /* ro Last block xferred */ #define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR) -#define DTC_BLK_CNT 0x101 /* rw +#define DTC_BLK_CNT 0x101 /* rw * # of 128-byte blocks to transfer */ -#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ +#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ #define DTC_SWITCH_REG 0x3982 /* ro - DIP switches */ #define DTC_RESUME_XFER 0x3982 /* wo - resume data xfer - * after disconnect/reconnect*/ + * after disconnect/reconnect */ #define DTC_5380_OFFSET 0x3880 /* 8 registers here, see NCR5380.h */ /*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */ -#define DTC_DATA_BUF 0x3900 /* rw 128 bytes long */ +#define DTC_DATA_BUF 0x3900 /* rw 128 bytes long */ static struct override { - unsigned int address; - int irq; + unsigned int address; + int irq; } overrides #ifdef OVERRIDE [] __initdata = OVERRIDE; #else -[4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO}}; +[4] __initdata = { + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO} +}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned long address; - int noauto; -} bases[] __initdata = {{0xcc000, 0}, {0xc8000, 0}, {0xdc000, 0}, {0xd8000, 0}}; + unsigned long address; + int noauto; +} bases[] __initdata = { + {0xcc000, 0}, + {0xc8000, 0}, + {0xdc000, 0}, + {0xd8000, 0} +}; #define NO_BASES (sizeof (bases) / sizeof (struct base)) static const struct signature { - const char *string; - int offset; -} signatures[] = { {"DATA TECHNOLOGY CORPORATION BIOS", 0x25}, }; + const char *string; + int offset; +} signatures[] = { + {"DATA TECHNOLOGY CORPORATION BIOS", 0x25}, +}; #define NO_SIGNATURES (sizeof (signatures) / sizeof (struct signature)) -/* - * Function : dtc_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. +/** + * dtc_setup - option setup for dtc3x80 * -*/ + * LILO command line initialization of the overrides array, + */ -void __init dtc_setup(char *str, int *ints){ - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("dtc_setup: usage dtc=address,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].address = ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; - } +static int __init dtc_setup(char *str) +{ + static int commandline_current = 0; + int i; + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + + if (ints[0] != 2) + printk(KERN_ERR "dtc_setup: usage dtc=address,irq\n"); + else if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].address = ints[1]; + overrides[commandline_current].irq = ints[2]; + for (i = 0; i < NO_BASES; ++i) + if (bases[i].address == ints[1]) { + bases[i].noauto = 1; + break; + } + ++commandline_current; + } + return 1; } -/* - * Function : int dtc_detect(Scsi_Host_Template * tpnt) +__setup("dtc=", dtc_setup); + +/** + * dtc_detect - detect DTC 3x80 controllers + * @tpnt: controller template * - * Purpose : detects and initializes DTC 3180/3280 controllers + * Detects and initializes DTC 3180/3280 controllers * that were autoprobed, overridden on the LILO command line, * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * -*/ - -int __init dtc_detect(Scsi_Host_Template * tpnt){ - static int current_override = 0, current_base = 0; - struct Scsi_Host *instance; - unsigned int base; - int sig, count; - - tpnt->proc_name = "dtc3x80"; - tpnt->proc_info = &dtc_proc_info; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - base = 0; - - if (overrides[current_override].address) - base = overrides[current_override].address; - else - for (; !base && (current_base < NO_BASES); ++current_base) { -#if (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : probing address %08x\n", bases[current_base].address); -#endif - for (sig = 0; sig < NO_SIGNATURES; ++sig) - if (!bases[current_base].noauto && - isa_check_signature(bases[current_base].address + - signatures[sig].offset, - signatures[sig].string, strlen(signatures[sig].string))) { - base = bases[current_base].address; -#if (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : detected board.\n"); -#endif - break; - } - } - -#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : base = %08x\n", base); -#endif - - if (!base) - break; + */ - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->base = base; - - NCR5380_init(instance, 0); - - NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */ - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, DTC_IRQS); +int __init dtc_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0, current_base = 0; + struct Scsi_Host *instance; + unsigned int base; + int sig, count; + + tpnt->proc_name = "dtc3x80"; + tpnt->proc_info = &dtc_proc_info; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) + { + base = 0; + + if (overrides[current_override].address) + base = overrides[current_override].address; + else + { + for (; !base && (current_base < NO_BASES); ++current_base) { + for (sig = 0; sig < NO_SIGNATURES; ++sig) + { + if (!bases[current_base].noauto && isa_check_signature(bases[current_base].address + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) { + base = bases[current_base].address; + break; + } + } + } + } + + if (!base) + break; + + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) + break; + + instance->base = base; + + NCR5380_init(instance, 0); + + NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */ + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, DTC_IRQS); #ifndef DONT_USE_INTR -/* With interrupts enabled, it will sometimes hang when doing heavy - * reads. So better not enable them until I finger it out. */ - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc")) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } - - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } + /* With interrupts enabled, it will sometimes hang when doing heavy + * reads. So better not enable them until I figure it out. */ + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc")) + { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + } #else - if (instance->irq != IRQ_NONE) - printk("scsi%d : interrupts not used. Might as well not jumper it.\n", - instance->host_no); - instance->irq = IRQ_NONE; + if (instance->irq != IRQ_NONE) + printk(KERN_INFO "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no); + instance->irq = IRQ_NONE; #endif -#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif - - printk("scsi%d : at 0x%05X", instance->host_no, (int)instance->base); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; + printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); + + ++current_override; + ++count; + } + return count; } -/* - * Function : int dtc_biosparam(Disk * disk, kdev_t dev, int *ip) +/** + * dtc_biosparam - compute disk geometry + * @disk: disk to generate for + * @dev: major/minor of device + * @ip: returned geometry * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for + * Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. - * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * -*/ - -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. -*/ + */ -int dtc_biosparam(Disk * disk, kdev_t dev, int * ip) +int dtc_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; + int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - return 0; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + return 0; } -/**************************************************************** - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) - * - * Purpose : Fast 5380 pseudo-dma read function, reads len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. -*/ - static int dtc_maxi = 0; static int dtc_wmaxi = 0; -static inline int NCR5380_pread (struct Scsi_Host *instance, - unsigned char *dst, int len) - { - unsigned char *d = dst; - int i; /* For counting time spent in the poll-loop */ - NCR5380_local_declare(); - NCR5380_setup(instance); - - i = 0; - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); - if (instance->irq == IRQ_NONE) - NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ); - else - NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE); - NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ - rtrc(1); - while (len > 0) { - rtrc(2); - while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) - ++i; - rtrc(3); - isa_memcpy_fromio(d, base + DTC_DATA_BUF, 128); - d += 128; - len -= 128; - rtrc(7); /*** with int's on, it sometimes hangs after here. +/** + * NCR5380_pread - fast pseudo DMA read + * @instance: controller + * @dst: destination buffer + * @len: expected/max size + * + * Fast 5380 pseudo-dma read function, reads len bytes from the controller + * mmio area into dst. + */ + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + unsigned char *d = dst; + int i; /* For counting time spent in the poll-loop */ + NCR5380_local_declare(); + NCR5380_setup(instance); + + i = 0; + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); + if (instance->irq == IRQ_NONE) + NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ); + else + NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE); + NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ + rtrc(1); + while (len > 0) { + rtrc(2); + while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) + ++i; + rtrc(3); + isa_memcpy_fromio(d, base + DTC_DATA_BUF, 128); + d += 128; + len -= 128; + rtrc(7); + /*** with int's on, it sometimes hangs after here. * Looks like something makes HBNR go away. */ - } - rtrc(4); - while ( !(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) - ++i; - NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ - rtrc(0); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - if (i > dtc_maxi) - dtc_maxi = i; - return(0); + } + rtrc(4); + while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) + ++i; + NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ + rtrc(0); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + if (i > dtc_maxi) + dtc_maxi = i; + return (0); } -/**************************************************************** - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) +/** + * NCR5380_pwrite - fast pseudo DMA write + * @instance: controller + * @dst: destination buffer + * @len: expected/max size * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. -*/ + * Fast 5380 pseudo-dma write function, writes len bytes to the + * controller mmio area from src. + */ -static inline int NCR5380_pwrite (struct Scsi_Host *instance, - unsigned char *src, int len) { - int i; - NCR5380_local_declare(); - NCR5380_setup(instance); - - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); - /* set direction (write) */ - if (instance->irq == IRQ_NONE) - NCR5380_write(DTC_CONTROL_REG, 0); - else - NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); - NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ - for (i = 0; len > 0; ++i) { - rtrc(5); - /* Poll until the host buffer can accept data. */ - while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) - ++i; - rtrc(3); - isa_memcpy_toio(base + DTC_DATA_BUF, src, 128); - src += 128; - len -= 128; - } - rtrc(4); - while ( !(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) - ++i; - rtrc(6); - /* Wait until the last byte has been sent to the disk */ - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) - ++i; - rtrc(7); - /* Check for parity error here. fixme. */ - NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ - rtrc(0); - if (i > dtc_wmaxi) - dtc_wmaxi = i; - return (0); +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + int i; + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); + /* set direction (write) */ + if (instance->irq == IRQ_NONE) + NCR5380_write(DTC_CONTROL_REG, 0); + else + NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); + NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ + for (i = 0; len > 0; ++i) { + rtrc(5); + /* Poll until the host buffer can accept data. */ + while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) + ++i; + rtrc(3); + isa_memcpy_toio(base + DTC_DATA_BUF, src, 128); + src += 128; + len -= 128; + } + rtrc(4); + while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) + ++i; + rtrc(6); + /* Wait until the last byte has been sent to the disk */ + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) + ++i; + rtrc(7); + /* Check for parity error here. fixme. */ + NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ + rtrc(0); + if (i > dtc_wmaxi) + dtc_wmaxi = i; + return (0); } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/eata.c linux-2.5/drivers/scsi/eata.c --- linux-2.5.1/drivers/scsi/eata.c Wed Dec 12 17:20:22 2001 +++ linux-2.5/drivers/scsi/eata.c Sat Jan 12 12:32:41 2002 @@ -1,6 +1,13 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 01 Jan 2002 Rev. 7.20 for linux 2.5.1 + * + Use the dynamic DMA mapping API. + * + * 19 Dec 2001 Rev. 7.02 for linux 2.5.1 + * + Use SCpnt->sc_data_direction if set. + * + Use sglist.page instead of sglist.address. + * * 11 Dec 2001 Rev. 7.00 for linux 2.5.1 * + Use host->host_lock instead of io_request_lock. * @@ -223,7 +230,7 @@ * This driver is based on the CAM (Common Access Method Committee) * EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol. * - * Copyright (C) 1994-2001 Dario Ballabio (ballabio_dario@emc.com) + * Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com) * * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it * @@ -297,7 +304,7 @@ * include in the list of i/o ports to be probed all the PCI SCSI controllers. * * Due to a DPT BIOS "feature", it might not be possible to force an EISA - * address on more then a single DPT PCI board, so in this case you have to + * address on more than a single DPT PCI board, so in this case you have to * let the PCI BIOS assign the addresses. * * The sequence of detection probes is: @@ -634,7 +641,7 @@ u_int32_t data_len; /* If sg=0 Data Length, if sg=1 sglist length */ u_int32_t cpp_index; /* Index of address to be returned in sp */ u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */ - u_int32_t sp_addr; /* Address where sp is DMA'ed when cp completes */ + u_int32_t sp_dma_addr; /* Address where sp is DMA'ed when cp completes */ u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */ /* Additional fields begin here. */ Scsi_Cmnd *SCpnt; @@ -656,7 +663,11 @@ unsigned long last_retried_pid; /* Pid of last retried command */ unsigned char subversion; /* Bus type, either ISA or EISA/PCI */ unsigned char protocol_rev; /* EATA 2.0 rev., 'A' or 'B' or 'C' */ - struct mssp sp[2]; /* Returned status for this board */ + unsigned char is_pci; /* TRUE is bus type is PCI */ + struct pci_dev *pdev; /* pdev for PCI bus, NULL otherwise */ + struct mssp *sp_cpu_addr; /* cpu addr for DMA buffer sp */ + dma_addr_t sp_dma_addr; /* dma handle for DMA buffer sp */ + struct mssp sp; /* Local copy of sp buffer */ }; static struct Scsi_Host *sh[MAX_BOARDS + 1]; @@ -693,10 +704,11 @@ #define HD(board) ((struct hostdata *) &sh[board]->hostdata) #define BN(board) (HD(board)->board_name) -#define H2DEV(x) htonl(x) -#define DEV2H(x) H2DEV(x) +/* Device is Big Endian */ +#define H2DEV(x) cpu_to_be32(x) +#define DEV2H(x) be32_to_cpu(x) + #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0) -#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0) static void do_interrupt_handler(int, void *, struct pt_regs *); static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); @@ -855,7 +867,7 @@ static inline int port_detect \ (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) { - unsigned char irq, dma_channel, subversion, i; + unsigned char irq, dma_channel, subversion, i, is_pci = FALSE; unsigned char protocol_rev; struct eata_info info; char *bus_type, dma_name[16], tag_type; @@ -907,10 +919,12 @@ if (!setup_done && j > 0 && j <= MAX_PCI) { bus_type = "PCI"; + is_pci = TRUE; subversion = ESA; } else if (port_base > MAX_EISA_ADDR || (protocol_rev == 'C' && info.pci)) { bus_type = "PCI"; + is_pci = TRUE; subversion = ESA; } else if (port_base >= MIN_EISA_ADDR || (protocol_rev == 'C' && info.eisa)) { @@ -923,6 +937,7 @@ } else if (port_base > MAX_ISA_ADDR) { bus_type = "PCI"; + is_pci = TRUE; subversion = ESA; } else { @@ -963,7 +978,13 @@ printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", name, irq); - pdev = get_pci_dev(port_base); + if (is_pci) { + pdev = get_pci_dev(port_base); + if (!pdev) + printk("%s: warning, failed to get pci_dev structure.\n", name); + } + else + pdev = NULL; if (pdev && (irq != pdev->irq)) { printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, pdev->irq); @@ -993,7 +1014,7 @@ /* Set board configuration */ memset((char *)&config, 0, sizeof(struct eata_config)); - config.len = (ushort) htons((ushort)510); + config.len = (ushort) cpu_to_be16((ushort)510); config.ocena = TRUE; if (do_dma(port_base, (unsigned long)&config, SET_CONFIG_DMA)) { @@ -1022,14 +1043,16 @@ sh[j]->n_io_port = REGION_SIZE; sh[j]->dma_channel = dma_channel; sh[j]->irq = irq; - sh[j]->sg_tablesize = (ushort) ntohs(info.scatt_size); + sh[j]->sg_tablesize = (ushort) be16_to_cpu(info.scatt_size); sh[j]->this_id = (ushort) info.host_addr[3]; - sh[j]->can_queue = (ushort) ntohs(info.queue_size); + sh[j]->can_queue = (ushort) be16_to_cpu(info.queue_size); sh[j]->cmd_per_lun = MAX_CMD_PER_LUN; sh[j]->select_queue_depths = select_queue_depths; memset(HD(j), 0, sizeof(struct hostdata)); HD(j)->subversion = subversion; HD(j)->protocol_rev = protocol_rev; + HD(j)->is_pci = is_pci; + HD(j)->pdev = pdev; HD(j)->board_number = j; if (HD(j)->subversion == ESA) @@ -1038,14 +1061,14 @@ unsigned long flags; scsi_register_blocked_host(sh[j]); sh[j]->unchecked_isa_dma = TRUE; - + flags=claim_dma_lock(); disable_dma(dma_channel); clear_dma_ff(dma_channel); set_dma_mode(dma_channel, DMA_MODE_CASCADE); enable_dma(dma_channel); release_dma_lock(flags); - + } strcpy(BN(j), name); @@ -1094,6 +1117,13 @@ return FALSE; } + if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, + sizeof(struct mssp), &HD(j)->sp_dma_addr))) { + printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j)); + eata2x_release(sh[j]); + return FALSE; + } + if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) max_queue_depth = MAX_TAGGED_CMD_PER_LUN; @@ -1108,7 +1138,7 @@ else tag_type = 'n'; if (j == 0) { - printk("EATA/DMA 2.0x: Copyright (C) 1994-2001 Dario Ballabio.\n"); + printk("EATA/DMA 2.0x: Copyright (C) 1994-2002 Dario Ballabio.\n"); printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c.\n", driver_name, tag_type, YESNO(linked_comm), max_queue_depth, YESNO(rev_scan), YESNO(ext_tran)); @@ -1144,7 +1174,11 @@ info.pci, info.eisa, info.raidnum); #endif - if (pdev) pci_set_master(pdev); + if (HD(j)->pdev) { + pci_set_master(HD(j)->pdev); + if (pci_set_dma_mask(HD(j)->pdev, 0xffffffff)) + printk("%s: warning, pci_set_dma_mask failed.\n", BN(j)); + } return TRUE; } @@ -1271,25 +1305,92 @@ return j; } -static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) { - unsigned int k; +static inline void map_dma(unsigned int i, unsigned int j) { + unsigned int k, count, pci_dir; struct scatterlist *sgpnt; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (SCpnt->sense_buffer) + cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer, + sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE)); + + cpp->sense_len = sizeof SCpnt->sense_buffer; + + if (!SCpnt->use_sg) { + + if (!SCpnt->request_bufflen) + cpp->data_address = V2DEV(SCpnt->request_buffer); + + else if (SCpnt->request_buffer) + cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, + SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir)); + + cpp->data_len = H2DEV(SCpnt->request_bufflen); + return; + } sgpnt = (struct scatterlist *) SCpnt->request_buffer; + count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir); - for (k = 0; k < SCpnt->use_sg; k++) { - cpp->sglist[k].address = V2DEV(sgpnt[k].address); - cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length); + for (k = 0; k < count; k++) { + cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k])); + cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k])); } + cpp->sg = TRUE; cpp->data_address = V2DEV(cpp->sglist); cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list))); } -static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { - unsigned int i, j, k; +static void unmap_dma(unsigned int i, unsigned int j) { + unsigned int pci_dir; struct mscp *cpp; - struct mssp *spp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (DEV2H(cpp->sense_addr)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); + + if (SCpnt->use_sg) + pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); + + else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); + +} + +static void sync_dma(unsigned int i, unsigned int j) { + unsigned int pci_dir; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (DEV2H(cpp->sense_addr)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); + + if (SCpnt->use_sg) + pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + SCpnt->use_sg, pci_dir); + + else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); + +} + +static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) { + unsigned int k; static const unsigned char data_out_cmds[] = { 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, @@ -1300,9 +1401,53 @@ static const unsigned char data_none_cmds[] = { 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, - 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5 + 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00 }; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; + SCpnt = cpp->SCpnt; + + if (SCpnt->sc_data_direction == SCSI_DATA_READ) { + cpp->din = TRUE; + cpp->dout = FALSE; + return; + } + else if (SCpnt->sc_data_direction == SCSI_DATA_WRITE) { + cpp->din = FALSE; + cpp->dout = TRUE; + return; + } + else if (SCpnt->sc_data_direction == SCSI_DATA_NONE) { + cpp->din = FALSE; + cpp->dout = FALSE; + return; + } + + if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) + panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j)); + + for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) + if (SCpnt->cmnd[0] == data_out_cmds[k]) { + cpp->dout = TRUE; + break; + } + + if ((cpp->din = !cpp->dout)) + for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) + if (SCpnt->cmnd[0] == data_none_cmds[k]) { + cpp->din = FALSE; + break; + } + +} + +static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { + unsigned int i, j, k; + struct mscp *cpp; + /* j is the board number */ j = ((struct hostdata *) SCpnt->host->hostdata)->board_number; @@ -1334,11 +1479,8 @@ memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *)); - /* Set pointer to status packet structure */ - spp = &HD(j)->sp[0]; - - /* The EATA protocol uses Big Endian format */ - cpp->sp_addr = V2DEV(spp); + /* Set pointer to status packet structure, Big Endian format */ + cpp->sp_dma_addr = H2DEV(HD(j)->sp_dma_addr); SCpnt->scsi_done = done; cpp->cpp_index = i; @@ -1348,19 +1490,6 @@ BN(j), i, SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); - for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) - if (SCpnt->cmnd[0] == data_out_cmds[k]) { - cpp->dout = TRUE; - break; - } - - if ((cpp->din = !cpp->dout)) - for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) - if (SCpnt->cmnd[0] == data_none_cmds[k]) { - cpp->din = FALSE; - break; - } - cpp->reqsen = TRUE; cpp->dispri = TRUE; #if 0 @@ -1371,8 +1500,13 @@ cpp->target = SCpnt->target; cpp->lun = SCpnt->lun; cpp->SCpnt = SCpnt; - cpp->sense_addr = V2DEV(SCpnt->sense_buffer); - cpp->sense_len = sizeof SCpnt->sense_buffer; + memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); + + /* Use data transfer direction SCpnt->sc_data_direction */ + scsi_to_dev_dir(i, j); + + /* Map DMA buffers and SG list */ + map_dma(i, j); if (SCpnt->device->tagged_queue) { @@ -1392,17 +1526,6 @@ cpp->mess[1] = SCpnt->device->current_tag++; } - if (SCpnt->use_sg) { - cpp->sg = TRUE; - build_sg_list(cpp, SCpnt); - } - else { - cpp->data_address = V2DEV(SCpnt->request_buffer); - cpp->data_len = H2DEV(SCpnt->request_bufflen); - } - - memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); - if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) { HD(j)->cp_stat[i] = READY; @@ -1412,6 +1535,7 @@ /* Send control packet to the board */ if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) { + unmap_dma(i, j); SCpnt->host_scribble = NULL; printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); @@ -1468,6 +1592,7 @@ printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i); if (SCarg->eh_state == SCSI_STATE_TIMEOUT) { + unmap_dma(i, j); SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n", @@ -1489,6 +1614,7 @@ } if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { + unmap_dma(i, j); SCarg->result = DID_ABORT << 16; SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; @@ -1586,10 +1712,10 @@ HD(j)->in_reset = TRUE; - spin_unlock_irq(&sh[j]->host_lock); + spin_unlock_irq(sh[j]->host_lock); time = jiffies; while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L); - spin_lock_irq(&sh[j]->host_lock); + spin_lock_irq(sh[j]->host_lock); printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit); @@ -1597,6 +1723,7 @@ if (HD(j)->cp_stat[i] == IN_RESET) { SCpnt = HD(j)->cp[i].SCpnt; + unmap_dma(i, j); SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; @@ -1609,6 +1736,7 @@ else if (HD(j)->cp_stat[i] == ABORTING) { SCpnt = HD(j)->cp[i].SCpnt; + unmap_dma(i, j); SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; @@ -1821,7 +1949,7 @@ static inline void ihdlr(int irq, unsigned int j) { Scsi_Cmnd *SCpnt; unsigned int i, k, c, status, tstatus, reg; - struct mssp *dspp, *spp; + struct mssp *spp; struct mscp *cpp; if (sh[j]->irq != irq) @@ -1843,14 +1971,13 @@ return; } - dspp = &HD(j)->sp[0]; - spp = &HD(j)->sp[1]; + spp = &HD(j)->sp; /* Make a local copy just before clearing the interrupt indication */ - memcpy(spp, dspp, sizeof(struct mssp)); + memcpy(spp, HD(j)->sp_cpu_addr, sizeof(struct mssp)); /* Clear the completion flag and cp pointer on the dynamic copy of sp */ - memset(dspp, 0, sizeof(struct mssp)); + memset(HD(j)->sp_cpu_addr, 0, sizeof(struct mssp)); /* Read the status register to clear the interrupt indication */ reg = inb(sh[j]->io_port + REG_STATUS); @@ -1908,6 +2035,8 @@ panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble); + sync_dma(i, j); + if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE); @@ -1985,6 +2114,7 @@ #else status = DID_BUS_BUSY << 16; #endif + HD(j)->retries++; HD(j)->last_retried_pid = SCpnt->pid; } @@ -2021,6 +2151,8 @@ SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, reg, HD(j)->iocount); + unmap_dma(i, j); + /* Set the command state to inactive */ SCpnt->host_scribble = NULL; @@ -2039,9 +2171,9 @@ /* Check if the interrupt must be processed by this handler */ if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return; - spin_lock_irqsave(&sh[j]->host_lock, spin_flags); + spin_lock_irqsave(sh[j]->host_lock, spin_flags); ihdlr(irq, j); - spin_unlock_irqrestore(&sh[j]->host_lock, spin_flags); + spin_unlock_irqrestore(sh[j]->host_lock, spin_flags); } int eata2x_release(struct Scsi_Host *shpnt) { @@ -2052,13 +2184,15 @@ if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n", driver_name); - if( sh[j]->unchecked_isa_dma ) { - scsi_deregister_blocked_host(sh[j]); - } + if(sh[j]->unchecked_isa_dma) scsi_deregister_blocked_host(sh[j]); for (i = 0; i < sh[j]->can_queue; i++) if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist); + if (HD(j)->sp_cpu_addr) + pci_free_consistent(HD(j)->pdev, sizeof(struct mssp), + HD(j)->sp_cpu_addr, HD(j)->sp_dma_addr); + free_irq(sh[j]->irq, &sha[j]); if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/eata.h linux-2.5/drivers/scsi/eata.h --- linux-2.5.1/drivers/scsi/eata.h Wed Dec 12 17:20:22 2001 +++ linux-2.5/drivers/scsi/eata.h Thu Jan 3 23:04:39 2002 @@ -13,7 +13,7 @@ int eata2x_reset(Scsi_Cmnd *); int eata2x_biosparam(Disk *, kdev_t, int *); -#define EATA_VERSION "7.00.00" +#define EATA_VERSION "7.20.00" #define EATA { \ name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/esp.c linux-2.5/drivers/scsi/esp.c --- linux-2.5.1/drivers/scsi/esp.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/scsi/esp.c Sun Jan 6 19:17:51 2002 @@ -1918,7 +1918,7 @@ unsigned long flags; int don; - spin_lock_irqsave(&esp->ehost->host_lock, flags); + spin_lock_irqsave(esp->ehost->host_lock, flags); ESPLOG(("esp%d: Aborting command\n", esp->esp_id)); esp_dump_state(esp); @@ -1934,7 +1934,7 @@ esp->msgout_len = 1; esp->msgout_ctr = 0; esp_cmd(esp, ESP_CMD_SATN); - spin_unlock_irqrestore(&esp->ehost->host_lock, flags); + spin_unlock_irqrestore(esp->ehost->host_lock, flags); return SCSI_ABORT_PENDING; } @@ -1963,7 +1963,7 @@ if (don) ESP_INTSON(esp->dregs); - spin_unlock_irqrestore(&esp->ehost->host_lock, flags); + spin_unlock_irqrestore(esp->ehost->host_lock, flags); return SCSI_ABORT_SUCCESS; } } @@ -1977,7 +1977,7 @@ if (esp->current_SC) { if (don) ESP_INTSON(esp->dregs); - spin_unlock_irqrestore(&esp->ehost->host_lock, flags); + spin_unlock_irqrestore(esp->ehost->host_lock, flags); return SCSI_ABORT_BUSY; } @@ -1990,7 +1990,7 @@ if (don) ESP_INTSON(esp->dregs); - spin_unlock_irqrestore(&esp->ehost->host_lock, flags); + spin_unlock_irqrestore(esp->ehost->host_lock, flags); return SCSI_ABORT_SNOOZE; } @@ -2052,9 +2052,9 @@ struct esp *esp = (struct esp *) SCptr->host->hostdata; unsigned long flags; - spin_lock_irqsave(&esp->ehost->host_lock, flags); + spin_lock_irqsave(esp->ehost->host_lock, flags); (void) esp_do_resetbus(esp); - spin_unlock_irqrestore(&esp->ehost->host_lock, flags); + spin_unlock_irqrestore(esp->ehost->host_lock, flags); return SCSI_RESET_PENDING; } @@ -4321,7 +4321,7 @@ struct esp *esp = dev_id; unsigned long flags; - spin_lock_irqsave(&esp->ehost->host_lock, flags); + spin_lock_irqsave(esp->ehost->host_lock, flags); if (ESP_IRQ_P(esp->dregs)) { ESP_INTSOFF(esp->dregs); @@ -4331,7 +4331,7 @@ ESP_INTSON(esp->dregs); } - spin_unlock_irqrestore(&esp->ehost->host_lock, flags); + spin_unlock_irqrestore(esp->ehost->host_lock, flags); } int esp_revoke(Scsi_Device* SDptr) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/fdomain.c linux-2.5/drivers/scsi/fdomain.c --- linux-2.5.1/drivers/scsi/fdomain.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/fdomain.c Mon Jan 14 22:39:45 2002 @@ -78,7 +78,7 @@ Please note that the drive ordering that Future Domain implemented in BIOS versions 3.4 and 3.5 is the opposite of the order (currently) used by the rest of the SCSI industry. If you have BIOS version 3.4 or 3.5, and have - more then one drive, then the drive ordering will be the reverse of that + more than one drive, then the drive ordering will be the reverse of that which you see under DOS. For example, under DOS SCSI ID 0 will be D: and SCSI ID 1 will be C: (the boot device). Under Linux, SCSI ID 0 will be /dev/sda and SCSI ID 1 will be /dev/sdb. The Linux ordering is consistent @@ -382,22 +382,23 @@ Write_FIFO = 12 }; -static int port_base = 0; -static unsigned long bios_base = 0; -static int bios_major = 0; -static int bios_minor = 0; -static int PCI_bus = 0; -static int Quantum = 0; /* Quantum board variant */ -static int interrupt_level = 0; -static volatile int in_command = 0; -static Scsi_Cmnd *current_SC = NULL; +/* .bss will zero all the static variables below */ +static int port_base; +static unsigned long bios_base; +static int bios_major; +static int bios_minor; +static int PCI_bus; +static int Quantum; /* Quantum board variant */ +static int interrupt_level; +static volatile int in_command; +static Scsi_Cmnd *current_SC; static enum chip_type chip = unknown; -static int adapter_mask = 0; -static int this_id = 0; -static int setup_called = 0; +static int adapter_mask; +static int this_id; +static int setup_called; #if DEBUG_RACE -static volatile int in_interrupt_flag = 0; +static volatile int in_interrupt_flag; #endif static int SCSI_Mode_Cntl_port; @@ -729,13 +730,13 @@ switch (Quantum) { case 2: /* ISA_200S */ case 3: /* ISA_250MG */ - base = readb(bios_base + 0x1fa2) + (readb(bios_base + 0x1fa3) << 8); + base = isa_readb(bios_base + 0x1fa2) + (isa_readb(bios_base + 0x1fa3) << 8); break; case 4: /* ISA_200S (another one) */ - base = readb(bios_base + 0x1fa3) + (readb(bios_base + 0x1fa4) << 8); + base = isa_readb(bios_base + 0x1fa3) + (isa_readb(bios_base + 0x1fa4) << 8); break; default: - base = readb(bios_base + 0x1fcc) + (readb(bios_base + 0x1fcd) << 8); + base = isa_readb(bios_base + 0x1fcc) + (isa_readb(bios_base + 0x1fcd) << 8); break; } @@ -983,7 +984,7 @@ /* Register the IRQ with the kernel */ retcode = request_irq( interrupt_level, - do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", NULL); + do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", shpnt); if (retcode < 0) { if (retcode == -EINVAL) { @@ -1265,9 +1266,9 @@ #if EVERY_ACCESS printk( " AFAIL " ); #endif - spin_lock_irqsave(&io_request_lock, flags); + spin_lock_irqsave(current_SC->host->host_lock, flags); my_done( DID_BUS_BUSY << 16 ); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irqrestore(current_SC->host->host_lock, flags); return; } current_SC->SCp.phase = in_selection; @@ -1291,9 +1292,9 @@ #if EVERY_ACCESS printk( " SFAIL " ); #endif - spin_lock_irqsave(&io_request_lock, flags); + spin_lock_irqsave(current_SC->host->host_lock, flags); my_done( DID_NO_CONNECT << 16 ); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irqrestore(current_SC->host->host_lock, flags); return; } else { #if EVERY_ACCESS @@ -1638,10 +1639,10 @@ #if EVERY_ACCESS printk( "BEFORE MY_DONE. . ." ); #endif - spin_lock_irqsave(&io_request_lock, flags); + spin_lock_irqsave(current_SC->host->host_lock, flags); my_done( (current_SC->SCp.Status & 0xff) | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) ); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irqrestore(current_SC->host->host_lock, flags); #if EVERY_ACCESS printk( "RETURNING.\n" ); #endif @@ -1932,11 +1933,11 @@ 0x0a bytes long. Heads are one less than we need to report. */ - if (MAJOR(dev) != SCSI_DISK0_MAJOR) { + if (major(dev) != SCSI_DISK0_MAJOR) { printk("scsi: <fdomain> fdomain_16x0_biosparam: too many disks"); return 0; } - drive = MINOR(dev) >> 4; + drive = minor(dev) >> 4; if (bios_major == 2) { switch (Quantum) { @@ -1955,7 +1956,7 @@ offset = bios_base + 0x1f31 + drive * 25; break; } - memcpy_fromio( &i, offset, sizeof( struct drive_info ) ); + isa_memcpy_fromio( &i, offset, sizeof( struct drive_info ) ); info_array[0] = i.heads; info_array[1] = i.sectors; info_array[2] = i.cylinders; @@ -2033,6 +2034,15 @@ } return 0; +} + +int fdomain_16x0_release(struct Scsi_Host *shpnt) +{ + if (shpnt->irq) + free_irq(shpnt->irq, shpnt); + if (shpnt->io_port && shpnt->n_io_port) + release_region(shpnt->io_port, shpnt->n_io_port); + } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/fdomain.h linux-2.5/drivers/scsi/fdomain.h --- linux-2.5.1/drivers/scsi/fdomain.h Fri Nov 12 00:57:30 1999 +++ linux-2.5/drivers/scsi/fdomain.h Thu Dec 13 16:32:36 2001 @@ -34,6 +34,7 @@ int fdomain_16x0_biosparam( Disk *, kdev_t, int * ); int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset, int length, int hostno, int inout ); +int fdomain_16x0_release( struct Scsi_Host *shpnt ); #define FDOMAIN_16X0 { proc_info: fdomain_16x0_proc_info, \ detect: fdomain_16x0_detect, \ @@ -43,6 +44,7 @@ abort: fdomain_16x0_abort, \ reset: fdomain_16x0_reset, \ bios_param: fdomain_16x0_biosparam, \ + release: fdomain_16x0_release, \ can_queue: 1, \ this_id: 6, \ sg_tablesize: 64, \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/g_NCR5380.c linux-2.5/drivers/scsi/g_NCR5380.c --- linux-2.5.1/drivers/scsi/g_NCR5380.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/g_NCR5380.c Tue Dec 18 15:31:05 2001 @@ -77,7 +77,7 @@ * IRQ line if overridden on the command line. * */ - + /* * $Log: generic_NCR5380.c,v $ */ @@ -124,787 +124,772 @@ #include <linux/isapnp.h> #define NCR_NOT_SET 0 -static int ncr_irq=NCR_NOT_SET; -static int ncr_dma=NCR_NOT_SET; -static int ncr_addr=NCR_NOT_SET; -static int ncr_5380=NCR_NOT_SET; -static int ncr_53c400=NCR_NOT_SET; -static int ncr_53c400a=NCR_NOT_SET; -static int dtc_3181e=NCR_NOT_SET; +static int ncr_irq = NCR_NOT_SET; +static int ncr_dma = NCR_NOT_SET; +static int ncr_addr = NCR_NOT_SET; +static int ncr_5380 = NCR_NOT_SET; +static int ncr_53c400 = NCR_NOT_SET; +static int ncr_53c400a = NCR_NOT_SET; +static int dtc_3181e = NCR_NOT_SET; static struct override { NCR5380_implementation_fields; - int irq; - int dma; - int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ -} overrides -#ifdef GENERIC_NCR5380_OVERRIDE - [] __initdata = GENERIC_NCR5380_OVERRIDE; + int irq; + int dma; + int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ +} overrides +#ifdef GENERIC_NCR5380_OVERRIDE +[] __initdata = GENERIC_NCR5380_OVERRIDE; #else - [1] __initdata = {{0,},}; +[1] __initdata = { { 0,},}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) -/* - * Function : static internal_setup(int board, char *str, int *ints) +/** + * internal_setup - handle lilo command string override + * @board: BOARD_* identifier for the board + * @str: unused + * @ints: numeric parameters * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : board - either BOARD_NCR5380 for a normal NCR5380 board, - * or BOARD_NCR53C400 for a NCR53C400 board. str - unused, ints - - * array of integer parameters with ints[0] equal to the number of ints. + * Do LILO command line initialization of the overrides array. Display + * errors when needed * + * Locks: none */ -static void __init internal_setup(int board, char *str, int *ints){ - static int commandline_current = 0; - switch (board) { - case BOARD_NCR5380: - if (ints[0] != 2 && ints[0] != 3) { - printk("generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); - return; - } - break; - case BOARD_NCR53C400: - if (ints[0] != 2) { - printk("generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - case BOARD_NCR53C400A: - if (ints[0] != 2) { - printk("generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - case BOARD_DTC3181E: - if (ints[0] != 2) { - printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - } - - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type)ints[1]; - overrides[commandline_current].irq = ints[2]; - if (ints[0] == 3) - overrides[commandline_current].dma = ints[3]; - else - overrides[commandline_current].dma = DMA_NONE; - overrides[commandline_current].board = board; - ++commandline_current; - } +static void __init internal_setup(int board, char *str, int *ints) +{ + static int commandline_current = 0; + switch (board) { + case BOARD_NCR5380: + if (ints[0] != 2 && ints[0] != 3) { + printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); + return; + } + break; + case BOARD_NCR53C400: + if (ints[0] != 2) { + printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + case BOARD_NCR53C400A: + if (ints[0] != 2) { + printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + case BOARD_DTC3181E: + if (ints[0] != 2) { + printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + } + + if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1]; + overrides[commandline_current].irq = ints[2]; + if (ints[0] == 3) + overrides[commandline_current].dma = ints[3]; + else + overrides[commandline_current].dma = DMA_NONE; + overrides[commandline_current].board = board; + ++commandline_current; + } } -/* - * Function : generic_NCR5380_setup (char *str, int *ints) +/** + * do_NCR53C80_setup - set up entry point + * @str: unused * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + * Setup function invoked at boot to parse the ncr5380= command + * line. */ -void __init generic_NCR5380_setup (char *str, int *ints){ - internal_setup (BOARD_NCR5380, str, ints); +static int __init do_NCR5380_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR5380, str, ints); + return 1; } -/* - * Function : generic_NCR53C400_setup (char *str, int *ints) +/** + * do_NCR53C400_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + * Setup function invoked at boot to parse the ncr53c400= command + * line. */ -void __init generic_NCR53C400_setup (char *str, int *ints){ - internal_setup (BOARD_NCR53C400, str, ints); +static int __init do_NCR53C400_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR53C400, str, ints); + return 1; } -/* - * Function : generic_NCR53C400A_setup (char *str, int *ints) +/** + * do_NCR53C400A_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + * Setup function invoked at boot to parse the ncr53c400a= command + * line. */ -void generic_NCR53C400A_setup (char *str, int *ints) { - internal_setup (BOARD_NCR53C400A, str, ints); +static int __init do_NCR53C400A_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR53C400A, str, ints); + return 1; } -/* - * Function : generic_DTC3181E_setup (char *str, int *ints) +/** + * do_DTC3181E_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + * Setup function invoked at boot to parse the dtc3181e= command + * line. */ -void generic_DTC3181E_setup (char *str, int *ints) { - internal_setup (BOARD_DTC3181E, str, ints); +static int __init do_DTC3181E_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_DTC3181E, str, ints); + return 1; } -/* - * Function : int generic_NCR5380_detect(Scsi_Host_Template * tpnt) +/** + * generic_NCR5380_detect - look for NCR5380 controllers + * @tpnt: the scsi template * - * Purpose : initializes generic NCR5380 driver based on the - * command line / compile time port and irq definitions. + * Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E + * and DTC436(ISAPnP) controllers. If overrides have been set we use + * them. * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. + * The caller supplied NCR5380_init function is invoked from here, before + * the interrupt line is taken. * + * Locks: none */ -int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){ - static int current_override = 0; - int count, i; - u_int *ports; - u_int ncr_53c400a_ports[] = {0x280, 0x290, 0x300, 0x310, 0x330, - 0x340, 0x348, 0x350, 0}; - u_int dtc_3181e_ports[] = {0x220, 0x240, 0x280, 0x2a0, 0x2c0, - 0x300, 0x320, 0x340, 0}; - int flags = 0; - struct Scsi_Host *instance; - - if (ncr_irq != NCR_NOT_SET) - overrides[0].irq=ncr_irq; - if (ncr_dma != NCR_NOT_SET) - overrides[0].dma=ncr_dma; - if (ncr_addr != NCR_NOT_SET) - overrides[0].NCR5380_map_name=(NCR5380_map_type)ncr_addr; - if (ncr_5380 != NCR_NOT_SET) - overrides[0].board=BOARD_NCR5380; - else if (ncr_53c400 != NCR_NOT_SET) - overrides[0].board=BOARD_NCR53C400; - else if (ncr_53c400a != NCR_NOT_SET) - overrides[0].board=BOARD_NCR53C400A; - else if (dtc_3181e != NCR_NOT_SET) - overrides[0].board=BOARD_DTC3181E; - - if (!current_override && isapnp_present()) { - struct pci_dev *dev = NULL; - count = 0; - while ((dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), dev))) { - if (count >= NO_OVERRIDES) - break; - if (!dev->active && dev->prepare(dev) < 0) { - printk(KERN_ERR "dtc436e probe: prepare failed\n"); - continue; - } - if (!(dev->resource[0].flags & IORESOURCE_IO)) - continue; - if (!dev->active && dev->activate(dev) < 0) { - printk(KERN_ERR "dtc436e probe: activate failed\n"); - continue; - } - if (dev->irq_resource[0].flags & IORESOURCE_IRQ) - overrides[count].irq=dev->irq_resource[0].start; - else - overrides[count].irq=IRQ_NONE; - if (dev->dma_resource[0].flags & IORESOURCE_DMA) - overrides[count].dma=dev->dma_resource[0].start; - else - overrides[count].dma=DMA_NONE; - overrides[count].NCR5380_map_name=(NCR5380_map_type)dev->resource[0].start; - overrides[count].board=BOARD_DTC3181E; - count++; - } - } - - tpnt->proc_name = "g_NCR5380"; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - if (!(overrides[current_override].NCR5380_map_name)) - continue; - - ports = 0; - switch (overrides[current_override].board) { - case BOARD_NCR5380: - flags = FLAG_NO_PSEUDO_DMA; - break; - case BOARD_NCR53C400: - flags = FLAG_NCR53C400; - break; - case BOARD_NCR53C400A: - flags = FLAG_NO_PSEUDO_DMA; - ports = ncr_53c400a_ports; - break; - case BOARD_DTC3181E: - flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E; - ports = dtc_3181e_ports; - break; +int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0; + int count, i; + unsigned int *ports; + static unsigned int __initdata ncr_53c400a_ports[] = { + 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 + }; + static unsigned int __initdata dtc_3181e_ports[] = { + 0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0 + }; + int flags = 0; + struct Scsi_Host *instance; + + if (ncr_irq != NCR_NOT_SET) + overrides[0].irq = ncr_irq; + if (ncr_dma != NCR_NOT_SET) + overrides[0].dma = ncr_dma; + if (ncr_addr != NCR_NOT_SET) + overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr; + if (ncr_5380 != NCR_NOT_SET) + overrides[0].board = BOARD_NCR5380; + else if (ncr_53c400 != NCR_NOT_SET) + overrides[0].board = BOARD_NCR53C400; + else if (ncr_53c400a != NCR_NOT_SET) + overrides[0].board = BOARD_NCR53C400A; + else if (dtc_3181e != NCR_NOT_SET) + overrides[0].board = BOARD_DTC3181E; + + if (!current_override && isapnp_present()) { + struct pci_dev *dev = NULL; + count = 0; + while ((dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) { + if (count >= NO_OVERRIDES) + break; + if (!dev->active && dev->prepare(dev) < 0) { + printk(KERN_ERR "dtc436e probe: prepare failed\n"); + continue; + } + if (!(dev->resource[0].flags & IORESOURCE_IO)) + continue; + if (!dev->active && dev->activate(dev) < 0) { + printk(KERN_ERR "dtc436e probe: activate failed\n"); + continue; + } + if (dev->irq_resource[0].flags & IORESOURCE_IRQ) + overrides[count].irq = dev->irq_resource[0].start; + else + overrides[count].irq = IRQ_NONE; + if (dev->dma_resource[0].flags & IORESOURCE_DMA) + overrides[count].dma = dev->dma_resource[0].start; + else + overrides[count].dma = DMA_NONE; + overrides[count].NCR5380_map_name = (NCR5380_map_type) dev->resource[0].start; + overrides[count].board = BOARD_DTC3181E; + count++; + } } + tpnt->proc_name = "g_NCR5380"; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) { + if (!(overrides[current_override].NCR5380_map_name)) + continue; + + ports = 0; + switch (overrides[current_override].board) { + case BOARD_NCR5380: + flags = FLAG_NO_PSEUDO_DMA; + break; + case BOARD_NCR53C400: + flags = FLAG_NCR53C400; + break; + case BOARD_NCR53C400A: + flags = FLAG_NO_PSEUDO_DMA; + ports = ncr_53c400a_ports; + break; + case BOARD_DTC3181E: + flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E; + ports = dtc_3181e_ports; + break; + } + #ifdef CONFIG_SCSI_G_NCR5380_PORT - if (ports) { - /* wakeup sequence for the NCR53C400A and DTC3181E*/ + if (ports) { + /* wakeup sequence for the NCR53C400A and DTC3181E */ - /* Disable the adapter and look for a free io port */ - outb(0x59, 0x779); - outb(0xb9, 0x379); - outb(0xc5, 0x379); - outb(0xae, 0x379); - outb(0xa6, 0x379); - outb(0x00, 0x379); - - if (overrides[current_override].NCR5380_map_name != PORT_AUTO) - for(i=0; ports[i]; i++) { - if (overrides[current_override].NCR5380_map_name == ports[i]) - break; - } - else - for(i=0; ports[i]; i++) { - if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff)) - break; - } - if (ports[i]) { - outb(0x59, 0x779); - outb(0xb9, 0x379); - outb(0xc5, 0x379); - outb(0xae, 0x379); - outb(0xa6, 0x379); - outb(0x80 | i, 0x379); /* set io port to be used */ - outb(0xc0, ports[i] + 9); - if (inb(ports[i] + 9) != 0x80) - continue; - else - overrides[current_override].NCR5380_map_name=ports[i]; - } else - continue; - } + /* Disable the adapter and look for a free io port */ + outb(0x59, 0x779); + outb(0xb9, 0x379); + outb(0xc5, 0x379); + outb(0xae, 0x379); + outb(0xa6, 0x379); + outb(0x00, 0x379); + + if (overrides[current_override].NCR5380_map_name != PORT_AUTO) + for (i = 0; ports[i]; i++) { + if (overrides[current_override].NCR5380_map_name == ports[i]) + break; + } else + for (i = 0; ports[i]; i++) { + if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff)) + break; + } + if (ports[i]) { + outb(0x59, 0x779); + outb(0xb9, 0x379); + outb(0xc5, 0x379); + outb(0xae, 0x379); + outb(0xa6, 0x379); + outb(0x80 | i, 0x379); /* set io port to be used */ + outb(0xc0, ports[i] + 9); + if (inb(ports[i] + 9) != 0x80) + continue; + else + overrides[current_override].NCR5380_map_name = ports[i]; + } else + continue; + } - request_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size, "ncr5380"); + request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); #else - if(check_mem_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size)) - continue; - request_mem_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size, "ncr5380"); + if (check_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size)) + continue; + request_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); #endif - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - { + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) { #ifdef CONFIG_SCSI_G_NCR5380_PORT - release_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size); + release_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size); #else - release_mem_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size); + release_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size); #endif - continue; - } - - instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; - - NCR5380_init(instance, flags); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, 0xffff); + continue; + } - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } + instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } + NCR5380_init(instance, flags); - printk("scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int)instance->NCR5380_instance_name); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; -} + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, 0xffff); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + } -const char * generic_NCR5380_info (struct Scsi_Host* host) { - static const char string[]="Generic NCR5380/53C400 Driver"; - return string; + printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); + + ++current_override; + ++count; + } + return count; +} + +/** + * generic_NCR5380_info - reporting string + * @host: NCR5380 to report on + * + * Report driver information for the NCR5380 + */ + +const char *generic_NCR5380_info(struct Scsi_Host *host) +{ + static const char string[] = "Generic NCR5380/53C400 Driver"; + return string; } -int generic_NCR5380_release_resources(struct Scsi_Host * instance) +/** + * generic_NCR5380_release_resources - free resources + * @instance: host adapter to clean up + * + * Free the generic interface resources from this adapter. + * + * Locks: none + */ + +int generic_NCR5380_release_resources(struct Scsi_Host *instance) { - NCR5380_local_declare(); - - NCR5380_setup(instance); + NCR5380_local_declare(); + NCR5380_setup(instance); #ifdef CONFIG_SCSI_G_NCR5380_PORT - release_region(instance->NCR5380_instance_name, NCR5380_region_size); + release_region(instance->NCR5380_instance_name, NCR5380_region_size); #else - release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); -#endif + release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); +#endif - if (instance->irq != IRQ_NONE) - free_irq(instance->irq, NULL); + if (instance->irq != IRQ_NONE) + free_irq(instance->irq, NULL); return 0; } #ifdef BIOSPARAM -/* - * Function : int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip) +/** + * generic_NCR5380_biosparam + * @disk: disk to compute geometry for + * @dev: device identifier for this disk + * @ip: sizes to fill in * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for - * the specified device / size. + * Generates a BIOS / DOS compatible H-C-S mapping for the specified + * device / size. * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} + * XXX Most SCSI boards use this mapping, I could be incorrect. Someone + * using hard disks on a trantor should verify that this mapping + * corresponds to that used by the BIOS / ASPI driver by running the linux + * fdisk program and matching the H_C_S coordinates to what DOS uses. * - * Returns : always 0 (success), initializes ip - * - */ - -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. + * Locks: none */ int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - return 0; + int size = disk->capacity; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + return 0; } #endif #if NCR53C400_PSEUDO_DMA -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, int len) -{ - int blocks = len / 128; - int start = 0; - int bl; -#ifdef CONFIG_SCSI_G_NCR5380_PORT - int i; -#endif - NCR5380_local_declare(); - - NCR5380_setup(instance); - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: About to read %d blocks for %d bytes\n", blocks, len); -#endif - - NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR); - NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); - while (1) { - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: %d blocks left\n", blocks); -#endif - - if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { -#if (NDEBUG & NDEBUG_C400_PREAD) - if (blocks) - printk("53C400r: blocks still == %d\n", blocks); - else - printk("53C400r: Exiting loop\n"); -#endif - break; - } - -#if 1 - if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { - printk("53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); - return -1; - } -#endif - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Waiting for buffer, bl=%d\n", bl); -#endif - - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Transferring 128 bytes\n"); -#endif +/** + * NCR5380_pread - pseudo DMA read + * @instance: adapter to read from + * @dst: buffer to read into + * @len: buffer length + * + * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * controller + */ + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + int blocks = len / 128; + int start = 0; + int bl; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR); + NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); + while (1) { + if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { + break; + } + if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { + printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); + return -1; + } + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY); #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - dst[start+i] = NCR5380_read(C400_HOST_BUFFER); + { + int i; + for (i = 0; i < 128; i++) + dst[start + i] = NCR5380_read(C400_HOST_BUFFER); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128); #endif - start+=128; - blocks--; - } - - if (blocks) { -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: EXTRA: Waiting for buffer\n"); -#endif - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; + start += 128; + blocks--; + } + + if (blocks) { + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + { + // FIXME - no timeout + } -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Transferring EXTRA 128 bytes\n"); -#endif #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - dst[start+i] = NCR5380_read(C400_HOST_BUFFER); + { + int i; + for (i = 0; i < 128; i++) + dst[start + i] = NCR5380_read(C400_HOST_BUFFER); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128); -#endif - start+=128; - blocks--; - } -#if (NDEBUG & NDEBUG_C400_PREAD) - else - printk("53C400r: No EXTRA required\n"); -#endif - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Final values: blocks=%d start=%d\n", blocks, start); -#endif - - if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) - printk("53C400r: no 53C80 gated irq after transfer"); -#if (NDEBUG & NDEBUG_C400_PREAD) - else - printk("53C400r: Got 53C80 interrupt and tried to clear it\n"); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128); #endif + start += 128; + blocks--; + } -/* DON'T DO THIS - THEY NEVER ARRIVE! - printk("53C400r: Waiting for 53C80 registers\n"); - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) - ; -*/ + if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) + printk("53C400r: no 53C80 gated irq after transfer"); - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) - printk("53C400r: no end dma signal\n"); -#if (NDEBUG & NDEBUG_C400_PREAD) - else - printk("53C400r: end dma as expected\n"); +#if 0 + /* + * DON'T DO THIS - THEY NEVER ARRIVE! + */ + printk("53C400r: Waiting for 53C80 registers\n"); + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) + ; #endif - - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - return 0; -} + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) + printk(KERN_ERR "53C400r: no end dma signal\n"); -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, int len) -{ - int blocks = len / 128; - int start = 0; - int i; - int bl; - NCR5380_local_declare(); - - NCR5380_setup(instance); - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: About to write %d blocks for %d bytes\n", blocks, len); -#endif - - NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); - NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); - while (1) { - if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { - printk("53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); - return -1; - } - - if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - if (blocks) - printk("53C400w: exiting loop, blocks still == %d\n", blocks); - else - printk("53C400w: exiting loop\n"); -#endif - break; - } + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + return 0; +} -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: %d blocks left\n", blocks); +/** + * NCR5380_write - pseudo DMA write + * @instance: adapter to read from + * @dst: buffer to read into + * @len: buffer length + * + * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * controller + */ - printk("53C400w: waiting for buffer, bl=%d\n", bl); -#endif - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + int blocks = len / 128; + int start = 0; + int bl; + int i; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); + NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); + while (1) { + if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { + printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); + return -1; + } -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: transferring 128 bytes\n"); -#endif + if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { + break; + } + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + ; // FIXME - timeout #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - NCR5380_write(C400_HOST_BUFFER, src[start+i]); + { + for (i = 0; i < 128; i++) + NCR5380_write(C400_HOST_BUFFER, src[start + i]); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128); #endif - start+=128; - blocks--; - } - if (blocks) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: EXTRA waiting for buffer\n"); -#endif - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; + start += 128; + blocks--; + } + if (blocks) { + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + ; // FIXME - no timeout -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: transferring EXTRA 128 bytes\n"); -#endif #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - NCR5380_write(C400_HOST_BUFFER, src[start+i]); + { + for (i = 0; i < 128; i++) + NCR5380_write(C400_HOST_BUFFER, src[start + i]); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128); -#endif - start+=128; - blocks--; - } -#if (NDEBUG & NDEBUG_C400_PWRITE) - else - printk("53C400w: No EXTRA required\n"); -#endif - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: Final values: blocks=%d start=%d\n", blocks, start); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128); #endif + start += 128; + blocks--; + } #if 0 - printk("53C400w: waiting for registers to be available\n"); - THEY NEVER DO! - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) - ; - printk("53C400w: Got em\n"); -#endif - - /* Let's wait for this instead - could be ugly */ - /* All documentation says to check for this. Maybe my hardware is too - * fast. Waiting for it seems to work fine! KLL - */ - while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) - ; - - /* - * I know. i is certainly != 0 here but the loop is new. See previous - * comment. - */ - if (i) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got 53C80 gated irq (last block)\n"); -#endif - if (!((i=NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER)) - printk("53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n",i); -#if (NDEBUG & NDEBUG_C400_PWRITE) - else - printk("53C400w: Got END OF DMA\n"); -#endif - } - else - printk("53C400w: no 53C80 gated irq after transfer (last block)\n"); + printk("53C400w: waiting for registers to be available\n"); + THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG); + printk("53C400w: Got em\n"); +#endif + + /* Let's wait for this instead - could be ugly */ + /* All documentation says to check for this. Maybe my hardware is too + * fast. Waiting for it seems to work fine! KLL + */ + while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) + ; // FIXME - no timeout + + /* + * I know. i is certainly != 0 here but the loop is new. See previous + * comment. + */ + if (i) { + if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER)) + printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i); + } else + printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n"); #if 0 - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) { - printk("53C400w: no end dma signal\n"); - } -#endif - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: waiting for last byte...\n"); -#endif - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) - ; - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got last byte.\n"); - printk("53C400w: pwrite exiting with status 0, whoopee!\n"); + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) { + printk(KERN_ERR "53C400w: no end dma signal\n"); + } #endif - return 0; + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) + ; // TIMEOUT + return 0; } -#endif /* PSEUDO_DMA */ +#endif /* PSEUDO_DMA */ +/* + * Include the NCR5380 core code that we build our driver around + */ + #include "NCR5380.c" #define PRINTP(x) len += sprintf(buffer+len, x) #define ANDP , -static int sprint_opcode(char* buffer, int len, int opcode) { - int start = len; - PRINTP("0x%02x " ANDP opcode); - return len-start; -} - -static int sprint_command (char* buffer, int len, unsigned char *command) { - int i,s,start=len; - len += sprint_opcode(buffer, len, command[0]); - for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - PRINTP("%02x " ANDP command[i]); - PRINTP("\n"); - return len-start; -} - -static int sprint_Scsi_Cmnd (char* buffer, int len, Scsi_Cmnd *cmd) { - int start = len; - PRINTP("host number %d destination target %d, lun %d\n" ANDP - cmd->host->host_no ANDP - cmd->target ANDP - cmd->lun); - PRINTP(" command = "); - len += sprint_command (buffer, len, cmd->cmnd); - return len-start; -} - -int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout) -{ - int len = 0; - NCR5380_local_declare(); - unsigned long flags; - unsigned char status; - int i; - struct Scsi_Host *scsi_ptr; - Scsi_Cmnd *ptr; - struct NCR5380_hostdata *hostdata; +static int sprint_opcode(char *buffer, int len, int opcode) +{ + int start = len; + PRINTP("0x%02x " ANDP opcode); + return len - start; +} + +static int sprint_command(char *buffer, int len, unsigned char *command) +{ + int i, s, start = len; + len += sprint_opcode(buffer, len, command[0]); + for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + PRINTP("%02x " ANDP command[i]); + PRINTP("\n"); + return len - start; +} + +/** + * sprintf_Scsi_Cmnd - print a scsi command + * @buffer: buffr to print into + * @len: buffer length + * @cmd: SCSI command block + * + * Print out the target and command data in hex + */ + +static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd) +{ + int start = len; + PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->host->host_no ANDP cmd->target ANDP cmd->lun); + PRINTP(" command = "); + len += sprint_command(buffer, len, cmd->cmnd); + return len - start; +} + +/** + * generic_NCR5380_proc_info - /proc for NCR5380 driver + * @buffer: buffer to print into + * @start: start position + * @offset: offset into buffer + * @len: length + * @hostno: instance to affect + * @inout: read/write + * + * Provide the procfs information for the 5380 controller. We fill + * this with useful debugging information including the commands + * being executed, disconnected command queue and the statistical + * data + * + * Locks: global cli/lock for queue walk + */ + +int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +{ + int len = 0; + NCR5380_local_declare(); + unsigned long flags; + unsigned char status; + int i; + struct Scsi_Host *scsi_ptr; + Scsi_Cmnd *ptr; + struct NCR5380_hostdata *hostdata; #ifdef NCR5380_STATS - Scsi_Device *dev; - extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; + Scsi_Device *dev; + extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); - for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next) - if (scsi_ptr->host_no == hostno) - break; - NCR5380_setup(scsi_ptr); - hostdata = (struct NCR5380_hostdata *)scsi_ptr->hostdata; - - PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name); - PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE); - PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE); + for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr = scsi_ptr->next) + if (scsi_ptr->host_no == hostno) + break; + NCR5380_setup(scsi_ptr); + hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata; + + PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name); + PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE); + PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE); #ifdef NCR53C400 - PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE); - PRINTP("NCR53C400 card%s detected\n" ANDP (((struct NCR5380_hostdata *)scsi_ptr->hostdata)->flags & FLAG_NCR53C400)?"":" not"); + PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE); + PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not"); # if NCR53C400_PSEUDO_DMA - PRINTP("NCR53C400 pseudo DMA used\n"); + PRINTP("NCR53C400 pseudo DMA used\n"); # endif #else - PRINTP("NO NCR53C400 driver extensions\n"); + PRINTP("NO NCR53C400 driver extensions\n"); #endif - PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name); - if (scsi_ptr->irq == IRQ_NONE) - PRINTP("no interrupt\n"); - else - PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq); + PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name); + if (scsi_ptr->irq == IRQ_NONE) + PRINTP("no interrupt\n"); + else + PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq); #ifdef NCR5380_STATS - if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue) - PRINTP("There are commands pending, transfer rates may be crud\n"); - if (hostdata->pendingr) - PRINTP(" %d pending reads" ANDP hostdata->pendingr); - if (hostdata->pendingw) - PRINTP(" %d pending writes" ANDP hostdata->pendingw); - if (hostdata->pendingr || hostdata->pendingw) - PRINTP("\n"); - for (dev = scsi_ptr->host_queue; dev; dev=dev->next) { - unsigned long br = hostdata->bytes_read[dev->id]; - unsigned long bw = hostdata->bytes_write[dev->id]; - long tr = hostdata->time_read[dev->id] / HZ; - long tw = hostdata->time_write[dev->id] / HZ; - - PRINTP(" T:%d %s " ANDP dev->id ANDP (dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int)dev->type] : "Unknown"); - for (i=0; i<8; i++) - if (dev->vendor[i] >= 0x20) - *(buffer+(len++)) = dev->vendor[i]; - *(buffer+(len++)) = ' '; - for (i=0; i<16; i++) - if (dev->model[i] >= 0x20) - *(buffer+(len++)) = dev->model[i]; - *(buffer+(len++)) = ' '; - for (i=0; i<4; i++) - if (dev->rev[i] >= 0x20) - *(buffer+(len++)) = dev->rev[i]; - *(buffer+(len++)) = ' '; - - PRINTP("\n%10ld kb read in %5ld secs" ANDP br/1024 ANDP tr); - if (tr) - PRINTP(" @ %5ld bps" ANDP br / tr); - - PRINTP("\n%10ld kb written in %5ld secs" ANDP bw/1024 ANDP tw); - if (tw) - PRINTP(" @ %5ld bps" ANDP bw / tw); - PRINTP("\n"); - } -#endif - - status = NCR5380_read(STATUS_REG); - if (!(status & SR_REQ)) - PRINTP("REQ not asserted, phase unknown.\n"); - else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i) - ; - PRINTP("Phase %s\n" ANDP phases[i].name); - } - - if (!hostdata->connected) { - PRINTP("No currently connected command\n"); - } else { - len += sprint_Scsi_Cmnd (buffer, len, (Scsi_Cmnd *) hostdata->connected); - } - - PRINTP("issue_queue\n"); - - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) - len += sprint_Scsi_Cmnd (buffer, len, ptr); - - PRINTP("disconnected_queue\n"); - - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) - len += sprint_Scsi_Cmnd (buffer, len, ptr); - - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; - restore_flags(flags); - return len; + if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue) + PRINTP("There are commands pending, transfer rates may be crud\n"); + if (hostdata->pendingr) + PRINTP(" %d pending reads" ANDP hostdata->pendingr); + if (hostdata->pendingw) + PRINTP(" %d pending writes" ANDP hostdata->pendingw); + if (hostdata->pendingr || hostdata->pendingw) + PRINTP("\n"); + for (dev = scsi_ptr->host_queue; dev; dev = dev->next) { + unsigned long br = hostdata->bytes_read[dev->id]; + unsigned long bw = hostdata->bytes_write[dev->id]; + long tr = hostdata->time_read[dev->id] / HZ; + long tw = hostdata->time_write[dev->id] / HZ; + + PRINTP(" T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown"); + for (i = 0; i < 8; i++) + if (dev->vendor[i] >= 0x20) + *(buffer + (len++)) = dev->vendor[i]; + *(buffer + (len++)) = ' '; + for (i = 0; i < 16; i++) + if (dev->model[i] >= 0x20) + *(buffer + (len++)) = dev->model[i]; + *(buffer + (len++)) = ' '; + for (i = 0; i < 4; i++) + if (dev->rev[i] >= 0x20) + *(buffer + (len++)) = dev->rev[i]; + *(buffer + (len++)) = ' '; + + PRINTP("\n%10ld kb read in %5ld secs" ANDP br / 1024 ANDP tr); + if (tr) + PRINTP(" @ %5ld bps" ANDP br / tr); + + PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw); + if (tw) + PRINTP(" @ %5ld bps" ANDP bw / tw); + PRINTP("\n"); + } +#endif + + status = NCR5380_read(STATUS_REG); + if (!(status & SR_REQ)) + PRINTP("REQ not asserted, phase unknown.\n"); + else { + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); + PRINTP("Phase %s\n" ANDP phases[i].name); + } + + if (!hostdata->connected) { + PRINTP("No currently connected command\n"); + } else { + len += sprint_Scsi_Cmnd(buffer, len, (Scsi_Cmnd *) hostdata->connected); + } + + PRINTP("issue_queue\n"); + + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + len += sprint_Scsi_Cmnd(buffer, len, ptr); + + PRINTP("disconnected_queue\n"); + + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + len += sprint_Scsi_Cmnd(buffer, len, ptr); + + *start = buffer + offset; + len -= offset; + if (len > length) + len = length; + restore_flags(flags); + return len; } #undef PRINTP #undef ANDP -/* Eventually this will go into an include file, but this will be later */ +/* + * Eventually this will go into an include file, but this will be later + */ static Scsi_Host_Template driver_template = GENERIC_NCR5380; #include <linux/module.h> #include "scsi_module.c" -#ifdef MODULE - MODULE_PARM(ncr_irq, "i"); MODULE_PARM(ncr_dma, "i"); MODULE_PARM(ncr_addr, "i"); @@ -913,65 +898,20 @@ MODULE_PARM(ncr_53c400a, "i"); MODULE_PARM(dtc_3181e, "i"); MODULE_LICENSE("GPL"); -#else - -static int __init do_NCR5380_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_NCR5380_setup(str,ints); - - return 1; -} - -static int __init do_NCR53C400_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_NCR53C400_setup(str,ints); - return 1; -} - -static int __init do_NCR53C400A_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_NCR53C400A_setup(str,ints); - - return 1; -} - -static int __init do_DTC3181E_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_DTC3181E_setup(str,ints); - - return 1; -} - -__setup("ncr5380=", do_NCR5380_setup); -__setup("ncr53c400=", do_NCR53C400_setup); -__setup("ncr53c400a=", do_NCR53C400A_setup); -__setup("dtc3181e=", do_DTC3181E_setup); static struct isapnp_device_id id_table[] __devinitdata = { { - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), - 0 - }, + ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), + 0}, {0} }; MODULE_DEVICE_TABLE(isapnp, id_table); -MODULE_LICENSE("GPL"); -#endif - +__setup("ncr5380=", do_NCR5380_setup); +__setup("ncr53c400=", do_NCR53C400_setup); +__setup("ncr53c400a=", do_NCR53C400A_setup); +__setup("dtc3181e=", do_DTC3181E_setup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/g_NCR5380.h linux-2.5/drivers/scsi/g_NCR5380.h --- linux-2.5.1/drivers/scsi/g_NCR5380.h Fri Jul 20 04:08:20 2001 +++ linux-2.5/drivers/scsi/g_NCR5380.h Mon Jan 7 21:49:49 2002 @@ -43,24 +43,18 @@ #define NCR5380_BIOSPARAM NULL #endif -#ifndef ASM int generic_NCR5380_abort(Scsi_Cmnd *); int generic_NCR5380_detect(Scsi_Host_Template *); int generic_NCR5380_release_resources(struct Scsi_Host *); -int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int generic_NCR5380_reset(Scsi_Cmnd *, unsigned int); -int notyet_generic_proc_info (char *buffer ,char **start, off_t offset, - int length, int hostno, int inout); -const char* generic_NCR5380_info(struct Scsi_Host *); +int notyet_generic_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); +const char *generic_NCR5380_info(struct Scsi_Host *); #ifdef BIOSPARAM int generic_NCR5380_biosparam(Disk *, kdev_t, int *); #endif -int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout); - -#ifndef NULL -#define NULL 0 -#endif +int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); #ifndef CMD_PER_LUN #define CMD_PER_LUN 2 @@ -92,19 +86,15 @@ #define STRVAL(x) __STRVAL(x) #ifdef CONFIG_SCSI_G_NCR5380_PORT - #define NCR5380_map_config port - #define NCR5380_map_type int - #define NCR5380_map_name port - #define NCR5380_instance_name io_port - #define NCR53C400_register_offset 0 - #define NCR53C400_address_adjust 8 - +/* + * FIXME: size should be runtime decided + */ #ifdef NCR53C400 #define NCR5380_region_size 16 #else @@ -114,28 +104,19 @@ #define NCR5380_read(reg) (inb(NCR5380_map_name + (reg))) #define NCR5380_write(reg, value) (outb((value), (NCR5380_map_name + (reg)))) -#else +#else /* therefore CONFIG_SCSI_G_NCR5380_MEM */ #define NCR5380_map_config memory - #define NCR5380_map_type unsigned long - #define NCR5380_map_name base - #define NCR5380_instance_name base - #define NCR53C400_register_offset 0x108 - #define NCR53C400_address_adjust 0 - #define NCR53C400_mem_base 0x3880 - #define NCR53C400_host_buffer 0x3900 - #define NCR5380_region_size 0x3a00 - #define NCR5380_read(reg) isa_readb(NCR5380_map_name + NCR53C400_mem_base + (reg)) #define NCR5380_write(reg, value) isa_writeb(NCR5380_map_name + NCR53C400_mem_base + (reg), value) @@ -164,7 +145,5 @@ #define BOARD_NCR53C400A 2 #define BOARD_DTC3181E 3 -#endif /* else def HOSTS_C */ -#endif /* ndef ASM */ -#endif /* GENERIC_NCR5380_H */ - +#endif /* else def HOSTS_C */ +#endif /* GENERIC_NCR5380_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/hosts.c linux-2.5/drivers/scsi/hosts.c --- linux-2.5.1/drivers/scsi/hosts.c Sun Dec 16 23:49:23 2001 +++ linux-2.5/drivers/scsi/hosts.c Sun Jan 6 19:17:51 2002 @@ -161,7 +161,8 @@ break; } } - spin_lock_init(&retval->host_lock); + spin_lock_init(&retval->default_lock); + scsi_assign_lock(retval, &retval->default_lock); atomic_set(&retval->host_active,0); retval->host_busy = 0; retval->host_failed = 0; @@ -268,15 +269,6 @@ } return retval; -} - -int -scsi_register_device(struct Scsi_Device_Template * sdpnt) -{ - if(sdpnt->next) panic("Device already registered"); - sdpnt->next = scsi_devicelist; - scsi_devicelist = sdpnt; - return 0; } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/hosts.h linux-2.5/drivers/scsi/hosts.h --- linux-2.5.1/drivers/scsi/hosts.h Sun Dec 16 23:46:45 2001 +++ linux-2.5/drivers/scsi/hosts.h Mon Jan 14 14:39:03 2002 @@ -312,7 +312,8 @@ struct Scsi_Host * next; Scsi_Device * host_queue; - spinlock_t host_lock; + spinlock_t default_lock; + spinlock_t *host_lock; struct task_struct * ehandler; /* Error recovery thread. */ struct semaphore * eh_wait; /* The error recovery thread waits on @@ -471,6 +472,11 @@ unsigned int scsi_init(void); extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j); extern void scsi_unregister(struct Scsi_Host * i); +static __inline__ void scsi_assign_lock(struct Scsi_Host *host, + spinlock_t *lock) +{ + host->host_lock = lock; +} extern void scsi_register_blocked_host(struct Scsi_Host * SHpnt); extern void scsi_deregister_blocked_host(struct Scsi_Host * SHpnt); @@ -521,17 +527,14 @@ void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt); -int scsi_register_device(struct Scsi_Device_Template * sdpnt); -/* These are used by loadable modules */ -extern int scsi_register_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 -#define MODULE_SCSI_CONST 2 -#define MODULE_SCSI_IOCTL 3 -#define MODULE_SCSI_DEV 4 +/* + * Driver registration/unregistration. + */ +extern int scsi_register_device(struct Scsi_Device_Template *); +extern int scsi_unregister_device(struct Scsi_Device_Template *); +extern int scsi_register_host(Scsi_Host_Template *); +extern int scsi_unregister_host(Scsi_Host_Template *); /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/i60uscsi.c linux-2.5/drivers/scsi/i60uscsi.c --- linux-2.5.1/drivers/scsi/i60uscsi.c Fri Nov 9 22:05:06 2001 +++ linux-2.5/drivers/scsi/i60uscsi.c Mon Jan 14 22:39:45 2002 @@ -640,7 +640,6 @@ ULONG idx; UCHAR index; UCHAR i; - ULONG flags; Ch = hcsp->HCS_Index; for (i = 0; i < 8; i++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/ide-scsi.c linux-2.5/drivers/scsi/ide-scsi.c --- linux-2.5.1/drivers/scsi/ide-scsi.c Tue Dec 11 17:44:13 2001 +++ linux-2.5/drivers/scsi/ide-scsi.c Sun Jan 6 19:17:51 2002 @@ -50,7 +50,6 @@ #include "scsi.h" #include "hosts.h" #include "sd.h" -#include "ide-scsi.h" #include <scsi/sg.h> #define IDESCSI_DEBUG_LOG 0 @@ -293,9 +292,9 @@ } } host = pc->scsi_cmd->host; - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); pc->done(pc->scsi_cmd); - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); idescsi_free_bio (rq->bio); kfree(pc); kfree(rq); scsi->pc = NULL; @@ -748,7 +747,7 @@ { idescsi_scsi_t *scsi = drive->driver_data; - if (MAJOR(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR) + if (major(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR) return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); return test_bit(IDESCSI_TRANSFORM, &scsi->transform); } @@ -806,9 +805,9 @@ rq->special = (char *) pc; rq->bio = idescsi_dma_bio (drive, pc); rq->flags = REQ_SPECIAL; - spin_unlock(&cmd->host->host_lock); + spin_unlock(cmd->host->host_lock); (void) ide_do_drive_cmd (drive, rq, ide_end); - spin_lock_irq(&cmd->host->host_lock); + spin_lock_irq(cmd->host->host_lock); return 0; abort: if (pc) kfree (pc); @@ -840,13 +839,29 @@ return 0; } -static Scsi_Host_Template idescsi_template = IDESCSI; +static Scsi_Host_Template idescsi_template = { + module: THIS_MODULE, + name: "idescsi", + detect: idescsi_detect, + release: idescsi_release, + info: idescsi_info, + ioctl: idescsi_ioctl, + queuecommand: idescsi_queue, + abort: idescsi_abort, + reset: idescsi_reset, + bios_param: idescsi_bios, + can_queue: 10, + this_id: -1, + sg_tablesize: 256, + cmd_per_lun: 5, + use_clustering: DISABLE_CLUSTERING, + emulated: 1, +}; static int __init init_idescsi_module(void) { idescsi_init(); - idescsi_template.module = THIS_MODULE; - scsi_register_module (MODULE_SCSI_HA, &idescsi_template); + scsi_register_host(&idescsi_template); return 0; } @@ -856,7 +871,7 @@ byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255}; int i, failed; - scsi_unregister_module (MODULE_SCSI_HA, &idescsi_template); + scsi_unregister_host(&idescsi_template); for (i = 0; media[i] != 255; i++) { failed = 0; while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/ide-scsi.h linux-2.5/drivers/scsi/ide-scsi.h --- linux-2.5.1/drivers/scsi/ide-scsi.h Fri Apr 10 22:22:21 1998 +++ linux-2.5/drivers/scsi/ide-scsi.h Thu Jan 1 00:00:00 1970 @@ -1,37 +0,0 @@ -/* - * linux/drivers/scsi/ide-scsi.h - * - * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il> - */ - -#ifndef IDESCSI_H -#define IDESCSI_H - -extern int idescsi_detect (Scsi_Host_Template *host_template); -extern int idescsi_release (struct Scsi_Host *host); -extern const char *idescsi_info (struct Scsi_Host *host); -extern int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg); -extern int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); -extern int idescsi_abort (Scsi_Cmnd *cmd); -extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags); -extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm); - -#define IDESCSI { \ - name: "idescsi", /* name */ \ - detect: idescsi_detect, /* detect */ \ - release: idescsi_release, /* release */ \ - info: idescsi_info, /* info */ \ - ioctl: idescsi_ioctl, /* ioctl */ \ - queuecommand: idescsi_queue, /* queuecommand */ \ - abort: idescsi_abort, /* abort */ \ - reset: idescsi_reset, /* reset */ \ - bios_param: idescsi_bios, /* bios_param */ \ - can_queue: 10, /* can_queue */ \ - this_id: -1, /* this_id */ \ - sg_tablesize: 256, /* sg_tablesize */ \ - cmd_per_lun: 5, /* cmd_per_lun */ \ - use_clustering: DISABLE_CLUSTERING, /* clustering */ \ - emulated: 1 /* emulated */ \ -} - -#endif /* IDESCSI_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/imm.c linux-2.5/drivers/scsi/imm.c --- linux-2.5.1/drivers/scsi/imm.c Sun Dec 9 04:02:47 2001 +++ linux-2.5/drivers/scsi/imm.c Sun Jan 6 19:17:51 2002 @@ -940,10 +940,10 @@ if (cmd->SCp.phase > 0) imm_pb_release(cmd->host->unique_id); - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); tmp->cur_cmd = 0; cmd->scsi_done(cmd); - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); return; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/in2000.c linux-2.5/drivers/scsi/in2000.c --- linux-2.5.1/drivers/scsi/in2000.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/in2000.c Thu Jan 3 23:04:39 2002 @@ -855,7 +855,7 @@ /* Get the spin_lock and disable further ints, for SMP */ - CLISPIN_LOCK(flags); + CLISPIN_LOCK(instance, flags); #ifdef PROC_STATISTICS hostdata->int_cnt++; @@ -993,7 +993,7 @@ write1_io(0, IO_LED_OFF); /* release the SMP spin_lock and restore irq state */ - CLISPIN_UNLOCK(flags); + CLISPIN_UNLOCK(instance, flags); return; } @@ -1011,7 +1011,7 @@ write1_io(0, IO_LED_OFF); /* release the SMP spin_lock and restore irq state */ - CLISPIN_UNLOCK(flags); + CLISPIN_UNLOCK(instance, flags); return; } @@ -1433,7 +1433,7 @@ hostdata->state = S_UNCONNECTED; /* release the SMP spin_lock and restore irq state */ - CLISPIN_UNLOCK(flags); + CLISPIN_UNLOCK(instance, flags); return; } DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid)) @@ -1609,7 +1609,7 @@ DB(DB_INTR,printk("} ")) /* release the SMP spin_lock and restore irq state */ - CLISPIN_UNLOCK(flags); + CLISPIN_UNLOCK(instance, flags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/in2000.h linux-2.5/drivers/scsi/in2000.h --- linux-2.5.1/drivers/scsi/in2000.h Wed Nov 28 18:22:27 2001 +++ linux-2.5/drivers/scsi/in2000.h Mon Jan 7 21:49:46 2002 @@ -393,8 +393,9 @@ # define in2000__INITFUNC(function) __initfunc(function) # define in2000__INIT __init # define in2000__INITDATA __initdata -# define CLISPIN_LOCK(flags) spin_lock_irqsave(&io_request_lock, flags) -# define CLISPIN_UNLOCK(flags) spin_unlock_irqrestore(&io_request_lock, flags) +# define CLISPIN_LOCK(host,flags) spin_lock_irqsave(host->host_lock, flags) +# define CLISPIN_UNLOCK(host,flags) spin_unlock_irqrestore(host->host_lock, \ + flags) int in2000_detect(Scsi_Host_Template *) in2000__INIT; int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/ips.c linux-2.5/drivers/scsi/ips.c --- linux-2.5.1/drivers/scsi/ips.c Fri Nov 9 22:05:06 2001 +++ linux-2.5/drivers/scsi/ips.c Sun Jan 6 19:17:51 2002 @@ -1769,14 +1769,13 @@ char *kern_area; u_int32_t datasize; - /* free io_request_lock */ - spin_unlock_irq(&io_request_lock); + spin_unlock_irq(SC->host->host_lock); /* wait for the command to finish */ down(&ha->ioctl_sem); /* reobtain the lock */ - spin_lock_irq(&io_request_lock); + spin_lock_irq(SC->host->host_lock); /* command finished -- copy back */ user_area = *((char **) &SC->cmnd[4]); @@ -1911,31 +1910,30 @@ /****************************************************************************/ void do_ipsintr(int irq, void *dev_id, struct pt_regs *regs) { - ips_ha_t *ha; + ips_ha_t *ha = (ips_ha_t *) dev_id; unsigned long cpu_flags; + struct Scsi_Host *host = ips_sh[ha->host_num]; METHOD_TRACE("do_ipsintr", 2); - ha = (ips_ha_t *) dev_id; - - spin_lock_irqsave(&io_request_lock, cpu_flags); + spin_lock_irqsave(host->host_lock, cpu_flags); if (test_and_set_bit(IPS_IN_INTR, &ha->flags)) { - spin_unlock_irqrestore(&io_request_lock, cpu_flags); + spin_unlock_irqrestore(host->host_lock, cpu_flags); return ; } if (!ha) { clear_bit(IPS_IN_INTR, &ha->flags); - spin_unlock_irqrestore(&io_request_lock, cpu_flags); + spin_unlock_irqrestore(host->host_lock, cpu_flags); return; } if (!ha->active) { clear_bit(IPS_IN_INTR, &ha->flags); - spin_unlock_irqrestore(&io_request_lock, cpu_flags); + spin_unlock_irqrestore(host->host_lock, cpu_flags); return; } @@ -1944,10 +1942,11 @@ clear_bit(IPS_IN_INTR, &ha->flags); - spin_unlock_irqrestore(&io_request_lock, cpu_flags); + spin_unlock_irqrestore(host->host_lock, cpu_flags); /* start the next command */ ips_next(ha, IPS_INTR_ON); + return; } /****************************************************************************/ @@ -2487,8 +2486,8 @@ task.routine = ips_scheduled_flash_bios; task.data = (void *) &flash_data; - /* Unlock the master lock */ - spin_unlock_irq(&io_request_lock); + /* Unlock the per-board lock */ + spin_unlock_irq(SC->host->host_lock); queue_task(&task, &tq_immediate); mark_bh(IMMEDIATE_BH); @@ -2496,8 +2495,8 @@ /* Wait for the flash to complete */ down(&ha->flash_ioctl_sem); - /* Obtain the master lock */ - spin_lock_irq(&io_request_lock); + /* Obtain the per-board lock */ + spin_lock_irq(SC->host->host_lock); return (flash_data.retcode); } @@ -2604,8 +2603,8 @@ task.routine = ips_flash_bios_section; task.data = (void *) &flash_data; - /* Unlock the master lock */ - spin_unlock_irq(&io_request_lock); + /* Unlock the per-board lock */ + spin_unlock_irq(SC->host->host_lock); queue_task(&task, &tq_immediate); mark_bh(IMMEDIATE_BH); @@ -2613,8 +2612,8 @@ /* Wait for the flash to complete */ down(&ha->flash_ioctl_sem); - /* Obtain the master lock */ - spin_lock_irq(&io_request_lock); + /* Obtain the per-board lock */ + spin_lock_irq(SC->host->host_lock); return (flash_data.retcode); } @@ -3572,18 +3571,21 @@ int intr_status; unsigned long cpu_flags; unsigned long cpu_flags2; + struct Scsi_Host *host; METHOD_TRACE("ips_next", 1); if (!ha) return ; + host = ips_sh[ha->host_num]; + /* * Block access to the queue function so * this command won't time out */ if (intr == IPS_INTR_ON) { - spin_lock_irqsave(&io_request_lock, cpu_flags2); + spin_lock_irqsave(host->host_lock, cpu_flags2); intr_status = IPS_INTR_IORL; } else { intr_status = intr; @@ -3608,7 +3610,7 @@ } if (intr == IPS_INTR_ON) - spin_unlock_irqrestore(&io_request_lock, cpu_flags2); + spin_unlock_irqrestore(host->host_lock, cpu_flags2); #ifndef NO_IPS_CMDLINE /* @@ -6604,6 +6606,8 @@ clear_bit(IPS_IN_INTR, &ha->flags); } else if (intr == IPS_INTR_HAL) { + struct Scsi_Host *host = ips_sh[ha->host_num]; + if (ha->waitflag == FALSE) { /* * controller generated an interrupt to @@ -6621,7 +6625,7 @@ * We were called under the HA lock so we can assume that interrupts * are masked. */ - spin_lock(&io_request_lock); + spin_lock(host->host_lock); while (test_and_set_bit(IPS_IN_INTR, &ha->flags)) udelay(1000); @@ -6630,7 +6634,7 @@ clear_bit(IPS_IN_INTR, &ha->flags); - spin_unlock(&io_request_lock); + spin_unlock(host->host_lock); } udelay(1000); /* 1 milisecond */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/lasi700.c linux-2.5/drivers/scsi/lasi700.c --- linux-2.5.1/drivers/scsi/lasi700.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/scsi/lasi700.c Fri Jan 4 17:05:20 2002 @@ -136,7 +136,6 @@ lasi700_driver_callback(struct parisc_device *dev) { unsigned long base = dev->hpa + LASI_SCSI_CORE_OFFSET; - int irq = busdevice_alloc_irq(dev); char *driver_name; struct Scsi_Host *host; struct NCR_700_Host_Parameters *hostdata = @@ -170,14 +169,15 @@ hostdata->chip710 = 1; hostdata->dmode_extra = DMODE_FC2; } + hostdata->pci_dev = ccio_get_fake(dev); if((host = NCR_700_detect(host_tpnt, hostdata)) == NULL) { kfree(hostdata); release_mem_region(host->base, 64); return 1; } - host->irq = irq; - if(request_irq(irq, NCR_700_intr, SA_SHIRQ, driver_name, host)) { - printk(KERN_ERR "%s: irq problem, detatching\n", + host->irq = dev->irq; + if(request_irq(dev->irq, NCR_700_intr, SA_SHIRQ, driver_name, host)) { + printk(KERN_ERR "%s: irq problem, detaching\n", driver_name); scsi_unregister(host); NCR_700_release(host); @@ -197,6 +197,7 @@ kfree(hostdata); free_irq(host->irq, host); release_mem_region(host->base, 64); + unregister_parisc_driver(&lasi700_driver); return 1; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/mac_scsi.c linux-2.5/drivers/scsi/mac_scsi.c --- linux-2.5.1/drivers/scsi/mac_scsi.c Sun Nov 12 03:01:11 2000 +++ linux-2.5/drivers/scsi/mac_scsi.c Sun Dec 30 20:01:41 2001 @@ -353,7 +353,7 @@ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; ) + for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); ) barrier(); /* switch on SCSI IRQ again */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/megaraid.c linux-2.5/drivers/scsi/megaraid.c --- linux-2.5.1/drivers/scsi/megaraid.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/drivers/scsi/megaraid.c Tue Jan 8 00:00:54 2002 @@ -586,10 +586,10 @@ #define DRIVER_LOCK(p) #define DRIVER_UNLOCK(p) #define IO_LOCK_T unsigned long io_flags = 0 -#define IO_LOCK(host) spin_lock_irqsave(&(host)->host_lock,io_flags) -#define IO_UNLOCK(host) spin_unlock_irqrestore(&(host)->host_lock,io_flags) -#define IO_LOCK_IRQ(host) spin_lock_irq(&(host)->host_lock) -#define IO_UNLOCK_IRQ(host) spin_unlock_irq(&(host)->host_lock) +#define IO_LOCK(host) spin_lock_irqsave((host)->host_lock,io_flags) +#define IO_UNLOCK(host) spin_unlock_irqrestore((host)->host_lock,io_flags) +#define IO_LOCK_IRQ(host) spin_lock_irq((host)->host_lock) +#define IO_UNLOCK_IRQ(host) spin_unlock_irq((host)->host_lock) #define queue_task_irq(a,b) queue_task(a,b) #define queue_task_irq_off(a,b) queue_task(a,b) @@ -4290,26 +4290,18 @@ static int mega_partsize(Disk * disk, kdev_t dev, int *geom) { - struct buffer_head *bh; struct partition *p, *largest = NULL; int i, largest_cyl; int heads, cyls, sectors; int capacity = disk->capacity; + unsigned char *buf; - int ma = MAJOR(dev); - int mi = (MINOR(dev) & ~0xf); - - int block = 1024; - - if(blksize_size[ma]) - block = blksize_size[ma][mi]; - - if(!(bh = bread(MKDEV(ma,mi), 0, block))) + if (!(buf = scsi_bios_ptable(dev))) return -1; - if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) { + if( *(unsigned short *)(buf + 64) == 0xAA55 ) { - for( largest_cyl = -1, p = (struct partition *)(0x1BE + bh->b_data), + for( largest_cyl = -1, p = (struct partition *)buf, i = 0; i < 4; ++i, ++p) { if (!p->sys_ind) continue; @@ -4328,7 +4320,7 @@ sectors = largest->end_sector & 0x3f; if (heads == 0 || sectors == 0) { - brelse(bh); + kfree(buf); return -1; } @@ -4338,11 +4330,11 @@ geom[1] = sectors; geom[2] = cyls; - brelse(bh); + kfree(buf); return 0; } - brelse(bh); + kfree(buf); return -1; } @@ -4541,7 +4533,6 @@ unsigned int cmd, unsigned long arg) { int adapno; - kdev_t dev; u32 inlen; struct uioctl_t ioc; char *kvaddr = NULL; @@ -4565,7 +4556,7 @@ #endif IO_LOCK_T; - if (!inode || !(dev = inode->i_rdev)) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; if (_IOC_TYPE (cmd) != MEGAIOC_MAGIC) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/mesh.c linux-2.5/drivers/scsi/mesh.c --- linux-2.5.1/drivers/scsi/mesh.c Tue Sep 18 21:23:14 2001 +++ linux-2.5/drivers/scsi/mesh.c Thu Jan 10 22:41:07 2002 @@ -28,7 +28,8 @@ #include <asm/irq.h> #include <asm/hydra.h> #include <asm/processor.h> -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #ifdef CONFIG_PMAC_PBOOK #include <linux/adb.h> #include <linux/pmu.h> @@ -155,7 +156,6 @@ struct mesh_target tgts[8]; void *dma_cmd_space; struct device_node *ofnode; - u8* mio_base; #ifndef MESH_NEW_STYLE_EH Scsi_Cmnd *completed_q; Scsi_Cmnd *completed_qtail; @@ -258,8 +258,6 @@ if (mesh == 0) mesh = find_compatible_devices("scsi", "chrp,mesh0"); for (; mesh != 0; mesh = mesh->next) { - struct device_node *mio; - if (mesh->n_addrs != 2 || mesh->n_intrs != 2) { printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs" " (got %d,%d)", mesh->n_addrs, mesh->n_intrs); @@ -325,12 +323,6 @@ if (mesh_sync_period < minper) mesh_sync_period = minper; - ms->mio_base = 0; - for (mio = ms->ofnode->parent; mio; mio = mio->parent) - if (strcmp(mio->name, "mac-io") == 0 && mio->n_addrs > 0) - break; - if (mio) - ms->mio_base = (u8 *) ioremap(mio->addrs[0].address, 0x40); set_mesh_power(ms, 1); mesh_init(ms); @@ -363,11 +355,9 @@ iounmap((void *) ms->mesh); if (ms->dma) iounmap((void *) ms->dma); - if (ms->mio_base) - iounmap((void *) ms->mio_base); kfree(ms->dma_cmd_space); free_irq(ms->meshintr, ms); - feature_clear(ms->ofnode, FEATURE_MESH_enable); + pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 0); return 0; } @@ -377,16 +367,10 @@ if (_machine != _MACH_Pmac) return; if (state) { - feature_set(ms->ofnode, FEATURE_MESH_enable); - /* This seems to enable the termination power. strangely - this doesn't fully agree with OF, but with MacOS */ - if (ms->mio_base) - out_8(ms->mio_base + 0x36, 0x70); + pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 1); mdelay(200); } else { - feature_clear(ms->ofnode, FEATURE_MESH_enable); - if (ms->mio_base) - out_8(ms->mio_base + 0x36, 0x34); + pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 0); mdelay(10); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/ncr53c8xx.c linux-2.5/drivers/scsi/ncr53c8xx.c --- linux-2.5.1/drivers/scsi/ncr53c8xx.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/scsi/ncr53c8xx.c Mon Dec 17 01:03:06 2001 @@ -8626,9 +8626,9 @@ if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n"); if (done_list) { - NCR_LOCK_SCSI_DONE(np, flags); + NCR_LOCK_SCSI_DONE(done_list->host, flags); ncr_flush_done_cmds(done_list); - NCR_UNLOCK_SCSI_DONE(np, flags); + NCR_UNLOCK_SCSI_DONE(done_list->host, flags); } } @@ -8649,9 +8649,9 @@ NCR_UNLOCK_NCB(np, flags); if (done_list) { - NCR_LOCK_SCSI_DONE(np, flags); + NCR_LOCK_SCSI_DONE(done_list->host, flags); ncr_flush_done_cmds(done_list); - NCR_UNLOCK_SCSI_DONE(np, flags); + NCR_UNLOCK_SCSI_DONE(done_list->host, flags); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/osst.c linux-2.5/drivers/scsi/osst.c --- linux-2.5.1/drivers/scsi/osst.c Tue Nov 13 17:19:41 2001 +++ linux-2.5/drivers/scsi/osst.c Thu Dec 27 22:10:28 2001 @@ -16,15 +16,15 @@ Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - $Header: /home/cvsroot/Driver/osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $ + $Header: /home/cvsroot/Driver/osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $ Microscopic alterations - Rik Ling, 2000/12/21 Last modified: Wed Feb 2 22:04:05 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 */ -static const char * cvsid = "$Id: osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $"; -const char * osst_version = "0.9.8"; +static const char * cvsid = "$Id: osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $"; +const char * osst_version = "0.9.10"; /* The "failure to reconnect" firmware bug */ #define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/ @@ -159,6 +159,7 @@ struct Scsi_Device_Template osst_template = { + module: THIS_MODULE, name: "OnStream tape", tag: "osst", scsi_type: TYPE_TAPE, @@ -225,20 +226,20 @@ SRpnt->sr_cmnd[0] != MODE_SENSE && SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ if (driver_byte(result) & DRIVER_SENSE) { - printk(KERN_WARNING "osst%d:W: Error with sense data: ", dev); - print_req_sense("osst", SRpnt); + printk(KERN_WARNING "osst%d:W: Command with sense data: ", dev); + print_req_sense("osst:", SRpnt); } else { static int notyetprinted = 1; printk(KERN_WARNING - "osst%d:W: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", + "osst%d:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK, host_byte(result)); if (notyetprinted) { notyetprinted = 0; printk(KERN_INFO - "osst%d:I: This error may be caused by your scsi controller,\n", dev); + "osst%d:I: This warning may be caused by your scsi controller,\n", dev); printk(KERN_INFO "osst%d:I: it has been reported with some Buslogic cards.\n", dev); } @@ -270,11 +271,10 @@ /* Wakeup from interrupt */ static void osst_sleep_done (Scsi_Cmnd * SCpnt) { - unsigned int dev; + unsigned int dev = TAPE_NR(SCpnt->request.rq_dev); OS_Scsi_Tape * STp; - if ((dev = TAPE_NR(SCpnt->request.rq_dev)) < osst_template.nr_dev) { - STp = os_scsi_tapes[dev]; + if (os_scsi_tapes && (STp = os_scsi_tapes[dev])) { if ((STp->buffer)->writing && (SCpnt->sense_buffer[0] & 0x70) == 0x70 && (SCpnt->sense_buffer[2] & 0x40)) { @@ -480,7 +480,8 @@ for (i=0; i < STp->buffer->sg_segs; i++) memset(STp->buffer->sg[i].address, 0, STp->buffer->sg[i].length); strcpy(STp->buffer->b_data, "READ ERROR ON FRAME"); - } + } else + STp->buffer->buffer_bytes = OS_FRAME_SIZE; return 1; } if (STp->buffer->syscall_result) { @@ -619,8 +620,10 @@ if (!SRpnt) return (-EBUSY); while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && - SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 && - (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8) ) { + (( SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 && + (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8) ) || + ( SRpnt->sr_sense_buffer[2] == 6 && SRpnt->sr_sense_buffer[12] == 0x28 && + SRpnt->sr_sense_buffer[13] == 0 ) )) { #if DEBUG if (debugging) { printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait ready\n", dev); @@ -628,7 +631,7 @@ debugging = 0; } #endif - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); memset(cmd, 0, MAX_COMMAND_SIZE); @@ -656,6 +659,66 @@ return 0; } +/* + * Wait for a tape to be inserted in the unit + */ +static int osst_wait_for_medium(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout) +{ + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Request * SRpnt; + long startwait = jiffies; +#if DEBUG + int dbg = debugging; + int dev = TAPE_NR(STp->devt); + + printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait for medium\n", dev); +#endif + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE); + *aSRpnt = SRpnt; + if (!SRpnt) return (-EBUSY); + + while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && + SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 0x3a && + SRpnt->sr_sense_buffer[13] == 0 ) { +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait medium\n", dev); + printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev); + debugging = 0; + } +#endif + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE); + } + *aSRpnt = SRpnt; +#if DEBUG + debugging = dbg; +#endif + if ( STp->buffer->syscall_result && SRpnt->sr_sense_buffer[2] != 2 && + SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait medium\n", dev); + printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev, + STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2], + SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]); +#endif + return 0; + } +#if DEBUG + printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait medium\n", dev); +#endif + return 1; +} + static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame) { int retval; @@ -694,7 +757,7 @@ result = osst_write_error_recovery(STp, aSRpnt, 0); result |= osst_wait_ready(STp, aSRpnt, 5 * 60); - STp->ps[STp->partition].rw = ST_IDLE; + STp->ps[STp->partition].rw = OS_WRITING_COMPLETE; return (result); } @@ -743,7 +806,7 @@ notyetprinted--; } #endif - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout (HZ / OSST_POLL_PER_SEC); } #if DEBUG @@ -901,6 +964,8 @@ #endif if ( osst_initiate_read(STp, aSRpnt) || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) { + if (STp->raw) + return (-EIO); position = osst_get_frame_position(STp, aSRpnt); if (position >= 0xbae && position < 0xbb8) position = 0xbb8; @@ -966,7 +1031,7 @@ if (cnt > 1) { STp->recover_count++; STp->recover_erreg++; - printk(KERN_WARNING "osst%d:I: Read error at position %d recovered\n", + printk(KERN_WARNING "osst%d:I: Don't worry, Read error at position %d recovered\n", dev, STp->read_error_frame); } STp->read_count++; @@ -1523,7 +1588,10 @@ retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending); else retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending); - printk(KERN_WARNING "osst%d:I: Write error%srecovered\n", dev, retval?" not ":" "); + printk(KERN_WARNING "osst%d:%s: %sWrite error%srecovered\n", dev, + retval?"E" :"I", + retval?"" :"Don't worry, ", + retval?" not ":" "); break; case OS_WRITE_LAST_MARK: printk(KERN_ERR "osst%d:E: Bad frame in update last marker, fatal\n", dev); @@ -1594,7 +1662,7 @@ mt_count, last_mark_ppos); #endif if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) { - osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG @@ -1626,7 +1694,7 @@ #if DEBUG printk(OSST_DEB_MSG "osst%d:D: Positioning to last mark at %d\n", dev, last_mark_ppos); #endif - osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); cnt++; if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG @@ -1753,7 +1821,7 @@ #endif return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); } else { - osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", @@ -1793,7 +1861,7 @@ #endif return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); } - osst_set_frame_position(STp, aSRpnt, STp->first_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG @@ -1825,7 +1893,7 @@ #if DEBUG else printk(OSST_DEB_MSG "osst%d:D: Positioning to next mark at %d\n", dev, next_mark_ppos); #endif - osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); cnt++; if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG @@ -2462,7 +2530,7 @@ } #if DEBUG - printk(KERN_INFO "osst%d:D: Block Size changed to 32.5K\n", dev); + printk(KERN_INFO "osst%d:D: Drive Block Size changed to 32.5K\n", dev); /* * In debug mode, we want to see as many errors as possible * to test the error recovery mechanism. @@ -3400,6 +3468,7 @@ if (retval) goto out; STps->rw = ST_IDLE; + /* FIXME -- this may leave the tape without EOD and up2date headers */ } if ((count % STp->block_size) != 0) { @@ -3812,6 +3881,10 @@ ioctl_result = osst_flush_write_buffer(STp, &SRpnt); else ioctl_result = 0; +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d:D: Writing %ld filemark(s).\n", dev, arg); +#endif for (i=0; i<arg; i++) ioctl_result |= osst_write_filemark(STp, &SRpnt); if (fileno >= 0) fileno += arg; @@ -3831,14 +3904,9 @@ cmd[4] = arg; timeout = STp->timeout; #if DEBUG - if (debugging) { - if (cmd_in == MTWEOF) - printk(OSST_DEB_MSG "osst%d:D: Writing %d filemarks.\n", dev, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - else - printk(OSST_DEB_MSG "osst%d:D: Writing %d setmarks.\n", dev, + if (debugging) + printk(OSST_DEB_MSG "osst%d:D: Writing %d setmark(s).\n", dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - } #endif if (fileno >= 0) fileno += arg; @@ -3851,8 +3919,12 @@ case MTRETEN: cmd[0] = START_STOP; cmd[1] = 1; /* Don't wait for completion */ - if (cmd_in == MTLOAD) + if (cmd_in == MTLOAD) { + if (STp->ready == ST_NO_TAPE) + cmd[4] = 4; /* open tray */ + else cmd[4] = 1; /* load */ + } if (cmd_in == MTRETEN) cmd[4] = 3; /* retension then mount */ if (cmd_in == MTOFFL) @@ -3991,7 +4063,7 @@ printk(OSST_DEB_MSG "osst%d:D: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result); #endif - if (!ioctl_result) { + if (!ioctl_result) { /* success */ if (cmd_in == MTFSFM) { fileno--; @@ -4068,6 +4140,8 @@ if (cmd_in == MTLOCK) STp->door_locked = ST_LOCK_FAILS; + if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60)) + ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60); } *aSRpnt = SRpnt; @@ -4108,6 +4182,7 @@ __MOD_INC_USE_COUNT(STp->device->host->hostt->module); if (osst_template.module) __MOD_INC_USE_COUNT(osst_template.module); + STp->device->access_count++; if (mode != STp->current_mode) { #if DEBUG @@ -4124,6 +4199,8 @@ STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); STp->raw = (MINOR(inode->i_rdev) & 0x40) != 0; + if (STp->raw) + STp->header_ok = 0; /* Allocate a buffer for this user */ need_dma_buffer = STp->restr_dma; @@ -4214,7 +4291,7 @@ STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ for (i=0; i < ST_NBR_PARTITIONS; i++) { STps = &(STp->ps[i]); - STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */ + STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */ STps->eof = ST_NOEOF; STps->at_sm = 0; STps->last_block_valid = FALSE; @@ -4262,8 +4339,8 @@ STp->door_locked = ST_LOCKED_AUTO; } if (!STp->frame_in_buffer) { - STp->block_size = (STp->raw) ? OS_FRAME_SIZE : ( - (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); + STp->block_size = (STm->default_blksize > 0) ? + STm->default_blksize : OS_DATA_SIZE; STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; } STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size; @@ -4356,8 +4433,6 @@ return 0; } - STp->min_block = STp->max_block = (-1); - osst_configure_onstream(STp, &SRpnt); /* STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */ @@ -4384,11 +4459,9 @@ } else STp->buffer->aux = NULL; /* this had better never happen! */ - STp->block_size = (STp->raw) ? OS_FRAME_SIZE : ( + STp->block_size = STp->raw ? OS_FRAME_SIZE : ( (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); - STp->min_block = 512; - STp->max_block = OS_DATA_SIZE; - STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size; + STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size; STp->buffer->buffer_bytes = STp->buffer->read_pointer = STp->frame_in_buffer = 0; @@ -4446,6 +4519,8 @@ STp->buffer = NULL; } STp->in_use = 0; + STp->header_ok = 0; + STp->device->access_count--; if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); @@ -4482,7 +4557,7 @@ if (result != 0 && result != (-ENOSPC)) goto out; } - if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) { + if ( STps->rw >= ST_WRITING && !(STp->device)->was_reset) { #if DEBUG if (debugging) { @@ -4492,16 +4567,17 @@ dev, STp->nbr_waits, STp->nbr_finished); } #endif + if (STp->write_type != OS_WRITE_NEW_MARK) { + /* true unless the user wrote the filemark for us */ + result = osst_flush_drive_buffer(STp, &SRpnt); + if (result < 0) goto out; + result = osst_write_filemark(STp, &SRpnt); + if (result < 0) goto out; - result = osst_flush_drive_buffer(STp, &SRpnt); - if (result < 0) goto out; - result = osst_write_filemark(STp, &SRpnt); - if (result < 0) goto out; - - if (STps->drv_file >= 0) - STps->drv_file++ ; - STps->drv_block = 0; - + if (STps->drv_file >= 0) + STps->drv_file++ ; + STps->drv_block = 0; + } result = osst_write_eod(STp, &SRpnt); osst_write_header(STp, &SRpnt, !(STp->rew_at_close)); @@ -4585,7 +4661,12 @@ if (STp->buffer != NULL) STp->buffer->in_use = 0; + if (STp->raw) + STp->header_ok = 0; + STp->in_use = 0; + STp->device->access_count--; + if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); if(osst_template.module) @@ -4635,7 +4716,10 @@ cmd_type = _IOC_TYPE(cmd_in); cmd_nr = _IOC_NR(cmd_in); - +#if DEBUG + printk(OSST_DEB_MSG "osst%d:D: Ioctl %d,%d in %s mode\n", dev, + cmd_type, cmd_nr, STp->raw?"raw":"normal"); +#endif if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { struct mtop mtc; @@ -4718,8 +4802,8 @@ } } - if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && - mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM && + if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM && + mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK && mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART) STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ @@ -4771,7 +4855,10 @@ } if (mtc.mt_op == MTSEEK) { - i = osst_seek_sector(STp, &SRpnt, mtc.mt_count); + if (STp->raw) + i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0); + else + i = osst_seek_sector(STp, &SRpnt, mtc.mt_count); if (!STp->can_partitions) STp->ps[0].rw = ST_IDLE; retval = i; @@ -4876,7 +4963,10 @@ retval = (-EINVAL); goto out; } - blk = osst_get_sector(STp, &SRpnt); + if (STp->raw) + blk = osst_get_frame_position(STp, &SRpnt); + else + blk = osst_get_sector(STp, &SRpnt); if (blk < 0) { retval = blk; goto out; @@ -4971,7 +5061,7 @@ tb = NULL; break; } - tb->sg[segs].page = NULL; + tb->sg[segs].page = NULL; tb->sg[segs].length = b_size; got += b_size; segs++; @@ -5423,6 +5513,8 @@ tpnt->partition = 0; tpnt->new_partition = 0; tpnt->nbr_partitions = 0; + tpnt->min_block = 512; + tpnt->max_block = OS_DATA_SIZE; tpnt->timeout = OSST_TIMEOUT; tpnt->long_timeout = OSST_LONG_TIMEOUT; @@ -5462,6 +5554,7 @@ tpnt->current_mode = 0; tpnt->modes[0].defined = TRUE; + tpnt->modes[2].defined = TRUE; tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE; init_MUTEX(&tpnt->lock); @@ -5583,8 +5676,7 @@ static int __init init_osst(void) { validate_options(); - osst_template.module = THIS_MODULE; - return scsi_register_module(MODULE_SCSI_DEV, &osst_template); + return scsi_register_device(&osst_template); } static void __exit exit_osst (void) @@ -5592,7 +5684,7 @@ int i; OS_Scsi_Tape * STp; - scsi_unregister_module(MODULE_SCSI_DEV, &osst_template); + scsi_unregister_device(&osst_template); #ifdef CONFIG_DEVFS_FS devfs_unregister_chrdev(MAJOR_NR, "osst"); #else diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/osst.h linux-2.5/drivers/scsi/osst.h --- linux-2.5.1/drivers/scsi/osst.h Fri Jul 20 04:18:00 2001 +++ linux-2.5/drivers/scsi/osst.h Thu Dec 13 16:32:36 2001 @@ -1,5 +1,5 @@ /* - * $Header: /home/cvsroot/Driver/osst.h,v 1.11 2001/01/26 01:54:49 riede Exp $ + * $Header: /home/cvsroot/Driver/osst.h,v 1.12 2001/10/11 00:30:15 riede Exp $ */ #include <asm/byteorder.h> @@ -638,3 +638,5 @@ #define OS_WRITE_HEADER 4 #define OS_WRITE_FILLER 5 +/* Additional rw state */ +#define OS_WRITING_COMPLETE 3 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/pas16.c linux-2.5/drivers/scsi/pas16.c --- linux-2.5.1/drivers/scsi/pas16.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/pas16.c Mon Jan 7 23:17:50 2002 @@ -1,7 +1,7 @@ #define AUTOSENSE #define PSEUDO_DMA -#define FOO -#define UNSAFE /* Not unsafe for PAS16 -- use it */ +#define BOARD_REQUIRES_NO_UDELAY /* PAS16 needs no I/O recovery delays */ +#define UNSAFE /* Not unsafe for PAS16 -- use it */ /* * This driver adapted from Drew Eckhardt's Trantor T128 driver @@ -52,8 +52,6 @@ * * PARITY - enable parity checking. Not supported. * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. This * parameter comes from the NCR5380 code. It is NOT unsafe with * the PAS16 and you should use it. If you don't you will have @@ -62,8 +60,6 @@ * want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or * twiddle with the transfer size in the high level code. * - * USLEEP - enable support for devices that don't disconnect. Untested. - * * The card is detected and initialized in one of several ways : * 1. Autoprobe (default) - There are many different models of * the Pro Audio Spectrum/Studio 16, and I only have one of @@ -109,7 +105,7 @@ * * (IRQ_AUTO == 254, IRQ_NONE == 255 in NCR5380.h) */ - + #include <linux/module.h> #include <asm/system.h> @@ -133,467 +129,402 @@ static int pas_wmaxi = 0; static unsigned short pas16_addr = 0; static int pas16_irq = 0; - -int scsi_irq_translate[] = - { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 }; +static int scsi_irq_translate[] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 }; /* The default_irqs array contains values used to set the irq into the * board via software (as must be done on newer model boards without * irq jumpers on the board). The first value in the array will be * assigned to logical board 0, the next to board 1, etc. */ -int default_irqs[] __initdata = - { PAS16_DEFAULT_BOARD_1_IRQ, - PAS16_DEFAULT_BOARD_2_IRQ, - PAS16_DEFAULT_BOARD_3_IRQ, - PAS16_DEFAULT_BOARD_4_IRQ - }; + +static int default_irqs[] __initdata = { + PAS16_DEFAULT_BOARD_1_IRQ, + PAS16_DEFAULT_BOARD_2_IRQ, + PAS16_DEFAULT_BOARD_3_IRQ, + PAS16_DEFAULT_BOARD_4_IRQ +}; static struct override { - unsigned short io_port; - int irq; -} overrides + unsigned short io_port; + int irq; +} overrides #ifdef PAS16_OVERRIDE - [] __initdata = PAS16_OVERRIDE; +[] __initdata = PAS16_OVERRIDE; #else - [4] __initdata = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO}, - {0,IRQ_AUTO}}; +[4] __initdata = { + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO} +}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned short io_port; - int noauto; -} bases[] __initdata = - { {PAS16_DEFAULT_BASE_1, 0}, - {PAS16_DEFAULT_BASE_2, 0}, - {PAS16_DEFAULT_BASE_3, 0}, - {PAS16_DEFAULT_BASE_4, 0} - }; + unsigned short io_port; + int noauto; +} bases[] __initdata = { + {PAS16_DEFAULT_BASE_1, 0}, + {PAS16_DEFAULT_BASE_2, 0}, + {PAS16_DEFAULT_BASE_3, 0}, + {PAS16_DEFAULT_BASE_4, 0} +}; #define NO_BASES (sizeof (bases) / sizeof (struct base)) -unsigned short pas16_offset[ 8 ] = - { - 0x1c00, /* OUTPUT_DATA_REG */ - 0x1c01, /* INITIATOR_COMMAND_REG */ - 0x1c02, /* MODE_REG */ - 0x1c03, /* TARGET_COMMAND_REG */ - 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */ - 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */ - 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?) - * START_DMA_TARGET_RECEIVE_REG wo - */ - 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro, - * START_DMA_INITIATOR_RECEIVE_REG wo - */ - }; +unsigned short pas16_offset[8] = { + 0x1c00, /* OUTPUT_DATA_REG */ + 0x1c01, /* INITIATOR_COMMAND_REG */ + 0x1c02, /* MODE_REG */ + 0x1c03, /* TARGET_COMMAND_REG */ + 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */ + 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */ + 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?) + * START_DMA_TARGET_RECEIVE_REG wo + */ + 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro, + * START_DMA_INITIATOR_RECEIVE_REG wo + */ +}; /*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at */ -/* 1 = blue - 2 = green - 3 = cyan - 4 = red - 5 = magenta - 6 = yellow - 7 = white -*/ -#if 1 -#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);} -#else -#define rtrc(i) {} -#endif - -/* - * Function : enable_board( int board_num, unsigned short port ) - * - * Purpose : set address in new model board - * - * Inputs : board_num - logical board number 0-3, port - base address +/** + * enable_board - enable a pas16 board + * @board_num: logical board id + * @port: port to assign it * + * Sets the address on new model PAS16 hardware */ -static void __init - enable_board( int board_num, unsigned short port ) +static void __init enable_board(int board_num, unsigned short port) { - outb( 0xbc + board_num, MASTER_ADDRESS_PTR ); - outb( port >> 2, MASTER_ADDRESS_PTR ); + outb(0xbc + board_num, MASTER_ADDRESS_PTR); + outb(port >> 2, MASTER_ADDRESS_PTR); } - - -/* - * Function : init_board( unsigned short port, int irq ) - * - * Purpose : Set the board up to handle the SCSI interface - * - * Inputs : port - base address of the board, - * irq - irq to assign to the SCSI port - * force_irq - set it even if it conflicts with sound driver +/** + * init_board - set up board + * @port: board address + * @irq: interrupt line + * @force_irq: if true allow scsi/audio on the same int * + * Set the board up to handle the SCSI interface */ -static void __init - init_board( unsigned short io_port, int irq, int force_irq ) +static void __init init_board(unsigned short io_port, int irq, int force_irq) { - unsigned int tmp; - unsigned int pas_irq_code; + unsigned int tmp; + unsigned int pas_irq_code; /* Initialize the SCSI part of the board */ - outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG ); /* Timeout counter */ - outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */ - outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */ + outb(0x30, io_port + P_TIMEOUT_COUNTER_REG); /* Timeout counter */ + outb(0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET); /* Reset TC */ + outb(0x01, io_port + WAIT_STATE); /* 1 Wait state */ - NCR5380_read( RESET_PARITY_INTERRUPT_REG ); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); - /* Set the SCSI interrupt pointer without mucking up the sound - * interrupt pointer in the same byte. + /* + * Set the SCSI interrupt pointer without mucking up the sound + * interrupt pointer in the same byte. */ - pas_irq_code = ( irq < 16 ) ? scsi_irq_translate[irq] : 0; - tmp = inb( io_port + IO_CONFIG_3 ); - - if( (( tmp & 0x0f ) == pas_irq_code) && pas_irq_code > 0 - && !force_irq ) - { - printk( "pas16: WARNING: Can't use same irq as sound " - "driver -- interrupts disabled\n" ); - /* Set up the drive parameters, disable 5380 interrupts */ - outb( 0x4d, io_port + SYS_CONFIG_4 ); - } - else - { - tmp = ( tmp & 0x0f ) | ( pas_irq_code << 4 ); - outb( tmp, io_port + IO_CONFIG_3 ); + + pas_irq_code = (irq < 16) ? scsi_irq_translate[irq] : 0; + tmp = inb(io_port + IO_CONFIG_3); + + if (((tmp & 0x0f) == pas_irq_code) && pas_irq_code > 0 && !force_irq) { + printk(KERN_WARNING "pas16: WARNING: Can't use same irq as sound " "driver -- interrupts disabled\n"); + /* Set up the drive parameters, disable 5380 interrupts */ + outb(0x4d, io_port + SYS_CONFIG_4); + } else { + tmp = (tmp & 0x0f) | (pas_irq_code << 4); + outb(tmp, io_port + IO_CONFIG_3); - /* Set up the drive parameters and enable 5380 interrupts */ - outb( 0x6d, io_port + SYS_CONFIG_4 ); + /* Set up the drive parameters and enable 5380 interrupts */ + outb(0x6d, io_port + SYS_CONFIG_4); } } -/* - * Function : pas16_hw_detect( unsigned short board_num ) - * - * Purpose : determine if a pas16 board is present - * - * Inputs : board_num - logical board number ( 0 - 3 ) +/** + * pas16_hw_detect - probe for hardware + * @board_num: logical board ID to probe for * - * Returns : 0 if board not found, 1 if found. + * Determine if a pas16 board is present */ -static int __init - pas16_hw_detect( unsigned short board_num ) +static int __init pas16_hw_detect(unsigned short board_num) { - unsigned char board_rev, tmp; - unsigned short io_port = bases[ board_num ].io_port; + unsigned char board_rev, tmp; + unsigned short io_port = bases[board_num].io_port; - /* See if we can find a PAS16 board at the address associated - * with this logical board number. - */ - - /* First, attempt to take a newer model board out of reset and - * give it a base address. This shouldn't affect older boards. - */ - enable_board( board_num, io_port ); + /* See if we can find a PAS16 board at the address associated + * with this logical board number. + */ - /* Now see if it looks like a PAS16 board */ - board_rev = inb( io_port + PCB_CONFIG ); + /* First, attempt to take a newer model board out of reset and + * give it a base address. This shouldn't affect older boards. + */ + enable_board(board_num, io_port); - if( board_rev == 0xff ) - return 0; + /* Now see if it looks like a PAS16 board */ + board_rev = inb(io_port + PCB_CONFIG); - tmp = board_rev ^ 0xe0; + if (board_rev == 0xff) + return 0; - outb( tmp, io_port + PCB_CONFIG ); - tmp = inb( io_port + PCB_CONFIG ); - outb( board_rev, io_port + PCB_CONFIG ); + tmp = board_rev ^ 0xe0; - if( board_rev != tmp ) /* Not a PAS-16 */ - return 0; + outb(tmp, io_port + PCB_CONFIG); + tmp = inb(io_port + PCB_CONFIG); + outb(board_rev, io_port + PCB_CONFIG); - if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 ) - return 0; /* return if no SCSI interface found */ + if (board_rev != tmp) /* Not a PAS-16 */ + return 0; - /* Mediavision has some new model boards that return ID bits - * that indicate a SCSI interface, but they're not (LMS). We'll - * put in an additional test to try to weed them out. - */ - - outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */ - NCR5380_write( MODE_REG, 0x20 ); /* Is it really SCSI? */ - if( NCR5380_read( MODE_REG ) != 0x20 ) /* Write to a reg. */ - return 0; /* and try to read */ - NCR5380_write( MODE_REG, 0x00 ); /* it back. */ - if( NCR5380_read( MODE_REG ) != 0x00 ) - return 0; + if ((inb(io_port + OPERATION_MODE_1) & 0x03) != 0x03) + return 0; /* return if no SCSI interface found */ - return 1; -} + /* Mediavision has some new model boards that return ID bits + * that indicate a SCSI interface, but they're not (LMS). We'll + * put in an additional test to try to weed them out. + */ + outb(0x01, io_port + WAIT_STATE); /* 1 Wait state */ + NCR5380_write(MODE_REG, 0x20); /* Is it really SCSI? */ + if (NCR5380_read(MODE_REG) != 0x20) /* Write to a reg. */ + return 0; /* and try to read */ + NCR5380_write(MODE_REG, 0x00); /* it back. */ + if (NCR5380_read(MODE_REG) != 0x00) + return 0; -/* - * Function : pas16_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + return 1; +} + +/** + * pas16_setup - parse command line + * @str: command line block * + * LILO command line initialization of the overrides array from + * the passed in pas16= options */ -void __init pas16_setup(char *str, int *ints) +int __init pas16_setup(char *str) { - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("pas16_setup : usage pas16=io_port,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].io_port = (unsigned short) ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].io_port == (unsigned short) ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; + static int commandline_current = 0; + int i; + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + if (ints[0] != 2) + printk(KERN_ERR "pas16_setup : usage pas16=io_port,irq\n"); + else if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].io_port = (unsigned short) ints[1]; + overrides[commandline_current].irq = ints[2]; + for (i = 0; i < NO_BASES; ++i) + if (bases[i].io_port == (unsigned short) ints[1]) { + bases[i].noauto = 1; + break; + } + ++commandline_current; } + return 1; } -/* - * Function : int pas16_detect(Scsi_Host_Template * tpnt) - * - * Purpose : detects and initializes PAS16 controllers - * that were autoprobed, overridden on the LILO command line, - * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. +__setup("pas16=", pas16_setup); + +/** + * pas16_detect - detect and configure a pas16 + * @tpnt: template * + * Detects and initializes PAS16 controllers that were autoprobed, + * overridden on the LILO command line, or specified at compile time. */ int __init pas16_detect(Scsi_Host_Template * tpnt) { - static int current_override = 0; - static unsigned short current_base = 0; - struct Scsi_Host *instance; - unsigned short io_port; - int count; + static int current_override = 0; + static unsigned short current_base = 0; + struct Scsi_Host *instance; + unsigned short io_port; + int count; + + tpnt->proc_name = "pas16"; + tpnt->proc_info = &pas16_proc_info; + + if (pas16_addr != 0) { + overrides[0].io_port = pas16_addr; + /* + * This is how we avoid seeing more than + * one host adapter at the same I/O port. + * Cribbed shamelessly from pas16_setup(). + */ + for (count = 0; count < NO_BASES; ++count) + if (bases[count].io_port == pas16_addr) { + bases[count].noauto = 1; + break; + } + } + if (pas16_irq != 0) + overrides[0].irq = pas16_irq; - tpnt->proc_name = "pas16"; - tpnt->proc_info = &pas16_proc_info; + for (count = 0; current_override < NO_OVERRIDES; ++current_override) { + io_port = 0; - if (pas16_addr != 0) { - overrides[0].io_port = pas16_addr; - /* - * This is how we avoid seeing more than - * one host adapter at the same I/O port. - * Cribbed shamelessly from pas16_setup(). - */ - for (count = 0; count < NO_BASES; ++count) - if (bases[count].io_port == pas16_addr) { - bases[count].noauto = 1; - break; - } - } - if (pas16_irq != 0) - overrides[0].irq = pas16_irq; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - io_port = 0; - - if (overrides[current_override].io_port) - { - io_port = overrides[current_override].io_port; - enable_board( current_override, io_port ); - init_board( io_port, overrides[current_override].irq, 1 ); - } - else - for (; !io_port && (current_base < NO_BASES); ++current_base) { -#if (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port); -#endif - if ( !bases[current_base].noauto && - pas16_hw_detect( current_base ) ){ - io_port = bases[current_base].io_port; - init_board( io_port, default_irqs[ current_base ], 0 ); -#if (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : detected board.\n"); -#endif + if (overrides[current_override].io_port) { + io_port = overrides[current_override].io_port; + enable_board(current_override, io_port); + init_board(io_port, overrides[current_override].irq, 1); + } + else + { + for (; !io_port && (current_base < NO_BASES); ++current_base) { + if (!bases[current_base].noauto && pas16_hw_detect(current_base)) { + io_port = bases[current_base].io_port; + init_board(io_port, default_irqs[current_base], 0); + } + } } - } + if (!io_port) + break; -#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port); -#endif + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) + break; + + instance->io_port = io_port; + + NCR5380_init(instance, 0); + + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", NULL)) { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + /* Disable 5380 interrupts, leave drive params the same */ + outb(0x4d, io_port + SYS_CONFIG_4); + outb((inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3); + } - if (!io_port) - break; + printk(KERN_INFO "scsi%d : at 0x%04x", instance->host_no, (int) + instance->io_port); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->io_port = io_port; - - NCR5380_init(instance, 0); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS); - - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", NULL)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } - - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - /* Disable 5380 interrupts, leave drive params the same */ - outb( 0x4d, io_port + SYS_CONFIG_4 ); - outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 ); + ++current_override; + ++count; } - -#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif - - printk("scsi%d : at 0x%04x", instance->host_no, (int) - instance->io_port); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; + return count; } -/* - * Function : int pas16_biosparam(Disk *disk, kdev_t dev, int *ip) +/** + * pas16_biosparam - generate C/H/S data + * @disk: Disk to set up + * @dev: device ident of disk + * @ip: array to return C/H/S mapping * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for + * Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. - * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * */ -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. - */ - -int pas16_biosparam(Disk * disk, kdev_t dev, int * ip) +int pas16_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; /* I think I have it as /(32*64) */ - if( ip[2] > 1024 ) { /* yes, >, not >= */ - ip[0]=255; - ip[1]=63; - ip[2]=size/(63*255); - if( ip[2] > 1023 ) /* yes >1023... */ - ip[2] = 1023; - } + int size = disk->capacity; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; /* I think I have it as /(32*64) */ + if (ip[2] > 1024) { /* yes, >, not >= */ + ip[0] = 255; + ip[1] = 63; + ip[2] = size / (63 * 255); + if (ip[2] > 1023) /* yes >1023... */ + ip[2] = 1023; + } - return 0; + return 0; } -/* - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) - * - * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. +/** + * NCR5380_pread - pseudo DMA read + * @instance: board to read from + * @dst: destination for data + * @len: expected/max block length + * + * Fast 5380 pseudo-dma read function, transfers len bytes to + * dst. Unlike most boards the PAS has IRQs enabled here, which + * helps no end. */ -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, - int len) { - register unsigned char *d = dst; - register unsigned short reg = (unsigned short) (instance->io_port + - P_DATA_REG_OFFSET); - register int i = len; - int ii = 0; - - while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) ) - ++ii; - - insb( reg, d, i ); - - if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { - outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); - printk("scsi%d : watchdog timer fired in NCR5380_pread()\n", - instance->host_no); - return -1; - } - if (ii > pas_maxi) - pas_maxi = ii; - return 0; +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + unsigned char *d = dst; + unsigned short reg = (unsigned short) (instance->io_port + P_DATA_REG_OFFSET); + int i = len; + int ii = 0; + + while (!(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY)) + ++ii; + + insb(reg, d, i); + + if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { + outb(P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); + printk(KERN_ERR "scsi%d : watchdog timer fired in NCR5380_pread()\n", instance->host_no); + return -1; + } + if (ii > pas_maxi) + pas_maxi = ii; + return 0; } -/* - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) - * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. +/** + * NCR5380_pwrite - pseudo DMA write + * @instance: board to write to + * @src: source for data + * @len: expected/max block length + * + * Fast 5380 pseudo-dma write function, transfers len bytes from + * src. Unlike most boards the PAS has IRQs enabled here, which + * helps no end. */ -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, - int len) { - register unsigned char *s = src; - register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET); - register int i = len; - int ii = 0; - - while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) ) - ++ii; - - outsb( reg, s, i ); - - if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { - outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); - printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n", - instance->host_no); - return -1; - } - if (ii > pas_maxi) - pas_wmaxi = ii; - return 0; +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + unsigned char *s = src; + unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET); + int i = len; + int ii = 0; + + while (!((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY)) + ++ii; + + outsb(reg, s, i); + + if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { + outb(P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); + printk(KERN_ERR "scsi%d : watchdog timer fired in NCR5380_pwrite()\n", instance->host_no); + return -1; + } + if (ii > pas_maxi) + pas_wmaxi = ii; + return 0; } #include "NCR5380.c" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/pci2000.c linux-2.5/drivers/scsi/pci2000.c --- linux-2.5.1/drivers/scsi/pci2000.c Fri Nov 9 22:05:06 2001 +++ linux-2.5/drivers/scsi/pci2000.c Sun Jan 6 19:17:51 2002 @@ -275,11 +275,6 @@ int z; unsigned long flags; - /* - * Disable interrupts, if they aren't already disabled and acquire - * the I/O spinlock. - */ - spin_lock_irqsave (&io_request_lock, flags); DEB(printk ("\npci2000 received interrupt ")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process @@ -298,9 +293,10 @@ if ( !shost ) { DEB (printk ("\npci2000: not my interrupt")); - goto irq_return; + goto out; } + spin_lock_irqsave(shost->host_lock, flags); padapter = HOSTDATA(shost); tag0 = tag & 0x7F; // mask off the error bit @@ -392,14 +388,10 @@ outb_p (CMD_DONE, padapter->cmd); // complete the op OpDone (SCpnt, DID_OK << 16); -irq_return:; - /* - * 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); - } +irq_return: + spin_unlock_irqrestore(shost->host_lock, flags); +out:; +} /**************************************************************** * Name: Pci2000_QueueCommand * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/pci2220i.c linux-2.5/drivers/scsi/pci2220i.c --- linux-2.5.1/drivers/scsi/pci2220i.c Fri Nov 9 22:05:06 2001 +++ linux-2.5/drivers/scsi/pci2220i.c Sun Jan 6 19:17:51 2002 @@ -1152,6 +1152,7 @@ static void TimerExpiry (unsigned long data) { PADAPTER2220I padapter = (PADAPTER2220I)data; + struct Scsi_Host *host = padapter->SCpnt->host; POUR_DEVICE pdev = padapter->pdev; UCHAR status = IDE_STATUS_BUSY; UCHAR temp, temp1; @@ -1161,7 +1162,7 @@ * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ - spin_lock_irqsave (&io_request_lock, flags); + spin_lock_irqsave(host->host_lock, flags); DEB (printk ("\nPCI2220I: Timeout expired ")); if ( padapter->failinprog ) @@ -1295,7 +1296,7 @@ * which will enable interrupts if and only if they were * enabled on entry. */ - spin_unlock_irqrestore (&io_request_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } /**************************************************************** * Name: SetReconstruct :LOCAL @@ -1328,7 +1329,8 @@ ****************************************************************/ static void ReconTimerExpiry (unsigned long data) { - PADAPTER2220I padapter; + PADAPTER2220I padapter = (PADAPTER2220I)data; + struct Scsi_Host *host = padapter->SCpnt->host; POUR_DEVICE pdev; ULONG testsize = 0; PIDENTIFY_DATA pid; @@ -1342,9 +1344,8 @@ * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ - spin_lock_irqsave (&io_request_lock, flags); + spin_lock_irqsave(host->host_lock, flags); - padapter = (PADAPTER2220I)data; if ( padapter->SCpnt ) goto reconTimerExpiry; @@ -1567,7 +1568,7 @@ * which will enable interrupts if and only if they were * enabled on entry. */ - spin_unlock_irqrestore (&io_request_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } /**************************************************************** * Name: Irq_Handler :LOCAL @@ -1596,12 +1597,6 @@ ULONG zl; unsigned long flags; - /* - * Disable interrupts, if they aren't already disabled and acquire - * the I/O spinlock. - */ - spin_lock_irqsave (&io_request_lock, flags); - // DEB (printk ("\npci2220i received interrupt\n")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process @@ -1619,9 +1614,10 @@ if ( !shost ) { DEB (printk ("\npci2220i: not my interrupt")); - goto irq_return; + goto out; } + spin_lock_irqsave(shost->host_lock, flags); padapter = HOSTDATA(shost); pdev = padapter->pdev; SCpnt = padapter->SCpnt; @@ -2023,13 +2019,9 @@ zl = DID_OK << 16; OpDone (padapter, zl); -irq_return:; - /* - * 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); +irq_return: + spin_unlock_irqrestore(shost->host_lock, flags); +out:; } /**************************************************************** * Name: Pci2220i_QueueCommand diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/pcmcia/aha152x_stub.c linux-2.5/drivers/scsi/pcmcia/aha152x_stub.c --- linux-2.5.1/drivers/scsi/pcmcia/aha152x_stub.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/pcmcia/aha152x_stub.c Thu Dec 27 22:10:28 2001 @@ -5,7 +5,7 @@ This driver supports the Adaptec AHA-1460, the New Media Bus Toaster, and the New Media Toast & Jam. - aha152x_cs.c 1.54 2000/06/12 21:27:25 + aha152x_cs.c 1.58 2001/10/13 00:08:51 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -22,8 +22,8 @@ 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 + 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 @@ -57,42 +57,39 @@ #include <pcmcia/cistpl.h> #include <pcmcia/ds.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 = -"aha152x_cs.c 1.54 2000/06/12 21:27:25 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); +MODULE_DESCRIPTION("Adaptec AHA152x-compatible PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); -/* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); -/* SCSI bus setup options */ -static int host_id = 7; -static int reconnect = 1; -static int parity = 1; -static int synchronous = 0; -static int reset_delay = 100; -static int ext_trans = 0; +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(host_id, "i"); -MODULE_PARM(reconnect, "i"); -MODULE_PARM(parity, "i"); -MODULE_PARM(synchronous, "i"); -MODULE_PARM(reset_delay, "i"); -MODULE_PARM(ext_trans, "i"); +INT_MODULE_PARM(irq_mask, 0xdeb8); +INT_MODULE_PARM(host_id, 7); +INT_MODULE_PARM(reconnect, 1); +INT_MODULE_PARM(parity, 1); +INT_MODULE_PARM(synchronous, 0); +INT_MODULE_PARM(reset_delay, 100); +INT_MODULE_PARM(ext_trans, 0); -MODULE_LICENSE("Dual MPL/GPL"); +#ifdef AHA152X_DEBUG +INT_MODULE_PARM(debug, 0); +#endif + +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"aha152x_cs.c 1.58 2001/10/13 00:08:51 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -277,7 +274,6 @@ release_region(link->io.BasePort1, link->io.NumPorts1); /* Set configuration options for the aha152x driver */ - ints[0] = 7; ints[1] = link->io.BasePort1; ints[2] = link->irq.AssignedIRQ; ints[3] = host_id; @@ -285,12 +281,16 @@ ints[5] = parity; ints[6] = synchronous; ints[7] = reset_delay; - if (ext_trans) { - ints[8] = ext_trans; ints[0] = 8; - } + ints[8] = ext_trans; +#ifdef AHA152X_DEBUG + ints[9] = debug; + ints[0] = 9; +#else + ints[0] = 8; +#endif aha152x_setup("PCMCIA setup", ints); - scsi_register_module(MODULE_SCSI_HA, &driver_template); + scsi_register_host(&driver_template); tail = &link->dev; info->ndev = 0; @@ -356,7 +356,7 @@ return; } - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + scsi_unregister_host(&driver_template); link->dev = NULL; CardServices(ReleaseConfiguration, link->handle); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/pcmcia/fdomain_stub.c linux-2.5/drivers/scsi/pcmcia/fdomain_stub.c --- linux-2.5.1/drivers/scsi/pcmcia/fdomain_stub.c Sat Mar 3 02:38:39 2001 +++ linux-2.5/drivers/scsi/pcmcia/fdomain_stub.c Thu Dec 27 22:10:28 2001 @@ -2,7 +2,7 @@ A driver for Future Domain-compatible PCMCIA SCSI cards - fdomain_cs.c 1.43 2000/06/12 21:27:25 + fdomain_cs.c 1.47 2001/10/13 00:08:52 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ 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 + 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 @@ -54,27 +54,30 @@ #include <pcmcia/cistpl.h> #include <pcmcia/ds.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 = -"fdomain_cs.c 1.43 2000/06/12 21:27:25 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); +MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; - -MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + /*====================================================================*/ typedef struct scsi_info_t { @@ -212,6 +215,7 @@ u_char tuple_data[64]; Scsi_Device *dev; dev_node_t *node, **tail; + char str[16]; struct Scsi_Host *host; DEBUG(0, "fdomain_config(0x%p)\n", link); @@ -252,9 +256,10 @@ ints[0] = 2; ints[1] = link->io.BasePort1; ints[2] = link->irq.AssignedIRQ; - fdomain_setup("PCMCIA setup", ints); + sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ); + fdomain_setup(str, ints); - scsi_register_module(MODULE_SCSI_HA, &driver_template); + scsi_register_host(&driver_template); tail = &link->dev; info->ndev = 0; @@ -319,7 +324,7 @@ return; } - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + scsi_unregister_host(&driver_template); link->dev = NULL; CardServices(ReleaseConfiguration, link->handle); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/pcmcia/nsp_cs.c linux-2.5/drivers/scsi/pcmcia/nsp_cs.c --- linux-2.5.1/drivers/scsi/pcmcia/nsp_cs.c Wed Nov 28 18:22:27 2001 +++ linux-2.5/drivers/scsi/pcmcia/nsp_cs.c Thu Dec 27 22:10:28 2001 @@ -1515,7 +1515,7 @@ goto cs_failed; } - scsi_register_module(MODULE_SCSI_HA, &driver_template); + scsi_register_host(&driver_template); DEBUG(0, "GET_SCSI_INFO\n"); tail = &link->dev; @@ -1611,7 +1611,7 @@ } /* Unlink the device chain */ - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + scsi_unregister_host(&driver_template); link->dev = NULL; if (link->win) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/pcmcia/qlogic_stub.c linux-2.5/drivers/scsi/pcmcia/qlogic_stub.c --- linux-2.5.1/drivers/scsi/pcmcia/qlogic_stub.c Sat Mar 3 02:38:39 2001 +++ linux-2.5/drivers/scsi/pcmcia/qlogic_stub.c Thu Dec 27 22:10:28 2001 @@ -2,7 +2,7 @@ A driver for the Qlogic SCSI card - qlogic_cs.c 1.79 2000/06/12 21:27:26 + qlogic_cs.c 1.83 2001/10/13 00:08:53 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ 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 + 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 @@ -40,6 +40,7 @@ #include <linux/timer.h> #include <linux/ioport.h> #include <asm/io.h> +#include <asm/byteorder.h> #include <scsi/scsi.h> #include <linux/major.h> #include <linux/blk.h> @@ -61,27 +62,30 @@ extern void qlogicfas_preset(int port, int irq); -#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 = -"qlogic_cs.c 1.79 2000/06/12 21:27:26 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); +MODULE_DESCRIPTION("Qlogic PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; - -MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"qlogic_cs.c 1.83 2001/10/13 00:08:53 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + /*====================================================================*/ typedef struct scsi_info_t { @@ -277,7 +281,7 @@ else qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ); - scsi_register_module(MODULE_SCSI_HA, &driver_template); + scsi_register_host(&driver_template); tail = &link->dev; info->ndev = 0; @@ -341,7 +345,7 @@ return; } - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + scsi_unregister_host(&driver_template); link->dev = NULL; CardServices(ReleaseConfiguration, link->handle); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/ppa.c linux-2.5/drivers/scsi/ppa.c --- linux-2.5.1/drivers/scsi/ppa.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/ppa.c Sat Jan 12 12:32:41 2002 @@ -704,7 +704,7 @@ * change things for "normal" hardware since generally * the 6th bit is always high. * This makes the CPU load higher on some hardware - * but otherwise we can not get more then 50K/secs + * but otherwise we can not get more than 50K/secs * on this problem hardware. */ if ((r & 0xc0) != 0xc0) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/qla1280.c linux-2.5/drivers/scsi/qla1280.c --- linux-2.5.1/drivers/scsi/qla1280.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/qla1280.c Sun Dec 30 21:17:30 2001 @@ -192,7 +192,6 @@ #include <stdarg.h> #include <asm/io.h> #include <asm/irq.h> -#include <asm/segment.h> #include <asm/byteorder.h> #include <linux/version.h> #include <linux/types.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/qlogicfas.c linux-2.5/drivers/scsi/qlogicfas.c --- linux-2.5.1/drivers/scsi/qlogicfas.c Thu Oct 25 20:53:51 2001 +++ linux-2.5/drivers/scsi/qlogicfas.c Sun Jan 6 19:17:51 2002 @@ -467,10 +467,11 @@ static void do_ql_ihandl(int irq, void *dev_id, struct pt_regs * regs) { unsigned long flags; + struct Scsi_Host *host = dev_id; - spin_lock_irqsave(&io_request_lock, flags); + spin_lock_irqsave(host->host_lock, flags); ql_ihandl(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/qlogicfc.c linux-2.5/drivers/scsi/qlogicfc.c --- linux-2.5.1/drivers/scsi/qlogicfc.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/scsi/qlogicfc.c Sun Jan 6 19:17:51 2002 @@ -1375,7 +1375,7 @@ hostdata->explore_timer.data = 0; del_timer(&hostdata->explore_timer); - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); if (hostdata->adapter_state & AS_REDO_FABRIC_PORTDB || hostdata->adapter_state & AS_REDO_LOOP_PORTDB) { isp2x00_make_portdb(host); @@ -1422,7 +1422,7 @@ hostdata->adapter_state = AS_LOOP_GOOD; } - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } @@ -1433,9 +1433,9 @@ struct Scsi_Host *host = dev_id; unsigned long flags; - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); isp2x00_intr_handler(irq, dev_id, regs); - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/qlogicisp.c linux-2.5/drivers/scsi/qlogicisp.c --- linux-2.5.1/drivers/scsi/qlogicisp.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/scsi/qlogicisp.c Sun Jan 6 19:17:51 2002 @@ -973,9 +973,9 @@ struct Scsi_Host *host = dev_id; unsigned long flags; - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); isp1020_intr_handler(irq, dev_id, regs); - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/qlogicpti.c linux-2.5/drivers/scsi/qlogicpti.c --- linux-2.5.1/drivers/scsi/qlogicpti.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/scsi/qlogicpti.c Sun Jan 6 19:17:51 2002 @@ -1445,7 +1445,7 @@ spin_unlock(&qpti->lock); if (dq != NULL) { - spin_lock(&qpti->qhost->host_lock); + spin_lock(qpti->qhost->host_lock); do { Scsi_Cmnd *next; @@ -1453,7 +1453,7 @@ dq->scsi_done(dq); dq = next; } while (dq != NULL); - spin_unlock(&qpti->qhost->host_lock); + spin_unlock(qpti->qhost->host_lock); } __restore_flags(flags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi.c linux-2.5/drivers/scsi/scsi.c --- linux-2.5.1/drivers/scsi/scsi.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/scsi/scsi.c Sun Jan 6 19:17:51 2002 @@ -195,19 +195,16 @@ { request_queue_t *q = &SDpnt->request_queue; - blk_init_queue(q, scsi_request_fn, &SHpnt->host_lock); + blk_init_queue(q, scsi_request_fn, SHpnt->host_lock); q->queuedata = (void *) SDpnt; /* Hardware imposed limit. */ blk_queue_max_hw_segments(q, SHpnt->sg_tablesize); - - /* - * When we remove scsi_malloc soonish, this can die too - */ - blk_queue_max_phys_segments(q, PAGE_SIZE / sizeof(struct scatterlist)); - blk_queue_max_sectors(q, SHpnt->max_sectors); + /* scsi_alloc_sgtable max */ + blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS); + if (!SHpnt->use_clustering) clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); } @@ -650,7 +647,7 @@ host = SCpnt->host; - ASSERT_LOCK(&host->host_lock, 0); + ASSERT_LOCK(host->host_lock, 0); /* Assign a unique nonzero serial_number. */ if (++serial_number == 0) @@ -701,9 +698,9 @@ * length exceeds what the host adapter can handle. */ if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) { - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); rtn = host->hostt->queuecommand(SCpnt, scsi_done); - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); if (rtn != 0) { scsi_delete_timer(SCpnt); scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); @@ -714,20 +711,20 @@ SCSI_LOG_MLQUEUE(3, printk("queuecommand : command too long.\n")); SCpnt->result = (DID_ABORT << 16); - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); scsi_done(SCpnt); - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); rtn = 1; } } else { int temp; SCSI_LOG_MLQUEUE(3, printk("command() : routine at %p\n", host->hostt->command)); - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); temp = host->hostt->command(SCpnt); SCpnt->result = temp; #ifdef DEBUG_DELAY - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); clock = jiffies + 4 * HZ; while (time_before(jiffies, clock)) { barrier(); @@ -735,10 +732,10 @@ } printk("done(host = %d, result = %04x) : routine at %p\n", host->host_no, temp, host->hostt->command); - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); #endif scsi_done(SCpnt); - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n")); return rtn; @@ -808,7 +805,7 @@ Scsi_Device * SDpnt = SRpnt->sr_device; struct Scsi_Host *host = SDpnt->host; - ASSERT_LOCK(&host->host_lock, 0); + ASSERT_LOCK(host->host_lock, 0); SCSI_LOG_MLQUEUE(4, { @@ -905,7 +902,7 @@ { struct Scsi_Host *host = SCpnt->host; - ASSERT_LOCK(&host->host_lock, 0); + ASSERT_LOCK(host->host_lock, 0); SCpnt->owner = SCSI_OWNER_MIDLEVEL; SRpnt->sr_command = SCpnt; @@ -995,7 +992,7 @@ { struct Scsi_Host *host = SCpnt->host; - ASSERT_LOCK(&host->host_lock, 0); + ASSERT_LOCK(host->host_lock, 0); SCpnt->pid = scsi_pid++; SCpnt->owner = SCSI_OWNER_MIDLEVEL; @@ -1349,7 +1346,7 @@ host = SCpnt->host; device = SCpnt->device; - ASSERT_LOCK(&host->host_lock, 0); + ASSERT_LOCK(host->host_lock, 0); /* * We need to protect the decrement, as otherwise a race condition @@ -1358,10 +1355,10 @@ * one execution context, but the device and host structures are * shared. */ - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); host->host_busy--; /* Indicate that we are free */ device->device_busy--; /* Decrement device usage counter. */ - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); /* * Clear the flags which say that the device/host is no longer @@ -1405,9 +1402,6 @@ SCpnt->done(SCpnt); } -static int scsi_register_host(Scsi_Host_Template *); -static int scsi_unregister_host(Scsi_Host_Template *); - /* * Function: scsi_release_commandblocks() * @@ -1842,7 +1836,7 @@ * This entry point should be called by a driver if it is trying * to add a low level scsi driver to the system. */ -static int scsi_register_host(Scsi_Host_Template * tpnt) +int scsi_register_host(Scsi_Host_Template * tpnt) { int pcount; struct Scsi_Host *shpnt; @@ -1992,7 +1986,7 @@ * 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. */ -static int scsi_unregister_host(Scsi_Host_Template * tpnt) +int scsi_unregister_host(Scsi_Host_Template * tpnt) { int online_status; int pcount0, pcount; @@ -2203,22 +2197,27 @@ return -1; } -static int scsi_unregister_device(struct Scsi_Device_Template *tpnt); - /* * This entry point should be called by a loadable module if it is trying * add a high level scsi driver to the system. */ -static int scsi_register_device_module(struct Scsi_Device_Template *tpnt) +int scsi_register_device(struct Scsi_Device_Template *tpnt) { Scsi_Device *SDpnt; struct Scsi_Host *shpnt; int out_of_space = 0; +#ifdef CONFIG_KMOD + if (scsi_hosts == NULL) + request_module("scsi_hostadapter"); +#endif + if (tpnt->next) return 1; - scsi_register_device(tpnt); + tpnt->next = scsi_devicelist; + scsi_devicelist = tpnt; + /* * First scan the devices that we know about, and see if we notice them. */ @@ -2274,7 +2273,7 @@ return 0; } -static int scsi_unregister_device(struct Scsi_Device_Template *tpnt) +int scsi_unregister_device(struct Scsi_Device_Template *tpnt) { Scsi_Device *SDpnt; struct Scsi_Host *shpnt; @@ -2332,60 +2331,6 @@ error_out: unlock_kernel(); return -1; -} - - -/* This function should be called by drivers which needs to register - * with the midlevel scsi system. As of 2.4.0-test9pre3 this is our - * main device/hosts register function /mathiasen - */ -int scsi_register_module(int module_type, void *ptr) -{ - switch (module_type) { - case MODULE_SCSI_HA: - return scsi_register_host((Scsi_Host_Template *) ptr); - - /* Load upper level device handler of some kind */ - case MODULE_SCSI_DEV: -#ifdef CONFIG_KMOD - if (scsi_hosts == NULL) - request_module("scsi_hostadapter"); -#endif - return scsi_register_device_module((struct Scsi_Device_Template *) ptr); - /* The rest of these are not yet implemented */ - - /* Load constants.o */ - case MODULE_SCSI_CONST: - - /* Load specialized ioctl handler for some device. Intended for - * cdroms that have non-SCSI2 audio command sets. */ - case MODULE_SCSI_IOCTL: - - default: - return 1; - } -} - -/* Reverse the actions taken above - */ -int scsi_unregister_module(int module_type, void *ptr) -{ - int retval = 0; - - switch (module_type) { - case MODULE_SCSI_HA: - retval = scsi_unregister_host((Scsi_Host_Template *) ptr); - break; - case MODULE_SCSI_DEV: - 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:; - } - return retval; } #ifdef CONFIG_PROC_FS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi.h linux-2.5/drivers/scsi/scsi.h --- linux-2.5.1/drivers/scsi/scsi.h Sun Dec 16 23:46:45 2001 +++ linux-2.5/drivers/scsi/scsi.h Mon Jan 14 14:39:03 2002 @@ -434,7 +434,7 @@ /* * Prototypes for functions in scsicam.c */ -extern int scsi_partsize(struct buffer_head *bh, unsigned long capacity, +extern int scsi_partsize(unsigned char *buf, unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs); @@ -548,10 +548,8 @@ */ struct scsi_device { -/* private: */ /* - * This information is private to the scsi mid-layer. Wrapping it in a - * struct private is a way of marking it in a sort of C++ type of way. + * This information is private to the scsi mid-layer. */ struct scsi_device *next; /* Used for linked list */ struct scsi_device *prev; /* Used for linked list */ @@ -563,7 +561,6 @@ volatile unsigned short device_busy; /* commands actually active on low-level */ Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */ -/* public: */ unsigned int id, lun, channel; unsigned int manufacturer; /* Manufacturer of device, for using @@ -681,11 +678,7 @@ */ struct scsi_cmnd { int sc_magic; -/* private: */ - /* - * This information is private to the scsi mid-layer. Wrapping it in a - * struct private is a way of marking it in a sort of C++ type of way. - */ + struct Scsi_Host *host; unsigned short state; unsigned short owner; @@ -726,8 +719,6 @@ unsigned volatile char internal_timeout; struct scsi_cmnd *bh_next; /* To enumerate the commands waiting to be processed. */ - -/* public: */ unsigned int target; unsigned int lun; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi_debug.c linux-2.5/drivers/scsi/scsi_debug.c --- linux-2.5.1/drivers/scsi/scsi_debug.c Sun Dec 16 20:20:20 2001 +++ linux-2.5/drivers/scsi/scsi_debug.c Thu Dec 27 15:14:59 2001 @@ -3,8 +3,19 @@ * * Copyright (C) 1992 Eric Youngdale * Simulate a host adapter with 2 disks attached. Do a lot of checking - * to make sure that we are not getting blocks mixed up, and panic if + * to make sure that we are not getting blocks mixed up, and PANIC if * anything out of the ordinary is seen. + * + * This version is more generic, simulating a variable number of disk + * (or disk like devices) sharing a common amount of RAM (default 8 MB + * but can be set at driver/module load time). + * + * For documentation see http://www.torque.net/sg/sdebug.html + * + * D. Gilbert (dpg) work for MOD device test [20010421] + * dpg, work for devfs large number of disks [20010809] + * dpg, make more generic [20011123] + * dpg, forked for lk 2.5 series [20011216] */ #include <linux/config.h> @@ -18,7 +29,9 @@ #include <linux/string.h> #include <linux/genhd.h> #include <linux/fs.h> +#include <linux/init.h> #include <linux/proc_fs.h> +#include <linux/smp_lock.h> #include <asm/system.h> #include <asm/io.h> @@ -27,201 +40,198 @@ #include "scsi.h" #include "hosts.h" -#include "sd.h" - #include<linux/stat.h> -/* A few options that we want selected */ +#ifndef LINUX_VERSION_CODE +#include <linux/version.h> +#endif + +static char scsi_debug_version_str[] = "Version: 1.57 (20011216)"; -#define NR_HOSTS_PRESENT 1 -#define NR_FAKE_DISKS 3 -#define N_HEAD 255 -#define N_SECTOR 63 -#define N_CYLINDER 524 +#ifndef SCSI_CMD_READ_16 +#define SCSI_CMD_READ_16 0x88 +#endif +#ifndef SCSI_CMD_WRITE_16 +#define SCSI_CMD_WRITE_16 0x8a +#endif + +/* A few options that we want selected */ +#define DEF_NR_FAKE_DEVS 1 +#define DEF_DEV_SIZE_MB 8 +#define DEF_FAKE_BLK0 0 + +static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS; + +#define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1) +#define N_HEAD 8 +#define N_SECTOR 32 #define DISK_READONLY(TGT) (0) -#define DISK_REMOVEABLE(TGT) (1) -#define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK); +#define DISK_REMOVEABLE(TGT) (0) +#define DEVICE_TYPE(TGT) (TYPE_DISK); + +#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1) + +static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; +#define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024) +#define STORE_ELEM_ORDER 1 +#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER)) +#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1) + +/* default sector size is 512 bytes, 2**9 bytes */ +#define POW2_SECT_SIZE 9 +#define SECT_SIZE (1 << POW2_SECT_SIZE) + +#define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD)) + +static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0; /* Do not attempt to use a timer to simulate a real disk with latency */ /* Only use this in the actual kernel, not in the simulator. */ #define IMMEDIATE -/* Skip some consistency checking. Good for benchmarking */ -#define SPEEDY -/* Read return zeros. Undefine for benchmarking */ -#define CLEAR - -/* Number of real scsi disks that will be detected ahead of time */ -static int NR_REAL = -1; - -#define NR_BLK_DEV 12 -#ifndef MAJOR_NR -#define MAJOR_NR 8 -#endif +#define SDEBUG_SG_ADDRESS + #define START_PARTITION 4 /* Time to wait before completing a command */ #define DISK_SPEED (HZ/10) /* 100ms */ #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER) -#define SIZE(TGT) (TGT == 2 ? 2248 : 512) +#define SECT_SIZE_PER(TGT) SECT_SIZE +#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE) static int starts[] = {N_SECTOR, N_HEAD * N_SECTOR, /* Single cylinder */ N_HEAD * N_SECTOR * 4, - CAPACITY, 0}; + 0 /* CAPACITY */, 0}; static int npart = 0; -#include "scsi_debug.h" -#ifdef DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif +typedef struct scsi_debug_store_elem { + unsigned char * p; +} Sd_store_elem; + +static Sd_store_elem * store_arr = 0; + +typedef struct sdebug_dev_info { + Scsi_Device * sdp; + unsigned short host_no; + unsigned short id; + char reset; + char sb_index; +} Sdebug_dev_info; +static Sdebug_dev_info * devInfop; + +static int num_aborts = 0; +static int num_dev_resets = 0; +static int num_bus_resets = 0; +static int num_host_resets = 0; -#ifdef SPEEDY -#define VERIFY1_DEBUG(RW) -#define VERIFY_DEBUG(RW) -#else +static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED; +static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED; -#define VERIFY1_DEBUG(RW) \ - if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \ - start = 0; \ - if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \ - if (bh){ \ - if (bh->b_size != 1024) panic ("Wrong bh size"); \ - if ((bh->b_blocknr << 1) + start != block) \ - { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \ - panic ("Wrong bh block#"); \ - }; \ - if (bh->b_dev != SCpnt->request.rq_dev) \ - panic ("Bad bh target"); \ - }; - -#define VERIFY_DEBUG(RW) \ - if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \ - start = 0; \ - if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition"); \ - if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \ - if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \ - if (SCpnt->request.sector + start != block) panic("Wrong block."); \ - if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \ - if (SCpnt->request.bh){ \ - if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \ - if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \ - { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \ - panic ("Wrong bh block#"); \ - }; \ - if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \ - panic ("Bad bh target");\ - }; -#endif +#include "scsi_debug.h" typedef void (*done_fct_t) (Scsi_Cmnd *); -static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = -{NULL,}; +static volatile done_fct_t * do_done = 0; struct Scsi_Host * SHpnt = NULL; +static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, + int num, int * errstsp, Sdebug_dev_info * devip); +static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, + int num, int * errstsp, Sdebug_dev_info * devip); static void scsi_debug_send_self_command(struct Scsi_Host * shpnt); static void scsi_debug_intr_handle(unsigned long); +static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp); +static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, + int asc, int asq, int inbandLen); +static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip); -static struct timer_list timeout[SCSI_DEBUG_MAILBOXES]; - -Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] = -{NULL,}; -static char SCrst[SCSI_DEBUG_MAILBOXES] = -{0,}; +static struct timer_list * timeout = 0; +static Scsi_Cmnd ** SCint = 0; /* * Semaphore used to simulate bus lockups. */ static int scsi_debug_lockup = 0; -static char sense_buffer[128] = -{0,}; +#define NUM_SENSE_BUFFS 4 +#define SENSE_BUFF_LEN 32 +static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN]; -static void scsi_dump(Scsi_Cmnd * SCpnt, int flag) +static int made_block0 = 0; + +static void scsi_debug_mkblock0(unsigned char * buff, int bufflen, + Scsi_Cmnd * SCpnt) { int i; -#if 0 - unsigned char *pnt; -#endif - unsigned int *lpnt; - struct scatterlist *sgpnt = NULL; - printk("use_sg: %d", SCpnt->use_sg); - if (SCpnt->use_sg) { - sgpnt = (struct scatterlist *) SCpnt->buffer; - for (i = 0; i < SCpnt->use_sg; i++) { - printk(":%p %d\n", sgpnt[i].address, sgpnt[i].length); - }; - } else { - printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer, - SCpnt->bufflen); - lpnt = (int *) SCpnt->request.buffer; - if (lpnt) - printk(" (Alt %x) ", lpnt[15]); - }; - lpnt = (unsigned int *) SCpnt; - for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { - if ((i & 7) == 0) - printk("\n"); - printk("%x ", *lpnt++); - }; - printk("\n"); - if (flag == 0) - return; -#if 0 - printk("\n"); - lpnt = (unsigned int *) sgpnt[0].address; - for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) { - if ((i & 7) == 0) - printk("\n"); - printk("%x ", *lpnt++); - }; - printk("\n"); -#endif + struct partition *p; + + memset(buff, 0, bufflen); + *((unsigned short *) (buff + 510)) = 0xAA55; + p = (struct partition *) (buff + 0x1be); + i = 0; + while (starts[i + 1]) { + int start_cyl, end_cyl; + + start_cyl = starts[i] / N_HEAD / N_SECTOR; + end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR; + p->boot_ind = 0; + + p->head = (i == 0 ? 1 : 0); + p->sector = 1 | ((start_cyl >> 8) << 6); + p->cyl = (start_cyl & 0xff); + + p->end_head = N_HEAD - 1; + p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6); + p->end_cyl = (end_cyl & 0xff); + + p->start_sect = starts[i]; + p->nr_sects = starts[i + 1] - starts[i]; + p->sys_ind = 0x83; /* Linux ext2 partition */ + p++; + i++; + } + if (!npart) + npart = i; + made_block0 = 1; + i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen; + memcpy(store_arr[0].p, buff, i); } int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) { unchar *cmd = (unchar *) SCpnt->cmnd; - struct partition *p; int block; - struct buffer_head *bh = NULL; + int upper_blk; unsigned char *buff; - int nbytes, sgcount; int scsi_debug_errsts; - struct scatterlist *sgpnt; int target = SCpnt->target; int bufflen = SCpnt->request_bufflen; - unsigned long flags; - int i; - sgcount = 0; - sgpnt = NULL; + unsigned long iflags; + int i, num, capac; + Sdebug_dev_info * devip = NULL; + char * sbuff; #ifdef CONFIG_SMP /* * The io_request_lock *must* be held at this point. */ - if( io_request_lock.lock == 0 ) + if(! spin_is_locked(&io_request_lock)) { - printk("Warning - io_request_lock is not held in queuecommand\n"); + printk("Warning - io_request_lock is not held in " + "queuecommand\n"); } #endif /* - * If we are being notified of the mid-level reposessing a command due to timeout, - * just return. + * If we are being notified of the mid-level reposessing a command + * due to timeout, just return. */ if (done == NULL) { return 0; } - DEB(if (target >= NR_FAKE_DISKS) { - SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0; - } - ); buff = (unsigned char *) SCpnt->request_buffer; @@ -229,249 +239,201 @@ * If a command comes for the ID of the host itself, just print * a silly message and return. */ - if( target == 7 ) { + if(target == 7) { printk("How do you do!\n"); SCpnt->result = 0; done(SCpnt); return 0; } - if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) { + if ((target > 7) || (SCpnt->lun != 0)) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; } - if (SCrst[target] != 0 && !scsi_debug_lockup) { - SCrst[target] = 0; - memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); - SCpnt->sense_buffer[0] = 0x70; - SCpnt->sense_buffer[2] = UNIT_ATTENTION; - SCpnt->result = (CHECK_CONDITION << 1); - done(SCpnt); +#if 0 + printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n", + (int)SCpnt->device->host->host_no, (int)SCpnt->device->id, + SCpnt->device, (int)(unsigned char)*cmd); +#endif + if (NULL == SCpnt->device->hostdata) { + devip = devInfoReg(SCpnt->device); + if (NULL == devip) { + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + } + SCpnt->device->hostdata = devip; } + devip = SCpnt->device->hostdata; + switch (*cmd) { - case REQUEST_SENSE: + case REQUEST_SENSE: /* mandatory */ SCSI_LOG_LLQUEUE(3, printk("Request sense...\n")); -#ifndef DEBUG - { - int i; - printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen); - for (i = 0; i < 12; i++) - printk("%d ", sense_buffer[i]); - printk("\n"); - }; -#endif - memset(buff, 0, bufflen); - memcpy(buff, sense_buffer, bufflen); - memset(sense_buffer, 0, sizeof(sense_buffer)); + if (devip) { + sbuff = &sense_buffers[(int)devip->sb_index][0]; + devip->sb_index = 0; + } + else + sbuff = &sense_buffers[0][0]; + memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ? + bufflen : SENSE_BUFF_LEN); + memset(sbuff, 0, SENSE_BUFF_LEN); + sbuff[0] = 0x70; SCpnt->result = 0; done(SCpnt); return 0; case START_STOP: + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } SCSI_LOG_LLQUEUE(3, printk("START_STOP\n")); scsi_debug_errsts = 0; break; case ALLOW_MEDIUM_REMOVAL: + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } if (cmd[4]) { - SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited...")); + SCSI_LOG_LLQUEUE(2, printk( + "Medium removal inhibited...")); } else { - SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled...")); + SCSI_LOG_LLQUEUE(2, + printk("Medium removal enabled...")); } scsi_debug_errsts = 0; break; - case INQUIRY: + case INQUIRY: /* mandatory */ SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen)); memset(buff, 0, bufflen); buff[0] = DEVICE_TYPE(target); - buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ - buff[2] = 1; - buff[4] = 33 - 5; - memcpy(&buff[8], "Foo Inc", 7); - memcpy(&buff[16], "XYZZY", 5); - memcpy(&buff[32], "1", 1); + buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; + /* Removable disk */ + buff[2] = 2; /* claim SCSI 2 */ + buff[4] = 36 - 5; + memcpy(&buff[8], "Linux ", 8); + memcpy(&buff[16], "scsi_debug ", 16); + memcpy(&buff[32], "0002", 4); scsi_debug_errsts = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) + if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) + SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; +#endif break; - case TEST_UNIT_READY: + case SEND_DIAGNOSTIC: /* mandatory */ + SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n")); + if (buff) + memset(buff, 0, bufflen); + scsi_debug_errsts = 0; + break; + case TEST_UNIT_READY: /* mandatory */ SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen)); if (buff) memset(buff, 0, bufflen); scsi_debug_errsts = 0; break; case READ_CAPACITY: + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n")); SHpnt = SCpnt->host; - if (NR_REAL < 0) - NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f; memset(buff, 0, bufflen); - buff[0] = (CAPACITY >> 24); - buff[1] = (CAPACITY >> 16) & 0xff; - buff[2] = (CAPACITY >> 8) & 0xff; - buff[3] = CAPACITY & 0xff; + capac = CAPACITY - 1; + buff[0] = (capac >> 24); + buff[1] = (capac >> 16) & 0xff; + buff[2] = (capac >> 8) & 0xff; + buff[3] = capac & 0xff; buff[4] = 0; buff[5] = 0; - buff[6] = (SIZE(target) >> 8) & 0xff; /* 512 byte sectors */ - buff[7] = SIZE(target) & 0xff; + buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; + buff[7] = SECT_SIZE_PER(target) & 0xff; scsi_debug_errsts = 0; break; + case SCSI_CMD_READ_16: /* SBC-2 */ + case READ_12: case READ_10: case READ_6: -#ifdef DEBUG - printk("Read..."); -#endif - if ((*cmd) == READ_10) - block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); - else - block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - VERIFY_DEBUG(READ); -#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE) - { - int delay = SCSI_SETUP_LATENCY; - - delay += SCpnt->request.nr_sectors * SCSI_DATARATE; - if (delay) - usleep(delay); - }; -#endif - -#ifdef DEBUG - printk("(r%d)", SCpnt->request.nr_sectors); -#endif - nbytes = bufflen; - if (SCpnt->use_sg) { - sgcount = 0; - sgpnt = (struct scatterlist *) buff; - buff = sgpnt[sgcount].address; - bufflen = sgpnt[sgcount].length; - bh = SCpnt->request.bh; - }; - scsi_debug_errsts = 0; - do { - VERIFY1_DEBUG(READ); - /* For the speedy test, we do not even want to fill the buffer with anything */ -#ifdef CLEAR - memset(buff, 0, bufflen); -#endif - /* If this is block 0, then we want to read the partition table for this - * device. Let's make one up */ - if (block == 0) { - int i; - memset(buff, 0, bufflen); - *((unsigned short *) (buff + 510)) = 0xAA55; - p = (struct partition *) (buff + 0x1be); - i = 0; - while (starts[i + 1]) { - int start_cyl, end_cyl; - - start_cyl = starts[i] / N_HEAD / N_SECTOR; - end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR; - p->boot_ind = 0; - - p->head = (i == 0 ? 1 : 0); - p->sector = 1 | ((start_cyl >> 8) << 6); - p->cyl = (start_cyl & 0xff); - - p->end_head = N_HEAD - 1; - p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6); - p->end_cyl = (end_cyl & 0xff); - - p->start_sect = starts[i]; - p->nr_sects = starts[i + 1] - starts[i]; - p->sys_ind = 0x81; /* Linux partition */ - p++; - i++; - }; - if (!npart) - npart = i; - scsi_debug_errsts = 0; - break; - }; -#ifdef DEBUG - if (SCpnt->use_sg) - printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors, - SCpnt->request.current_nr_sectors); -#endif - -#if 0 - /* Simulate a disk change */ - if (block == 0xfff0) { - sense_buffer[0] = 0x70; - sense_buffer[2] = UNIT_ATTENTION; - starts[0] += 10; - starts[1] += 10; - starts[2] += 10; - -#ifdef DEBUG - { - int i; - printk("scsi_debug: Filling sense buffer:"); - for (i = 0; i < 12; i++) - printk("%d ", sense_buffer[i]); - printk("\n"); - }; -#endif - scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); - break; - } /* End phony disk change code */ -#endif - -#ifdef CLEAR - memcpy(buff, &target, sizeof(target)); - memcpy(buff + sizeof(target), cmd, 24); - memcpy(buff + 60, &block, sizeof(block)); - memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd)); -#endif - nbytes -= bufflen; - if (SCpnt->use_sg) { -#ifdef CLEAR - memcpy(buff + 128, bh, sizeof(struct buffer_head)); -#endif - block += bufflen >> 9; - bh = bh->b_reqnext; - sgcount++; - if (nbytes) { - if (!bh) - panic("Too few blocks for linked request."); - buff = sgpnt[sgcount].address; - bufflen = sgpnt[sgcount].length; - }; - } - } while (nbytes); - + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } + upper_blk = 0; + if ((*cmd) == SCSI_CMD_READ_16) { + upper_blk = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + block = cmd[9] + (cmd[8] << 8) + + (cmd[7] << 16) + (cmd[6] << 24); + num = cmd[13] + (cmd[12] << 8) + + (cmd[11] << 16) + (cmd[10] << 24); + } + else if ((*cmd) == READ_12) { + block = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + num = cmd[9] + (cmd[8] << 8) + + (cmd[7] << 16) + (cmd[6] << 24); + } + else if ((*cmd) == READ_10) { + block = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + num = cmd[8] + (cmd[7] << 8); + } + else { + block = cmd[3] + (cmd[2] << 8) + + ((cmd[1] & 0x1f) << 16); + num = cmd[4]; + } + if (scsi_debug_read(SCpnt, upper_blk, block, num, + &scsi_debug_errsts, devip)) + break; SCpnt->result = 0; - (done) (SCpnt); +/* calls bottom half in upper layers before return from scsi_do_...() */ + (done) (SCpnt); return 0; - - if (SCpnt->use_sg && !scsi_debug_errsts) - if (bh) - scsi_dump(SCpnt, 0); - break; + case SCSI_CMD_WRITE_16: /* SBC-2 */ + case WRITE_12: case WRITE_10: case WRITE_6: -#ifdef DEBUG - printk("Write\n"); -#endif - if ((*cmd) == WRITE_10) - block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); - else - block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - VERIFY_DEBUG(WRITE); - /* printk("(w%d)",SCpnt->request.nr_sectors); */ - if (SCpnt->use_sg) { - if ((bufflen >> 9) != SCpnt->request.nr_sectors) - panic("Trying to write wrong number of blocks\n"); - sgpnt = (struct scatterlist *) buff; - buff = sgpnt[sgcount].address; - }; -#if 0 - if (block != *((unsigned long *) (buff + 60))) { - printk("%x %x :", block, *((unsigned long *) (buff + 60))); - scsi_dump(SCpnt, 1); - panic("Bad block written.\n"); - }; -#endif - scsi_debug_errsts = 0; - break; + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } + upper_blk = 0; + if ((*cmd) == SCSI_CMD_WRITE_16) { + upper_blk = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + block = cmd[9] + (cmd[8] << 8) + + (cmd[7] << 16) + (cmd[6] << 24); + num = cmd[13] + (cmd[12] << 8) + + (cmd[11] << 16) + (cmd[10] << 24); + } + else if ((*cmd) == WRITE_12) { + block = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + num = cmd[9] + (cmd[8] << 8) + + (cmd[7] << 16) + (cmd[6] << 24); + } + else if ((*cmd) == WRITE_10) { + block = cmd[5] + (cmd[4] << 8) + + (cmd[3] << 16) + (cmd[2] << 24); + num = cmd[8] + (cmd[7] << 8); + } + else { + block = cmd[3] + (cmd[2] << 8) + + ((cmd[1] & 0x1f) << 16); + num = cmd[4]; + } + if (scsi_debug_write(SCpnt, upper_blk, block, num, + &scsi_debug_errsts, devip)) + break; + SCpnt->result = 0; +/* calls bottom half in upper layers before return from scsi_do_...() */ + (done) (SCpnt); + return 0; case MODE_SENSE: /* * Used to detect write protected status. @@ -480,26 +442,36 @@ memset(buff, 0, 6); break; default: +#if 0 SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd)); SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; - }; +#else + if (check_reset(SCpnt, devip)) { + done(SCpnt); + return 0; + } + scsi_debug_errsts = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14); + break; +#endif + } - save_flags(flags); - cli(); + spin_lock_irqsave(&mailbox_lock, iflags); for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) { if (timeout[i].function == NULL) break; - }; + } /* - * If all of the slots are full, just return 1. The new error handling scheme - * allows this, and the mid-level should queue things. + * If all of the slots are full, just return 1. The new error + * handling scheme allows this, and the mid-level should queue things. */ if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) { SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n")); - restore_flags(flags); + spin_unlock_irqrestore(&mailbox_lock, iflags); return 1; } SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i)); @@ -511,7 +483,7 @@ do_done[i] = done; scsi_debug_intr_handle(i); /* No timer - do this one right away */ } - restore_flags(flags); + spin_unlock_irqrestore(&mailbox_lock, iflags); #else SCpnt->result = scsi_debug_errsts; @@ -521,16 +493,197 @@ SCint[i] = SCpnt; do_done[i] = done; - restore_flags(flags); + spin_unlock_irqrestore(&mailbox_lock, iflags); add_timer(&timeout[i]); if (!done) - panic("scsi_debug_queuecommand: done can't be NULL\n"); + printk("scsi_debug_queuecommand: done can't be NULL\n"); #if 0 - printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies); + printk("Sending command (%d %x %d %d)...", i, done, + timeout[i].expires, jiffies); +#endif +#endif + + return 0; +} + +static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip) +{ + if (devip->reset) { + devip->reset = 0; + mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14); + SCpnt->result = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + return 1; + } + return 0; +} + +static inline +unsigned char * sdebug_scatg2virt(const struct scatterlist * sclp) +{ + if (NULL == sclp) + return NULL; + else if (sclp->page) + return (unsigned char *)page_address(sclp->page) + + sclp->offset; + else { +#ifdef SDEBUG_SG_ADDRESS + return sclp->address; +#else + return NULL; +#endif + } +} + +static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, + int num, int * errstsp, Sdebug_dev_info * devip) +{ + unsigned char *buff = (unsigned char *) SCpnt->request_buffer; + int nbytes, sgcount; + struct scatterlist *sgpnt = NULL; + int bufflen = SCpnt->request_bufflen; + unsigned long iflags; + + if (upper_blk || (block + num > CAPACITY)) { + *errstsp = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14); + return 1; + } +#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE) + { + int delay = SCSI_SETUP_LATENCY; + + delay += SCpnt->request.nr_sectors * SCSI_DATARATE; + if (delay) + usleep(delay); + } #endif + + read_lock_irqsave(&sdebug_atomic_rw, iflags); + sgcount = 0; + nbytes = bufflen; + /* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n", + block, bufflen); */ + if (SCpnt->use_sg) { + sgcount = 0; + sgpnt = (struct scatterlist *) buff; + buff = sdebug_scatg2virt(&sgpnt[sgcount]); + bufflen = sgpnt[sgcount].length; + } + *errstsp = 0; + do { + int resid, k, off, len, rem, blk; + unsigned char * bp; + + /* If this is block 0, then we want to read the partition + * table for this device. Let's make one up */ + if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) { + scsi_debug_mkblock0(buff, bufflen, SCpnt); + *errstsp = 0; + break; + } + bp = buff; + blk = block; + for (resid = bufflen; resid > 0; resid -= len) { + k = blk / SECT_PER_ELEM; + off = (blk % SECT_PER_ELEM) * SECT_SIZE; + rem = STORE_ELEM_SIZE - off; + len = (resid > rem) ? rem : resid; +/* printk("sdr: blk=%d k=%d off=%d rem=%d resid" + "=%d len=%d sgcount=%d\n", blk, k, + off, rem, resid, len, sgcount); */ + memcpy(bp, store_arr[k].p + off, len); + bp += len; + blk += len / SECT_SIZE; + } +#if 0 + /* Simulate a disk change */ + if (block == 0xfff0) { + sense_buffer[0] = 0x70; + sense_buffer[2] = UNIT_ATTENTION; + starts[0] += 10; + starts[1] += 10; + starts[2] += 10; + + *errstsp = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + read_unlock_irqrestore(&sdebug_atomic_rw, iflags); + return 1; + } /* End phony disk change code */ #endif + nbytes -= bufflen; + if (SCpnt->use_sg) { + block += bufflen >> POW2_SECT_SIZE; + sgcount++; + if (nbytes) { + buff = sdebug_scatg2virt(&sgpnt[sgcount]); + bufflen = sgpnt[sgcount].length; + } + } + else if (nbytes > 0) + printk("sdebug_read: unexpected nbytes=%d\n", nbytes); + } while (nbytes); + read_unlock_irqrestore(&sdebug_atomic_rw, iflags); + return 0; +} + +static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, + int num, int * errstsp, Sdebug_dev_info * devip) +{ + unsigned char *buff = (unsigned char *) SCpnt->request_buffer; + int nbytes, sgcount; + struct scatterlist *sgpnt = NULL; + int bufflen = SCpnt->request_bufflen; + unsigned long iflags; + + if (upper_blk || (block + num > CAPACITY)) { + *errstsp = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14); + return 1; + } + write_lock_irqsave(&sdebug_atomic_rw, iflags); + sgcount = 0; + nbytes = bufflen; + if (SCpnt->use_sg) { + sgcount = 0; + sgpnt = (struct scatterlist *) buff; + buff = sdebug_scatg2virt(&sgpnt[sgcount]); + bufflen = sgpnt[sgcount].length; + } + *errstsp = 0; + do { + int resid, k, off, len, rem, blk; + unsigned char * bp; + + bp = buff; + blk = block; + for (resid = bufflen; resid > 0; resid -= len) { + k = blk / SECT_PER_ELEM; + off = (blk % SECT_PER_ELEM) * SECT_SIZE; + rem = STORE_ELEM_SIZE - off; + len = (resid > rem) ? rem : resid; + memcpy(store_arr[k].p + off, bp, len); + bp += len; + blk += len / SECT_SIZE; + } + + nbytes -= bufflen; + if (SCpnt->use_sg) { + block += bufflen >> POW2_SECT_SIZE; + sgcount++; + if (nbytes) { + buff = sdebug_scatg2virt(&sgpnt[sgcount]); + bufflen = sgpnt[sgcount].length; + } + } + else if (nbytes > 0) + printk("sdebug_write: unexpected nbytes=%d\n", nbytes); + } while (nbytes); + write_unlock_irqrestore(&sdebug_atomic_rw, iflags); return 0; } @@ -581,10 +734,6 @@ { Scsi_Cmnd *SCtmp; void (*my_done) (Scsi_Cmnd *); -#ifdef DEBUG - int to; -#endif - #if 0 del_timer(&timeout[indx]); #endif @@ -599,59 +748,213 @@ printk("scsi_debug_intr_handle: Unexpected interrupt\n"); return; } -#ifdef DEBUG +#if 0 printk("In intr_handle..."); printk("...done %d %x %d %d\n", i, my_done, to, jiffies); printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done); #endif my_done(SCtmp); -#ifdef DEBUG +#if 0 printk("Called done.\n"); #endif } +static int initialized = 0; + +static int do_init(void) +{ + int sz; + + starts[3] = CAPACITY; + sz = sizeof(Sd_store_elem) * STORE_ELEMENTS; + store_arr = kmalloc(sz, GFP_ATOMIC); + if (NULL == store_arr) + return 1; + memset(store_arr, 0, sz); + sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES; + do_done = kmalloc(sz, GFP_ATOMIC); + if (NULL == do_done) { + kfree(store_arr); + return 1; + } + memset((void *)do_done, 0, sz); + sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES; + timeout = kmalloc(sz, GFP_ATOMIC); + if (NULL == timeout) { + kfree((void *)do_done); + kfree(store_arr); + return 1; + } + memset(timeout, 0, sz); + sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES; + SCint = kmalloc(sz, GFP_ATOMIC); + if (NULL == SCint) { + kfree(timeout); + kfree((void *)do_done); + kfree(store_arr); + return 1; + } + memset(SCint, 0, sz); + return 0; +} + +static void do_end(void) +{ + kfree(SCint); + kfree(timeout); + kfree((void *)do_done); + kfree(store_arr); +} + int scsi_debug_detect(Scsi_Host_Template * tpnt) { - int i; + int k, num, sz; + + if (0 == initialized) { + ++initialized; + sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs; + devInfop = kmalloc(sz, GFP_ATOMIC); + if (NULL == devInfop) { + printk("scsi_debug_detect: out of memory, 0.5\n"); + return 0; + } + memset(devInfop, 0, sz); + if (do_init()) { + printk("scsi_debug_detect: out of memory, 0\n"); + return 0; + } + for (k = 0; k < STORE_ELEMENTS; ++k) { + store_arr[k].p = (unsigned char *) + __get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER); + if (0 == store_arr[k].p) + goto detect_err; + memset(store_arr[k].p, 0, STORE_ELEM_SIZE); + } + for (k = 0; k < NUM_SENSE_BUFFS; ++k) + sense_buffers[k][0] = 0x70; + for (k = 0; k < NR_HOSTS_PRESENT; k++) { + tpnt->proc_name = "scsi_debug"; /* In the loop??? */ + scsi_register(tpnt, 0); + } + return NR_HOSTS_PRESENT; + } + else { + printk("scsi_debug_detect: called again\n"); + return 0; + } + +detect_err: + num = k; + for (k = 0; k < STORE_ELEMENTS; ++k) { + if (0 != store_arr[k].p) { + free_pages((unsigned long)store_arr[k].p, + STORE_ELEM_ORDER); + store_arr[k].p = NULL; + } + } + printk("scsi_debug_detect: out of memory: %d out of %d bytes\n", + (int)(num * STORE_ELEM_SIZE), + (int)(scsi_debug_dev_size_mb * 1024 * 1024)); + return 0; +} + + +static int num_releases = 0; + +int scsi_debug_release(struct Scsi_Host * hpnt) +{ + int k; + + scsi_unregister(hpnt); + if (++num_releases != NR_HOSTS_PRESENT) + return 0; + + for (k = 0; k < STORE_ELEMENTS; ++k) { + if (0 != store_arr[k].p) { + free_pages((unsigned long)store_arr[k].p, + STORE_ELEM_ORDER); + store_arr[k].p = NULL; + } + } + do_end(); + kfree(devInfop); + return 0; +} - for (i = 0; i < NR_HOSTS_PRESENT; i++) { - tpnt->proc_name = "scsi_debug"; /* Huh? In the loop??? */ - scsi_register(tpnt, 0); +static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp) +{ + int k; + unsigned short host_no, id; + Sdebug_dev_info * devip; + + host_no = sdp->host->host_no; + id = (unsigned short)sdp->id; + for (k = 0; k < scsi_debug_num_devs; ++k) { + devip = &devInfop[k]; + if (devip->sdp && (host_no == devip->host_no) && + (id == devip->id)) { + devip->sdp = sdp; /* overwrite previous sdp */ + return devip; + } + if (NULL == devip->sdp) { + devip->sdp = sdp; + devip->host_no = host_no; + devip->id = id; + devip->reset = 1; + devip->sb_index = 0; + return devip; + } } - return NR_HOSTS_PRESENT; + return NULL; +} + +static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, + int asc, int asq, int inbandLen) +{ + char * sbuff; + if ((index < 0) || (index >= NUM_SENSE_BUFFS)) + return; + if (devip) + devip->sb_index = index; + sbuff = &sense_buffers[index][0]; + memset(sbuff, 0, SENSE_BUFF_LEN); + sbuff[0] = 0x70; + sbuff[2] = key; + sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0; + sbuff[12] = asc; + sbuff[13] = asq; } int scsi_debug_abort(Scsi_Cmnd * SCpnt) { -#if 0 +#if 1 + ++num_aborts; + return SUCCESS; +#else int j; void (*my_done) (Scsi_Cmnd *); - unsigned long flags; -#endif - - DEB(printk("scsi_debug_abort\n")); -#if 0 + unsigned long iflags; SCpnt->result = SCpnt->abort_reason << 16; for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) { if (SCpnt == SCint[j]) { my_done = do_done[j]; my_done(SCpnt); - save_flags(flags); - cli(); + spin_lock_irqsave(&mailbox_lock, iflags); timeout[j] = 0; SCint[j] = NULL; do_done[j] = NULL; - restore_flags(flags); - }; - }; -#endif + spin_unlock_irqrestore(&mailbox_lock, iflags); + } + } return SCSI_ABORT_SNOOZE; +#endif } int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info) { + /* int size = disk->capacity; */ info[0] = N_HEAD; info[1] = N_SECTOR; info[2] = N_CYLINDER; @@ -660,35 +963,130 @@ return 0; } +#if 0 int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why) { int i; - unsigned long flags; + unsigned long iflags; void (*my_done) (Scsi_Cmnd *); printk("Bus unlocked by reset - %d\n", why); scsi_debug_lockup = 0; - DEB(printk("scsi_debug_reset called\n")); for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) { if (SCint[i] == NULL) continue; SCint[i]->result = DID_RESET << 16; my_done = do_done[i]; my_done(SCint[i]); - save_flags(flags); - cli(); + spin_lock_irqsave(&mailbox_lock, iflags); SCint[i] = NULL; do_done[i] = NULL; timeout[i].function = NULL; - restore_flags(flags); + spin_unlock_irqrestore(&mailbox_lock, iflags); } return SCSI_RESET_SUCCESS; } +#endif + +int scsi_debug_device_reset(Scsi_Cmnd * SCpnt) +{ + Scsi_Device * sdp; + int k; + + ++num_dev_resets; + if (SCpnt && ((sdp = SCpnt->device))) { + for (k = 0; k < scsi_debug_num_devs; ++k) { + if (sdp->hostdata == (devInfop + k)) + break; + } + if (k < scsi_debug_num_devs) + devInfop[k].reset = 1; + } + return SUCCESS; +} -const char *scsi_debug_info(void) +int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt) { - static char buffer[] = " "; /* looks nicer without anything here */ - return buffer; + Scsi_Device * sdp; + struct Scsi_Host * hp; + int k; + + ++num_bus_resets; + if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { + for (k = 0; k < scsi_debug_num_devs; ++k) { + if (hp == devInfop[k].sdp->host) + devInfop[k].reset = 1; + } + } + return SUCCESS; +} + +int scsi_debug_host_reset(Scsi_Cmnd * SCpnt) +{ + int k; + + ++num_host_resets; + for (k = 0; k < scsi_debug_num_devs; ++k) + devInfop[k].reset = 1; + + return SUCCESS; +} + +#ifndef MODULE +static int __init scsi_debug_num_devs_setup(char *str) +{ + int tmp; + + if (get_option(&str, &tmp) == 1) { + if (tmp > 0) + scsi_debug_num_devs = tmp; + return 1; + } else { + printk("scsi_debug_num_devs: usage scsi_debug_num_devs=<n> " + "(<n> can be from 1 to around 2000)\n"); + return 0; + } +} + +__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup); + +static int __init scsi_debug_dev_size_mb_setup(char *str) +{ + int tmp; + + if (get_option(&str, &tmp) == 1) { + if (tmp > 0) + scsi_debug_dev_size_mb = tmp; + return 1; + } else { + printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=<n>\n" + " (<n> is number of MB ram shared by all devs\n"); + return 0; + } +} + +__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup); +#endif + +MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); +MODULE_DESCRIPTION("SCSI debug adapter driver"); +MODULE_PARM(scsi_debug_num_devs, "i"); +MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate"); +MODULE_PARM(scsi_debug_dev_size_mb, "i"); +MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs"); + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +static char sdebug_info[256]; + +const char * scsi_debug_info(struct Scsi_Host * shp) +{ + sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, " + "dev_size_mb=%d\n", scsi_debug_version_str, + scsi_debug_num_devs, scsi_debug_dev_size_mb); + return sdebug_info; } /* scsi_debug_proc_info @@ -738,10 +1136,20 @@ } begin = 0; - pos = len = sprintf(buffer, - "This driver is not a real scsi driver, but it plays one on TV.\n" + pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n" + "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n" + "cylinders=%d, heads=%d, sectors=%d\n" + "number of aborts=%d, device_reset=%d, bus_resets=%d, " + "host_resets=%d\n", + scsi_debug_version_str, scsi_debug_num_devs, + scsi_debug_dev_size_mb, SECT_SIZE, + N_CYLINDER, N_HEAD, N_SECTOR, + num_aborts, num_dev_resets, num_bus_resets, num_host_resets); +#if 0 + "This driver is not a real scsi driver, but it plays one on TV.\n" "It is very handy for debugging specific problems because you\n" "can simulate a variety of error conditions\n"); +#endif if (pos < offset) { len = 0; begin = pos; @@ -754,44 +1162,8 @@ return (len); } -#ifdef CONFIG_USER_DEBUG -/* - * This is a hack for the user space emulator. It allows us to - * "insert" arbitrary numbers of additional drivers. - */ -void *scsi_debug_get_handle(void) -{ - static Scsi_Host_Template driver_copy = SCSI_DEBUG; - void *rtn; - rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC); - if(rtn==NULL) - return NULL; - memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy)); - return rtn; -} -#endif - /* Eventually this will go into an include file, but this will be later */ -static Scsi_Host_Template driver_template = SCSI_DEBUG; +static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE; #include "scsi_module.c" -/* - * Overrides for Emacs so that we almost 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: - */ -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi_debug.h linux-2.5/drivers/scsi/scsi_debug.h --- linux-2.5.1/drivers/scsi/scsi_debug.h Wed Nov 28 18:22:27 2001 +++ linux-2.5/drivers/scsi/scsi_debug.h Thu Dec 27 15:14:59 2001 @@ -8,34 +8,41 @@ int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int scsi_debug_abort(Scsi_Cmnd *); int scsi_debug_biosparam(Disk *, kdev_t, int[]); -int scsi_debug_reset(Scsi_Cmnd *, unsigned int); +int scsi_debug_bus_reset(Scsi_Cmnd *); +int scsi_debug_dev_reset(Scsi_Cmnd *); +int scsi_debug_host_reset(Scsi_Cmnd *); int scsi_debug_proc_info(char *, char **, off_t, int, int, int); +const char * scsi_debug_info(struct Scsi_Host *); #ifndef NULL #define NULL 0 #endif - -#define SCSI_DEBUG_MAILBOXES 1 - /* - * Allow the driver to reject commands. Thus we accept only one, but - * and the mid-level will queue the remainder. + * This driver is written for the lk 2.5 series */ #define SCSI_DEBUG_CANQUEUE 255 -#define SCSI_DEBUG {proc_info: scsi_debug_proc_info, \ +#define SCSI_DEBUG_MAX_CMD_LEN 16 + +#define SCSI_DEBUG_TEMPLATE \ + {proc_info: scsi_debug_proc_info, \ name: "SCSI DEBUG", \ + info: scsi_debug_info, \ detect: scsi_debug_detect, \ + release: scsi_debug_release, \ queuecommand: scsi_debug_queuecommand, \ - abort: scsi_debug_abort, \ - reset: scsi_debug_reset, \ + eh_abort_handler: scsi_debug_abort, \ + eh_bus_reset_handler: scsi_debug_bus_reset, \ + eh_device_reset_handler: scsi_debug_device_reset, \ + eh_host_reset_handler: scsi_debug_host_reset, \ bios_param: scsi_debug_biosparam, \ can_queue: SCSI_DEBUG_CANQUEUE, \ this_id: 7, \ - sg_tablesize: 16, \ + sg_tablesize: 64, \ cmd_per_lun: 3, \ unchecked_isa_dma: 0, \ use_clustering: ENABLE_CLUSTERING, \ } + #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi_error.c linux-2.5/drivers/scsi/scsi_error.c --- linux-2.5.1/drivers/scsi/scsi_error.c Wed Dec 12 21:41:03 2001 +++ linux-2.5/drivers/scsi/scsi_error.c Sun Jan 6 19:17:51 2002 @@ -583,7 +583,7 @@ unsigned long flags; struct Scsi_Host *host = SCpnt->host; - ASSERT_LOCK(&host->host_lock, 0); + ASSERT_LOCK(host->host_lock, 0); retry: /* @@ -605,9 +605,9 @@ SCpnt->host->eh_action = &sem; SCpnt->request.rq_status = RQ_SCSI_BUSY; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); host->hostt->queuecommand(SCpnt, scsi_eh_done); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); down(&sem); @@ -630,10 +630,10 @@ * abort a timed out command or not. Not sure how * we should treat them differently anyways. */ - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); if (SCpnt->host->hostt->eh_abort_handler) SCpnt->host->hostt->eh_abort_handler(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); SCpnt->request.rq_status = RQ_SCSI_DONE; SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; @@ -650,9 +650,9 @@ * timeout protection here, since we would end up waiting in * the actual low level driver, we don't know how to wake it up. */ - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); temp = host->hostt->command(SCpnt); - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); SCpnt->result = temp; /* Fall through to code below to examine status. */ @@ -772,9 +772,9 @@ SCpnt->owner = SCSI_OWNER_LOWLEVEL; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); return rtn; } @@ -804,9 +804,9 @@ } SCpnt->owner = SCSI_OWNER_LOWLEVEL; - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS; @@ -837,9 +837,9 @@ return FAILED; } - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS; @@ -883,9 +883,9 @@ if (SCpnt->host->hostt->eh_host_reset_handler == NULL) { return FAILED; } - spin_lock_irqsave(&SCpnt->host->host_lock, flags); + spin_lock_irqsave(SCpnt->host->host_lock, flags); rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt); - spin_unlock_irqrestore(&SCpnt->host->host_lock, flags); + spin_unlock_irqrestore(SCpnt->host->host_lock, flags); if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS; @@ -1226,7 +1226,7 @@ Scsi_Device *SDpnt; unsigned long flags; - ASSERT_LOCK(&host->host_lock, 0); + ASSERT_LOCK(host->host_lock, 0); /* * Next free up anything directly waiting upon the host. This will be @@ -1243,7 +1243,7 @@ * now that error recovery is done, we will need to ensure that these * requests are started. */ - spin_lock_irqsave(&host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { request_queue_t *q = &SDpnt->request_queue; @@ -1256,7 +1256,7 @@ q->request_fn(q); } - spin_unlock_irqrestore(&host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } /* @@ -1303,7 +1303,7 @@ Scsi_Cmnd *SCdone; int timed_out; - ASSERT_LOCK(&host->host_lock, 0); + ASSERT_LOCK(host->host_lock, 0); SCdone = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi_lib.c linux-2.5/drivers/scsi/scsi_lib.c --- linux-2.5.1/drivers/scsi/scsi_lib.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/scsi_lib.c Mon Jan 14 23:05:30 2002 @@ -83,7 +83,6 @@ rq->q = NULL; rq->bio = rq->biotail = NULL; rq->nr_phys_segments = 0; - rq->elevator_sequence = 0; /* * We have the option of inserting the head or the tail of the queue. @@ -92,7 +91,7 @@ * device, or a host that is unable to accept a particular command. */ spin_lock_irqsave(q->queue_lock, flags); - __elv_add_request(q, rq, !at_head, 0); + _elv_add_request(q, rq, !at_head, 0); q->request_fn(q); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -262,7 +261,7 @@ * the bad sector. */ SCpnt->request.special = (void *) SCpnt; - __elv_add_request(q, &SCpnt->request, 0, 0); + _elv_add_request(q, &SCpnt->request, 0, 0); } /* @@ -366,7 +365,7 @@ * If there are blocks left over at the end, set up the command * to queue the remainder of them. */ - if (end_that_request_first(req, 1, sectors)) { + if (end_that_request_first(req, uptodate, sectors)) { if (!requeue) return SCpnt; @@ -385,7 +384,7 @@ if (req->waiting) complete(req->waiting); - add_blkdev_randomness(MAJOR(req->rq_dev)); + add_blkdev_randomness(major(req->rq_dev)); /* * This will goose the queue request function at the end, so we don't @@ -445,7 +444,7 @@ { struct request *req = &SCpnt->request; - ASSERT_LOCK(&SCpnt->host->host_lock, 0); + ASSERT_LOCK(SCpnt->host->host_lock, 0); /* * Free up any indirection buffers we allocated for DMA purposes. @@ -744,7 +743,7 @@ { struct Scsi_Device_Template *spnt; kdev_t dev = req->rq_dev; - int major = MAJOR(dev); + int major = major(dev); for (spnt = scsi_devicelist; spnt; spnt = spnt->next) { /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi_merge.c linux-2.5/drivers/scsi/scsi_merge.c --- linux-2.5.1/drivers/scsi/scsi_merge.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/scsi_merge.c Thu Dec 20 19:14:29 2001 @@ -59,12 +59,10 @@ */ int scsi_init_io(Scsi_Cmnd *SCpnt) { - struct request *req; + struct request *req = &SCpnt->request; struct scatterlist *sgpnt; int count, gfp_mask; - req = &SCpnt->request; - /* * First we need to know how many scatter gather segments are needed. */ @@ -85,14 +83,13 @@ BUG_ON(!sgpnt); SCpnt->request_buffer = (char *) sgpnt; - SCpnt->request_bufflen = 0; + SCpnt->request_bufflen = req->nr_sectors << 9; req->buffer = NULL; /* * Next, walk the list, and fill in the addresses and sizes of * each segment. */ - SCpnt->request_bufflen = req->nr_sectors << 9; count = blk_rq_map_sg(req->q, req, SCpnt->request_buffer); /* @@ -142,8 +139,7 @@ bounce_limit = BLK_BOUNCE_ANY; else bounce_limit = SHpnt->pci_dev->dma_mask; - } - if (SHpnt->unchecked_isa_dma) + } else if (SHpnt->unchecked_isa_dma) bounce_limit = BLK_BOUNCE_ISA; blk_queue_bounce_limit(q, bounce_limit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi_module.c linux-2.5/drivers/scsi/scsi_module.c --- linux-2.5.1/drivers/scsi/scsi_module.c Wed Sep 20 20:11:53 2000 +++ linux-2.5/drivers/scsi/scsi_module.c Thu Dec 27 22:10:28 2001 @@ -35,17 +35,17 @@ static int __init init_this_scsi_driver(void) { driver_template.module = THIS_MODULE; - scsi_register_module(MODULE_SCSI_HA, &driver_template); + scsi_register_host(&driver_template); if (driver_template.present) return 0; - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + scsi_unregister_host(&driver_template); return -ENODEV; } static void __exit exit_this_scsi_driver(void) { - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + scsi_unregister_host(&driver_template); } module_init(init_this_scsi_driver); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi_queue.c linux-2.5/drivers/scsi/scsi_queue.c --- linux-2.5.1/drivers/scsi/scsi_queue.c Wed Dec 12 21:41:09 2001 +++ linux-2.5/drivers/scsi/scsi_queue.c Sun Jan 6 19:17:51 2002 @@ -137,10 +137,10 @@ * Decrement the counters, since these commands are no longer * active on the host/device. */ - spin_lock_irqsave(&cmd->host->host_lock, flags); + spin_lock_irqsave(cmd->host->host_lock, flags); cmd->host->host_busy--; cmd->device->device_busy--; - spin_unlock_irqrestore(&cmd->host->host_lock, flags); + spin_unlock_irqrestore(cmd->host->host_lock, flags); /* * Insert this command at the head of the queue for it's device. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi_scan.c linux-2.5/drivers/scsi/scsi_scan.c --- linux-2.5.1/drivers/scsi/scsi_scan.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/scsi_scan.c Mon Jan 14 22:39:45 2002 @@ -155,11 +155,14 @@ {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN}, {"CMD", "CRA-7280", "*", BLIST_SPARSELUN}, // CMD RAID Controller {"CNSI", "G7324", "*", BLIST_SPARSELUN}, // Chaparral G7324 RAID + {"CNSi", "G8324", "*", BLIST_SPARSELUN}, // Chaparral G8324 RAID {"Zzyzx", "RocketStor 500S", "*", BLIST_SPARSELUN}, {"Zzyzx", "RocketStor 2000", "*", BLIST_SPARSELUN}, {"SONY", "TSL", "*", BLIST_FORCELUN}, // DDS3 & DDS4 autoloaders {"DELL", "PERCRAID", "*", BLIST_FORCELUN}, {"HP", "NetRAID-4M", "*", BLIST_FORCELUN}, + {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN}, + {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN}, /* * Must be at end of list... @@ -498,6 +501,7 @@ Scsi_Request * SRpnt; int bflags, type = -1; extern devfs_handle_t scsi_devfs_handle; + int scsi_level; SDpnt->host = shpnt; SDpnt->id = dev; @@ -628,6 +632,7 @@ switch (type = (scsi_result[0] & 0x1f)) { case TYPE_TAPE: case TYPE_DISK: + case TYPE_PRINTER: case TYPE_MOD: case TYPE_PROCESSOR: case TYPE_SCANNER: @@ -670,6 +675,7 @@ (SDpnt->scsi_level == 1 && (scsi_result[3] & 0x0f) == 1)) SDpnt->scsi_level++; + scsi_level = SDpnt->scsi_level; /* * Accommodate drivers that want to sleep when they should be in a polling @@ -747,6 +753,7 @@ SDpnt->queue_depth = 1; SDpnt->host = shpnt; SDpnt->online = TRUE; + SDpnt->scsi_level = scsi_level; /* * Register the queue for the device. All I/O requests will come diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsi_syms.c linux-2.5/drivers/scsi/scsi_syms.c --- linux-2.5.1/drivers/scsi/scsi_syms.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/scsi_syms.c Thu Dec 27 22:10:28 2001 @@ -31,12 +31,15 @@ * This source file contains the symbol table used by scsi loadable * modules. */ -EXPORT_SYMBOL(scsi_register_module); -EXPORT_SYMBOL(scsi_unregister_module); +EXPORT_SYMBOL(scsi_register_device); +EXPORT_SYMBOL(scsi_unregister_device); +EXPORT_SYMBOL(scsi_register_host); +EXPORT_SYMBOL(scsi_unregister_host); EXPORT_SYMBOL(scsi_register); EXPORT_SYMBOL(scsi_unregister); EXPORT_SYMBOL(scsicam_bios_param); EXPORT_SYMBOL(scsi_partsize); +EXPORT_SYMBOL(scsi_bios_ptable); EXPORT_SYMBOL(scsi_allocate_device); EXPORT_SYMBOL(scsi_do_cmd); EXPORT_SYMBOL(scsi_command_size); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/scsicam.c linux-2.5/drivers/scsi/scsicam.c --- linux-2.5.1/drivers/scsi/scsicam.c Fri Nov 19 03:09:14 1999 +++ linux-2.5/drivers/scsi/scsicam.c Tue Jan 8 00:44:24 2002 @@ -26,6 +26,36 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs); +unsigned char *scsi_bios_ptable(kdev_t dev) +{ + struct block_device *bdev; + unsigned char *res = kmalloc(66, GFP_KERNEL); + kdev_t rdev = mk_kdev(major(dev), minor(dev) & ~0x0f); + + if (res) { + struct buffer_head *bh; + int err; + + bdev = bdget(kdev_t_to_nr(rdev)); + if (!bdev) + goto fail; + err = blkdev_get(bdev, FMODE_READ, 0, BDEV_FILE); + if (err) + goto fail; + bh = __bread(bdev, 0, block_size(rdev)); + if (!bh) + goto fail2; + memcpy(res, bh->b_data + 0x1be, 66); + brelse(bh); + blkdev_put(bdev, BDEV_FILE); + } + return res; +fail2: + blkdev_put(bdev, BDEV_FILE); +fail: + kfree(res); + return NULL; +} /* * Function : int scsicam_bios_param (Disk *disk, int dev, int *ip) @@ -42,26 +72,18 @@ kdev_t dev, /* Device major, minor */ int *ip /* Heads, sectors, cylinders in that order */ ) { - struct buffer_head *bh; int ret_code; int size = disk->capacity; unsigned long temp_cyl; + unsigned char *p = scsi_bios_ptable(dev); - int ma = MAJOR(dev); - int mi = (MINOR(dev) & ~0xf); - - int block = 1024; - - if(blksize_size[ma]) - block = blksize_size[ma][mi]; - - if (!(bh = bread(MKDEV(ma,mi), 0, block))) + if (!p) return -1; /* try to infer mapping from partition table */ - ret_code = scsi_partsize(bh, (unsigned long) size, (unsigned int *) ip + 2, + ret_code = scsi_partsize(p, (unsigned long) size, (unsigned int *) ip + 2, (unsigned int *) ip + 0, (unsigned int *) ip + 1); - brelse(bh); + kfree(p); if (ret_code == -1) { /* pick some standard mapping with at most 1024 cylinders, @@ -86,7 +108,7 @@ } /* - * Function : static int scsi_partsize(struct buffer_head *bh, unsigned long + * Function : static int scsi_partsize(unsigned char *buf, unsigned long * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); * * Purpose : to determine the BIOS mapping used to create the partition @@ -96,18 +118,17 @@ * */ -int scsi_partsize(struct buffer_head *bh, unsigned long capacity, +int scsi_partsize(unsigned char *buf, unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs) { - struct partition *p, *largest = NULL; + struct partition *p = (struct partition *)buf, *largest = NULL; int i, largest_cyl; int cyl, ext_cyl, end_head, end_cyl, end_sector; unsigned int logical_end, physical_end, ext_physical_end; - if (*(unsigned short *) (bh->b_data + 510) == 0xAA55) { - for (largest_cyl = -1, p = (struct partition *) - (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) { + if (*(unsigned short *) (buf + 66) == 0xAA55) { + for (largest_cyl = -1, i = 0; i < 4; ++i, ++p) { if (!p->sys_ind) continue; #ifdef DEBUG diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sd.c linux-2.5/drivers/scsi/sd.c --- linux-2.5.1/drivers/scsi/sd.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/sd.c Thu Jan 10 22:14:47 2002 @@ -66,7 +66,7 @@ #define SCSI_DISKS_PER_MAJOR 16 #define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8) #define SD_MINOR_NUMBER(i) ((i) & 255) -#define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), (i) & 255) +#define MKDEV_SD_PARTITION(i) mk_kdev(SD_MAJOR_NUMBER(i), (i) & 255) #define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4) #define N_USED_SD_MAJORS (1 + ((sd_template.dev_max - 1) >> 4)) @@ -99,6 +99,7 @@ static int sd_init_command(Scsi_Cmnd *); static struct Scsi_Device_Template sd_template = { + module:THIS_MODULE, name:"disk", tag:"sd", scsi_type:TYPE_DISK, @@ -568,7 +569,6 @@ major: SCSI_DISK0_MAJOR, major_name: "sd", minor_shift: 4, - max_p: 1 << 4, fops: &sd_fops, }; @@ -968,9 +968,9 @@ */ int hard_sector = sector_size; int sz = rscsi_disks[i].capacity * (hard_sector/256); + request_queue_t *queue = &rscsi_disks[i].device->request_queue; - /* There are 16 minors allocated for each major device */ - blk_queue_hardsect_size(blk_get_queue(SD_MAJOR(i)), hard_sector); + blk_queue_hardsect_size(queue, hard_sector); printk("SCSI device %s: " "%d %d-byte hdwr sectors (%d MB)\n", nbuff, rscsi_disks[i].capacity, @@ -1115,7 +1115,7 @@ } for (i = 0; i < N_USED_SD_MAJORS; i++) { - request_queue_t *q = blk_get_queue(SD_MAJOR(i)); + request_queue_t *q = blk_get_queue(mk_kdev(SD_MAJOR(i), 0)); int parts_per_major = (SCSI_DISKS_PER_MAJOR << 4); blksize_size[SD_MAJOR(i)] = @@ -1140,12 +1140,9 @@ sd_gendisks[i].major = SD_MAJOR(i); sd_gendisks[i].major_name = "sd"; sd_gendisks[i].minor_shift = 4; - sd_gendisks[i].max_p = 1 << 4; sd_gendisks[i].part = sd + i * (N << 4); sd_gendisks[i].sizes = sd_sizes + i * (N << 4); sd_gendisks[i].nr_real = 0; - sd_gendisks[i].real_devices = - (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR); } return 0; @@ -1308,7 +1305,7 @@ for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++) if (dpnt->device == SDp) { - max_p = sd_gendisk.max_p; + max_p = 1 << sd_gendisk.minor_shift; start = i << sd_gendisk.minor_shift; dev = MKDEV_SD_PARTITION(start); wipe_partitions(dev); @@ -1332,14 +1329,14 @@ static int __init init_sd(void) { sd_template.module = THIS_MODULE; - return scsi_register_module(MODULE_SCSI_DEV, &sd_template); + return scsi_register_device(&sd_template); } static void __exit exit_sd(void) { int i; - scsi_unregister_module(MODULE_SCSI_DEV, &sd_template); + scsi_unregister_device(&sd_template); for (i = 0; i < N_USED_SD_MAJORS; i++) devfs_unregister_blkdev(SD_MAJOR(i), "sd"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sd.h linux-2.5/drivers/scsi/sd.h --- linux-2.5.1/drivers/scsi/sd.h Sun Dec 16 23:46:45 2001 +++ linux-2.5/drivers/scsi/sd.h Mon Jan 14 14:39:03 2002 @@ -45,7 +45,7 @@ #define N_SD_MAJORS 8 #define SD_MAJOR_MASK (N_SD_MAJORS - 1) -#define SD_PARTITION(i) (((MAJOR(i) & SD_MAJOR_MASK) << 8) | (MINOR(i) & 255)) +#define SD_PARTITION(i) (((major(i) & SD_MAJOR_MASK) << 8) | (minor(i) & 255)) #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sg.c linux-2.5/drivers/scsi/sg.c --- linux-2.5.1/drivers/scsi/sg.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/sg.c Fri Jan 4 16:27:40 2002 @@ -19,9 +19,9 @@ */ #include <linux/config.h> #ifdef CONFIG_PROC_FS - static char sg_version_str[] = "Version: 3.1.20 (20010814)"; + static char sg_version_str[] = "Version: 3.5.23 (20020103)"; #endif - static int sg_version_num = 30120; /* 2 digits for each component */ + static int sg_version_num = 30523; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First @@ -76,12 +76,18 @@ #include <linux/version.h> #endif /* LINUX_VERSION_CODE */ +#define SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST + #define SG_ALLOW_DIO_DEF 0 #define SG_ALLOW_DIO_CODE /* compile out be commenting this define */ #ifdef SG_ALLOW_DIO_CODE #include <linux/iobuf.h> #endif +#define SG_NEW_KIOVEC 0 /* use alloc_kiovec(), not alloc_kiovec_sz() */ + +#define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1) + int sg_big_buff = SG_DEF_RESERVED_SIZE; /* N.B. This variable is readable and writeable via /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer @@ -95,14 +101,8 @@ #define SG_SECTOR_SZ 512 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) -#define SG_LOW_POOL_THRESHHOLD 30 -#define SG_MAX_POOL_SECTORS 320 /* Max. number of pool sectors to take */ - -static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS; - #define SG_HEAP_PAGE 1 /* heap from kernel via get_free_pages() */ #define SG_HEAP_KMAL 2 /* heap from kernel via kmalloc() */ -#define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */ #define SG_USER_MEM 4 /* memory belongs to user space */ #define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */ @@ -121,6 +121,7 @@ static struct Scsi_Device_Template sg_template = { + module:THIS_MODULE, tag:"sg", scsi_type:0xff, major:SCSI_GENERIC_MAJOR, @@ -135,10 +136,10 @@ typedef struct sg_scatter_hold /* holding area for scsi scatter gather info */ { unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */ - unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */ unsigned bufflen; /* Size of (aggregate) data buffer */ unsigned b_malloc_len; /* actual len malloc'ed in buffer */ - void * buffer; /* Data buffer or scatter list,12 bytes each*/ + void * buffer; /* Data buffer or scatter list + mem_src_arr */ struct kiobuf * kiobp; /* for direct IO information */ char mapped; /* indicates kiobp has locked pages */ char buffer_mem_src; /* heap whereabouts of 'buffer' */ @@ -181,6 +182,7 @@ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ + char mmap_called; /* 0 -> mmap() never called on this fd */ } Sg_fd; /* 2760 bytes long on i386 */ typedef struct sg_device /* holds the state of each scsi generic device */ @@ -202,7 +204,8 @@ static int sg_start_req(Sg_request * srp); static void sg_finish_rem_req(Sg_request * srp); static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size); -static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp); +static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, + int tablesize); static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count, Sg_request * srp); static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count, @@ -232,13 +235,15 @@ static Sg_request * sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(Sg_fd * sfp); -static void sg_clr_srpnt(Scsi_Request * SRpnt); static int sg_ms_to_jif(unsigned int msecs); -static unsigned sg_jif_to_ms(int jifs); +static inline unsigned sg_jif_to_ms(int jifs); static int sg_allow_access(unsigned char opcode, char dev_type); static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len); static void sg_unmap_and(Sg_scatter_hold * schp, int free_also); static Sg_device * sg_get_dev(int dev); +static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp); +static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp); +static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp); #ifdef CONFIG_PROC_FS static int sg_last_dev(void); #endif @@ -253,7 +258,7 @@ static int sg_open(struct inode * inode, struct file * filp) { - int dev = MINOR(inode->i_rdev); + int dev = minor(inode->i_rdev); int flags = filp->f_flags; Sg_device * sdp; Sg_fd * sfp; @@ -336,10 +341,9 @@ Sg_device * sdp; Sg_fd * sfp; - if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) { + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; - } - SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", MINOR(sdp->i_rdev))); + SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev))); sg_fasync(-1, filp, 0); /* remove filp from async notification list */ if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */ if (! sdp->detached) { @@ -368,7 +372,7 @@ if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n", - MINOR(sdp->i_rdev), (int)count)); + minor(sdp->i_rdev), (int)count)); if (ppos != &filp->f_pos) ; /* FIXME: Hmm. Seek to the right place, or fail? */ if ((k = verify_area(VERIFY_WRITE, buf, count))) @@ -513,7 +517,7 @@ if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", - MINOR(sdp->i_rdev), (int)count)); + minor(sdp->i_rdev), (int)count)); if (sdp->detached) return -ENODEV; if (! ((filp->f_flags & O_NONBLOCK) || @@ -614,6 +618,20 @@ sg_remove_request(sfp, srp); return -ENOSYS; } + if (hp->flags & SG_FLAG_MMAP_IO) { + if (hp->dxfer_len > sfp->reserve.bufflen) { + sg_remove_request(sfp, srp); + return -ENOMEM; /* MMAP_IO size must fit in reserve buffer */ + } + if (hp->flags & SG_FLAG_DIRECT_IO) { + sg_remove_request(sfp, srp); + return -EINVAL; /* either MMAP_IO or DIRECT_IO (not both) */ + } + if (sg_res_in_use(sfp)) { + sg_remove_request(sfp, srp); + return -EBUSY; /* reserve buffer already being used */ + } + } timeout = sg_ms_to_jif(srp->header.timeout); if ((! hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof(cmnd))) { sg_remove_request(sfp, srp); @@ -730,7 +748,7 @@ if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n", - MINOR(sdp->i_rdev), (int)cmd_in)); + minor(sdp->i_rdev), (int)cmd_in)); read_only = (O_RDWR != (filp->f_flags & O_ACCMODE)); switch(cmd_in) @@ -848,7 +866,7 @@ result = get_user(val, (int *)arg); if (result) return result; if (val != sfp->reserve.bufflen) { - if (sg_res_in_use(sfp)) + if (sg_res_in_use(sfp) || sfp->mmap_called) return -EBUSY; sg_remove_scat(&sfp->reserve); sg_build_reserve(sfp, val); @@ -1010,7 +1028,7 @@ else if (count < SG_MAX_QUEUE) res |= POLLOUT | POLLWRNORM; SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n", - MINOR(sdp->i_rdev), (int)res)); + minor(sdp->i_rdev), (int)res)); return res; } @@ -1023,18 +1041,158 @@ if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n", - MINOR(sdp->i_rdev), mode)); + minor(sdp->i_rdev), mode)); retval = fasync_helper(fd, filp, mode, &sfp->async_qp); return (retval < 0) ? retval : 0; } +static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp) +{ + return (sclp && sclp->page) ? + (unsigned char *)page_address(sclp->page) + sclp->offset : + NULL; +} + +static void sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish) +{ + void * page_ptr; + struct page * page; + int k, m; + + SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, " + "scatg=%d\n", startFinish, rsv_schp->k_use_sg)); + /* N.B. correction _not_ applied to base page of aech allocation */ + if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */ + struct scatterlist * sclp = rsv_schp->buffer; + + for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) { + for (m = PAGE_SIZE; m < sclp->length; m += PAGE_SIZE) { + page_ptr = sg_scatg2virt(sclp) + m; + page = virt_to_page(page_ptr); + if (startFinish) + get_page(page); /* increment page count */ + else { + if (page_count(page) > 0) + put_page_testzero(page); /* decrement page count */ + } + } + } + } + else { /* reserve buffer is just a single allocation */ + for (m = PAGE_SIZE; m < rsv_schp->bufflen; m += PAGE_SIZE) { + page_ptr = (unsigned char *)rsv_schp->buffer + m; + page = virt_to_page(page_ptr); + if (startFinish) + get_page(page); /* increment page count */ + else { + if (page_count(page) > 0) + put_page_testzero(page); /* decrement page count */ + } + } + } +} + +static struct page * sg_vma_nopage(struct vm_area_struct *vma, + unsigned long addr, int unused) +{ + Sg_fd * sfp; + struct page * page = NOPAGE_SIGBUS; + void * page_ptr = NULL; + unsigned long offset; + Sg_scatter_hold * rsv_schp; + + if ((NULL == vma) || (! (sfp = (Sg_fd *)vma->vm_private_data))) + return page; + rsv_schp = &sfp->reserve; + offset = addr - vma->vm_start; + if (offset >= rsv_schp->bufflen) + return page; + SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n", + offset, rsv_schp->k_use_sg)); + if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */ + int k; + unsigned long sa = vma->vm_start; + unsigned long len; + struct scatterlist * sclp = rsv_schp->buffer; + + for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); + ++k, ++sclp) { + len = vma->vm_end - sa; + len = (len < sclp->length) ? len : sclp->length; + if (offset < len) { + page_ptr = sg_scatg2virt(sclp) + offset; + page = virt_to_page(page_ptr); + get_page(page); /* increment page count */ + break; + } + sa += len; + offset -= len; + } + } + else { /* reserve buffer is just a single allocation */ + page_ptr = (unsigned char *)rsv_schp->buffer + offset; + page = virt_to_page(page_ptr); + get_page(page); /* increment page count */ + } + return page; +} + +static struct vm_operations_struct sg_mmap_vm_ops = { + nopage : sg_vma_nopage, +}; + +static int sg_mmap(struct file * filp, struct vm_area_struct *vma) +{ + Sg_fd * sfp; + unsigned long req_sz = vma->vm_end - vma->vm_start; + Sg_scatter_hold * rsv_schp; + + if ((! filp) || (! vma) || (! (sfp = (Sg_fd *)filp->private_data))) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n", + (void *)vma->vm_start, (int)req_sz)); + if (vma->vm_pgoff) + return -EINVAL; /* want no offset */ + rsv_schp = &sfp->reserve; + if (req_sz > rsv_schp->bufflen) + return -ENOMEM; /* cannot map more than reserved buffer */ + + if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */ + int k; + unsigned long sa = vma->vm_start; + unsigned long len; + struct scatterlist * sclp = rsv_schp->buffer; + + for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); + ++k, ++sclp) { + if (0 != sclp->offset) + return -EFAULT; /* non page aligned memory ?? */ + len = vma->vm_end - sa; + len = (len < sclp->length) ? len : sclp->length; + sa += len; + } + } + else { /* reserve buffer is just a single allocation */ + if ((unsigned long)rsv_schp->buffer & (PAGE_SIZE - 1)) + return -EFAULT; /* non page aligned memory ?? */ + } + if (0 == sfp->mmap_called) { + sg_rb_correct4mmap(rsv_schp, 1); /* do only once per fd lifetime */ + sfp->mmap_called = 1; + } + vma->vm_flags |= (VM_RESERVED | VM_IO); + vma->vm_private_data = sfp; + vma->vm_ops = &sg_mmap_vm_ops; + return 0; +} + /* This function is a "bottom half" handler that is called by the * mid level when a command is completed (or has failed). */ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) { Scsi_Request * SRpnt = SCpnt->sc_request; - int dev = MINOR(SRpnt->sr_request.rq_dev); + int dev = minor(SRpnt->sr_request.rq_dev); Sg_device * sdp = NULL; Sg_fd * sfp; Sg_request * srp = NULL; @@ -1075,7 +1233,14 @@ srp->data.sglist_len = SRpnt->sr_sglist_len; srp->data.bufflen = SRpnt->sr_bufflen; srp->data.buffer = SRpnt->sr_buffer; - sg_clr_srpnt(SRpnt); + /* now clear out request structure */ + SRpnt->sr_use_sg = 0; + SRpnt->sr_sglist_len = 0; + SRpnt->sr_bufflen = 0; + SRpnt->sr_buffer = NULL; + SRpnt->sr_underflow = 0; + SRpnt->sr_request.rq_dev = mk_kdev(0, 0); /* "sg" _disowns_ request blk */ + srp->my_cmdp = NULL; srp->done = 1; read_unlock(&sg_dev_arr_lock); @@ -1120,14 +1285,15 @@ if (NULL == sfp->headrp) { SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n")); - sg_remove_sfp(sdp, sfp); + if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */ + sdp->device->access_count--; + if (sdp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); + } + if (sg_template.module) + __MOD_DEC_USE_COUNT(sg_template.module); sfp = NULL; } - sdp->device->access_count--; - if (sg_template.module) - __MOD_DEC_USE_COUNT(sg_template.module); - if (sdp->device->host->hostt->module) - __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); } else if (srp && srp->orphan) { if (sfp->keep_orphan) @@ -1151,6 +1317,7 @@ poll: sg_poll, ioctl: sg_ioctl, open: sg_open, + mmap: sg_mmap, release: sg_release, fasync: sg_fasync, }; @@ -1175,7 +1342,7 @@ if(!sg_registered) { if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) { - printk("Unable to get major %d for generic SCSI device\n", + printk(KERN_ERR "Unable to get major %d for generic SCSI device\n", SCSI_GENERIC_MAJOR); write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 1; @@ -1188,7 +1355,7 @@ sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * sizeof(Sg_device *), GFP_ATOMIC); if (NULL == sg_dev_arr) { - printk("sg_init: no space for sg_dev_arr\n"); + printk(KERN_ERR "sg_init: no space for sg_dev_arr\n"); write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 1; } @@ -1211,8 +1378,8 @@ sg_big_buff = tmp; return 1; } else { - printk("sg_def_reserved_size : usage sg_def_reserved_size=n " - "(n could be 65536, 131072 or 262144)\n"); + printk(KERN_WARNING "sg_def_reserved_size : usage " + "sg_def_reserved_size=n (n could be 65536, 131072 or 262144)\n"); return 0; } } @@ -1237,7 +1404,7 @@ if (NULL == tmp_da) { scsidp->attached--; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - printk("sg_attach: device array cannot be resized\n"); + printk(KERN_ERR "sg_attach: device array cannot be resized\n"); return 1; } memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *)); @@ -1249,13 +1416,13 @@ for(k = 0; k < sg_template.dev_max; k++) if(! sg_dev_arr[k]) break; - if (k > MINORMASK) { + if (k > SG_MAX_DEVS_MASK) { scsidp->attached--; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - printk("Unable to attach sg device <%d, %d, %d, %d>" + printk(KERN_WARNING "Unable to attach sg device <%d, %d, %d, %d>" " type=%d, minor number exceed %d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, scsidp->type, - MINORMASK); + SG_MAX_DEVS_MASK); return 1; } if(k < sg_template.dev_max) @@ -1265,7 +1432,7 @@ if (NULL == sdp) { scsidp->attached--; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - printk("sg_attach: Sg_device cannot be allocated\n"); + printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n"); return 1; } @@ -1277,7 +1444,7 @@ sdp->sgdebug = 0; sdp->detached = 0; sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; - sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k); + sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k); sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT, SCSI_GENERIC_MAJOR, k, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, @@ -1292,8 +1459,8 @@ 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, + printk(KERN_NOTICE "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; @@ -1370,7 +1537,10 @@ MODULE_AUTHOR("Douglas Gilbert"); MODULE_DESCRIPTION("SCSI generic (sg) driver"); + +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif MODULE_PARM(def_reserved_size, "i"); MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); @@ -1378,8 +1548,7 @@ static int __init init_sg(void) { if (def_reserved_size >= 0) sg_big_buff = def_reserved_size; - sg_template.module = THIS_MODULE; - return scsi_register_module(MODULE_SCSI_DEV, &sg_template); + return scsi_register_device(&sg_template); } static void __exit exit_sg( void) @@ -1387,7 +1556,7 @@ #ifdef CONFIG_PROC_FS sg_proc_cleanup(); #endif /* CONFIG_PROC_FS */ - scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); + scsi_unregister_device(&sg_template); devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); if(sg_dev_arr != NULL) { kfree((char *)sg_dev_arr); @@ -1417,9 +1586,8 @@ if (res <= 0) /* -ve -> error, 0 -> done, 1 -> try indirect */ return res; } - if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) { + if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) sg_link_reserve(sfp, srp, dxfer_len); - } else { res = sg_build_indi(req_schp, sfp, dxfer_len); if (res) { @@ -1445,23 +1613,24 @@ sg_remove_request(sfp, srp); } -static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp) +static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, + int tablesize) { int mem_src, ret_sz; - int sg_bufflen = PAGE_SIZE; int elem_sz = sizeof(struct scatterlist) + sizeof(char); - int mx_sc_elems = (sg_bufflen / elem_sz) - 1; + /* scatter gather array, followed by mem_src_arr (array of chars) */ + int sg_bufflen = tablesize * elem_sz; + int mx_sc_elems = tablesize; mem_src = SG_HEAP_KMAL; - schp->buffer = (struct scatterlist *)sg_malloc(sfp, sg_bufflen, - &ret_sz, &mem_src); - schp->buffer_mem_src = (char)mem_src; + schp->buffer = sg_malloc(sfp, sg_bufflen, &ret_sz, &mem_src); if (! schp->buffer) return -ENOMEM; else if (ret_sz != sg_bufflen) { sg_bufflen = ret_sz; - mx_sc_elems = (sg_bufflen / elem_sz) - 1; + mx_sc_elems = sg_bufflen / elem_sz; } + schp->buffer_mem_src = (char)mem_src; schp->sglist_len = sg_bufflen; memset(schp->buffer, 0, sg_bufflen); return mx_sc_elems; /* number of scat_gath elements allocated */ @@ -1470,13 +1639,15 @@ static void sg_unmap_and(Sg_scatter_hold * schp, int free_also) { #ifdef SG_ALLOW_DIO_CODE + int nbhs = 0; + if (schp && schp->kiobp) { if (schp->mapped) { unmap_kiobuf(schp->kiobp); schp->mapped = 0; } if (free_also) { - free_kiovec(1, &schp->kiobp); + sg_free_kiovec(1, &schp->kiobp, &nbhs); schp->kiobp = NULL; } } @@ -1494,10 +1665,12 @@ sg_io_hdr_t * hp = &srp->header; Sg_scatter_hold * schp = &srp->data; int sg_tablesize = sfp->parentdp->sg_tablesize; + int nbhs = 0; - res = alloc_kiovec(1, &schp->kiobp); + res = sg_alloc_kiovec(1, &schp->kiobp, &nbhs); if (0 != res) { - SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: alloc_kiovec res=%d\n", res)); + SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: sg_alloc_kiovec res=%d\n", + res)); return 1; } res = map_user_kiobuf((SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0, @@ -1527,7 +1700,7 @@ hp->info |= SG_INFO_DIRECT_IO; return 0; } - mx_sc_elems = sg_build_sgat(schp, sfp); + mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize); if (mx_sc_elems <= 1) { sg_unmap_and(schp, 1); sg_remove_scat(schp); @@ -1535,19 +1708,22 @@ } mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist)); for (k = 0, sclp = schp->buffer, rem_sz = dxfer_len; - (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); + (rem_sz > 0) && (k < mx_sc_elems); ++k, ++sclp) { offset = (0 == k) ? kp->offset : 0; num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) : rem_sz; + sclp->page = kp->maplist[k]; + sclp->offset = offset; +#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST sclp->address = page_address(kp->maplist[k]) + offset; - sclp->page = NULL; +#endif sclp->length = num; mem_src_arr[k] = SG_USER_MEM; rem_sz -= num; SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: k=%d, a=0x%p, len=%d, ms=%d\n", - k, sclp->address, num, mem_src_arr[k])); + k, sg_scatg2virt(sclp), num, mem_src_arr[k])); } schp->k_use_sg = k; SCSI_LOG_TIMEOUT(5, @@ -1569,7 +1745,7 @@ { int ret_sz, mem_src; int blk_size = buff_size; - char * p = NULL; + unsigned char * p = NULL; if ((blk_size < 0) || (! sfp)) return -EFAULT; @@ -1609,14 +1785,14 @@ char * mem_src_arr; /* N.B. ret_sz and mem_src carried into this block ... */ - mx_sc_elems = sg_build_sgat(schp, sfp); + mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize); if (mx_sc_elems < 0) return mx_sc_elems; /* most likely -ENOMEM */ mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist)); for (k = 0, sclp = schp->buffer, rem_sz = blk_size; - (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); + (rem_sz > 0) && (k < mx_sc_elems); ++k, rem_sz -= ret_sz, ++sclp) { if (first) first = 0; @@ -1627,14 +1803,17 @@ if (! p) break; } + sclp->page = virt_to_page(p); + sclp->offset = (unsigned long)p & ~PAGE_MASK; +#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST sclp->address = p; - sclp->page = NULL; +#endif sclp->length = ret_sz; mem_src_arr[k] = mem_src; SCSI_LOG_TIMEOUT(5, printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n", - k, sclp->address, ret_sz, mem_src)); + k, sg_scatg2virt(sclp), ret_sz, mem_src)); } /* end of for loop */ schp->k_use_sg = k; SCSI_LOG_TIMEOUT(5, @@ -1664,7 +1843,8 @@ if (schp->bufflen < num_xfer) num_xfer = schp->bufflen; } - if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags))) + if ((num_xfer <= 0) || + (new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags))) return 0; SCSI_LOG_TIMEOUT(4, @@ -1698,14 +1878,15 @@ struct scatterlist * sclp = (struct scatterlist *)schp->buffer; char * mem_src_arr = sg_get_sgat_msa(schp); ksglen = (int)sclp->length; - p = sclp->address; + p = sg_scatg2virt(sclp); for (j = 0, k = 0; j < onum; ++j) { res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up); if (res) return res; for (; (k < schp->k_use_sg) && p; - ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) { + ++k, ++sclp, ksglen = (int)sclp->length, + p = sg_scatg2virt(sclp)) { ok = (SG_USER_MEM != mem_src_arr[k]); if (usglen <= 0) break; @@ -1766,7 +1947,7 @@ static char * sg_get_sgat_msa(Sg_scatter_hold * schp) { int elem_sz = sizeof(struct scatterlist) + sizeof(char); - int mx_sc_elems = (schp->sglist_len / elem_sz) - 1; + int mx_sc_elems = schp->sglist_len / elem_sz; return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems); } @@ -1779,14 +1960,17 @@ struct scatterlist * sclp = (struct scatterlist *)schp->buffer; char * mem_src_arr = sg_get_sgat_msa(schp); - for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) { + for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) { mem_src = mem_src_arr[k]; SCSI_LOG_TIMEOUT(5, printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n", - k, sclp->address, sclp->length, mem_src)); - sg_free(sclp->address, sclp->length, mem_src); - sclp->address = NULL; + k, sg_scatg2virt(sclp), sclp->length, mem_src)); + sg_free(sg_scatg2virt(sclp), sclp->length, mem_src); sclp->page = NULL; + sclp->offset = 0; +#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST + sclp->address = 0; +#endif sclp->length = 0; } sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src); @@ -1814,7 +1998,8 @@ if (schp->bufflen < num_xfer) num_xfer = schp->bufflen; } - if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags))) + if ((num_xfer <= 0) || + (new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags))) return 0; SCSI_LOG_TIMEOUT(4, @@ -1848,14 +2033,15 @@ struct scatterlist * sclp = (struct scatterlist *)schp->buffer; char * mem_src_arr = sg_get_sgat_msa(schp); ksglen = (int)sclp->length; - p = sclp->address; + p = sg_scatg2virt(sclp); for (j = 0, k = 0; j < onum; ++j) { res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up); if (res) return res; for (; (k < schp->k_use_sg) && p; - ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) { + ++k, ++sclp, ksglen = (int)sclp->length, + p = sg_scatg2virt(sclp)) { ok = (SG_USER_MEM != mem_src_arr[k]); if (usglen <= 0) break; @@ -1896,14 +2082,14 @@ int k, num; struct scatterlist * sclp = (struct scatterlist *)schp->buffer; - for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) { + for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) { num = (int)sclp->length; if (num > num_read_xfer) { - __copy_to_user(outp, sclp->address, num_read_xfer); + __copy_to_user(outp, sg_scatg2virt(sclp), num_read_xfer); break; } else { - __copy_to_user(outp, sclp->address, num); + __copy_to_user(outp, sg_scatg2virt(sclp), num); num_read_xfer -= num; if (num_read_xfer <= 0) break; @@ -1949,7 +2135,7 @@ if (rem <= num) { if (0 == k) { req_schp->k_use_sg = 0; - req_schp->buffer = sclp->address; + req_schp->buffer = sg_scatg2virt(sclp); } else { sfp->save_scat_len = num; @@ -2189,6 +2375,8 @@ if (sfp->reserve.bufflen > 0) { SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg)); + if (sfp->mmap_called) + sg_rb_correct4mmap(&sfp->reserve, 0); /* undo correction */ sg_remove_scat(&sfp->reserve); } sfp->parentdp = NULL; @@ -2237,7 +2425,7 @@ /* MOD_INC's to inhibit unloading sg and associated adapter driver */ if (sg_template.module) __MOD_INC_USE_COUNT(sg_template.module); - if (sdp->device->host->hostt->module) + if (sdp->device->host->hostt->module) __MOD_INC_USE_COUNT(sdp->device->host->hostt->module); SCSI_LOG_TIMEOUT(1, printk( "sg_remove_sfp: worrisome, %d writes pending\n", dirty)); @@ -2270,30 +2458,6 @@ if (resp && retSzp) *retSzp = rqSz; return resp; } - if (SG_HEAP_POOL == mem_src) { - int num_sect = rqSz / SG_SECTOR_SZ; - - if (0 != (rqSz & SG_SECTOR_MSK)) { - if (! retSzp) - return resp; - ++num_sect; - rqSz = num_sect * SG_SECTOR_SZ; - } - while (num_sect > 0) { - if ((num_sect <= sg_pool_secs_avail)) { - resp = kmalloc(rqSz, page_mask); - if (resp) { - if (retSzp) *retSzp = rqSz; - sg_pool_secs_avail -= num_sect; - return resp; - } - } - if (! retSzp) - return resp; - num_sect /= 2; /* try half as many */ - rqSz = num_sect * SG_SECTOR_SZ; - } - } else if (SG_HEAP_PAGE == mem_src) { int order, a_size; int resSz = rqSz; @@ -2311,7 +2475,8 @@ if (retSzp) *retSzp = resSz; } else - printk("sg_low_malloc: bad mem_src=%d, rqSz=%df\n", mem_src, rqSz); + printk(KERN_ERR "sg_low_malloc: bad mem_src=%d, rqSz=%df\n", + mem_src, rqSz); return resp; } @@ -2330,29 +2495,20 @@ switch (*mem_srcp) { case SG_HEAP_PAGE: - l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE; + l_ms = (size < PAGE_SIZE) ? SG_HEAP_KMAL : SG_HEAP_PAGE; resp = sg_low_malloc(size, low_dma, l_ms, 0); if (resp) break; resp = sg_low_malloc(size, low_dma, l_ms, &size); if (! resp) { - l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL; + l_ms = (SG_HEAP_KMAL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_KMAL; resp = sg_low_malloc(size, low_dma, l_ms, &size); - if (! resp) { - l_ms = SG_HEAP_KMAL; - resp = sg_low_malloc(size, low_dma, l_ms, &size); - } } if (resp && retSzp) *retSzp = size; break; case SG_HEAP_KMAL: - l_ms = SG_HEAP_PAGE; + l_ms = SG_HEAP_KMAL; /* was SG_HEAP_PAGE */ resp = sg_low_malloc(size, low_dma, l_ms, 0); - if (resp) - break; - l_ms = SG_HEAP_POOL; - resp = sg_low_malloc(size, low_dma, l_ms, &size); - if (resp && retSzp) *retSzp = size; break; default: SCSI_LOG_TIMEOUT(1, printk("sg_malloc: bad ms=%d\n", *mem_srcp)); @@ -2365,18 +2521,19 @@ return resp; } +static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp) +{ +#if SG_NEW_KIOVEC + return alloc_kiovec_sz(nr, bufp, szp); +#else + return alloc_kiovec(nr, bufp); +#endif +} + static void sg_low_free(char * buff, int size, int mem_src) { if (! buff) return; switch (mem_src) { - case SG_HEAP_POOL: - { - int num_sect = size / SG_SECTOR_SZ; - - kfree(buff); - sg_pool_secs_avail += num_sect; - } - break; case SG_HEAP_KMAL: kfree(buff); /* size not used */ break; @@ -2392,7 +2549,7 @@ case SG_USER_MEM: break; /* nothing to do */ default: - printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n", + printk(KERN_ERR "sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n", mem_src, buff, size); break; } @@ -2408,14 +2565,13 @@ sg_low_free(buff, size, mem_src); } -static void sg_clr_srpnt(Scsi_Request * SRpnt) +static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp) { - SRpnt->sr_use_sg = 0; - SRpnt->sr_sglist_len = 0; - SRpnt->sr_bufflen = 0; - SRpnt->sr_buffer = NULL; - SRpnt->sr_underflow = 0; - SRpnt->sr_request.rq_dev = MKDEV(0, 0); /* "sg" _disowns_ command blk */ +#if SG_NEW_KIOVEC + free_kiovec_sz(nr, bufp, szp); +#else + free_kiovec(nr, bufp); +#endif } static int sg_ms_to_jif(unsigned int msecs) @@ -2427,7 +2583,7 @@ : (((int)msecs / 1000) * HZ); } -static unsigned sg_jif_to_ms(int jifs) +static inline unsigned sg_jif_to_ms(int jifs) { if (jifs <= 0) return 0U; @@ -2477,8 +2633,8 @@ if (sg_dev_arr && (dev >= 0)) { read_lock_irqsave(&sg_dev_arr_lock, iflags); - if (dev < sg_template.dev_max) - sdp = sg_dev_arr[dev]; + if (dev < sg_template.dev_max) + sdp = sg_dev_arr[dev]; read_unlock_irqrestore(&sg_dev_arr_lock, iflags); } return sdp; @@ -2671,7 +2827,7 @@ { Sg_device * sdp; const sg_io_hdr_t * hp; - int j, max_dev; + int j, max_dev, new_interface; if (NULL == sg_dev_arr) { PRINT_PROC("sg_dev_arr NULL, driver not initialized\n"); @@ -2680,8 +2836,7 @@ max_dev = sg_last_dev(); PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n", sg_template.dev_max, max_dev); - PRINT_PROC(" sg_pool_secs_aval=%d def_reserved_size=%d\n", - sg_pool_secs_avail, sg_big_buff); + PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff); for (j = 0; j < max_dev; ++j) { if ((sdp = sg_get_dev(j))) { Sg_fd * fp; @@ -2694,7 +2849,7 @@ PRINT_PROC("device %d detached ??\n", j); continue; } - dev = MINOR(sdp->i_rdev); + dev = minor(sdp->i_rdev); if (sg_get_nth_sfp(sdp, 0)) { PRINT_PROC(" >>> device=sg%d ", dev); @@ -2717,8 +2872,10 @@ (int)fp->keep_orphan, (int)fp->closed); for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) { hp = &srp->header; + new_interface = (hp->interface_id == '\0') ? 0 : 1; /* stop indenting so far ... */ - PRINT_PROC(srp->res_used ? " rb>> " : + PRINT_PROC(srp->res_used ? ((new_interface && + (SG_FLAG_MMAP_IO & hp->flags)) ? " mmap>> " : " rb>> ") : ((SG_INFO_DIRECT_IO_MASK & hp->info) ? " dio>> " : " ")); blen = srp->my_cmdp ? srp->my_cmdp->sr_bufflen : srp->data.bufflen; usg = srp->my_cmdp ? srp->my_cmdp->sr_use_sg : srp->data.k_use_sg; @@ -2728,8 +2885,8 @@ if (srp->done) PRINT_PROC(" dur=%d", hp->duration); else - PRINT_PROC(" t_o/elap=%d/%d", ((hp->interface_id == '\0') ? - sg_jif_to_ms(fp->timeout) : hp->timeout), + PRINT_PROC(" t_o/elap=%d/%d", new_interface ? hp->timeout : + sg_jif_to_ms(fp->timeout), sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0)); PRINT_PROC("ms sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode); /* reset indenting */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sim710.c linux-2.5/drivers/scsi/sim710.c --- linux-2.5.1/drivers/scsi/sim710.c Sun Sep 30 19:26:07 2001 +++ linux-2.5/drivers/scsi/sim710.c Sun Jan 6 19:17:51 2002 @@ -904,11 +904,12 @@ static void do_sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs) { + struct Scsi_Host *host = dev_id; unsigned long flags; - spin_lock_irqsave(&io_request_lock, flags); - sim710_intr_handle(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_lock_irqsave(host->host_lock, flags); + sim710_intr_handle(irq, host, regs); + spin_unlock_irqrestore(host->host_lock, flags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sr.c linux-2.5/drivers/scsi/sr.c --- linux-2.5.1/drivers/scsi/sr.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/sr.c Mon Jan 7 23:34:03 2002 @@ -71,6 +71,7 @@ static struct Scsi_Device_Template sr_template = { + module:THIS_MODULE, name:"cdrom", tag:"sr", scsi_type:TYPE_ROM, @@ -98,11 +99,11 @@ static void sr_release(struct cdrom_device_info *cdi) { - if (scsi_CDs[MINOR(cdi->dev)].device->sector_size > 2048) - sr_set_blocklength(MINOR(cdi->dev), 2048); - scsi_CDs[MINOR(cdi->dev)].device->access_count--; - if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module) - __MOD_DEC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module); + if (scsi_CDs[minor(cdi->dev)].device->sector_size > 2048) + sr_set_blocklength(minor(cdi->dev), 2048); + scsi_CDs[minor(cdi->dev)].device->access_count--; + if (scsi_CDs[minor(cdi->dev)].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_CDs[minor(cdi->dev)].device->host->hostt->module); if (sr_template.module) __MOD_DEC_USE_COUNT(sr_template.module); } @@ -149,7 +150,7 @@ /* no changer support */ return -EINVAL; } - retval = scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device, + retval = scsi_ioctl(scsi_CDs[minor(cdi->dev)].device, SCSI_IOCTL_TEST_UNIT_READY, 0); if (retval) { @@ -158,13 +159,13 @@ * and we will figure it out later once the drive is * available again. */ - scsi_CDs[MINOR(cdi->dev)].device->changed = 1; + scsi_CDs[minor(cdi->dev)].device->changed = 1; return 1; /* This will force a flush, if called from * check_disk_change */ }; - retval = scsi_CDs[MINOR(cdi->dev)].device->changed; - scsi_CDs[MINOR(cdi->dev)].device->changed = 0; + retval = scsi_CDs[minor(cdi->dev)].device->changed; + scsi_CDs[minor(cdi->dev)].device->changed = 0; /* If the disk changed, the capacity will now be different, * so we force a re-read of this information */ if (retval) { @@ -178,9 +179,9 @@ * be trying to use something that is too small if the disc * has changed. */ - scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1; + scsi_CDs[minor(cdi->dev)].needs_sector_size = 1; - scsi_CDs[MINOR(cdi->dev)].device->sector_size = 2048; + scsi_CDs[minor(cdi->dev)].device->sector_size = 2048; } return retval; } @@ -252,17 +253,17 @@ /* * No such device */ - if (MINOR(dev) >= sr_template.dev_max || !scsi_CDs[MINOR(dev)].device) + if (minor(dev) >= sr_template.dev_max || !scsi_CDs[minor(dev)].device) return NULL; - return &scsi_CDs[MINOR(dev)].device->request_queue; + return &scsi_CDs[minor(dev)].device->request_queue; } static int sr_init_command(Scsi_Cmnd * SCpnt) { int dev, devm, block=0, this_count, s_size; - devm = MINOR(SCpnt->request.rq_dev); + devm = minor(SCpnt->request.rq_dev); dev = DEVICE_NR(SCpnt->request.rq_dev); SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block)); @@ -287,9 +288,6 @@ return 0; } - if (rq_data_dir(&SCpnt->request) == WRITE && !scsi_CDs[dev].device->writeable) - return 0; - /* * we do lazy blocksize switching (when reading XA sectors, * see CDROMREADMODE2 ioctl) @@ -401,20 +399,20 @@ { check_disk_change(cdi->dev); - if (MINOR(cdi->dev) >= sr_template.dev_max - || !scsi_CDs[MINOR(cdi->dev)].device) { + if (minor(cdi->dev) >= sr_template.dev_max + || !scsi_CDs[minor(cdi->dev)].device) { return -ENXIO; /* No such device */ } /* * If the device is in error recovery, wait until it is done. * If the device is offline, then disallow any access to it. */ - if (!scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device)) { + if (!scsi_block_when_processing_errors(scsi_CDs[minor(cdi->dev)].device)) { return -ENXIO; } - scsi_CDs[MINOR(cdi->dev)].device->access_count++; - if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module) - __MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module); + scsi_CDs[minor(cdi->dev)].device->access_count++; + if (scsi_CDs[minor(cdi->dev)].device->host->hostt->module) + __MOD_INC_USE_COUNT(scsi_CDs[minor(cdi->dev)].device->host->hostt->module); if (sr_template.module) __MOD_INC_USE_COUNT(sr_template.module); @@ -423,8 +421,8 @@ * this is the case, and try again. */ - if (scsi_CDs[MINOR(cdi->dev)].needs_sector_size) - get_sectorsize(MINOR(cdi->dev)); + if (scsi_CDs[minor(cdi->dev)].needs_sector_size) + get_sectorsize(minor(cdi->dev)); return 0; } @@ -477,6 +475,7 @@ int the_result, retries; int sector_size; Scsi_Request *SRpnt; + request_queue_t *queue; buffer = (unsigned char *) kmalloc(512, GFP_DMA); SRpnt = scsi_allocate_request(scsi_CDs[i].device); @@ -525,7 +524,7 @@ scsi_CDs[i].needs_sector_size = 1; } else { #if 0 - if (cdrom_get_last_written(MKDEV(MAJOR_NR, i), + if (cdrom_get_last_written(mkdev(MAJOR_NR, i), &scsi_CDs[i].capacity)) #endif scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | @@ -566,8 +565,9 @@ */ scsi_CDs[i].needs_sector_size = 0; sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9); - }; - blk_queue_hardsect_size(blk_get_queue(MAJOR_NR), sector_size); + } + queue = &scsi_CDs[i].device->request_queue; + blk_queue_hardsect_size(queue, sector_size); kfree(buffer); } @@ -671,13 +671,13 @@ */ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc) { - Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device; + Scsi_Device *device = scsi_CDs[minor(cdi->dev)].device; /* set the LUN */ 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); + cgc->stat = sr_do_ioctl(minor(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense); return cgc->stat; } @@ -766,7 +766,7 @@ scsi_CDs[i].cdi.ops = &sr_dops; scsi_CDs[i].cdi.handle = &scsi_CDs[i]; - scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i); + scsi_CDs[i].cdi.dev = mk_kdev(MAJOR_NR, i); scsi_CDs[i].cdi.mask = 0; scsi_CDs[i].cdi.capacity = 1; /* @@ -809,7 +809,7 @@ * the device. * We should be kind to our buffer cache, however. */ - invalidate_device(MKDEV(MAJOR_NR, i), 0); + invalidate_device(mk_kdev(MAJOR_NR, i), 0); /* * Reset things back to a sane state so that one can @@ -829,13 +829,12 @@ static int __init init_sr(void) { - sr_template.module = THIS_MODULE; - return scsi_register_module(MODULE_SCSI_DEV, &sr_template); + return scsi_register_device(&sr_template); } static void __exit exit_sr(void) { - scsi_unregister_module(MODULE_SCSI_DEV, &sr_template); + scsi_unregister_device(&sr_template); devfs_unregister_blkdev(MAJOR_NR, "sr"); sr_registered--; if (scsi_CDs != NULL) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sr_ioctl.c linux-2.5/drivers/scsi/sr_ioctl.c --- linux-2.5.1/drivers/scsi/sr_ioctl.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/sr_ioctl.c Thu Jan 3 04:56:41 2002 @@ -68,7 +68,7 @@ sr_cmd[6] = trk1_te.cdte_addr.msf.minute; sr_cmd[7] = trk1_te.cdte_addr.msf.second; sr_cmd[8] = trk1_te.cdte_addr.msf.frame; - return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); + return sr_do_ioctl(minor(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); } /* We do our own retries because we want to know what the specific @@ -206,17 +206,17 @@ u_char sr_cmd[10]; sr_cmd[0] = GPCMD_START_STOP_UNIT; - sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ? - ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0; + 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 */ ; - return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); + return sr_do_ioctl(minor(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); } int sr_lock_door(struct cdrom_device_info *cdi, int lock) { - return scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device, + return scsi_ioctl(scsi_CDs[minor(cdi->dev)].device, lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK, 0); } @@ -227,7 +227,7 @@ /* we have no changer support */ return -EINVAL; } - if (0 == test_unit_ready(MINOR(cdi->dev))) + if (0 == test_unit_ready(minor(cdi->dev))) return CDS_DISC_OK; return CDS_TRAY_OPEN; @@ -256,7 +256,7 @@ if (!have_datatracks) return CDS_AUDIO; - if (scsi_CDs[MINOR(cdi->dev)].xa_flag) + if (scsi_CDs[minor(cdi->dev)].xa_flag) return CDS_XA_2_1; else return CDS_DATA_1; @@ -265,9 +265,9 @@ int sr_get_last_session(struct cdrom_device_info *cdi, struct cdrom_multisession *ms_info) { - ms_info->addr.lba = scsi_CDs[MINOR(cdi->dev)].ms_offset; - ms_info->xa_flag = scsi_CDs[MINOR(cdi->dev)].xa_flag || - (scsi_CDs[MINOR(cdi->dev)].ms_offset > 0); + ms_info->addr.lba = scsi_CDs[minor(cdi->dev)].ms_offset; + ms_info->xa_flag = scsi_CDs[minor(cdi->dev)].xa_flag || + (scsi_CDs[minor(cdi->dev)].ms_offset > 0); return 0; } @@ -279,8 +279,8 @@ int result; sr_cmd[0] = GPCMD_READ_SUBCHANNEL; - sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ? - ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0; + 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; @@ -289,7 +289,7 @@ sr_cmd[8] = 24; sr_cmd[9] = 0; - result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL); + result = sr_do_ioctl(minor(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL); memcpy(mcn->medium_catalog_number, buffer + 9, 13); mcn->medium_catalog_number[13] = 0; @@ -314,12 +314,12 @@ 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->scsi_level <= SCSI_2) ? - ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0; + 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 */ - if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL)) + if (sr_do_ioctl(minor(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL)) return -EIO; return 0; } @@ -333,7 +333,7 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) { u_char sr_cmd[10]; - int result, target = MINOR(cdi->dev); + int result, target = minor(cdi->dev); unsigned char buffer[32]; memset(sr_cmd, 0, sizeof(sr_cmd)); @@ -541,7 +541,7 @@ { int target; - target = MINOR(cdi->dev); + target = minor(cdi->dev); switch (cmd) { case BLKGETSIZE: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sr_vendor.c linux-2.5/drivers/scsi/sr_vendor.c --- linux-2.5.1/drivers/scsi/sr_vendor.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/sr_vendor.c Thu Jan 3 05:00:25 2002 @@ -158,7 +158,7 @@ unsigned char cmd[MAX_COMMAND_SIZE]; /* the scsi-command */ int rc, no_multi, minor; - minor = MINOR(cdi->dev); + minor = minor(cdi->dev); if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION) return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/st.c linux-2.5/drivers/scsi/st.c --- linux-2.5.1/drivers/scsi/st.c Fri Nov 9 21:52:21 2001 +++ linux-2.5/drivers/scsi/st.c Sat Jan 5 16:01:51 2002 @@ -133,8 +133,8 @@ #define ST_TIMEOUT (900 * HZ) #define ST_LONG_TIMEOUT (14000 * HZ) -#define TAPE_NR(x) (MINOR(x) & ~(128 | ST_MODE_MASK)) -#define TAPE_MODE(x) ((MINOR(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) +#define TAPE_NR(x) (minor(x) & ~(-1 << ST_MODE_SHIFT)) +#define TAPE_MODE(x) ((minor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) /* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower 24 bits) */ @@ -878,7 +878,7 @@ } STp->in_use = 1; write_unlock_irqrestore(&st_dev_arr_lock, flags); - STp->rew_at_close = STp->autorew_dev = (MINOR(inode->i_rdev) & 0x80) == 0; + STp->rew_at_close = STp->autorew_dev = (minor(inode->i_rdev) & 0x80) == 0; if (STp->device->host->hostt->module) __MOD_INC_USE_COUNT(STp->device->host->hostt->module); @@ -3717,7 +3717,7 @@ tpnt->tape_type = MT_ISSCSI2; tpnt->inited = 0; - tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i); + tpnt->devt = mk_kdev(SCSI_TAPE_MAJOR, i); tpnt->dirty = 0; tpnt->in_use = 0; tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ @@ -3867,14 +3867,14 @@ validate_options(); st_template.module = THIS_MODULE; - return scsi_register_module(MODULE_SCSI_DEV, &st_template); + return scsi_register_device(&st_template); } static void __exit exit_st(void) { int i; - scsi_unregister_module(MODULE_SCSI_DEV, &st_template); + scsi_unregister_device(&st_template); devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st"); st_registered--; if (scsi_tapes != NULL) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sun3_scsi.c linux-2.5/drivers/scsi/sun3_scsi.c --- linux-2.5.1/drivers/scsi/sun3_scsi.c Thu Oct 25 20:53:51 2001 +++ linux-2.5/drivers/scsi/sun3_scsi.c Tue Jan 8 01:17:10 2002 @@ -357,7 +357,7 @@ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; ) + for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); ) barrier(); /* switch on SCSI IRQ again */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sym53c8xx.c linux-2.5/drivers/scsi/sym53c8xx.c --- linux-2.5.1/drivers/scsi/sym53c8xx.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/sym53c8xx.c Sun Jan 6 19:17:51 2002 @@ -643,9 +643,9 @@ #define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags) #define NCR_LOCK_SCSI_DONE(host, flags) \ - spin_lock_irqsave(&((host)->host_lock), flags) + spin_lock_irqsave(((host)->host_lock), flags) #define NCR_UNLOCK_SCSI_DONE(host, flags) \ - spin_unlock_irqrestore(&((host)->host_lock), flags) + spin_unlock_irqrestore(((host)->host_lock), flags) #else diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sym53c8xx_2/sym_glue.c linux-2.5/drivers/scsi/sym53c8xx_2/sym_glue.c --- linux-2.5.1/drivers/scsi/sym53c8xx_2/sym_glue.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/sym53c8xx_2/sym_glue.c Sun Jan 6 19:17:51 2002 @@ -138,11 +138,11 @@ #define SYM_LOCK_DRIVER(flags) spin_lock_irqsave(&sym53c8xx_lock, flags) #define SYM_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&sym53c8xx_lock,flags) -#define SYM_INIT_LOCK_HCB(np) spin_lock_init(&np->s.host->host_lock); +#define SYM_INIT_LOCK_HCB(np) spin_lock_init(np->s.host->host_lock); #define SYM_LOCK_HCB(np, flags) \ - spin_lock_irqsave(&np->s.host->host_lock, flags) + spin_lock_irqsave(np->s.host->host_lock, flags) #define SYM_UNLOCK_HCB(np, flags) \ - spin_unlock_irqrestore(&np->s.host->host_lock, flags) + spin_unlock_irqrestore(np->s.host->host_lock, flags) /* * These simple macros limit expression involving diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sym53c8xx_2/sym_hipd.c linux-2.5/drivers/scsi/sym53c8xx_2/sym_hipd.c --- linux-2.5.1/drivers/scsi/sym53c8xx_2/sym_hipd.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/sym53c8xx_2/sym_hipd.c Mon Dec 17 01:03:07 2001 @@ -50,7 +50,7 @@ * SUCH DAMAGE. */ -#define SYM_DRIVER_NAME "sym-2.1.16a" +#define SYM_DRIVER_NAME "sym-2.1.17a" #ifdef __FreeBSD__ #include <dev/sym/sym_glue.h> @@ -5797,6 +5797,13 @@ goto attach_failed; /* + * Allocate the array of lists of CCBs hashed by DSA. + */ + np->ccbh = sym_calloc(sizeof(ccb_p *)*CCB_HASH_SIZE, "CCBH"); + if (!np->ccbh) + goto attach_failed; + + /* * Initialyze the CCB free and busy queues. */ sym_que_init(&np->free_ccbq); @@ -5925,6 +5932,8 @@ np->target[i].head.lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa)); } + if (np->ccbh) + sym_mfree(np->ccbh, sizeof(ccb_p *)*CCB_HASH_SIZE, "CCBH"); /* * Now check the cache handling of the pci chipset. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/sym53c8xx_comm.h linux-2.5/drivers/scsi/sym53c8xx_comm.h --- linux-2.5.1/drivers/scsi/sym53c8xx_comm.h Sun Dec 16 20:20:21 2001 +++ linux-2.5/drivers/scsi/sym53c8xx_comm.h Sun Jan 6 19:17:51 2002 @@ -438,10 +438,10 @@ #define NCR_LOCK_NCB(np, flags) spin_lock_irqsave(&np->smp_lock, flags) #define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags) -#define NCR_LOCK_SCSI_DONE(np, flags) \ - spin_lock_irqsave(&io_request_lock, flags) -#define NCR_UNLOCK_SCSI_DONE(np, flags) \ - spin_unlock_irqrestore(&io_request_lock, flags) +#define NCR_LOCK_SCSI_DONE(host, flags) \ + spin_lock_irqsave((host)->host_lock, flags) +#define NCR_UNLOCK_SCSI_DONE(host, flags) \ + spin_unlock_irqrestore(((host)->host_lock), flags) #else @@ -452,8 +452,8 @@ #define NCR_LOCK_NCB(np, flags) do { save_flags(flags); cli(); } while (0) #define NCR_UNLOCK_NCB(np, flags) do { restore_flags(flags); } while (0) -#define NCR_LOCK_SCSI_DONE(np, flags) do {;} while (0) -#define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0) +#define NCR_LOCK_SCSI_DONE(host, flags) do {;} while (0) +#define NCR_UNLOCK_SCSI_DONE(host, flags) do {;} while (0) #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/t128.c linux-2.5/drivers/scsi/t128.c --- linux-2.5.1/drivers/scsi/t128.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/scsi/t128.c Thu Dec 13 16:32:36 2001 @@ -47,17 +47,12 @@ * increase compared to polled I/O. * * PARITY - enable parity checking. Not supported. - * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You * only really want to use this if you're having a problem with * dropped characters during high speed communications, and even * then, you're going to be better off twiddling with transfersize. * - * USLEEP - enable support for devices that don't disconnect. Untested. - * * The card is detected and initialized in one of several ways : * 1. Autoprobe (default) - since the board is memory mapped, * a BIOS signature is scanned for to locate the registers. @@ -101,10 +96,6 @@ * 14 10-12 * 15 9-11 */ - -/* - * $Log: t128.c,v $ - */ #include <asm/system.h> #include <linux/signal.h> @@ -123,276 +114,252 @@ #include <linux/module.h> static struct override { - unsigned long address; - int irq; -} overrides + unsigned long address; + int irq; +} overrides #ifdef T128_OVERRIDE - [] __initdata = T128_OVERRIDE; +[] __initdata = T128_OVERRIDE; #else - [4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, - {0 ,IRQ_AUTO}, {0, IRQ_AUTO}}; +[4] __initdata = { + { 0, IRQ_AUTO}, + { 0, IRQ_AUTO}, + { 0, IRQ_AUTO}, + { 0, IRQ_AUTO} +}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned int address; - int noauto; + unsigned int address; + int noauto; } bases[] __initdata = { - { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0} + {0xcc000, 0}, + {0xc8000, 0}, + {0xdc000, 0}, + {0xd8000, 0} }; #define NO_BASES (sizeof (bases) / sizeof (struct base)) static const struct signature { - const char *string; - int offset; + const char *string; + int offset; } signatures[] __initdata = { -{"TSROM: SCSI BIOS, Version 1.12", 0x36}, + {"TSROM: SCSI BIOS, Version 1.12", 0x36}, }; #define NO_SIGNATURES (sizeof (signatures) / sizeof (struct signature)) -/* - * Function : t128_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. +/** + * t128_setup + * @str: command line * + * LILO command line initialization of the overrides array, */ -void __init t128_setup(char *str, int *ints){ - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("t128_setup : usage t128=address,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].address = ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; +int __init t128_setup(char *str) +{ + static int commandline_current = 0; + int ints[10]; + int i; + + get_options(str, sizeof(ints) / sizeof(int), ints); + + if (ints[0] != 2) + printk(KERN_ERR "t128_setup : usage t128=address,irq\n"); + else if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].address = ints[1]; + overrides[commandline_current].irq = ints[2]; + for (i = 0; i < NO_BASES; ++i) + if (bases[i].address == ints[1]) { + bases[i].noauto = 1; + break; + } + ++commandline_current; } + return 1; } -/* - * Function : int t128_detect(Scsi_Host_Template * tpnt) +__setup("t128=", t128_setup); + +/** + * t128_detect - detect controllers + * @tpnt: SCSI template * - * Purpose : detects and initializes T128,T128F, or T228 controllers + * Detects and initializes T128,T128F, or T228 controllers * that were autoprobed, overridden on the LILO command line, * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * */ -int __init t128_detect(Scsi_Host_Template * tpnt){ - static int current_override = 0, current_base = 0; - struct Scsi_Host *instance; - unsigned long base; - int sig, count; - - tpnt->proc_name = "t128"; - tpnt->proc_info = &t128_proc_info; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - base = 0; - - if (overrides[current_override].address) - base = overrides[current_override].address; - else - for (; !base && (current_base < NO_BASES); ++current_base) { -#if (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : probing address %08x\n", bases[current_base].address); -#endif - for (sig = 0; sig < NO_SIGNATURES; ++sig) - if (!bases[current_base].noauto && - isa_check_signature(bases[current_base].address + - signatures[sig].offset, - signatures[sig].string, - strlen(signatures[sig].string))) { - base = bases[current_base].address; -#if (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : detected board.\n"); -#endif +int __init t128_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0, current_base = 0; + struct Scsi_Host *instance; + unsigned long base; + int sig, count; + + tpnt->proc_name = "t128"; + tpnt->proc_info = &t128_proc_info; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) + { + base = 0; + + if (overrides[current_override].address) + base = overrides[current_override].address; + else + for (; !base && (current_base < NO_BASES); ++current_base) { + for (sig = 0; sig < NO_SIGNATURES; ++sig) + if (!bases[current_base].noauto && + isa_check_signature(bases[current_base].address + signatures[sig].offset, + signatures[sig].string, + strlen(signatures[sig].string))) + { + base = bases[current_base].address; + break; + } + } + + if (!base) break; - } - } -#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : base = %08x\n", (unsigned int) base); -#endif + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) + break; - if (!base) - break; + instance->base = base; - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->base = base; - - NCR5380_init(instance, 0); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, T128_IRQS); - - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", NULL)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } - - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } + NCR5380_init(instance, 0); -#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, T128_IRQS); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", NULL)) + { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + } + + printk(KERN_INFO "scsi%d : at 0x%08lx", instance->host_no,instance->base); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); - printk("scsi%d : at 0x%08lx", instance->host_no, instance->base); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; + ++current_override; + ++count; + } + return count; } -/* - * Function : int t128_biosparam(Disk * disk, kdev_t dev, int *ip) +/** + * t128_biosparam - disk geometry + * @disk: device + * @dev: device major/minor + * @ip: array to return results * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for + * Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * + * Most SCSI boards use this mapping, I could be incorrect. Some one + * using hard disks on a trantor should verify that this mapping + * corresponds to that used by the BIOS / ASPI driver by running the + * linux fdisk program and matching the H_C_S coordinates to those + * that DOS uses. */ -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. - */ - -int t128_biosparam(Disk * disk, kdev_t dev, int * ip) +int t128_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - return 0; + int size = disk->capacity; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + return 0; } -/* - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) +/** + * NCR5380_pread - pseudo DMA read + * @instance: controller + * @dst: buffer to write to + * @len: expect/max length * - * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. + * Fast 5380 pseudo-dma read function, transfers len bytes to + * dst from the controller. */ -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, - int len) { - unsigned long reg = instance->base + T_DATA_REG_OFFSET; - unsigned char *d = dst; - register int i = len; - - -#if 0 - for (; i; --i) { - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); -#else - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); - for (; i; --i) { -#endif - *d++ = isa_readb(reg); - } +static inline int NCR5380_pread(struct Scsi_Host *instance, + unsigned char *dst, int len) +{ + unsigned long reg = instance->base + T_DATA_REG_OFFSET; + unsigned char *d = dst; + int i = len; + + while (!(isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_RDY)) + barrier(); + for (; i; --i) { + *d++ = isa_readb(reg); + } - if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { - unsigned char tmp; - unsigned long foo; - foo = instance->base + T_CONTROL_REG_OFFSET; - tmp = isa_readb(foo); - isa_writeb(tmp | T_CR_CT, foo); - isa_writeb(tmp, foo); - printk("scsi%d : watchdog timer fired in NCR5380_pread()\n", - instance->host_no); - return -1; - } else - return 0; + if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { + unsigned char tmp; + unsigned long foo; + foo = instance->base + T_CONTROL_REG_OFFSET; + tmp = isa_readb(foo); + isa_writeb(tmp | T_CR_CT, foo); + isa_writeb(tmp, foo); + printk(KERN_ERR "scsi%d : watchdog timer fired in t128 NCR5380_pread.\n", instance->host_no); + return -1; + } else + return 0; } -/* - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) +/** + * NCR5380_pwrite - pseudo DMA write + * @instance: controller + * @dst: buffer to write to + * @len: expect/max length * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. + * Fast 5380 pseudo-dma write function, transfers len bytes from + * dst to the controller. */ -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, - int len) { - unsigned long reg = instance->base + T_DATA_REG_OFFSET; - unsigned char *s = src; - register int i = len; - -#if 0 - for (; i; --i) { - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); -#else - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); - for (; i; --i) { -#endif - isa_writeb(*s++, reg); - } - if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { - unsigned char tmp; - unsigned long foo; - foo = instance->base + T_CONTROL_REG_OFFSET; - tmp = isa_readb(foo); - isa_writeb(tmp | T_CR_CT, foo); - isa_writeb(tmp, foo); - printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n", - instance->host_no); - return -1; - } else - return 0; +static inline int NCR5380_pwrite(struct Scsi_Host *instance, + unsigned char *src, int len) +{ + unsigned long reg = instance->base + T_DATA_REG_OFFSET; + unsigned char *s = src; + int i = len; + + while (!(isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_RDY)) + barrier(); + for (; i; --i) { + isa_writeb(*s++, reg); + } + + if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { + unsigned char tmp; + unsigned long foo; + foo = instance->base + T_CONTROL_REG_OFFSET; + tmp = isa_readb(foo); + isa_writeb(tmp | T_CR_CT, foo); + isa_writeb(tmp, foo); + printk(KERN_ERR "scsi%d : watchdog timer fired in t128 NCR5380_pwrite()\n", instance->host_no); + return -1; + } else + return 0; } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/tmscsim.c linux-2.5/drivers/scsi/tmscsim.c --- linux-2.5.1/drivers/scsi/tmscsim.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/scsi/tmscsim.c Thu Dec 27 22:10:28 2001 @@ -1371,7 +1371,7 @@ #include <asm/unaligned.h> /* - * Function : static int partsize(struct buffer_head *bh, unsigned long + * Function : static int partsize(unsigned char *buf, unsigned long * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); * * Purpose : to determine the BIOS mapping used to create the partition @@ -1381,7 +1381,7 @@ * */ -static int partsize(struct buffer_head *bh, unsigned long capacity, +static int partsize(unsigned char *buf, unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs) { struct partition *p, *largest = NULL; int i, largest_cyl; @@ -1389,9 +1389,9 @@ unsigned int logical_end, physical_end, ext_physical_end; - if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { - for (largest_cyl = -1, p = (struct partition *) - (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) { + if (*(unsigned short *) (buf+64) == 0xAA55) { + for (largest_cyl = -1, p = (struct partition *) buf, + i = 0; i < 4; ++i, ++p) { if (!p->sys_ind) continue; cyl = p->cyl + ((p->sector & 0xc0) << 2); @@ -1446,16 +1446,16 @@ { int heads, sectors, cylinders; PACB pACB = (PACB) disk->device->host->hostdata; - struct buffer_head *bh; int ret_code = -1; int size = disk->capacity; + unsigned char *buf; - if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, 1024))) + if ((buf = scsi_bios_ptable(devno))) { /* try to infer mapping from partition table */ - ret_code = partsize (bh, (unsigned long) size, (unsigned int *) geom + 2, + ret_code = partsize (buf, (unsigned long) size, (unsigned int *) geom + 2, (unsigned int *) geom + 0, (unsigned int *) geom + 1); - brelse (bh); + kfree (buf); } if (ret_code == -1) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/u14-34f.c linux-2.5/drivers/scsi/u14-34f.c --- linux-2.5.1/drivers/scsi/u14-34f.c Wed Dec 12 17:20:22 2001 +++ linux-2.5/drivers/scsi/u14-34f.c Sat Jan 12 12:32:41 2002 @@ -1,6 +1,13 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 01 Jan 2002 Rev. 7.20 for linux 2.5.1 + * + Use the dynamic DMA mapping API. + * + * 19 Dec 2001 Rev. 7.02 for linux 2.5.1 + * + Use SCpnt->sc_data_direction if set. + * + Use sglist.page instead of sglist.address. + * * 11 Dec 2001 Rev. 7.00 for linux 2.5.1 * + Use host->host_lock instead of io_request_lock. * @@ -160,7 +167,7 @@ * Auto detects if U14F boards have an old firmware revision. * Max number of scatter/gather lists set to 16 for all boards * (most installation run fine using 33 sglists, while other - * has problems when using more then 16). + * has problems when using more than 16). * * 16 Jan 1995 rev. 1.13 for linux 1.1.81 * Display a message if check_region detects a port address @@ -186,7 +193,7 @@ * * Multiple U14F and/or U34F host adapters are supported. * - * Copyright (C) 1994-2001 Dario Ballabio (ballabio_dario@emc.com) + * Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com) * * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it * @@ -268,7 +275,7 @@ * * For U34F boards the latest bios prom is 38008-002 (BIOS rev. 2.01), * the latest firmware prom is 28008-006. Older firmware 28008-005 has - * problems when using more then 16 scatter/gather lists. + * problems when using more than 16 scatter/gather lists. * * The list of i/o ports to be probed can be totally replaced by the * boot command line option: "u14-34f=port0,port1,port2,...", where the @@ -377,6 +384,7 @@ #include "u14-34f.h" #include <linux/stat.h> #include <linux/config.h> +#include <linux/pci.h> #include <linux/init.h> #include <linux/ctype.h> #include <linux/spinlock.h> @@ -483,13 +491,13 @@ unsigned char clink_id; /* identifies command in chain */ unsigned char use_sg; /* (if sg is set) 8 bytes per list */ unsigned char sense_len; - unsigned char scsi_cdbs_len; /* 6, 10, or 12 */ - unsigned char scsi_cdbs[12]; /* SCSI commands */ + unsigned char cdb_len; /* 6, 10, or 12 */ + unsigned char cdb[12]; /* SCSI Command Descriptor Block */ unsigned char adapter_status; /* non-zero indicates HA error */ unsigned char target_status; /* non-zero indicates target error */ unsigned int sense_addr PACKED; Scsi_Cmnd *SCpnt; - unsigned int index; /* cp index */ + unsigned int cpp_index; /* cp index */ struct sg_list *sglist; }; @@ -507,6 +515,7 @@ unsigned int retries; /* Number of internal retries */ unsigned long last_retried_pid; /* Pid of last retried command */ unsigned char subversion; /* Bus type, either ISA or ESA */ + struct pci_dev *pdev; /* Always NULL */ unsigned char heads; unsigned char sectors; @@ -537,21 +546,11 @@ #define HD(board) ((struct hostdata *) &sh[board]->hostdata) #define BN(board) (HD(board)->board_name) -#define SWAP_BYTE(x) ((unsigned long)( \ - (((unsigned long)(x) & 0x000000ffU) << 24) | \ - (((unsigned long)(x) & 0x0000ff00U) << 8) | \ - (((unsigned long)(x) & 0x00ff0000U) >> 8) | \ - (((unsigned long)(x) & 0xff000000U) >> 24))) +/* Device is Little Endian */ +#define H2DEV(x) cpu_to_le32(x) +#define DEV2H(x) le32_to_cpu(x) -#if defined(__BIG_ENDIAN) -#define H2DEV(x) SWAP_BYTE(x) -#else -#define H2DEV(x) (x) -#endif - -#define DEV2H(x) H2DEV(x) #define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0) -#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0) static void do_interrupt_handler(int, void *, struct pt_regs *); static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); @@ -653,8 +652,8 @@ cpp->xdir = DTD_IN; cpp->data_address = V2DEV(HD(j)->board_id); cpp->data_len = H2DEV(sizeof(HD(j)->board_id)); - cpp->scsi_cdbs_len = 6; - cpp->scsi_cdbs[0] = HA_CMD_INQUIRY; + cpp->cdb_len = 6; + cpp->cdb[0] = HA_CMD_INQUIRY; if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { printk("%s: board_inquiry, adapter busy.\n", BN(j)); @@ -832,14 +831,14 @@ unsigned long flags; scsi_register_blocked_host(sh[j]); sh[j]->unchecked_isa_dma = TRUE; - + flags=claim_dma_lock(); disable_dma(dma_channel); clear_dma_ff(dma_channel); set_dma_mode(dma_channel, DMA_MODE_CASCADE); enable_dma(dma_channel); release_dma_lock(flags); - + sh[j]->dma_channel = dma_channel; sprintf(BN(j), "U14F%d", j); bus_type = "ISA"; @@ -879,7 +878,7 @@ if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN; if (j == 0) { - printk("UltraStor 14F/34F: Copyright (C) 1994-2001 Dario Ballabio.\n"); + printk("UltraStor 14F/34F: Copyright (C) 1994-2002 Dario Ballabio.\n"); printk("%s config options -> of:%c, lc:%c, mq:%d, et:%c.\n", driver_name, YESNO(have_old_firmware), YESNO(linked_comm), max_queue_depth, YESNO(ext_tran)); @@ -949,8 +948,7 @@ return 1; } -int u14_34f_detect(Scsi_Host_Template *tpnt) -{ +int u14_34f_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; tpnt->proc_name = "u14-34f"; @@ -978,26 +976,95 @@ return j; } -static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) { - unsigned int k, data_len = 0; +static inline void map_dma(unsigned int i, unsigned int j) { + unsigned int data_len = 0; + unsigned int k, count, pci_dir; struct scatterlist *sgpnt; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (SCpnt->sense_buffer) + cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer, + sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE)); + + cpp->sense_len = sizeof SCpnt->sense_buffer; + + if (!SCpnt->use_sg) { + + if (!SCpnt->request_bufflen) + cpp->data_address = V2DEV(SCpnt->request_buffer); + + else if (SCpnt->request_buffer) + cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, + SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir)); + + cpp->data_len = H2DEV(SCpnt->request_bufflen); + return; + } sgpnt = (struct scatterlist *) SCpnt->request_buffer; + count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir); - for (k = 0; k < SCpnt->use_sg; k++) { - cpp->sglist[k].address = V2DEV(sgpnt[k].address); - cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length); + for (k = 0; k < count; k++) { + cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k])); + cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k])); data_len += sgpnt[k].length; } + cpp->sg = TRUE; cpp->use_sg = SCpnt->use_sg; cpp->data_address = V2DEV(cpp->sglist); cpp->data_len = H2DEV(data_len); } -static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { - unsigned int i, j, k; +static void unmap_dma(unsigned int i, unsigned int j) { + unsigned int pci_dir; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (DEV2H(cpp->sense_addr)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); + + if (SCpnt->use_sg) + pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); + + else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); + +} + +static void sync_dma(unsigned int i, unsigned int j) { + unsigned int pci_dir; struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); + + if (DEV2H(cpp->sense_addr)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); + + if (SCpnt->use_sg) + pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + SCpnt->use_sg, pci_dir); + + else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); + +} + +static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) { + unsigned int k; static const unsigned char data_out_cmds[] = { 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, @@ -1008,9 +1075,51 @@ static const unsigned char data_none_cmds[] = { 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, - 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5 + 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00 }; + struct mscp *cpp; + Scsi_Cmnd *SCpnt; + + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; + + if (SCpnt->sc_data_direction == SCSI_DATA_READ) { + cpp->xdir = DTD_IN; + return; + } + else if (SCpnt->sc_data_direction == SCSI_DATA_WRITE) { + cpp->xdir = DTD_OUT; + return; + } + else if (SCpnt->sc_data_direction == SCSI_DATA_NONE) { + cpp->xdir = DTD_NONE; + return; + } + + if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) + panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j)); + + cpp->xdir = DTD_IN; + + for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) + if (SCpnt->cmnd[0] == data_out_cmds[k]) { + cpp->xdir = DTD_OUT; + break; + } + + if (cpp->xdir == DTD_IN) + for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) + if (SCpnt->cmnd[0] == data_none_cmds[k]) { + cpp->xdir = DTD_NONE; + break; + } + +} + +static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { + unsigned int i, j, k; + struct mscp *cpp; + /* j is the board number */ j = ((struct hostdata *) SCpnt->host->hostdata)->board_number; @@ -1042,47 +1151,26 @@ memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *)); SCpnt->scsi_done = done; - cpp->index = i; - SCpnt->host_scribble = (unsigned char *) &cpp->index; + cpp->cpp_index = i; + SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index; if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n", BN(j), i, SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); - cpp->xdir = DTD_IN; - - for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) - if (SCpnt->cmnd[0] == data_out_cmds[k]) { - cpp->xdir = DTD_OUT; - break; - } - - if (cpp->xdir == DTD_IN) - for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) - if (SCpnt->cmnd[0] == data_none_cmds[k]) { - cpp->xdir = DTD_NONE; - break; - } - cpp->opcode = OP_SCSI; cpp->channel = SCpnt->channel; cpp->target = SCpnt->target; cpp->lun = SCpnt->lun; cpp->SCpnt = SCpnt; - cpp->sense_addr = V2DEV(SCpnt->sense_buffer); - cpp->sense_len = sizeof SCpnt->sense_buffer; + cpp->cdb_len = SCpnt->cmd_len; + memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); - if (SCpnt->use_sg) { - cpp->sg = TRUE; - build_sg_list(cpp, SCpnt); - } - else { - cpp->data_address = V2DEV(SCpnt->request_buffer); - cpp->data_len = H2DEV(SCpnt->request_bufflen); - } + /* Use data transfer direction SCpnt->sc_data_direction */ + scsi_to_dev_dir(i, j); - cpp->scsi_cdbs_len = SCpnt->cmd_len; - memcpy(cpp->scsi_cdbs, SCpnt->cmnd, cpp->scsi_cdbs_len); + /* Map DMA buffers and SG list */ + map_dma(i, j); if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) { @@ -1092,6 +1180,7 @@ } if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { + unmap_dma(i, j); SCpnt->host_scribble = NULL; printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n", BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); @@ -1154,6 +1243,7 @@ printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i); if (SCarg->eh_state == SCSI_STATE_TIMEOUT) { + unmap_dma(i, j); SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n", @@ -1175,6 +1265,7 @@ } if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { + unmap_dma(i, j); SCarg->result = DID_ABORT << 16; SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; @@ -1272,18 +1363,19 @@ #endif HD(j)->in_reset = TRUE; - - spin_unlock_irq(&sh[j]->host_lock); + + spin_unlock_irq(sh[j]->host_lock); time = jiffies; while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L); - spin_lock_irq(&sh[j]->host_lock); - + spin_lock_irq(sh[j]->host_lock); + printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit); for (i = 0; i < sh[j]->can_queue; i++) { if (HD(j)->cp_stat[i] == IN_RESET) { SCpnt = HD(j)->cp[i].SCpnt; + unmap_dma(i, j); SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; @@ -1296,6 +1388,7 @@ else if (HD(j)->cp_stat[i] == ABORTING) { SCpnt = HD(j)->cp[i].SCpnt; + unmap_dma(i, j); SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; @@ -1536,23 +1629,25 @@ return; } - spp = (struct mscp *)DEV2V(ret = inl(sh[j]->io_port + REG_ICM)); - cpp = spp; + ret = inl(sh[j]->io_port + REG_ICM); /* Clear interrupt pending flag */ outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR); -#if defined(DEBUG_GENERATE_ABORTS) - if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return; -#endif - /* Find the mailbox to be serviced on this board */ - i = cpp - HD(j)->cp; + for (i = 0; i < sh[j]->can_queue; i++) + if (V2DEV(&(HD(j)->cp[i])) == ret) break; - if (cpp < HD(j)->cp || cpp >= HD(j)->cp + sh[j]->can_queue - || i >= sh[j]->can_queue) + if (i >= sh[j]->can_queue) panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j), - (void *)ret, HD(j)->cp); + (void *)ret, (void *)V2DEV(HD(j)->cp)); + + cpp = &(HD(j)->cp[i]); + spp = cpp; + +#if defined(DEBUG_GENERATE_ABORTS) + if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return; +#endif if (HD(j)->cp_stat[i] == IGNORE) { HD(j)->cp_stat[i] = FREE; @@ -1588,6 +1683,8 @@ panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble); + sync_dma(i, j); + if (linked_comm && SCpnt->device->queue_depth > 2 && TLDEV(SCpnt->device->type)) flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE); @@ -1705,6 +1802,8 @@ SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, reg, HD(j)->iocount); + unmap_dma(i, j); + /* Set the command state to inactive */ SCpnt->host_scribble = NULL; @@ -1723,9 +1822,9 @@ /* Check if the interrupt must be processed by this handler */ if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return; - spin_lock_irqsave(&sh[j]->host_lock, spin_flags); + spin_lock_irqsave(sh[j]->host_lock, spin_flags); ihdlr(irq, j); - spin_unlock_irqrestore(&sh[j]->host_lock, spin_flags); + spin_unlock_irqrestore(sh[j]->host_lock, spin_flags); } int u14_34f_release(struct Scsi_Host *shpnt) { @@ -1736,9 +1835,7 @@ if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n", driver_name); - if( sh[j]->unchecked_isa_dma ) { - scsi_deregister_blocked_host(sh[j]); - } + if(sh[j]->unchecked_isa_dma) scsi_deregister_blocked_host(sh[j]); for (i = 0; i < sh[j]->can_queue; i++) if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/u14-34f.h linux-2.5/drivers/scsi/u14-34f.h --- linux-2.5.1/drivers/scsi/u14-34f.h Wed Dec 12 17:20:22 2001 +++ linux-2.5/drivers/scsi/u14-34f.h Thu Jan 3 23:04:40 2002 @@ -13,7 +13,7 @@ int u14_34f_reset(Scsi_Cmnd *); int u14_34f_biosparam(Disk *, kdev_t, int *); -#define U14_34F_VERSION "7.00.00" +#define U14_34F_VERSION "7.20.00" #define ULTRASTOR_14_34F { \ name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/scsi/wd7000.c linux-2.5/drivers/scsi/wd7000.c --- linux-2.5.1/drivers/scsi/wd7000.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/scsi/wd7000.c Sun Jan 6 19:17:51 2002 @@ -140,6 +140,11 @@ * 03/01/1998 * * WD7000 driver now work on kernels >= 2.1.x + * + * + * 12/31/2001 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * + * use host->host_lock, not io_request_lock, cleanups */ #include <linux/module.h> @@ -166,6 +171,11 @@ #define ANY2SCSI_INLINE /* undef this to use old macros */ #undef WD7000_DEBUG /* general debug */ +#ifdef WD7000_DEBUG +#define dprintk printk +#else +#define dprintk(format,args...) +#endif #include "wd7000.h" #include <linux/stat.h> @@ -557,7 +567,7 @@ } Icb; #ifdef MODULE -static char * wd7000 = NULL; +static char *wd7000; MODULE_PARM(wd7000, "s"); #endif @@ -568,23 +578,23 @@ * structure is not part of the Adapter structure. */ static Scb scbs[MAX_SCBS]; -static Scb *scbfree = NULL; /* free list */ +static Scb *scbfree; /* free list */ static int freescbs = MAX_SCBS; /* free list counter */ /* * END of data/declarations - code follows. */ -static void setup_error (char *mesg, int *ints) +static void __init setup_error(char *mesg, int *ints) { if (ints[0] == 3) - printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n", - ints[1], ints[2], ints[3], mesg); + printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n", + ints[1], ints[2], ints[3], mesg); else if (ints[0] == 4) - printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n", - ints[1], ints[2], ints[3], ints[4], mesg); + printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n", + ints[1], ints[2], ints[3], ints[4], mesg); else - printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n", - ints[1], ints[2], ints[3], ints[4], ints[5], mesg); + printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n", + ints[1], ints[2], ints[3], ints[4], ints[5], mesg); } @@ -604,21 +614,23 @@ */ static int __init wd7000_setup(char *str) { - static short wd7000_card_num = 0; - short i, j; + static short wd7000_card_num; /* .bss will zero this */ + short i; int ints[6]; (void)get_options(str, ARRAY_SIZE(ints), ints); if (wd7000_card_num >= NUM_CONFIGS) { - printk("wd7000_setup: Too many \"wd7000=\" configurations in " - "command line!\n"); + printk(KERN_ERR __FUNCTION__ + ": Too many \"wd7000=\" configurations in " + "command line!\n"); return 0; } if ((ints[0] < 3) || (ints[0] > 5)) { - printk("wd7000_setup: Error in command line! " - "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>[,<BUS_OFF>]]\n"); + printk(KERN_ERR __FUNCTION__ ": Error in command line! " + "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" + "[,<BUS_OFF>]]\n"); } else { for (i = 0; i < NUM_IRQS; i++) if (ints[1] == wd7000_irq[i]) @@ -652,7 +664,8 @@ if (ints[0] > 3) { if ((ints[4] < 500) || (ints[4] > 31875)) { - setup_error("BUS_ON value is out of range (500 to 31875 nanoseconds)!", ints); + setup_error("BUS_ON value is out of range (500" + " to 31875 nanoseconds)!", ints); configs[wd7000_card_num].bus_on = BUS_ON; } else configs[wd7000_card_num].bus_on = ints[4] / 125; @@ -661,36 +674,47 @@ if (ints[0] > 4) { if ((ints[5] < 500) || (ints[5] > 31875)) { - setup_error("BUS_OFF value is out of range (500 to 31875 nanoseconds)!", ints); + setup_error("BUS_OFF value is out of range (500" + " to 31875 nanoseconds)!", ints); configs[wd7000_card_num].bus_off = BUS_OFF; } else - configs[wd7000_card_num].bus_off = ints[5] / 125; + configs[wd7000_card_num].bus_off = ints[5] / + 125; } else configs[wd7000_card_num].bus_off = BUS_OFF; if (wd7000_card_num) { - for (i = 0; i < (wd7000_card_num - 1); i++) - for (j = i + 1; j < wd7000_card_num; j++) + for (i = 0; i < (wd7000_card_num - 1); i++) { + int j = i + 1; + + for (; j < wd7000_card_num; j++) if (configs[i].irq == configs[j].irq) { - setup_error("duplicated IRQ!", ints); + setup_error("duplicated IRQ!", + ints); return 0; - } else if (configs[i].dma == configs[j].dma) { - setup_error("duplicated DMA channel!", ints); + } + if (configs[i].dma == configs[j].dma) { + setup_error("duplicated DMA " + "channel!", ints); return 0; - } else if (configs[i].iobase == configs[j].iobase) { - setup_error ("duplicated I/O base address!", ints); + } + if (configs[i].iobase == + configs[j].iobase) { + setup_error("duplicated I/O " + "base address!", + ints); return 0; } + } } -#ifdef WD7000_DEBUG - printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, BUS_ON=%dns, BUS_OFF=%dns\n", + dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, " + "BUS_ON=%dns, BUS_OFF=%dns\n", configs[wd7000_card_num].irq, configs[wd7000_card_num].dma, configs[wd7000_card_num].iobase, configs[wd7000_card_num].bus_on * 125, configs[wd7000_card_num].bus_off * 125); -#endif wd7000_card_num++; } @@ -811,7 +835,7 @@ return (1); } - printk ("wd7000 command_out: WAIT failed(%d)\n", len + 1); + printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1); return (0); } @@ -827,7 +851,7 @@ * the satisfiability of a request is not dependent on the size of the * request. */ -static inline Scb *alloc_scbs (int needed) +static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed) { register Scb *scb, *p; register unsigned long flags; @@ -842,18 +866,18 @@ save_flags (flags); cli (); while (busy) { /* someone else is allocating */ - spin_unlock_irq(&io_request_lock); + spin_unlock_irq(host->host_lock); for (now = jiffies; now == jiffies; ); /* wait a jiffy */ - spin_lock_irq(&io_request_lock); + spin_lock_irq(host->host_lock); } busy = 1; /* not busy now; it's our turn */ while (freescbs < needed) { timeout = jiffies + WAITnexttimeout; do { - spin_unlock_irq(&io_request_lock); + spin_unlock_irq(host->host_lock); for (now = jiffies; now == jiffies; ); /* wait a jiffy */ - spin_lock_irq(&io_request_lock); + spin_lock_irq(host->host_lock); } while (freescbs < needed && time_before_eq(jiffies, timeout)); /* * If we get here with enough free Scbs, we can take them. @@ -929,9 +953,7 @@ Mailbox *ogmbs = host->mb.ogmb; int *next_ogmb = &(host->next_ogmb); -#ifdef WD7000_DEBUG - printk ("wd7000_mail_out: 0x%06lx", (long) scbptr); -#endif + dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr); /* We first look for a free outgoing mailbox */ save_flags (flags); @@ -939,9 +961,7 @@ ogmb = *next_ogmb; for (i = 0; i < OGMB_CNT; i++) { if (ogmbs[ogmb].status == 0) { -#ifdef WD7000_DEBUG - printk (" using OGMB 0x%x", ogmb); -#endif + dprintk(" using OGMB 0x%x", ogmb); ogmbs[ogmb].status = 1; any2scsi ((unchar *) ogmbs[ogmb].scbptr, (int) scbptr); @@ -953,9 +973,7 @@ } restore_flags (flags); -#ifdef WD7000_DEBUG - printk (", scb is 0x%06lx", (long) scbptr); -#endif + dprintk(", scb is 0x%06lx", (long) scbptr); if (i >= OGMB_CNT) { /* @@ -966,9 +984,7 @@ * that marks OGMB's free, waiting even with interrupts off * should work, since they are freed very quickly in most cases. */ -#ifdef WD7000_DEBUG - printk (", no free OGMBs.\n"); -#endif + dprintk(", no free OGMBs.\n"); return (0); } @@ -977,9 +993,7 @@ start_ogmb = START_OGMB | ogmb; command_out (host, &start_ogmb, 1); -#ifdef WD7000_DEBUG - printk (", awaiting interrupt.\n"); -#endif + dprintk(", awaiting interrupt.\n"); return (1); } @@ -1026,7 +1040,7 @@ } #ifdef WD7000_DEBUG if (scsierr || hosterr) - printk ("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", + dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", scsierr, in_error, hosterr); #endif return (scsierr | (hosterr << 16)); @@ -1035,10 +1049,7 @@ static void wd7000_scsi_done (Scsi_Cmnd *SCpnt) { -#ifdef WD7000_DEBUG - printk ("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt); -#endif - + dprintk("wd7000_scsi_done: 0x%06lx\n", (long)SCpnt); SCpnt->SCp.phase = 0; } @@ -1057,15 +1068,11 @@ host->int_counter++; -#ifdef WD7000_DEBUG - printk ("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host); -#endif + dprintk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host); flag = inb (host->iobase + ASC_INTR_STAT); -#ifdef WD7000_DEBUG - printk ("wd7000_intr_handle: intr stat = 0x%02x\n", flag); -#endif + dprintk("wd7000_intr_handle: intr stat = 0x%02x\n", flag); if (!(inb (host->iobase + ASC_STAT) & INT_IM)) { /* NB: these are _very_ possible if IRQ 15 is being used, since @@ -1076,9 +1083,7 @@ * can sort these out. Otherwise, electrical noise and other such * problems would be indistinguishable from valid interrupts... */ -#ifdef WD7000_DEBUG - printk ("wd7000_intr_handle: phantom interrupt...\n"); -#endif + dprintk("wd7000_intr_handle: phantom interrupt...\n"); wd7000_intr_ack (host); return; } @@ -1086,9 +1091,7 @@ if (flag & MB_INTR) { /* The interrupt is for a mailbox */ if (!(flag & IMB_INTR)) { -#ifdef WD7000_DEBUG - printk ("wd7000_intr_handle: free outgoing mailbox\n"); -#endif + dprintk("wd7000_intr_handle: free outgoing mailbox\n"); /* * If sleep_on() and the "interrupt on free OGMB" command are * used in mail_out(), wake_up() should correspondingly be called @@ -1102,10 +1105,8 @@ icmb = flag & MB_MASK; icmb_status = icmbs[icmb].status; if (icmb_status & 0x80) { /* unsolicited - result in ICMB */ -#ifdef WD7000_DEBUG - printk ("wd7000_intr_handle: unsolicited interrupt 0x%02x\n", + dprintk("wd7000_intr_handle: unsolicited interrupt 0x%02x\n", icmb_status); -#endif wd7000_intr_ack (host); return; } @@ -1135,18 +1136,17 @@ wd7000_intr_ack (host); -#ifdef WD7000_DEBUG - printk ("wd7000_intr_handle: return from interrupt handler\n"); -#endif + dprintk("wd7000_intr_handle: return from interrupt handler\n"); } void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; + struct Scsi_Host *host = dev_id; - spin_lock_irqsave(&io_request_lock, flags); + spin_lock_irqsave(host->host_lock, flags); wd7000_intr_handle(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } @@ -1163,7 +1163,7 @@ idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7); SCpnt->scsi_done = done; SCpnt->SCp.phase = 1; - scb = alloc_scbs (1); + scb = alloc_scbs(SCpnt->host, 1); scb->idlun = idlun; memcpy (scb->cdb, cdb, cdblen); scb->direc = 0x40; /* Disable direction check */ @@ -1179,9 +1179,7 @@ if (SCpnt->host->sg_tablesize == SG_NONE) { panic ("wd7000_queuecommand: scatter/gather not supported.\n"); } -#ifdef WD7000_DEBUG - printk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg); -#endif + dprintk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg); sgb = scb->sgb; scb->op = 1; @@ -1367,14 +1365,12 @@ save_flags (flags); cli (); -#ifdef WD7000_DEBUG - printk ("Buffer = <%.*s>, length = %d\n", length, buffer, length); -#endif + dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length); /* * Currently this is a no-op */ - printk ("Sorry, this function is currently out of order...\n"); + dprintk("Sorry, this function is currently out of order...\n"); restore_flags (flags); @@ -1521,9 +1517,7 @@ Adapter *host = NULL; struct Scsi_Host *sh; -#ifdef WD7000_DEBUG - printk ("wd7000_detect: started\n"); -#endif + dprintk("wd7000_detect: started\n"); #ifdef MODULE if (wd7000) @@ -1573,12 +1567,12 @@ * BIOS SIGNATURE has been found. */ #ifdef WD7000_DEBUG - printk ("wd7000_detect: pass %d\n", pass + 1); + dprintk("wd7000_detect: pass %d\n", pass + 1); if (biosaddr_ptr == NUM_ADDRS) - printk ("WD-7000 SST BIOS not detected...\n"); + dprintk("WD-7000 SST BIOS not detected...\n"); else - printk ("WD-7000 SST BIOS detected at 0x%lx: checking...\n", + dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n", wd7000_biosaddr[biosaddr_ptr]); #endif @@ -1587,15 +1581,11 @@ iobase = configs[pass].iobase; -#ifdef WD7000_DEBUG - printk ("wd7000_detect: check IO 0x%x region...\n", iobase); -#endif + dprintk("wd7000_detect: check IO 0x%x region...\n", iobase); if (request_region (iobase, 4, "wd7000")) { -#ifdef WD7000_DEBUG - printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase); -#endif + dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase); /* * ASC reset... */ @@ -1603,17 +1593,11 @@ delay (1); outb (0, iobase + ASC_CONTROL); - if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) -#ifdef WD7000_DEBUG - { - printk ("failed!\n"); + if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { + dprintk("failed!\n"); goto err_release; - } - else - printk ("ok!\n"); -#else - goto err_release; -#endif + } else + dprintk("ok!\n"); if (inb (iobase + ASC_INTR_STAT) == 1) { /* @@ -1629,10 +1613,8 @@ host = (Adapter *) sh->hostdata; -#ifdef WD7000_DEBUG - printk ("wd7000_detect: adapter allocated at 0x%x\n", (int) host); -#endif - + dprintk("wd7000_detect: adapter allocated at 0x%x\n", + (int)host); memset (host, 0, sizeof (Adapter)); host->irq = configs[pass].irq; @@ -1643,11 +1625,9 @@ host->bus_off = configs[pass].bus_off; host->sh = wd7000_host[host->irq - IRQ_MIN] = sh; -#ifdef WD7000_DEBUG - printk ("wd7000_detect: Trying init WD-7000 card at IO " + dprintk("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma); -#endif if (!wd7000_init (host)) /* Initialization failed */ goto err_unregister; @@ -1675,12 +1655,9 @@ printk (" BUS_ON time: %dns, BUS_OFF time: %dns\n", host->bus_on * 125, host->bus_off * 125); } - } - -#ifdef WD7000_DEBUG - else - printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase); -#endif + } else + dprintk("wd7000_detect: IO 0x%x region already allocated!\n", + iobase); continue; @@ -1730,9 +1707,8 @@ */ int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip) { -#ifdef WD7000_DEBUG - printk ("wd7000_biosparam: dev=%s, size=%d, ", kdevname (dev), disk->capacity); -#endif + dprintk("wd7000_biosparam: dev=%s, size=%d, ", kdevname(dev), + disk->capacity); /* * try default translation @@ -1766,14 +1742,13 @@ ip[2] = info[2]; if (info[0] == 255) - printk ("wd7000_biosparam: current partition table is using extended translation.\n"); + printk(KERN_INFO __FUNCTION__ ": current partition table is " + "using extended translation.\n"); } } -#ifdef WD7000_DEBUG - printk ("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]); - printk ("WARNING: check, if the bios geometry is correct.\n"); -#endif + dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]); + dprintk("WARNING: check, if the bios geometry is correct.\n"); return (0); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sgi/char/sgiserial.c linux-2.5/drivers/sgi/char/sgiserial.c --- linux-2.5.1/drivers/sgi/char/sgiserial.c Mon Aug 27 15:56:31 2001 +++ linux-2.5/drivers/sgi/char/sgiserial.c Sun Dec 30 13:55:22 2001 @@ -49,8 +49,6 @@ #define NUM_SERIAL 1 /* One chip on board. */ #define NUM_CHANNELS (NUM_SERIAL * 2) -extern wait_queue_head_t keypress_wait; - struct sgi_zslayout *zs_chips[NUM_SERIAL] = { 0, }; struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, }; struct sgi_zschannel *zs_conschan; @@ -100,6 +98,7 @@ DECLARE_TASK_QUEUE(tq_serial); struct tty_driver serial_driver, callout_driver; +struct console sgi_console_driver; struct console *sgisercon; static int serial_refcount; @@ -428,8 +427,6 @@ show_buffers(); return; } - /* It is a 'keyboard interrupt' ;-) */ - wake_up(&keypress_wait); } /* Look for kgdb 'stop' character, consult the gdb documentation * for remote target debugging and arch/sparc/kernel/sparc-stub.c @@ -1890,7 +1887,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sgi_console_driver; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -2117,12 +2116,6 @@ rs_fair_output(); } -static int zs_console_wait_key(struct console *con) -{ - sleep_on(&keypress_wait); - return 0; -} - static kdev_t zs_console_device(struct console *con) { return MKDEV(TTY_MAJOR, 64 + con->index); @@ -2274,7 +2267,6 @@ name: "ttyS", write: zs_console_write, device: zs_console_device, - wait_key: zs_console_wait_key, setup: zs_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/Config.in linux-2.5/drivers/sound/Config.in --- linux-2.5.1/drivers/sound/Config.in Fri Nov 9 22:06:42 2001 +++ linux-2.5/drivers/sound/Config.in Thu Dec 13 16:32:36 2001 @@ -40,6 +40,9 @@ 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 dep_tristate ' Intel ICH (i8xx) audio support' CONFIG_SOUND_ICH $CONFIG_PCI +if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then + dep_tristate ' IT8172G Sound' CONFIG_SOUND_IT8172 $CONFIG_SOUND +fi dep_tristate ' RME Hammerfall (RME96XX) support' CONFIG_SOUND_RME96XX $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND if [ "$CONFIG_VISWS" = "y" ]; then diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/Makefile linux-2.5/drivers/sound/Makefile --- linux-2.5.1/drivers/sound/Makefile Fri Sep 14 21:04:07 2001 +++ linux-2.5/drivers/sound/Makefile Thu Dec 13 16:32:36 2001 @@ -73,6 +73,7 @@ obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o obj-$(CONFIG_SOUND_BT878) += btaudio.o obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o +obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o ifeq ($(CONFIG_MIDI_EMU10K1),y) obj-$(CONFIG_SOUND_EMU10K1) += sound.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/ad1848.c linux-2.5/drivers/sound/ad1848.c --- linux-2.5.1/drivers/sound/ad1848.c Wed Nov 28 00:44:37 2001 +++ linux-2.5/drivers/sound/ad1848.c Fri Dec 28 01:01:25 2001 @@ -134,7 +134,7 @@ static int loaded; -static int ad_format_mask[10 /*devc->model */ ] = +static int ad_format_mask[13 /*devc->model */ ] = { 0, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, @@ -145,7 +145,10 @@ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE /* CS4235 */, - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW /* Ensoniq Soundscape*/ + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW /* Ensoniq Soundscape*/, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM }; static ad1848_info adev_info[MAX_AUDIO_DEV]; @@ -2965,6 +2968,10 @@ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021), 1, 0, 0, 1, 1}, + {"Advanced Gravis InterWave Audio", + ISAPNP_VENDOR('G','R','V'), ISAPNP_DEVICE(0x0001), + ISAPNP_VENDOR('G','R','V'), ISAPNP_FUNCTION(0x0000), + 0, 0, 0, 1, 0}, {0} }; @@ -2977,6 +2984,8 @@ ISAPNP_VENDOR('C','S','C'), ISAPNP_FUNCTION(0x0100), 0 }, { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021), 0 }, + { ISAPNP_VENDOR('G','R','V'), ISAPNP_DEVICE(0x0001), + ISAPNP_VENDOR('G','R','V'), ISAPNP_FUNCTION(0x0000), 0 }, {0} }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/aedsp16.c linux-2.5/drivers/sound/aedsp16.c --- linux-2.5.1/drivers/sound/aedsp16.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/sound/aedsp16.c Mon Jan 14 22:39:45 2002 @@ -1,5 +1,5 @@ /* - drivers/sound/lowlevel/aedsp16.c + drivers/sound/aedsp16.c Audio Excel DSP 16 software configuration routines Copyright (C) 1995,1996,1997,1998 Riccardo Facchetti (fizban@tin.it) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/btaudio.c linux-2.5/drivers/sound/btaudio.c --- linux-2.5.1/drivers/sound/btaudio.c Wed Oct 17 21:19:20 2001 +++ linux-2.5/drivers/sound/btaudio.c Mon Jan 14 22:39:45 2002 @@ -300,7 +300,7 @@ static int btaudio_mixer_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct btaudio *bta; for (bta = btaudios; bta != NULL; bta = bta->next) @@ -459,7 +459,7 @@ static int btaudio_dsp_open_digital(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct btaudio *bta; for (bta = btaudios; bta != NULL; bta = bta->next) @@ -475,7 +475,7 @@ static int btaudio_dsp_open_analog(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct btaudio *bta; for (bta = btaudios; bta != NULL; bta = bta->next) @@ -885,6 +885,12 @@ } bta = kmalloc(sizeof(*bta),GFP_ATOMIC); + if (!bta) { + printk(KERN_WARNING + "btaudio: not enough memory\n"); + rc = -ENOMEM; + goto fail1; + } memset(bta,0,sizeof(*bta)); bta->pci = pci_dev; @@ -1030,7 +1036,7 @@ name: "btaudio", id_table: btaudio_pci_tbl, probe: btaudio_probe, - remove: btaudio_remove, + remove: __devexit_p(btaudio_remove), }; int btaudio_init_module(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/cs4281/cs4281m.c linux-2.5/drivers/sound/cs4281/cs4281m.c --- linux-2.5.1/drivers/sound/cs4281/cs4281m.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/sound/cs4281/cs4281m.c Mon Jan 14 22:39:45 2002 @@ -1,12 +1,12 @@ /******************************************************************************* * -* "cs4281.c" -- Cirrus Logic-Crystal CS4281 linux audio driver. +* "cs4281m.c" -- Cirrus Logic-Crystal CS4281 linux audio driver. * * Copyright (C) 2000,2001 Cirrus Logic Corp. * -- adapted from drivers by Thomas Sailer, * -- but don't bug him; Problems should go to: * -- tom woller (twoller@crystal.cirrus.com) or -* (audio@crystal.cirrus.com). +* (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 @@ -51,6 +51,18 @@ * 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use * defaultorder-100 as power of 2 for the buffer size. example: * 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size. +* 04/02/01 trw - reworked the includes, so kgdb wouldn't get confused. +* 04/17/01 trw - added ifdef CONFIG_PM for 2.4.x non-pm kernels. static pmprint. +* 04/19/01 trw - reworked all of the wrapper macros to keep native 2.4.x code +* predominate in the driver. +* 07/01/01 trw - added ability to modify the record source mask to alleviate +* problems with toshiba systems. also, check for toshiba +* system to set default up properly. +* 11/12/01 trw - removed cs4281_update_ptr() in the polling interface code. +* returning with only a few bytes available in the write buffer +* seems to cause some problems with some apps (xmms OSS plugin). +* Also, fixed bug in cs4281_update_ptr() code to wakeup when +* 1/2 buffer is empty, not when completely full. * *******************************************************************************/ @@ -77,13 +89,17 @@ #include <linux/wrapper.h> #include <asm/uaccess.h> #include <asm/hardirq.h> -//#include "cs_dm.h" #include "cs4281_hwdefs.h" -#include "cs4281pm.h" -struct cs4281_state; EXPORT_NO_SYMBOLS; +struct cs4281_state; +int cs4281_suspend(struct cs4281_state *s); +int cs4281_resume(struct cs4281_state *s); + +#include "cs4281_wrapper.h" +#include "cs4281pm-24.h" + static void stop_dac(struct cs4281_state *s); static void stop_adc(struct cs4281_state *s); static void start_dac(struct cs4281_state *s); @@ -99,18 +115,40 @@ #define PCI_DEVICE_ID_CRYSTAL_CS4281 0x6005 #endif +#ifndef SS_ID_TOSHIBA_1640CDT +#define SS_ID_TOSHIBA_1640CDT 0xff00 +#endif + +#ifndef PCI_VENDOR_ID_TOSHIBA +#define PCI_VENDOR_ID_TOSHIBA 0x1179 +#endif + #define CS4281_MAGIC ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS) #define CS4281_CFLR_DEFAULT 0x00000001 /* CFLR must be in AC97 link mode */ +#define CS4281_BA0_CPWR_DEFAULT 0x4281 -// buffer order determines the size of the dma buffer for the driver. -// under Linux, a smaller buffer allows more responsiveness from many of the -// applications (e.g. games). A larger buffer allows some of the apps (esound) -// to not underrun the dma buffer as easily. As default, use 32k (order=3) -// rather than 64k as some of the games work more responsively. -// log base 2( buff sz = 32k). +/* buffer order determines the size of the dma buffer for the driver. +* under Linux, a smaller buffer allows more responsiveness from many of the +* applications (e.g. games). A larger buffer allows some of the apps (esound) +* to not underrun the dma buffer as easily. As default, use 32k (order=3) +* rather than 64k as some of the games work more responsively. +* (2^N) * PAGE_SIZE = allocated buffer size +* +* also added fractional "defaultorder" inputs. if >100 then use +* defaultorder-100 as power of 2 for the buffer size. example: +* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size. +* games are even MORE responsive now, but prone to underruns. +*/ static unsigned long defaultorder = 3; MODULE_PARM(defaultorder, "i"); +/* +* use this module parm to invalidate recording sources +* as on some machines (Toshiba Satellites... again) setting to LINE +* causes an error and some of the mixers (gmix) to not load. +*/ +static unsigned long recsrc_invalid = 0; +MODULE_PARM(recsrc_invalid, "i"); // // Turn on/off debugging compilation by commenting out "#define CSDEBUG" // @@ -172,7 +210,7 @@ #define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) #define CS4281_MAJOR_VERSION 1 -#define CS4281_MINOR_VERSION 13 +#define CS4281_MINOR_VERSION 30 #ifdef __ia64__ #define CS4281_ARCH 64 //architecture key #else @@ -182,7 +220,6 @@ #define CS_TYPE_ADC 0 #define CS_TYPE_DAC 1 - static const char invalid_magic[] = KERN_CRIT "cs4281: invalid magic value\n"; @@ -194,16 +231,12 @@ } \ }) -//LIST_HEAD(cs4281_devs); struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs }; -struct cs4281_state; - -#include "cs4281_wrapper-24.c" - struct cs4281_state { // magic unsigned int magic; + u16 ss_id, ss_vendor; /* subsystem and vendor IDs from pci space */ // we keep the cards in a linked list struct cs4281_state *next; @@ -221,6 +254,7 @@ unsigned int pBA0phys, pBA1phys; char *pBA0, *pBA1; unsigned int irq; + unsigned recsrc; // mixer registers struct { @@ -291,12 +325,12 @@ unsigned char obuf[MIDIOUTBUF]; } midi; +#ifndef NOT_CS4281_PM struct cs4281_pm pm; struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES]; +#endif }; -#include "cs4281pm-24.c" - #if CSDEBUG // DEBUG ROUTINES @@ -527,7 +561,13 @@ static void delayus(struct cs4281_state *s, u32 delay) { u32 j; - if ((delay > 9999) && (s->pm.flags & CS4281_PM_IDLE)) { + if ((delay > 9999) +#ifndef NOT_CS4281_PM + && (s->pm.flags & CS4281_PM_IDLE)) +#else + ) +#endif + { j = (delay * HZ) / 1000000; /* calculate delay in jiffies */ if (j < 1) j = 1; /* minimum one jiffy. */ @@ -578,7 +618,7 @@ card->pBA0 + BA0_ACCTL); // Wait for the read to occur. - for (count = 0; count < 10; count++) { + for (count = 0; count < 100; count++) { // First, we want to wait for a short time. udelay(25); @@ -593,7 +633,7 @@ return 1; // Wait for the valid status bit to go active. - for (count = 0; count < 10; count++) { + for (count = 0; count < 100; count++) { // Read the AC97 status register. // ACSTS = Status Register = 464h status = readl(card->pBA0 + BA0_ACSTS); @@ -703,12 +743,26 @@ CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO "cs4281: cs4281_hw_init() CFLR invalid - resetting from 0x%x to 0x%x\n", temp2,CS4281_CFLR_DEFAULT)); + temp2 = readl(card->pBA0 + BA0_CWPR); + if(temp2 != CS4281_BA0_CPWR_DEFAULT) + { + writel(CS4281_BA0_CPWR_DEFAULT, card->pBA0 + BA0_CWPR); + temp2 = readl(card->pBA0 + BA0_CWPR); + if(temp2 != CS4281_BA0_CPWR_DEFAULT) + { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO + "cs4281: cs4281_hw_init() Invalid hardware - unable to configure CPWR (0x%x)\n", + temp2)); + return 1; + } + } writel(CS4281_CFLR_DEFAULT, card->pBA0 + BA0_CFLR); temp2 = readl(card->pBA0 + BA0_CFLR); if(temp2 != CS4281_CFLR_DEFAULT) { CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO - "cs4281: cs4281_hw_init() Invalid hardware - unable to configure CFLR\n")); + "cs4281: cs4281_hw_init() Invalid hardware - unable to configure CFLR (0x%x)\n", + temp2)); return 1; } } @@ -1021,15 +1075,6 @@ int Count,i; CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()+\n")); -/* -* change the state, save the current hwptr, then stop the dac/adc -*/ - s->pm.flags &= ~CS4281_PM_IDLE; - s->pm.flags |= CS4281_PM_SUSPENDING; - s->pm.u32hwptr_playback = readl(s->pBA0 + BA0_DCA0); - s->pm.u32hwptr_capture = readl(s->pBA0 + BA0_DCA1); - stop_dac(s); - stop_adc(s); for(Count = 0x2, i=0; (Count <= CS4281_AC97_HIGHESTREGTORESTORE) && (i < CS4281_AC97_NUMBER_RESTORE_REGS); @@ -1269,6 +1314,14 @@ pm->u32DacSR = readl(s->pBA0 + BA0_DACSR); pm->u32AdcSR = readl(s->pBA0 + BA0_ADCSR); +/* +* save the current hwptr, then stop the dac/adc +*/ + pm->u32hwptr_playback = readl(s->pBA0 + BA0_DCA0); + pm->u32hwptr_capture = readl(s->pBA0 + BA0_DCA1); + stop_dac(s); + stop_adc(s); + // // Loop through all of the PipeLines // @@ -1582,9 +1635,9 @@ #ifndef NOT_CS4281_PM && (s->pm.flags & CS4281_PM_IDLE)) #else -) + ) #endif - { + { s->ena |= FMODE_WRITE; temp1 = readl(s->pBA0 + BA0_DCR0) & ~DCRn_MSK; // Clear DMA0 channel mask. writel(temp1, s->pBA0 + BA0_DCR0); // Start DMA'ing. @@ -1640,7 +1693,7 @@ #ifndef NOT_CS4281_PM && (s->pm.flags & CS4281_PM_IDLE)) #else -) + ) #endif { if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) { @@ -1689,7 +1742,7 @@ // --------------------------------------------------------------------- -#define DMABUF_MINORDER 1 // ==> min buffer size = 8K. +#define DMABUF_MINORDER 0 // ==> min buffer size = 8K. extern void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db) @@ -1698,21 +1751,21 @@ if (db->rawbuf) { // Undo prog_dmabuf()'s marking the pages as reserved - mapend = - virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - - 1); + mapend = virt_to_page(db->rawbuf + + (PAGE_SIZE << db->buforder) - 1); for (map = virt_to_page(db->rawbuf); map <= mapend; map++) cs4x_mem_map_unreserve(map); - free_dmabuf(s, db); + pci_free_consistent(s->pcidev, PAGE_SIZE << db->buforder, + db->rawbuf, db->dmaaddr); } if (s->tmpbuff && (db->type == CS_TYPE_ADC)) { // Undo prog_dmabuf()'s marking the pages as reserved - mapend = - virt_to_page(s->tmpbuff + - (PAGE_SIZE << s->buforder_tmpbuff) - 1); + mapend = virt_to_page(s->tmpbuff + + (PAGE_SIZE << s->buforder_tmpbuff) - 1); for (map = virt_to_page(s->tmpbuff); map <= mapend; map++) cs4x_mem_map_unreserve(map); - free_dmabuf2(s, db); + pci_free_consistent(s->pcidev, PAGE_SIZE << s->buforder_tmpbuff, + s->tmpbuff, s->dmaaddr_tmpbuff); } s->tmpbuff = NULL; db->rawbuf = NULL; @@ -1735,7 +1788,7 @@ * check for order within limits, but do not overwrite value, check * later for a fractional defaultorder (i.e. 100+). */ - if((defaultorder > 0) && (defaultorder < 12)) + if((defaultorder >= 0) && (defaultorder < 12)) df = defaultorder; else df = 1; @@ -1744,7 +1797,7 @@ db->ready = db->mapped = 0; for (order = df; order >= DMABUF_MINORDER; order--) if ( (db->rawbuf = (void *) pci_alloc_consistent( - s->pcidev, PAGE_SIZE << order, &db-> dmaaddr))) + s->pcidev, PAGE_SIZE << order, &db->dmaaddr))) break; if (!db->rawbuf) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR @@ -1969,10 +2022,8 @@ if (s->dma_adc.count > s->dma_adc.dmasize) s->dma_adc.count = s->dma_adc.dmasize; if (s->dma_adc.mapped) { - if (s->dma_adc.count >= - (signed) s->dma_adc.fragsize) wake_up(&s-> - dma_adc. - wait); + if (s->dma_adc.count >= (signed) s->dma_adc.fragsize) + wake_up(&s->dma_adc.wait); } else { if (s->dma_adc.count > 0) wake_up(&s->dma_adc.wait); @@ -2143,6 +2194,7 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long arg) { + int return_mask=0; // Index to mixer_src[] is value of AC97 Input Mux Select Reg. // Value of array member is recording source Device ID Mask. static const unsigned int mixer_src[8] = { @@ -2307,9 +2359,14 @@ SOUND_MASK_SPEAKER, (int *) arg); case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source - return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | + return_mask = (((SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME | - SOUND_MASK_LINE1, (int *) arg); + SOUND_MASK_LINE1) ) & ~recsrc_invalid); + + CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO + "cs4281: mixer_ioctl(): return_mask=0x%x recsrc_invalid=0x%x\n", + (unsigned)return_mask,(unsigned)recsrc_invalid)); + return put_user(return_mask, (int *) arg); case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | @@ -2346,6 +2403,13 @@ i = hweight32(val); // i = # bits on in val. if (i != 1) // One & only 1 bit must be on. return 0; + if(val & recsrc_invalid) + { + CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO + "cs4281: mixer_ioctl(): REC SOURCE select error - record source invalid on this system (0x%x)\n", + val)); + return -EINVAL; + } for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) { if (val == mixer_src[i]) { temp1 = (i << 8) | i; @@ -2567,9 +2631,17 @@ // --------------------------------------------------------------------- +static loff_t cs4281_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + + +// --------------------------------------------------------------------- + static int cs4281_open_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct cs4281_state *s=NULL; struct list_head *entry; @@ -2622,7 +2694,7 @@ // Mixer file operations struct. // ****************************************************************************************** static /*const */ struct file_operations cs4281_mixer_fops = { - llseek:no_llseek, + llseek:cs4281_llseek, ioctl:cs4281_ioctl_mixdev, open:cs4281_open_mixdev, release:cs4281_release_mixdev, @@ -2684,9 +2756,18 @@ int count; unsigned tmo; + CS_DBGOUT(CS_FUNCTION, 2, + printk(KERN_INFO "cs4281: drain_dac()+\n")); if (s->dma_dac.mapped) + { + CS_DBGOUT(CS_FUNCTION, 2, + printk(KERN_INFO "cs4281: drain_dac()- (mmap) 0\n")); + return 0; + } + if (s->ena & FMODE_WRITE) + add_wait_queue(&s->dma_dac.wait, &wait); + else return 0; - add_wait_queue(&s->dma_dac.wait, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); @@ -2699,6 +2780,8 @@ if (nonblock) { remove_wait_queue(&s->dma_dac.wait, &wait); current->state = TASK_RUNNING; + CS_DBGOUT(CS_FUNCTION, 2, + printk(KERN_INFO "cs4281: drain_dac()- -EBUSY\n")); return -EBUSY; } tmo = @@ -2714,7 +2797,13 @@ remove_wait_queue(&s->dma_dac.wait, &wait); current->state = TASK_RUNNING; if (signal_pending(current)) + { + CS_DBGOUT(CS_FUNCTION, 2, + printk(KERN_INFO "cs4281: drain_dac()- -ERESTARTSYS\n")); return -ERESTARTSYS; + } + CS_DBGOUT(CS_FUNCTION, 2, + printk(KERN_INFO "cs4281: drain_dac()- 0\n")); return 0; } @@ -3051,6 +3140,9 @@ return ret; } +/* +* cs4281_poll(struct file *file, struct poll_table_struct *wait) +*/ static unsigned int cs4281_poll(struct file *file, struct poll_table_struct *wait) @@ -3061,7 +3153,7 @@ unsigned int mask = 0; CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, - printk(KERN_INFO "cs4281: cs4281_poll()+\n")); + printk(KERN_INFO "cs4281: cs4281_poll()+ wait=0x%x\n", (unsigned)wait)); VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, @@ -3070,17 +3162,17 @@ if(!s->dma_dac.ready && prog_dmabuf_dac(s)) return 0; poll_wait(file, &s->dma_dac.wait, wait); - } - if (file->f_mode & FMODE_READ) { + + } else if (file->f_mode & FMODE_READ) { CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, printk(KERN_INFO "cs4281: cs4281_poll() wait on FMODE_READ\n")); - if(!s->dma_dac.ready && prog_dmabuf_adc(s)) + if(!s->dma_adc.ready && prog_dmabuf_adc(s)) return 0; poll_wait(file, &s->dma_adc.wait, wait); + } spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); if (file->f_mode & FMODE_WRITE) { if (s->dma_dac.mapped) { if (s->dma_dac.count >= @@ -3139,7 +3231,7 @@ // db = &s->dma_dac; - if (cs4x_pgoff(vma) != 0) + if ((vma->vm_pgoff) != 0) return -EINVAL; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) @@ -3408,7 +3500,7 @@ if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s))) return val; spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); + cs4281_update_ptr(s,CS_TRUE); abinfo.fragsize = s->dma_dac.fragsize; if (s->dma_dac.mapped) abinfo.bytes = s->dma_dac.dmasize; @@ -3431,7 +3523,7 @@ if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s))) return val; spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); + cs4281_update_ptr(s,CS_TRUE); if (s->conversion) { abinfo.fragsize = s->dma_adc.fragsize / 2; abinfo.bytes = s->dma_adc.count / 2; @@ -3459,7 +3551,7 @@ if(!s->dma_dac.ready && prog_dmabuf_dac(s)) return 0; spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); + cs4281_update_ptr(s,CS_TRUE); val = s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); return put_user(val, (int *) arg); @@ -3470,7 +3562,7 @@ if(!s->dma_adc.ready && prog_dmabuf_adc(s)) return 0; spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); + cs4281_update_ptr(s,CS_TRUE); cinfo.bytes = s->dma_adc.total_bytes; if (s->dma_adc.mapped) { cinfo.blocks = @@ -3503,7 +3595,7 @@ if(!s->dma_dac.ready && prog_dmabuf_dac(s)) return 0; spin_lock_irqsave(&s->lock, flags); - cs4281_update_ptr(s,CS_FALSE); + cs4281_update_ptr(s,CS_TRUE); cinfo.bytes = s->dma_dac.total_bytes; if (s->dma_dac.mapped) { cinfo.blocks = @@ -3538,6 +3630,10 @@ case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (int *) arg)) return -EFAULT; + + CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO + "cs4281: cs4281_ioctl(): Attempt to set fragsize=%d fragnum=%d\n", + 1 << (val & 0xffff), (val >> 16) & 0xffff )); return 0; // Say OK, but do nothing. case SNDCTL_DSP_SUBDIVIDE: @@ -3625,7 +3721,7 @@ static int cs4281_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct cs4281_state *s=NULL; struct list_head *entry; @@ -3739,7 +3835,7 @@ // Wave (audio) file operations struct. // ****************************************************************************************** static /*const */ struct file_operations cs4281_audio_fops = { - llseek:no_llseek, + llseek:cs4281_llseek, read:cs4281_read, write:cs4281_write, poll:cs4281_poll, @@ -3966,7 +4062,7 @@ static int cs4281_midi_open(struct inode *inode, struct file *file) { unsigned long flags, temp1; - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct cs4281_state *s=NULL; struct list_head *entry; list_for_each(entry, &cs4281_devs) @@ -4088,7 +4184,7 @@ // Midi file operations struct. // ****************************************************************************************** static /*const */ struct file_operations cs4281_midi_fops = { - llseek:no_llseek, + llseek:cs4281_llseek, read:cs4281_midi_read, write:cs4281_midi_write, poll:cs4281_midi_poll, @@ -4263,6 +4359,35 @@ } #endif +/* +* ss_vendor and ss_id must be setup prior to calling this routine. +* setup the invalid recording source bitmask, +* and also return a valid default initialization value as +* the return value; +*/ +static int cs4281_setup_record_src(struct cs4281_state *s) +{ + if(s->ss_vendor == PCI_VENDOR_ID_TOSHIBA) + { + if(s->ss_id == SS_ID_TOSHIBA_1640CDT) + { + CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO + "cs4281: cs4281_setup_record_src(): setting LINE invalid\n")); + recsrc_invalid |= SOUND_MASK_LINE; + } + } +/* +* only return a valid recsrc value here, default to something useful. +*/ + if(!(recsrc_invalid & SOUND_MASK_MIC)) + return(SOUND_MASK_MIC); + else if(!(recsrc_invalid & SOUND_MASK_LINE)) + return(SOUND_MASK_LINE); + else if(!(recsrc_invalid & SOUND_MASK_LINE1)) + return(SOUND_MASK_LINE1); + return 0; +} + static int __devinit cs4281_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { @@ -4285,22 +4410,22 @@ } 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")); + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs4281: probe()- Memory region not assigned\n")); return -ENODEV; - } - if (pcidev->irq == 0) { - CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR - "cs4281: probe() IRQ not assigned\n")); + } + if (pcidev->irq == 0) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs4281: probe() IRQ not assigned\n")); return -ENODEV; - } + } 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")); + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n")); return i; - } + } 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")); @@ -4404,10 +4529,18 @@ #endif pci_set_master(pcidev); // enable bus mastering + pci_read_config_word(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &s->ss_vendor); + pci_read_config_word(pcidev, PCI_SUBSYSTEM_ID, &s->ss_id); + printk(KERN_INFO "cs4281: Subsystem vendor/id (%04X:%04X) IRQ %d\n", + s->ss_vendor, s->ss_id, s->irq); + + if(!recsrc_invalid) + val = cs4281_setup_record_src(s); + else + val = SOUND_MASK_MIC; fs = get_fs(); set_fs(KERNEL_DS); - val = SOUND_MASK_LINE; mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val); for (i = 0; i < sizeof(initvol) / sizeof(initvol[0]); i++) { val = initvol[i].vol; @@ -4455,7 +4588,7 @@ unregister_sound_midi(s->dev_midi); iounmap(s->pBA1); iounmap(s->pBA0); - pci_set_drvdata(pci_dev,NULL); + pci_set_drvdata(pci_dev, s); list_del(&s->list); kfree(s); CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO @@ -4494,6 +4627,12 @@ CS4281_ARCH); rtn = pci_module_init(&cs4281_pci_driver); + if(rtn == -ENODEV) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk( + "cs4281: Unable to locate any cs4281 device with valid IDs 0x%x-0x%x\n", + PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CRYSTAL_CS4281)); + } CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs4281_init_module()- (%d)\n",rtn)); return rtn; @@ -4510,7 +4649,7 @@ } // --------------------------------------------------------------------- -MODULE_AUTHOR("gw boynton, audio@crystal.cirrus.com"); +MODULE_AUTHOR("gw boynton, pcaudio@crystal.cirrus.com"); MODULE_DESCRIPTION("Cirrus Logic CS4281 Driver"); MODULE_LICENSE("GPL"); @@ -4525,3 +4664,4 @@ return cs4281_init_module(); } #endif +#include "cs4281pm-24.c" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/cs4281/cs4281pm-24.c linux-2.5/drivers/sound/cs4281/cs4281pm-24.c --- linux-2.5.1/drivers/sound/cs4281/cs4281pm-24.c Sun Feb 4 18:05:29 2001 +++ linux-2.5/drivers/sound/cs4281/cs4281pm-24.c Mon Jan 14 22:39:45 2002 @@ -4,7 +4,7 @@ * * Copyright (C) 2000,2001 Cirrus Logic Corp. * -- tom woller (twoller@crystal.cirrus.com) or -* (audio@crystal.cirrus.com). +* (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 @@ -25,28 +25,44 @@ *******************************************************************************/ #ifndef NOT_CS4281_PM -#include <linux/pm.h> -#define cs_pm_register(a, b, c) pm_register((a), (b), (c)); -#define cs_pm_unregister_all(a) pm_unregister_all((a)); +#if CS4281_PCI_PM_SUPPORT_ENABLE +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,12) +static int cs4281_suspend_tbl(struct pci_dev *pcidev, u32 unused) +{ + struct cs4281_state *s = pci_get_drvdata(pcidev); + cs4281_suspend(s); + return 0; +} -int cs4281_suspend(struct cs4281_state *s); -int cs4281_resume(struct cs4281_state *s); -/* -* for now (12/22/00) only enable the pm_register PM support. -* allow these table entries to be null. -#define CS4281_SUSPEND_TBL cs4281_suspend_tbl -#define CS4281_RESUME_TBL cs4281_resume_tbl -*/ -#define CS4281_SUSPEND_TBL cs4281_null -#define CS4281_RESUME_TBL cs4281_null +static int cs4281_resume_tbl(struct pci_dev *pcidev) +{ + struct cs4281_state *s = pci_get_drvdata(pcidev); + cs4281_resume(s); + return 0; +} +#else +void cs4281_suspend_tbl(struct pci_dev *pcidev) +{ + struct cs4281_state *s = pci_get_drvdata(pcidev); + cs4281_suspend(s); + return; +} +void cs4281_resume_tbl(struct pci_dev *pcidev) +{ + struct cs4281_state *s = pci_get_drvdata(pcidev); + cs4281_resume(s); + return; +} +#endif +#else int cs4281_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) { struct cs4281_state *state; - CS_DBGOUT(CS_PM, 2, printk(KERN_INFO - "cs4281: cs4281_pm_callback dev=0x%x rqst=0x%x state=%d\n", + CS_DBGOUT(CS_PM, 2, printk( + "cs4281: cs4281_pm_callback()+ dev=0x%x rqst=0x%x state=%d\n", (unsigned)dev,(unsigned)rqst,(unsigned)data)); state = (struct cs4281_state *) dev->data; if (state) { @@ -73,12 +89,13 @@ break; } } + CS_DBGOUT(CS_PM, 2, printk("cs4281: cs4281_pm_callback()- 0\n")); return 0; } +#endif //#if CS4281_PCI_PM_SUPPORT_ENABLE -#else /* CS4281_PM */ -#define CS4281_SUSPEND_TBL cs4281_null -#define CS4281_RESUME_TBL cs4281_null -#endif /* CS4281_PM */ - +#else /* NOT_CS4281_PM */ +#define CS4281_SUSPEND_TBL cs4281_null_suspend +#define CS4281_RESUME_TBL cs4281_null_resume +#endif /* NOT_CS4281_PM */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/cs46xx.c linux-2.5/drivers/sound/cs46xx.c --- linux-2.5.1/drivers/sound/cs46xx.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/sound/cs46xx.c Mon Jan 14 22:39:45 2002 @@ -1835,7 +1835,7 @@ static int cs_midi_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct cs_card *card=NULL; unsigned long flags; struct list_head *entry; @@ -1910,11 +1910,8 @@ break; if (signal_pending(current)) break; - if (file->f_flags & O_NONBLOCK) { - remove_wait_queue(&card->midi.owait, &wait); - current->state = TASK_RUNNING; - return -EBUSY; - } + if (file->f_flags & O_NONBLOCK) + break; tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "cs46xx: midi timed out??\n"); @@ -3003,7 +3000,7 @@ return -ENODEV; case SNDCTL_DSP_SETDUPLEX: - return -EINVAL; + return 0; case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) @@ -3198,7 +3195,7 @@ struct cs_state *state = NULL; struct dmabuf *dmabuf = NULL; struct list_head *entry; - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); int ret=0; unsigned int tmp; @@ -4047,7 +4044,7 @@ static int cs_open_mixdev(struct inode *inode, struct file *file) { int i=0; - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct cs_card *card=NULL; struct list_head *entry; unsigned int tmp; @@ -4094,7 +4091,7 @@ static int cs_release_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct cs_card *card=NULL; struct list_head *entry; int i; @@ -5249,6 +5246,8 @@ {0x1681, 0x0052, "Hercules Game Theatre XP", amp_hercules, NULL, NULL}, {0x1681, 0x0053, "Hercules Game Theatre XP", amp_hercules, NULL, NULL}, {0x1681, 0x0054, "Hercules Game Theatre XP", amp_hercules, NULL, NULL}, + {0x1681, 0xa010, "Hercules Fortissimo II", amp_none, NULL, NULL}, + /* Not sure if the 570 needs the clkrun hack */ {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}, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/Config.in linux-2.5/drivers/sound/dmasound/Config.in --- linux-2.5.1/drivers/sound/dmasound/Config.in Tue Apr 11 05:58:59 2000 +++ linux-2.5/drivers/sound/dmasound/Config.in Thu Dec 27 16:32:31 2001 @@ -4,7 +4,7 @@ dep_tristate ' Atari DMA sound support' CONFIG_DMASOUND_ATARI $CONFIG_SOUND fi if [ "$CONFIG_ALL_PPC" = "y" ]; then - dep_tristate ' PowerMac DMA sound support' CONFIG_DMASOUND_AWACS $CONFIG_SOUND + dep_tristate ' PowerMac DMA sound support' CONFIG_DMASOUND_PMAC $CONFIG_SOUND fi if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_APUS" = "y" ]; then dep_tristate ' Amiga DMA sound support' CONFIG_DMASOUND_PAULA $CONFIG_SOUND @@ -13,15 +13,27 @@ dep_tristate ' Q40 sound support' CONFIG_DMASOUND_Q40 $CONFIG_SOUND fi if [ "$CONFIG_DMASOUND_ATARI" = "y" -o \ - "$CONFIG_DMASOUND_AWACS" = "y" -o \ + "$CONFIG_DMASOUND_PMAC" = "y" -o \ "$CONFIG_DMASOUND_PAULA" = "y" -o \ "$CONFIG_DMASOUND_Q40" = "y" ]; then define_tristate CONFIG_DMASOUND y else if [ "$CONFIG_DMASOUND_ATARI" = "m" -o \ - "$CONFIG_DMASOUND_AWACS" = "m" -o \ + "$CONFIG_DMASOUND_PMAC" = "m" -o \ "$CONFIG_DMASOUND_PAULA" = "m" -o \ "$CONFIG_DMASOUND_Q40" = "m" ]; then define_tristate CONFIG_DMASOUND m fi fi + +# the new dmasound_pmac driver needs access to the i2c bus +if [ "$CONFIG_DMASOUND_PMAC" = "y" ] ; then + define_tristate CONFIG_I2C y + define_tristate CONFIG_I2C_KEYWEST y +else + if [ "$CONFIG_DMASOUND_PMAC" = "m" ] ; then + define_tristate CONFIG_I2C m + define_tristate CONFIG_I2C_KEYWEST m + fi +fi + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/Makefile linux-2.5/drivers/sound/dmasound/Makefile --- linux-2.5.1/drivers/sound/dmasound/Makefile Fri Dec 29 22:07:23 2000 +++ linux-2.5/drivers/sound/dmasound/Makefile Thu Dec 27 16:32:31 2001 @@ -7,15 +7,21 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... +O_TARGET = dmasound.o + export-objs := dmasound_core.o -obj-$(CONFIG_DMASOUND_ATARI) += dmasound_core.o dmasound_atari.o -obj-$(CONFIG_DMASOUND_AWACS) += dmasound_core.o dmasound_awacs.o -obj-$(CONFIG_DMASOUND_PAULA) += dmasound_core.o dmasound_paula.o -obj-$(CONFIG_DMASOUND_Q40) += dmasound_core.o dmasound_q40.o - -ifeq ($(CONFIG_DMASOUND),y) - O_TARGET = dmasound.o -endif +list-multi := dmasound_pmac.o + +dmasound_pmac-objs := dmasound_awacs.o trans_16.o tas3001c.o dac3550a.o + +obj-$(CONFIG_DMASOUND) += dmasound_core.o +obj-$(CONFIG_DMASOUND_ATARI) += dmasound_atari.o +obj-$(CONFIG_DMASOUND_PMAC) += dmasound_pmac.o +obj-$(CONFIG_DMASOUND_PAULA) += dmasound_paula.o +obj-$(CONFIG_DMASOUND_Q40) += dmasound_q40.o include $(TOPDIR)/Rules.make + +dmasound_pmac.o: $(dmasound_pmac-objs) + $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(dmasound_pmac-objs) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/awacs_defs.h linux-2.5/drivers/sound/dmasound/awacs_defs.h --- linux-2.5.1/drivers/sound/dmasound/awacs_defs.h Sun Sep 17 16:48:05 2000 +++ linux-2.5/drivers/sound/dmasound/awacs_defs.h Thu Dec 27 16:32:31 2001 @@ -71,17 +71,20 @@ /* ------- - --- ----- - ------ */ #define MASK_GAINRIGHT (0xf) /* Gain Right Mask */ #define MASK_GAINLEFT (0xf << 4) /* Gain Left Mask */ -#define MASK_GAINLINE (0x1 << 8) /* Change Gain for Line??? */ -#define MASK_GAINMIC (0x0 << 8) /* Change Gain for Mic??? */ +#define MASK_GAINLINE (0x1 << 8) /* Disable Mic preamp */ +#define MASK_GAINMIC (0x0 << 8) /* Enable Mic preamp */ #define MASK_MUX_CD (0x1 << 9) /* Select CD in MUX */ -#define MASK_MUX_AUDIN (0x1 << 10) /* Select Audio In in MUX */ -#define MASK_MUX_MIC (0x1 << 11) /* Select Mic in MUX */ +#define MASK_MUX_MIC (0x1 << 10) /* Select Mic in MUX */ +#define MASK_MUX_AUDIN (0x1 << 11) /* Select Audio In in MUX */ #define MASK_MUX_LINE MASK_MUX_AUDIN #define GAINRIGHT(x) ((x) & MASK_GAINRIGHT) #define GAINLEFT(x) (((x) << 4) & MASK_GAINLEFT) +#define DEF_CD_GAIN 0x00bb +#define DEF_MIC_GAIN 0x00cc + /* Address 1 Bit Masks */ /* ------- - --- ----- */ #define MASK_ADDR1RES1 (0x3) /* Reserved */ @@ -93,7 +96,10 @@ #define MASK_ADDR1RES2 (0x1 << 8) /* Reserved */ #define MASK_AMUTE (0x1 << 9) /* Output A (Headphone) Mute when 1 */ #define MASK_HDMUTE MASK_AMUTE -#define MASK_PAROUT (0x3 << 10) /* Parallel Out (???) */ +#define MASK_PAROUT0 (0x1 << 10) /* Parallel Output 0 */ +#define MASK_PAROUT1 (0x2 << 10) /* Parallel Output 1 */ + +#define MASK_MIC_BOOST (0x4) /* screamer mic boost */ #define SAMPLERATE_48000 (0x0 << 3) /* 48 or 44.1 kHz */ #define SAMPLERATE_32000 (0x1 << 3) /* 32 or 29.4 kHz */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/dac3550a.c linux-2.5/drivers/sound/dmasound/dac3550a.c --- linux-2.5.1/drivers/sound/dmasound/dac3550a.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/sound/dmasound/dac3550a.c Thu Dec 27 16:32:31 2001 @@ -0,0 +1,269 @@ +/* + * Driver for the i2c/i2s based DAC3550a sound chip used + * on some Apple iBooks. Also known as "DACA". + * + * 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/version.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include <linux/ioport.h> +#include <linux/sysctl.h> +#include <linux/types.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <asm/errno.h> +#include <asm/io.h> + +#include "dmasound.h" + +/* FYI: This code was derived from the tas3001c.c Texas/Tumbler mixer + * control code, as well as info derived from the AppleDACAAudio driver + * from Darwin CVS (main thing I derived being register numbers and + * values, as well as when to make the calls). */ + +#define I2C_DRIVERID_DACA (0xFDCB) + +#define DACA_VERSION "0.1" +#define DACA_DATE "20010930" + +static int cur_left_vol; +static int cur_right_vol; +static struct i2c_client * daca_client = NULL; + +static int daca_attach_adapter(struct i2c_adapter *adapter); + +static int daca_attach_adapter(struct i2c_adapter *adapter); +static int daca_detect_client(struct i2c_adapter *adapter, int address); +static int daca_detach_client(struct i2c_client *client); + +/* Unique ID allocation */ +static int daca_id; +static int daca_initialized; + +struct daca_data +{ + int arf; /* place holder for furture use */ +}; + +struct i2c_driver daca_driver = { + name: "DAC3550A driver V " DACA_VERSION, + id: I2C_DRIVERID_DACA, + flags: I2C_DF_NOTIFY, + attach_adapter: &daca_attach_adapter, + detach_client: &daca_detach_client, + command: NULL, + inc_use: NULL, /* &daca_inc_use, */ + dec_use: NULL /* &daca_dev_use */ + }; + + +#define VOL_MAX ((1<<20) - 1) + +void +daca_get_volume(uint * left_vol, uint *right_vol) +{ + *left_vol = cur_left_vol >> 5; + *right_vol = cur_right_vol >> 5; +} + +int +daca_set_volume(uint left_vol, uint right_vol) +{ + unsigned short voldata; + + if (!daca_client) + return -1; + + /* Derived from experience, not from any specific values */ + left_vol <<= 5; + right_vol <<= 5; + + if (left_vol > VOL_MAX) + left_vol = VOL_MAX; + if (right_vol > VOL_MAX) + right_vol = VOL_MAX; + + voldata = ((left_vol >> 14) & 0x3f) << 8; + voldata |= (right_vol >> 14) & 0x3f; + + if (i2c_smbus_write_word_data(daca_client, 2, voldata) < 0) { + printk("daca: failed to set volume \n"); + return -1; + } + + cur_left_vol = left_vol; + cur_right_vol = right_vol; + + return 0; +} + +int +daca_leave_sleep(void) +{ + if (!daca_client) + return -1; + + /* Do a short sleep, just to make sure I2C bus is awake and paying + * attention to us + */ + wait_ms(20); + /* Write the sample rate reg the value it needs */ + i2c_smbus_write_byte_data(daca_client, 1, 8); + daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5); + /* Another short delay, just to make sure the other I2C bus writes + * have taken... + */ + wait_ms(20); + /* Write the global config reg - invert right power amp, + * DAC on, use 5-volt mode */ + i2c_smbus_write_byte_data(daca_client, 3, 0x45); + + return 0; +} + +int +daca_enter_sleep(void) +{ + if (!daca_client) + return -1; + + i2c_smbus_write_byte_data(daca_client, 1, 8); + daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5); + + /* Write the global config reg - invert right power amp, + * DAC on, enter low-power mode, use 5-volt mode + */ + i2c_smbus_write_byte_data(daca_client, 3, 0x65); + + return 0; +} + +static int +daca_attach_adapter(struct i2c_adapter *adapter) +{ + if (!strncmp(adapter->name, "mac-io", 6)) + daca_detect_client(adapter, 0x4d); + return 0; +} + +static int +daca_init_client(struct i2c_client * new_client) +{ + /* + * Probe is not working with the current i2c-keywest + * driver. We try to use addr 0x4d on each adapters + * instead, by setting the format register. + * + * FIXME: I'm sure that can be obtained from the + * device-tree. --BenH. + */ + + /* Write the global config reg - invert right power amp, + * DAC on, use 5-volt mode + */ + if (i2c_smbus_write_byte_data(new_client, 3, 0x45)) + return -1; + + i2c_smbus_write_byte_data(new_client, 1, 8); + daca_client = new_client; + daca_set_volume(15000, 15000); + + return 0; +} + +static int +daca_detect_client(struct i2c_adapter *adapter, int address) +{ + int rc = 0; + struct i2c_client *new_client; + + struct daca_data *data; + const char *client_name = "DAC 3550A Digital Equalizer"; + + new_client = kmalloc( + sizeof(struct i2c_client) + sizeof(struct daca_data), + GFP_KERNEL); + if (!new_client) { + rc = -ENOMEM; + goto bail; + } + + /* This is tricky, but it will set the data to the right value. */ + new_client->data = new_client + 1; + data = (struct daca_data *) (new_client->data); + + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &daca_driver; + new_client->flags = 0; + + strcpy(new_client->name,client_name); + + new_client->id = daca_id++; /* Automatically unique */ + + if (daca_init_client(new_client)) { + rc = -ENODEV; + goto bail; + } + + /* Tell the i2c layer a new client has arrived */ + if (i2c_attach_client(new_client)) { + rc = -ENODEV; + goto bail; + } +bail: + if (rc && new_client) + kfree(new_client); + return rc; +} + + +static int +daca_detach_client(struct i2c_client *client) +{ + if (client == daca_client) + daca_client = NULL; + + i2c_detach_client(client); + kfree(client); + + return 0; +} + +int +daca_cleanup(void) +{ + if (!daca_initialized) + return -ENODEV; + i2c_del_driver(&daca_driver); + daca_initialized = 0; + + return 0; +} + +int +daca_init(void) +{ + int rc; + + if (daca_initialized) + return 0; + + printk("dac3550a driver version %s (%s)\n",DACA_VERSION,DACA_DATE); + + if ((rc = i2c_add_driver(&daca_driver))) { + printk("dac3550a: Driver registration failed, module not inserted.\n"); + daca_cleanup(); + return rc; + } + daca_initialized = 1; + + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/dmasound.h linux-2.5/drivers/sound/dmasound/dmasound.h --- linux-2.5.1/drivers/sound/dmasound/dmasound.h Wed Aug 15 08:22:16 2001 +++ linux-2.5/drivers/sound/dmasound/dmasound.h Thu Dec 27 16:32:31 2001 @@ -1,4 +1,4 @@ - +#ifndef _dmasound_h_ /* * linux/drivers/sound/dmasound/dmasound.h * @@ -10,11 +10,11 @@ * device for true DSP processors but it will be called something else. * In v3.0 it's /dev/sndproc but this could be a temporary solution. */ +#define _dmasound_h_ - +#include <linux/types.h> #include <linux/config.h> - #define SND_NDEVS 256 /* Number of supported devices */ #define SND_DEV_CTL 0 /* Control port /dev/mixer */ #define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM @@ -29,23 +29,16 @@ #define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ #define SND_DEV_PSS SND_DEV_SNDPROC -#define DSP_DEFAULT_SPEED 8000 - -#define ON 1 -#define OFF 0 +/* switch on various prinks */ +#define DEBUG_DMASOUND 1 #define MAX_AUDIO_DEV 5 -#define MAX_MIXER_DEV 2 +#define MAX_MIXER_DEV 4 #define MAX_SYNTH_DEV 3 #define MAX_MIDI_DEV 6 #define MAX_TIMER_DEV 3 - #define MAX_CATCH_RADIUS 10 -#define MIN_BUFFERS 4 -#define MIN_BUFSIZE 4 /* in KB */ -#define MAX_BUFSIZE 128 /* Limit for Amiga in KB */ - #define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff)) #define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff)) @@ -67,21 +60,34 @@ */ #undef HAS_8BIT_TABLES -#undef HAS_14BIT_TABLES -#undef HAS_16BIT_TABLES #undef HAS_RECORD #if defined(CONFIG_DMASOUND_ATARI) || defined(CONFIG_DMASOUND_ATARI_MODULE) ||\ defined(CONFIG_DMASOUND_PAULA) || defined(CONFIG_DMASOUND_PAULA_MODULE) ||\ defined(CONFIG_DMASOUND_Q40) || defined(CONFIG_DMASOUND_Q40_MODULE) #define HAS_8BIT_TABLES +#define MIN_BUFFERS 4 +#define MIN_BUFSIZE (1<<12) /* in bytes (- where does this come from ?) */ +#define MIN_FRAG_SIZE 8 /* not 100% sure about this */ +#define MAX_BUFSIZE (1<<17) /* Limit for Amiga is 128 kb */ +#define MAX_FRAG_SIZE 15 /* allow *4 for mono-8 => stereo-16 (for multi) */ + +#else /* is pmac and multi is off */ + +#define MIN_BUFFERS 2 +#define MIN_BUFSIZE (1<<8) /* in bytes */ +#define MIN_FRAG_SIZE 8 +#define MAX_BUFSIZE (1<<18) /* this is somewhat arbitrary for pmac */ +#define MAX_FRAG_SIZE 16 /* need to allow *4 for mono-8 => stereo-16 */ #endif -#if defined(CONFIG_DMASOUND_AWACS) || defined(CONFIG_DMASOUND_AWACS_MODULE) -#define HAS_16BIT_TABLES + +#define DEFAULT_N_BUFFERS 4 +#define DEFAULT_BUFF_SIZE (1<<15) + +#if defined(CONFIG_DMASOUND_PMAC) || defined(CONFIG_DMASOUND_PMAC_MODULE) #define HAS_RECORD #endif - /* * Initialization */ @@ -93,6 +99,14 @@ #define dmasound_deinit() do { } while (0) #endif +/* description of the set-up applies to either hard or soft settings */ + +typedef struct { + int format; /* AFMT_* */ + int stereo; /* 0 = mono, 1 = stereo */ + int size; /* 8/16 bit*/ + int speed; /* speed */ +} SETTINGS; /* * Machine definitions @@ -117,30 +131,29 @@ int (*setTreble)(int); int (*setGain)(int); void (*play)(void); - void (*record)(void); /* optional */ - void (*mixer_init)(void); /* optional */ - int (*mixer_ioctl)(u_int, u_long); /* optional */ - void (*write_sq_setup)(void); /* optional */ - void (*read_sq_setup)(void); /* optional */ - void (*sq_open)(void); /* optional */ - int (*state_info)(char *); /* optional */ - void (*abort_read)(void); /* optional */ + void (*record)(void); /* optional */ + void (*mixer_init)(void); /* optional */ + int (*mixer_ioctl)(u_int, u_long); /* optional */ + int (*write_sq_setup)(void); /* optional */ + int (*read_sq_setup)(void); /* optional */ + int (*sq_open)(mode_t); /* optional */ + int (*state_info)(char *, size_t); /* optional */ + void (*abort_read)(void); /* optional */ int min_dsp_speed; + int max_dsp_speed; + int version ; + int hardware_afmts ; /* OSS says we only return h'ware info */ + /* when queried via SNDCTL_DSP_GETFMTS */ + int capabilities ; /* low-level reply to SNDCTL_DSP_GETCAPS */ + SETTINGS default_hard ; /* open() or init() should set something valid */ + SETTINGS default_soft ; /* you can make it look like old OSS, if you want to */ } MACHINE; - /* * Low level stuff */ typedef struct { - int format; /* AFMT_* */ - int stereo; /* 0 = mono, 1 = stereo */ - int size; /* 8/16 bit*/ - int speed; /* speed */ -} SETTINGS; - -typedef struct { ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); @@ -170,11 +183,10 @@ extern struct sound_settings dmasound; +#ifdef HAS_8BIT_TABLES extern char dmasound_ulaw2dma8[]; extern char dmasound_alaw2dma8[]; -extern short dmasound_ulaw2dma16[]; -extern short dmasound_alaw2dma16[]; - +#endif /* * Mid level stuff @@ -207,14 +219,17 @@ struct sound_queue { /* buffers allocated for this queue */ - int numBufs; - int bufSize; /* in bytes */ + int numBufs; /* real limits on what the user can have */ + int bufSize; /* in bytes */ char **buffers; /* current parameters */ - int max_count; - int block_size; /* in bytes */ - int max_active; + int locked ; /* params cannot be modified when != 0 */ + int user_frags ; /* user requests this many */ + int user_frag_size ; /* of this size */ + int max_count; /* actual # fragments <= numBufs */ + int block_size; /* internal block size in bytes */ + int max_active; /* in-use fragments <= max_count */ /* it shouldn't be necessary to declare any of these volatile */ int front, rear, count; @@ -230,19 +245,35 @@ int active; wait_queue_head_t action_queue, open_queue, sync_queue; int open_mode; - int busy, syncing; + int busy, syncing, xruns, died; }; #define SLEEP(queue) interruptible_sleep_on_timeout(&queue, HZ) #define WAKE_UP(queue) (wake_up_interruptible(&queue)) extern struct sound_queue dmasound_write_sq; +#ifdef HAS_RECORD extern struct sound_queue dmasound_read_sq; +#endif #define write_sq dmasound_write_sq +#ifdef HAS_RECORD #define read_sq dmasound_read_sq +#endif extern int dmasound_catchRadius; #define catchRadius dmasound_catchRadius +/* define the value to be put in the byte-swap reg in mac-io + when we want it to swap for us. +*/ +#define BS_VAL 1 + +static inline void wait_ms(unsigned int ms) +{ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1 + ms * HZ / 1000); +} + +#endif /* _dmasound_h_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/dmasound_atari.c linux-2.5/drivers/sound/dmasound/dmasound_atari.c --- linux-2.5.1/drivers/sound/dmasound/dmasound_atari.c Thu Oct 25 20:53:52 2001 +++ linux-2.5/drivers/sound/dmasound/dmasound_atari.c Thu Dec 27 16:32:31 2001 @@ -1,10 +1,16 @@ - /* * linux/drivers/sound/dmasound/dmasound_atari.c * * Atari TT and Falcon DMA Sound Driver * * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits + * prior to 28/01/2001 + * + * 28/01/2001 [0.1] Iain Sandoe + * - added versioning + * - put in and populated the hardware_afmts field. + * [0.2] - put in SNDCTL_DSP_GETCAPS value. + * 01/02/2001 [0.3] - put in default hard/soft settings. */ @@ -21,10 +27,11 @@ #include "dmasound.h" +#define DMASOUND_ATARI_REVISION 0 +#define DMASOUND_ATARI_EDITION 3 extern void atari_microwire_cmd(int cmd); - static int is_falcon; static int write_sq_ignore_int = 0; /* ++TeSche: used for Falcon */ @@ -137,9 +144,9 @@ static int TTMixerIoctl(u_int cmd, u_long arg); static int FalconMixerIoctl(u_int cmd, u_long arg); static void AtaWriteSqSetup(void); -static void AtaSqOpen(void); -static int TTStateInfo(char *buffer); -static int FalconStateInfo(char *buffer); +static int AtaSqOpen(mode_t mode); +static int TTStateInfo(char *buffer, size_t space); +static int FalconStateInfo(char *buffer, size_t space); /*** Translations ************************************************************/ @@ -1438,43 +1445,73 @@ return AtaMixerIoctl(cmd, arg); } -static void AtaWriteSqSetup(void) +static int AtaWriteSqSetup(void) { write_sq_ignore_int = 0; + return 0 ; } -static void AtaSqOpen(void) +static int AtaSqOpen(mode_t mode) { write_sq_ignore_int = 1; + return 0 ; } -static int TTStateInfo(char *buffer) +static int TTStateInfo(char *buffer, size_t space) { int len = 0; - len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n", + len += sprintf(buffer+len, "\tvol left %ddB [-40... 0]\n", dmasound.volume_left); - len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n", + len += sprintf(buffer+len, "\tvol right %ddB [-40... 0]\n", dmasound.volume_right); - len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n", + len += sprintf(buffer+len, "\tbass %ddB [-12...+12]\n", dmasound.bass); - len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n", + len += sprintf(buffer+len, "\ttreble %ddB [-12...+12]\n", dmasound.treble); + if (len >= space) { + printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ; + len = space ; + } return len; } -static int FalconStateInfo(char *buffer) +static int FalconStateInfo(char *buffer, size_t space) { int len = 0; - len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n", + len += sprintf(buffer+len, "\tvol left %ddB [-22.5 ... 0]\n", dmasound.volume_left); - len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n", + len += sprintf(buffer+len, "\tvol right %ddB [-22.5 ... 0]\n", dmasound.volume_right); + if (len >= space) { + printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ; + len = space ; + } return len; } /*** Machine definitions *****************************************************/ +static SETTINGS def_hard_falcon = { + format: AFMT_S8, + stereo: 0, + size: 8, + speed: 8195 +} ; + +static SETTINGS def_hard_tt = { + format: AFMT_S8, + stereo: 0, + size: 8, + speed: 12517 +} ; + +static SETTINGS def_soft = { + format: AFMT_U8, + stereo: 0, + size: 8, + speed: 8000 +} ; static MACHINE machTT = { name: "Atari", @@ -1501,6 +1538,9 @@ sq_open: AtaSqOpen, state_info: TTStateInfo, min_dsp_speed: 6258, + version: ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION), + hardware_afmts: AFMT_S8, /* h'ware-supported formats *only* here */ + capabilities: DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */ }; static MACHINE machFalcon = { @@ -1525,6 +1565,9 @@ sq_open: AtaSqOpen, state_info: FalconStateInfo, min_dsp_speed: 8195, + version: ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION), + hardware_afmts: (AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */ + capabilities: DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */ }; @@ -1536,9 +1579,13 @@ if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) { if (ATARIHW_PRESENT(CODEC)) { dmasound.mach = machFalcon; + dmasound.mach.default_soft = def_soft ; + dmasound.mach.default_hard = def_hard_falcon ; is_falcon = 1; } else if (ATARIHW_PRESENT(MICROWIRE)) { dmasound.mach = machTT; + dmasound.mach.default_soft = def_soft ; + dmasound.mach.default_hard = def_hard_tt ; is_falcon = 0; } else return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/dmasound_awacs.c linux-2.5/drivers/sound/dmasound/dmasound_awacs.c --- linux-2.5.1/drivers/sound/dmasound/dmasound_awacs.c Thu Oct 25 20:53:52 2001 +++ linux-2.5/drivers/sound/dmasound/dmasound_awacs.c Thu Dec 27 16:32:31 2001 @@ -1,13 +1,54 @@ - /* * linux/drivers/sound/dmasound/dmasound_awacs.c * * PowerMac `AWACS' and `Burgundy' DMA Sound Driver + * with some limited support for DACA & Tumbler * - * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits - */ - + * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and + * history prior to 2001/01/26. + * + * 26/01/2001 ed 0.1 Iain Sandoe + * - added version info. + * - moved dbdma command buffer allocation to PMacXXXSqSetup() + * - fixed up beep dbdma cmd buffers + * + * 08/02/2001 [0.2] + * - make SNDCTL_DSP_GETFMTS return the correct info for the h/w + * - move soft format translations to a separate file + * - [0.3] make SNDCTL_DSP_GETCAPS return correct info. + * - [0.4] more informative machine name strings. + * - [0.5] + * - record changes. + * - made the default_hard/soft entries. + * 04/04/2001 [0.6] + * - minor correction to bit assignments in awacs_defs.h + * - incorporate mixer changes from 2.2.x back-port. + * - take out passthru as a rec input (it isn't). + * - make Input Gain slider work the 'right way up'. + * - try to make the mixer sliders more logical - so now the + * input selectors are just two-state (>50% == ON) and the + * Input Gain slider handles the rest of the gain issues. + * - try to pick slider representations that most closely match + * the actual use - e.g. IGain for input gain... + * - first stab at over/under-run detection. + * - minor cosmetic changes to IRQ identification. + * - fix bug where rates > max would be reported as supported. + * - first stab at over/under-run detection. + * - make use of i2c for mixer settings conditional on perch + * rather than cuda (some machines without perch have cuda). + * - fix bug where TX stops when dbdma status comes up "DEAD" + * so far only reported on PowerComputing clones ... but. + * - put in AWACS/Screamer register write timeouts. + * - part way to partitioning the init() stuff + * - first pass at 'tumbler' stuff (not support - just an attempt + * to allow the driver to load on new G4s). +*/ + +/* GENERAL FIXME/TODO: check that the assumptions about what is written to + mac-io is valid for DACA & Tumbler. +*/ +#include <linux/types.h> #include <linux/module.h> #include <linux/config.h> #include <linux/slab.h> @@ -18,6 +59,9 @@ #include <linux/nvram.h> #include <linux/tty.h> #include <linux/vt_kern.h> +#include <linux/irq.h> +#include <linux/kmod.h> +#include <asm/semaphore.h> #ifdef CONFIG_ADB_CUDA #include <linux/cuda.h> #endif @@ -25,20 +69,30 @@ #include <linux/pmu.h> #endif +#include <linux/i2c-dev.h> + #include <asm/uaccess.h> #include <asm/prom.h> #include <asm/machdep.h> #include <asm/io.h> #include <asm/dbdma.h> -#include <asm/feature.h> +#include <asm/pmac_feature.h> #include <asm/irq.h> +#include <asm/nvram.h> #include "awacs_defs.h" #include "dmasound.h" +#define DMASOUND_AWACS_REVISION 0 +#define DMASOUND_AWACS_EDITION 6 +#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ +#define AWACS_TUMBLER 90 /* fake revision # for tumbler */ +#define AWACS_DACA 80 /* fake revision # for daca (ibook) */ +#define AWACS_AWACS 2 /* holding revision for AWACS */ +#define AWACS_SCREAMER 3 /* holding revision for Screamer */ /* - * Interrupt numbers and addresses, obtained from the device tree. + * Interrupt numbers and addresses, & info obtained from the device tree. */ static int awacs_irq, awacs_tx_irq, awacs_rx_irq; static volatile struct awacs_regs *awacs; @@ -50,28 +104,58 @@ static char awacs_name[64]; static int awacs_revision; -int awacs_is_screamer = 0; -int awacs_device_id = 0; -int awacs_has_iic = 0; -#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ +static int awacs_sleeping; +static DECLARE_MUTEX(dmasound_sem); + +static int sound_device_id; /* exists after iMac revA */ +static int hw_can_byteswap = 1 ; /* most pmac sound h/w can */ + +/* model info */ +/* To be replaced with better interaction with pmac_feature.c */ +static int is_pbook_3X00; +static int is_pbook_g3; + +/* expansion info */ +static int has_perch; +static int has_ziva; + +/* for earlier powerbooks which need fiddling with mac-io to enable + * cd etc. +*/ +static unsigned char *latch_base; +static unsigned char *macio_base; /* * Space for the DBDMA command blocks. */ static void *awacs_tx_cmd_space; static volatile struct dbdma_cmd *awacs_tx_cmds; +static int number_of_tx_cmd_buffers = 0; static void *awacs_rx_cmd_space; static volatile struct dbdma_cmd *awacs_rx_cmds; +static int number_of_rx_cmd_buffers = 0; /* * Cached values of AWACS registers (we can't read them). - * Except on the burgundy. XXX + * Except on the burgundy (and screamer). XXX */ + int awacs_reg[8]; +int awacs_reg1_save; + +/* tracking values for the mixer contents +*/ -#define HAS_16BIT_TABLES -#undef HAS_8BIT_TABLES +static int spk_vol = 0 ; +static int line_vol = 0 ; +static int passthru_vol = 0 ; + +static int ip_gain = 0 ; /* mic preamp settings */ +static int rec_lev = 0x4545 ; /* default CD gain 69 % */ +static int mic_lev = 0 ; +static int cd_lev = 0x6363 ; /* 99 % */ +static int line_lev = 0 ; /* * Stuff for outputting a beep. The values range from -327 to +327 @@ -113,20 +197,18 @@ -269, -245, -218, -187, -153, -117, -79, -40, }; +/* beep support */ #define BEEP_SRATE 22050 /* 22050 Hz sample rate */ #define BEEP_BUFLEN 512 #define BEEP_VOLUME 15 /* 0 - 100 */ -static int beep_volume = BEEP_VOLUME; +static int beep_vol = BEEP_VOLUME; static int beep_playing = 0; static int awacs_beep_state = 0; static short *beep_buf; +static void *beep_dbdma_cmd_space; static volatile struct dbdma_cmd *beep_dbdma_cmd; static void (*orig_mksound)(unsigned int, unsigned int); -static int is_pbook_3400; -static unsigned char *latch_base; -static int is_pbook_G3; -static unsigned char *macio_base; /* Burgundy functions */ static void awacs_burgundy_wcw(unsigned addr,unsigned newval); @@ -136,6 +218,18 @@ static void awacs_burgundy_write_mvolume(unsigned address, int volume); static int awacs_burgundy_read_mvolume(unsigned address); +/* we will allocate a single 'emergency' dbdma cmd block to use if the + tx status comes up "DEAD". This happens on some PowerComputing Pmac + clones, either owing to a bug in dbdma or some interaction between + IDE and sound. However, this measure would deal with DEAD status if + if appeared elsewhere. + + for the sake of memory efficiency we'll allocate this cmd as part of + the beep cmd stuff. +*/ + +static volatile struct dbdma_cmd *emergency_dbdma_cmd; + #ifdef CONFIG_PMAC_PBOOK /* * Stuff for restoring after a sleep. @@ -146,78 +240,11 @@ }; #endif /* CONFIG_PMAC_PBOOK */ -static int expand_bal; /* Balance factor for expanding (not volume!) */ -static int expand_data; /* Data for expanding */ - - -/*** Translations ************************************************************/ - - -/* ++TeSche: radically changed for new expanding purposes... - * - * These two routines now deal with copying/expanding/translating the samples - * from user space into our buffer at the right frequency. They take care about - * how much data there's actually to read, how much buffer space there is and - * to convert samples into the right frequency/encoding. They will only work on - * complete samples so it may happen they leave some bytes in the input stream - * if the user didn't write a multiple of the current sample size. They both - * return the number of bytes they've used from both streams so you may detect - * such a situation. Luckily all programs should be able to cope with that. - * - * I think I've optimized anything as far as one can do in plain C, all - * variables should fit in registers and the loops are really short. There's - * one loop for every possible situation. Writing a more generalized and thus - * parameterized loop would only produce slower code. Feel free to optimize - * this in assembler if you like. :) - * - * I think these routines belong here because they're not yet really hardware - * independent, especially the fact that the Falcon can play 16bit samples - * only in stereo is hardcoded in both of them! - * - * ++geert: split in even more functions (one per format) - */ - -static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); - +/* for (soft) sample rate translations */ +int expand_bal; /* Balance factor for expanding (not volume!) */ /*** Low level stuff *********************************************************/ - static void PMacOpen(void); static void PMacRelease(void); static void *PMacAlloc(unsigned int size, int flags); @@ -244,565 +271,212 @@ /*** Mid level stuff **********************************************************/ - static int PMacMixerIoctl(u_int cmd, u_long arg); -static void PMacWriteSqSetup(void); -static void PMacReadSqSetup(void); +static int PMacWriteSqSetup(void); +static int PMacReadSqSetup(void); static void PMacAbortRead(void); +extern TRANS transAwacsNormal ; +extern TRANS transAwacsExpand ; +extern TRANS transAwacsNormalRead ; + +extern int daca_init(void); +extern int daca_cleanup(void); +extern int daca_set_volume(uint left_vol, uint right_vol); +extern void daca_get_volume(uint * left_vol, uint *right_vol); +extern int daca_enter_sleep(void); +extern int daca_leave_sleep(void); + +extern int tas_init(void); +extern int tas_cleanup(void); +extern int tumbler_set_volume(uint left_vol, uint right_vol); +extern void tumbler_get_volume(uint * left_vol, uint *right_vol); +extern void tumbler_set_treble(int treble); +extern void tumbler_get_treble(int *treble); +extern void tumbler_set_bass(int bass); +extern void tumbler_get_bass(int *bass); +extern void tumbler_set_pcm_lvl(int pcm_lvl); +extern void tumbler_get_pcm_lvl(int *pcm_lvl); + +#define TRY_LOCK() \ + if ((rc = down_interruptible(&dmasound_sem)) != 0) \ + return rc; +#define LOCK() down(&dmasound_sem); + +#define UNLOCK() up(&dmasound_sem); + +/* We use different versions that the ones provided in dmasound.h + * + * FIXME: Use different names ;) + */ +#undef IOCTL_IN +#undef IOCTL_OUT -/*** Translations ************************************************************/ - - -static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - short *table = dmasound.soft.format == AFMT_MU_LAW - ? dmasound_ulaw2dma16 : dmasound_alaw2dma16; - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - if (get_user(data, userPtr++)) - return -EFAULT; - val = table[data]; - *p++ = val; - if (stereo) { - if (get_user(data, userPtr++)) - return -EFAULT; - val = table[data]; - } - *p++ = val; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - - -static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - if (get_user(data, userPtr++)) - return -EFAULT; - val = data << 8; - *p++ = val; - if (stereo) { - if (get_user(data, userPtr++)) - return -EFAULT; - val = data << 8; - } - *p++ = val; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - - -static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - if (get_user(data, userPtr++)) - return -EFAULT; - val = (data ^ 0x80) << 8; - *p++ = val; - if (stereo) { - if (get_user(data, userPtr++)) - return -EFAULT; - val = (data ^ 0x80) << 8; - } - *p++ = val; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - - -static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - if (!stereo) { - short *up = (short *) userPtr; - while (count > 0) { - short data; - if (get_user(data, up++)) - return -EFAULT; - *fp++ = data; - *fp++ = data; - count--; - } - } else { - if (copy_from_user(fp, userPtr, count * 4)) - return -EFAULT; - } - *frameUsed += used * 4; - return stereo? used * 4: used * 2; -} +#define IOCTL_IN(arg, ret) \ + rc = get_user(ret, (int *)(arg)); \ + if (rc) break; +#define IOCTL_OUT(arg, ret) \ + ioctl_return2((int *)(arg), ret) -static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - short *up = (short *) userPtr; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - int data; - if (get_user(data, up++)) - return -EFAULT; - data ^= mask; - *fp++ = data; - if (stereo) { - if (get_user(data, up++)) - return -EFAULT; - data ^= mask; - } - *fp++ = data; - count--; - } - *frameUsed += used * 4; - return stereo? used * 4: used * 2; +static inline int ioctl_return2(int *addr, int value) +{ + return value < 0 ? value : put_user(value, addr); } -static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - unsigned short *table = (unsigned short *) - (dmasound.soft.format == AFMT_MU_LAW - ? dmasound_ulaw2dma16 : dmasound_alaw2dma16); - unsigned int data = expand_data; - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - int stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - u_char c; - if (bal < 0) { - if (userCount == 0) - break; - if (get_user(c, userPtr++)) - return -EFAULT; - data = table[c]; - if (stereo) { - if (get_user(c, userPtr++)) - return -EFAULT; - data = (data << 16) + table[c]; - } else - data = (data << 16) + data; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - expand_bal = bal; - expand_data = data; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 2: utotal; -} +/*** AE - TUMBLER START *********************************************************/ -static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - unsigned int data = expand_data; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.soft.stereo; - int utotal, ftotal; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - u_char c; - if (bal < 0) { - if (userCount == 0) - break; - if (get_user(c, userPtr++)) - return -EFAULT; - data = c << 8; - if (stereo) { - if (get_user(c, userPtr++)) - return -EFAULT; - data = (data << 16) + (c << 8); - } else - data = (data << 16) + data; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - expand_bal = bal; - expand_data = data; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 2: utotal; -} +int gpio_audio_reset, gpio_audio_reset_pol; +int gpio_amp_mute, gpio_amp_mute_pol; +int gpio_headphone_mute, gpio_headphone_mute_pol; +int gpio_headphone_detect, gpio_headphone_detect_pol; +int gpio_headphone_irq; +int +setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol) +{ + struct device_node *np; + u32* pp; + + np = find_devices("gpio"); + if (!np) + return -ENODEV; -static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - unsigned int data = expand_data; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.soft.stereo; - int utotal, ftotal; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - u_char c; - if (bal < 0) { - if (userCount == 0) + np = np->child; + while(np != 0) { + if (name) { + char *property = get_property(np,"audio-gpio",NULL); + if (property != 0 && strcmp(property,name) == 0) break; - if (get_user(c, userPtr++)) - return -EFAULT; - data = (c ^ 0x80) << 8; - if (stereo) { - if (get_user(c, userPtr++)) - return -EFAULT; - data = (data << 16) + ((c ^ 0x80) << 8); - } else - data = (data << 16) + data; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - expand_bal = bal; - expand_data = data; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 2: utotal; + } else if (compatible && device_is_compatible(np, compatible)) + break; + np = np->sibling; + } + if (!np) + return -ENODEV; + pp = (u32 *)get_property(np, "AAPL,address", NULL); + if (!pp) + return -ENODEV; + *gpio_addr = (*pp) & 0x0000ffff; + pp = (u32 *)get_property(np, "audio-gpio-active-state", NULL); + if (pp) + *gpio_pol = *pp; + else + *gpio_pol = 1; + if (np->n_intrs > 0) + return np->intrs[0].line; + + return 0; } - -static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - unsigned int data = expand_data; - unsigned short *up = (unsigned short *) userPtr; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.soft.stereo; - int utotal, ftotal; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - unsigned short c; - if (bal < 0) { - if (userCount == 0) - break; - if (get_user(data, up++)) - return -EFAULT; - if (stereo) { - if (get_user(c, up++)) - return -EFAULT; - data = (data << 16) + c; - } else - data = (data << 16) + data; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - expand_bal = bal; - expand_data = data; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 4: utotal * 2; +static inline void +write_audio_gpio(int gpio_addr, int data) +{ + if (!gpio_addr) + return; + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_addr, data ? 0x05 : 0x04); } +static inline int +read_audio_gpio(int gpio_addr) +{ + if (!gpio_addr) + return 0; + return ((pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_addr, 0) & 0x02) !=0); +} -static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - unsigned int data = expand_data; - unsigned short *up = (unsigned short *) userPtr; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.soft.stereo; - int utotal, ftotal; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - unsigned short c; - if (bal < 0) { - if (userCount == 0) - break; - if (get_user(data, up++)) - return -EFAULT; - data ^= mask; - if (stereo) { - if (get_user(c, up++)) - return -EFAULT; - data = (data << 16) + (c ^ mask); - } else - data = (data << 16) + data; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - expand_bal = bal; - expand_data = data; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 4: utotal * 2; -} - -static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - - val = *p++; - data = val >> 8; - if (put_user(data, (u_char *)userPtr++)) - return -EFAULT; - if (stereo) { - val = *p; - data = val >> 8; - if (put_user(data, (u_char *)userPtr++)) - return -EFAULT; - } - p++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - - -static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - - val = *p++; - data = (val >> 8) ^ 0x80; - if (put_user(data, (u_char *)userPtr++)) - return -EFAULT; - if (stereo) { - val = *p; - data = (val >> 8) ^ 0x80; - if (put_user(data, (u_char *)userPtr++)) - return -EFAULT; - } - p++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - - -static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - if (!stereo) { - short *up = (short *) userPtr; - while (count > 0) { - short data; - data = *fp; - if (put_user(data, up++)) - return -EFAULT; - fp+=2; - count--; - } +static void +headphone_intr(int irq, void *devid, struct pt_regs *regs) +{ + if (read_audio_gpio(gpio_headphone_detect) == gpio_headphone_detect_pol) { + printk(KERN_INFO "Audio jack plugged, muting speakers.\n"); + write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); + write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol); } else { - if (copy_to_user((u_char *)userPtr, fp, count * 4)) - return -EFAULT; + printk(KERN_INFO "Audio jack unplugged, enabling speakers.\n"); + write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol); + write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); } - *frameUsed += used * 4; - return stereo? used * 4: used * 2; } -static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - short *up = (short *) userPtr; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - int data; - - data = *fp++; - data ^= mask; - if (put_user(data, up++)) - return -EFAULT; - if (stereo) { - data = *fp; - data ^= mask; - if (put_user(data, up++)) - return -EFAULT; - } - fp++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 4: used * 2; + +/* Initialize tumbler */ + +static int +awacs_tumbler_init(void) +{ + setup_audio_gpio( + "audio-hw-reset", + NULL, + &gpio_audio_reset, + &gpio_audio_reset_pol); + setup_audio_gpio( + "amp-mute", + NULL, + &gpio_amp_mute, + &gpio_amp_mute_pol); + setup_audio_gpio("headphone-mute", + NULL, + &gpio_headphone_mute, + &gpio_headphone_mute_pol); + gpio_headphone_irq = setup_audio_gpio( + "headphone-detect", + NULL, + &gpio_headphone_detect, + &gpio_headphone_detect_pol); + /* Fix some broken OF entries in desktop machines */ + if (!gpio_headphone_irq) + gpio_headphone_irq = setup_audio_gpio( + NULL, + "keywest-gpio15", + &gpio_headphone_detect, + &gpio_headphone_detect_pol); + + write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); + wait_ms(100); + write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol); + wait_ms(100); + if (gpio_headphone_irq) { + if (request_irq(gpio_headphone_irq,headphone_intr,0,"Headphone detect",0) < 0) { + printk(KERN_ERR "tumbler: Can't request headphone interrupt\n"); + gpio_headphone_irq = 0; + } else { + u8 val; + /* Activate headphone status interrupts */ + val = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_headphone_detect, 0); + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80); + /* Trigger it */ + headphone_intr(0,0,0); + } + } + if (!gpio_headphone_irq) { + /* Some machine enter this case ? */ + printk(KERN_WARNING "tumbler: Headphone detect IRQ not found, enabling all outputs !\n"); + write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol); + write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol); + } + return 0; } -static TRANS transAwacsNormal = { - ct_ulaw: pmac_ct_law, - ct_alaw: pmac_ct_law, - ct_s8: pmac_ct_s8, - ct_u8: pmac_ct_u8, - ct_s16be: pmac_ct_s16, - ct_u16be: pmac_ct_u16, - ct_s16le: pmac_ct_s16, - ct_u16le: pmac_ct_u16, -}; +static int +awacs_tumbler_cleanup(void) +{ + if (gpio_headphone_irq) + free_irq(gpio_headphone_irq, 0); + return 0; +} -static TRANS transAwacsExpand = { - ct_ulaw: pmac_ctx_law, - ct_alaw: pmac_ctx_law, - ct_s8: pmac_ctx_s8, - ct_u8: pmac_ctx_u8, - ct_s16be: pmac_ctx_s16, - ct_u16be: pmac_ctx_u16, - ct_s16le: pmac_ctx_s16, - ct_u16le: pmac_ctx_u16, -}; -static TRANS transAwacsNormalRead = { - ct_s8: pmac_ct_s8_read, - ct_u8: pmac_ct_u8_read, - ct_s16be: pmac_ct_s16_read, - ct_u16be: pmac_ct_u16_read, - ct_s16le: pmac_ct_s16_read, - ct_u16le: pmac_ct_u16_read, -}; +/*** AE - TUMBLER END *********************************************************/ -/*** Low level stuff *********************************************************/ +/*** Low level stuff *********************************************************/ /* - * PCI PowerMac, with AWACS and DBDMA. + * PCI PowerMac, with AWACS, Screamer, Burgundy, DACA or Tumbler and DBDMA. */ static void PMacOpen(void) @@ -827,9 +501,9 @@ static int __init PMacIrqInit(void) { - if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0) - || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0) - || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0)) + if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", 0) + || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", 0) + || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "Built-in Sound in", 0)) return 0; return 1; } @@ -837,25 +511,44 @@ #ifdef MODULE static void PMacIrqCleanup(void) { - /* turn off output dma */ - out_le32(&awacs_txdma->control, RUN<<16); + /* turn off input & output dma */ + DBDMA_DO_STOP(awacs_txdma); + DBDMA_DO_STOP(awacs_rxdma); + /* disable interrupts from awacs interface */ out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff); -#ifdef CONFIG_PMAC_PBOOK - if (is_pbook_G3) { - feature_clear(awacs_node, FEATURE_Sound_power); - feature_clear(awacs_node, FEATURE_Sound_CLK_enable); + + /* Switch off the sound clock */ + pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); + /* Make sure proper bits are set on pismo & tipb */ + if (machine_is_compatible("PowerBook3,1") || + machine_is_compatible("PowerBook3,2")) { + awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; + awacs_write(MASK_ADDR1 | awacs_reg[1]); + wait_ms(200); } -#endif free_irq(awacs_irq, 0); free_irq(awacs_tx_irq, 0); free_irq(awacs_rx_irq, 0); - kfree(awacs_tx_cmd_space); + /* all OF versions I've seen use this value */ + iounmap((void *)awacs); + iounmap((void *)awacs_txdma); + iounmap((void *)awacs_rxdma); + + release_OF_resource(awacs_node, 0); + release_OF_resource(awacs_node, 1); + release_OF_resource(awacs_node, 2); + + if (awacs_tx_cmd_space) + kfree(awacs_tx_cmd_space); if (awacs_rx_cmd_space) kfree(awacs_rx_cmd_space); - if (beep_buf) + if (beep_dbdma_cmd_space) + kfree(beep_dbdma_cmd_space); + if (beep_buf) { kfree(beep_buf); - kd_mksound = orig_mksound; + kd_mksound = orig_mksound; + } #ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&awacs_sleep_notifier); #endif @@ -865,7 +558,32 @@ static void PMacSilence(void) { /* turn off output dma */ - out_le32(&awacs_txdma->control, RUN<<16); + DBDMA_DO_STOP(awacs_txdma); +} + +static int tumbler_freqs[2] = { 48000, 44100 } ; +static int tumbler_freqs_ok[2] = { 1, 1 } ; + +/* don't know what to do really - just have to leave it where + * OF left things +*/ + +static int tumbler_set_frame_rate(void) +{ + dmasound.hard.speed = 44100 ; + awacs_rate_index = 0 ; + return 44100 ; +} + +/* don't know what to do really - just have to leave it where + * OF left things +*/ + +static int daca_set_frame_rate(void) +{ + dmasound.hard.speed = 44100 ; + awacs_rate_index = 0 ; + return 44100 ; } static int awacs_freqs[8] = { @@ -873,59 +591,115 @@ }; static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; -static void PMacInit(void) +static int awacs_set_frame_rate(int desired, int catch_r) { - int i, tolerance; - - switch (dmasound.soft.format) { - case AFMT_S16_LE: - case AFMT_U16_LE: - dmasound.hard.format = AFMT_S16_LE; - break; - default: - dmasound.hard.format = AFMT_S16_BE; - break; - } - dmasound.hard.stereo = 1; - dmasound.hard.size = 16; - + int tolerance, i = 8 ; /* * If we have a sample rate which is within catchRadius percent * of the requested value, we don't have to expand the samples. * Otherwise choose the next higher rate. - * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz. + * N.B.: burgundy awacs only works at 44100 Hz. */ - i = 8; do { - tolerance = catchRadius * awacs_freqs[--i] / 100; + tolerance = catch_r * awacs_freqs[--i] / 100; if (awacs_freqs_ok[i] && dmasound.soft.speed <= awacs_freqs[i] + tolerance) break; } while (i > 0); - if (dmasound.soft.speed >= awacs_freqs[i] - tolerance) - dmasound.trans_write = &transAwacsNormal; - else - dmasound.trans_write = &transAwacsExpand; - dmasound.trans_read = &transAwacsNormalRead; dmasound.hard.speed = awacs_freqs[i]; awacs_rate_index = i; - /* XXX disable error interrupt on burgundy for now */ - out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 - | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0)); + out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 ); awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3); awacs_write(awacs_reg[1] | MASK_ADDR1); - out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE); + return dmasound.hard.speed; +} + +static int burgundy_frame_rates = 1 ; +static int burgundy_set_frame_rate(void) +{ +#ifdef DEBUG_DMASOUND +if (burgundy_frame_rates > 1) + printk("dmasound_pmac: warning Burgundy had more than one frame rate\n"); +#endif + awacs_rate_index = 0 ; + awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) ; + /* XXX disable error interrupt on burgundy for now */ + out_le32(&awacs->control, MASK_IEPC | 0 | 0x11 | MASK_IEE); + return 44100 ; +} + +static int set_frame_rate(int desired, int catch_r) +{ + switch (awacs_revision) { + case AWACS_BURGUNDY: + dmasound.hard.speed = + burgundy_set_frame_rate(); + break ; + case AWACS_TUMBLER: + dmasound.hard.speed = + tumbler_set_frame_rate(); + break ; + case AWACS_DACA: + dmasound.hard.speed = + daca_set_frame_rate(); + break ; + default: + dmasound.hard.speed = + awacs_set_frame_rate(desired, catch_r); + break ; + } + return dmasound.hard.speed ; +} - /* We really want to execute a DMA stop command, after the AWACS - * is initialized. - * For reasons I don't understand, it stops the hissing noise - * common to many PowerBook G3 systems (like mine :-). +static void +awacs_recalibrate(void) +{ + /* Sorry for the horrible delays... I hope to get that improved + * by making the whole PM process asynchronous in a future version */ - out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); - st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); - out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); - out_le32(&awacs_txdma->control, RUN | (RUN << 16)); + wait_ms(750); + awacs_reg[1] |= MASK_CMUTE | MASK_AMUTE; + awacs_write(awacs_reg[1] | MASK_RECALIBRATE | MASK_ADDR1); + wait_ms(1000); + awacs_write(awacs_reg[1] | MASK_ADDR1); +} + +static void PMacInit(void) +{ + int tolerance; + + switch (dmasound.soft.format) { + case AFMT_S16_LE: + case AFMT_U16_LE: + if (hw_can_byteswap) + dmasound.hard.format = AFMT_S16_LE; + else + dmasound.hard.format = AFMT_S16_BE; + break; + default: + dmasound.hard.format = AFMT_S16_BE; + break; + } + dmasound.hard.stereo = 1; + dmasound.hard.size = 16; + + /* set dmasound.hard.speed - on the basis of what we want (soft) + * and the tolerance we'll allow. + */ + set_frame_rate(dmasound.soft.speed, catchRadius) ; + + tolerance = (catchRadius * dmasound.hard.speed) / 100; + if (dmasound.soft.speed >= dmasound.hard.speed - tolerance) + dmasound.trans_write = &transAwacsNormal; + else + dmasound.trans_write = &transAwacsExpand; + dmasound.trans_read = &transAwacsNormalRead; + + if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) + out_le32(&awacs->byteswap, BS_VAL); + else + out_le32(&awacs->byteswap, 0); expand_bal = -dmasound.soft.speed; } @@ -933,7 +707,8 @@ static int PMacSetFormat(int format) { int size; - + int req_format = format; + switch (format) { case AFMT_QUERY: return dmasound.soft.format; @@ -943,10 +718,16 @@ case AFMT_S8: size = 8; break; - case AFMT_S16_BE: - case AFMT_U16_BE: case AFMT_S16_LE: + if(!hw_can_byteswap) + format = AFMT_S16_BE; + case AFMT_S16_BE: + size = 16; + break; case AFMT_U16_LE: + if(!hw_can_byteswap) + format = AFMT_U16_BE; + case AFMT_U16_BE: size = 16; break; default: /* :-) */ @@ -955,16 +736,16 @@ size = 8; format = AFMT_U8; } - - dmasound.soft.format = format; - dmasound.soft.size = size; - if (dmasound.minDev == SND_DEV_DSP) { - dmasound.dsp.format = format; - dmasound.dsp.size = size; + + if (req_format == format) { + dmasound.soft.format = format; + dmasound.soft.size = size; + if (dmasound.minDev == SND_DEV_DSP) { + dmasound.dsp.format = format; + dmasound.dsp.size = size; + } } - PMacInit(); - return format; } @@ -1007,48 +788,91 @@ return awacs_volume_setter(volume, 2, MASK_AMUTE, 6); } -static void PMacPlay(void) +static void __PMacPlay(void) { volatile struct dbdma_cmd *cp; - int i, count; + int next_frg, count; unsigned long flags; + /* CHECK: how much of this *really* needs IRQs masked? */ + save_flags(flags); cli(); + count = 300 ; /* > two cycles at the lowest sample rate */ + + /* what we want to send next */ + next_frg = (write_sq.front + write_sq.active) % write_sq.max_count; + if (awacs_beep_state) { /* sound takes precedence over beeps */ + /* stop the dma channel */ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + while ( (in_le32(&awacs_txdma->status) & RUN) && count--) + udelay(1); + /* FIXME: check that this is OK for other chip sets */ out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) | (awacs_rate_index << 8)); - out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE); - out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(write_sq.front+write_sq.active) % write_sq.max_count]))); + + if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) + out_le32(&awacs->byteswap, BS_VAL); + else + out_le32(&awacs->byteswap, 0); + out_le32(&awacs_txdma->cmdptr, + virt_to_bus(&(awacs_tx_cmds[next_frg]))); beep_playing = 0; awacs_beep_state = 0; } - i = write_sq.front + write_sq.active; - if (i >= write_sq.max_count) - i -= write_sq.max_count; + /* this won't allow more than two frags to be in the output queue at + once. (or one, if the max frags is 2 - because count can't exceed + 2 in that case) + */ while (write_sq.active < 2 && write_sq.active < write_sq.count) { - count = (write_sq.count == write_sq.active + 1)?write_sq.rear_size:write_sq.block_size; - if (count < write_sq.block_size && !write_sq.syncing) - /* last block not yet filled, and we're not syncing. */ - break; - cp = &awacs_tx_cmds[i]; + count = (write_sq.count == write_sq.active + 1) ? + write_sq.rear_size:write_sq.block_size ; + if (count < write_sq.block_size) { + if (!write_sq.syncing) /* last block not yet filled,*/ + break; /* and we're not syncing or POST-ed */ + else { + /* pretend the block is full to force a new + block to be started on the next write */ + write_sq.rear_size = write_sq.block_size ; + write_sq.syncing &= ~2 ; /* clear POST */ + } + } + cp = &awacs_tx_cmds[next_frg]; st_le16(&cp->req_count, count); st_le16(&cp->xfer_status, 0); - if (++i >= write_sq.max_count) - i = 0; - out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP); - out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS); + st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS); + /* put a STOP at the end of the queue - but only if we have + space for it. This means that, if we under-run and we only + have two fragments, we might re-play sound from an existing + queued frag. I guess the solution to that is not to set two + frags if you are likely to under-run... + */ + if (write_sq.count < write_sq.max_count) { + if (++next_frg >= write_sq.max_count) + next_frg = 0 ; /* wrap */ + /* if we get here then we've underrun so we will stop*/ + st_le16(&awacs_tx_cmds[next_frg].command, DBDMA_STOP); + } + /* set the dbdma controller going, if it is not already */ if (write_sq.active == 0) out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp)); + (void)in_le32(&awacs_txdma->status); out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); ++write_sq.active; } restore_flags(flags); } +static void PMacPlay(void) +{ + LOCK(); + if (!awacs_sleeping) + __PMacPlay(); + UNLOCK(); +} static void PMacRecord(void) { @@ -1067,6 +891,26 @@ restore_flags(flags); } +/* if the TX status comes up "DEAD" - reported on some Power Computing machines + we need to re-start the dbdma - but from a different physical start address + and with a different transfer length. It would get very messy to do this + with the normal dbdma_cmd blocks - we would have to re-write the buffer start + addresses each time. So, we will keep a single dbdma_cmd block which can be + fiddled with. + When DEAD status is first reported the content of the faulted dbdma block is + copied into the emergency buffer and we note that the buffer is in use. + we then bump the start physical address by the amount that was successfully + output before it died. + On any subsequent DEAD result we just do the bump-ups (we know that we are + already using the emergency dbdma_cmd). + CHECK: this just tries to "do it". It is possible that we should abandon + xfers when the number of residual bytes gets below a certain value - I can + see that this might cause a loop-forever if too small a transfer causes + DEAD status. However this is a TODO for now - we'll see what gets reported. + When we get a successful transfer result with the emergency buffer we just + pretend that it completed using the original dmdma_cmd and carry on. The + 'next_cmd' field will already point back to the original loop of blocks. +*/ static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs) @@ -1074,35 +918,92 @@ int i = write_sq.front; int stat; volatile struct dbdma_cmd *cp; + /* != 0 when we are dealing with a DEAD xfer */ + static int emergency_in_use = 0 ; - while (write_sq.active > 0) { - cp = &awacs_tx_cmds[i]; + while (write_sq.active > 0) { /* we expect to have done something*/ + if (emergency_in_use) /* we are dealing with DEAD xfer */ + cp = emergency_dbdma_cmd ; + else + cp = &awacs_tx_cmds[i]; stat = ld_le16(&cp->xfer_status); + if (stat & DEAD) { + unsigned short req, res ; + unsigned int phy ; +#ifdef DEBUG_DMASOUND +printk("dmasound_pmac: tx-irq: xfer died - patching it up...\n") ; +#endif + /* to clear DEAD status we must first clear RUN + set it to quiescent to be on the safe side */ + (void)in_le32(&awacs_txdma->status); + out_le32(&awacs_txdma->control, + (RUN|PAUSE|FLUSH|WAKE) << 16); + write_sq.died++ ; + if (!emergency_in_use) { /* new problem */ + memcpy((void *)emergency_dbdma_cmd, (void *)cp, + sizeof(struct dbdma_cmd)); + emergency_in_use = 1; + cp = emergency_dbdma_cmd; + } + /* now bump the values to reflect the amount + we haven't yet shifted */ + req = ld_le16(&cp->req_count); + res = ld_le16(&cp->res_count); + phy = ld_le32(&cp->phy_addr); + phy += (req - res); + st_le16(&cp->req_count, res); + st_le16(&cp->res_count, 0); + st_le16(&cp->xfer_status, 0); + st_le32(&cp->phy_addr, phy); + st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS); + /* point at our patched up command block */ + out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp)); + /* we must re-start the controller */ + (void)in_le32(&awacs_txdma->status); + /* should complete clearing the DEAD status */ + out_le32(&awacs_txdma->control, + ((RUN|WAKE) << 16) + (RUN|WAKE)); + break; /* this block is still going */ + } if ((stat & ACTIVE) == 0) break; /* this frame is still going */ + if (emergency_in_use) + emergency_in_use = 0 ; /* done that */ --write_sq.count; --write_sq.active; if (++i >= write_sq.max_count) i = 0; } + + /* if we stopped and we were not sync-ing - then we under-ran */ + if( write_sq.syncing == 0 ){ + stat = in_le32(&awacs_txdma->status) ; + /* we hit the dbdma_stop */ + if( (stat & ACTIVE) == 0 ) write_sq.xruns++ ; + } + + /* if we used some data up then wake the writer to supply some more*/ if (i != write_sq.front) WAKE_UP(write_sq.action_queue); write_sq.front = i; - PMacPlay(); - - if (!write_sq.active) - WAKE_UP(write_sq.sync_queue); + /* but make sure we funnel what we've already got */\ + if (!awacs_sleeping) + __PMacPlay(); + + /* make the wake-on-empty conditional on syncing */ + if (!write_sq.active && (write_sq.syncing & 1)) + WAKE_UP(write_sq.sync_queue); /* any time we're empty */ } static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs) { - + int stat ; /* For some reason on my PowerBook G3, I get one interrupt * when the interrupt vector is installed (like something is - * pending). This happens before the dbdma is initialize by + * pending). This happens before the dbdma is initialized by * us, so I just check the command pointer and if it is zero, * just blow it off. */ @@ -1118,8 +1019,35 @@ * interrupt processing for a long time. Geeze, I really hope * this doesn't happen. */ - while (awacs_rx_cmds[read_sq.rear].xfer_status) { + while ((stat=awacs_rx_cmds[read_sq.rear].xfer_status)) { + /* if we got a "DEAD" status then just log it for now. + and try to restart dma. + TODO: figure out how best to fix it up + */ + if (stat & DEAD){ +#ifdef DEBUG_DMASOUND +printk("dmasound_pmac: rx-irq: DIED - attempting resurection\n"); +#endif + /* to clear DEAD status we must first clear RUN + set it to quiescent to be on the safe side */ + (void)in_le32(&awacs_txdma->status); + out_le32(&awacs_txdma->control, + (RUN|PAUSE|FLUSH|WAKE) << 16); + awacs_rx_cmds[read_sq.rear].xfer_status = 0; + awacs_rx_cmds[read_sq.rear].res_count = 0; + read_sq.died++ ; + (void)in_le32(&awacs_txdma->status); + /* re-start the same block */ + out_le32(&awacs_rxdma->cmdptr, + virt_to_bus(&awacs_rx_cmds[read_sq.rear])); + /* we must re-start the controller */ + (void)in_le32(&awacs_rxdma->status); + /* should complete clearing the DEAD status */ + out_le32(&awacs_rxdma->control, + ((RUN|WAKE) << 16) + (RUN|WAKE)); + return; /* try this block again */ + } /* Clear status and move on to next buffer. */ awacs_rx_cmds[read_sq.rear].xfer_status = 0; @@ -1138,6 +1066,7 @@ */ if (read_sq.rear == read_sq.front) { read_sq.front++; + read_sq.xruns++ ; /* we overan */ if (read_sq.front >= read_sq.max_active) read_sq.front = 0; } @@ -1157,8 +1086,9 @@ } if (ctrl & MASK_CNTLERR) { int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16; - if (err != 0 && awacs_revision < AWACS_BURGUNDY) - printk(KERN_ERR "AWACS: error %x\n", err); + /* CHECK: we just swallow burgundy errors at the moment..*/ + if (err != 0 && awacs_revision != AWACS_BURGUNDY) + printk(KERN_ERR "dmasound_pmac: error %x\n", err); } /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */ out_le32(&awacs->control, ctrl); @@ -1167,25 +1097,38 @@ static void awacs_write(int val) { - if (awacs_revision >= AWACS_BURGUNDY) - return; - while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) - ; /* XXX should have timeout */ + int count = 300 ; + if (awacs_revision >= AWACS_DACA) + return ; + + while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--) + udelay(1) ; /* timeout is > 2 samples at lowest rate */ out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22)); + (void)in_le32(&awacs->byteswap); } +/* this is called when the beep timer expires... it will be called even + if the beep has been overidden by other sound output. +*/ static void awacs_nosound(unsigned long xx) { unsigned long flags; + int count = 600 ; /* > four samples at lowest rate */ save_flags(flags); cli(); if (beep_playing) { st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + while ((in_le32(&awacs_txdma->status) & RUN) && count--) + udelay(1); + /* FIXME: check this is OK for DACA, Tumbler */ out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) | (awacs_rate_index << 8)); - out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE); + if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) + out_le32(&awacs->byteswap, BS_VAL); + else + out_le32(&awacs->byteswap, 0); beep_playing = 0; } restore_flags(flags); @@ -1195,6 +1138,11 @@ function: awacs_nosound }; +/* we generate the beep with a single dbdma command that loops a buffer + forever - without generating interrupts. + So, to stop it you have to stop dma output as per awacs_nosound. +*/ + static void awacs_mksound(unsigned int hz, unsigned int ticks) { unsigned long flags; @@ -1207,11 +1155,19 @@ static int beep_nsamples_cache; static int beep_volume_cache; - for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i) - if (awacs_freqs_ok[i]) - beep_speed = i; - srate = awacs_freqs[beep_speed]; + if (beep_buf == NULL) + return; + + /* quick-hack fix for DACA, Burgundy & Tumbler */ + if (awacs_revision >= AWACS_DACA){ + srate = 44100 ; + } else { + for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i) + if (awacs_freqs_ok[i]) + beep_speed = i; + srate = awacs_freqs[beep_speed]; + } if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) { #if 1 /* this is a hack for broken X server code */ @@ -1237,7 +1193,7 @@ st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS); restore_flags(flags); - if (hz == beep_hz_cache && beep_volume == beep_volume_cache) { + if (hz == beep_hz_cache && beep_vol == beep_volume_cache) { nsamples = beep_nsamples_cache; } else { period = srate * 256 / hz; /* fixed point */ @@ -1247,11 +1203,11 @@ j = 0; p = beep_buf; for (i = 0; i < nsamples; ++i, p += 2) { - p[0] = p[1] = beep_wform[j >> 8] * beep_volume; + p[0] = p[1] = beep_wform[j >> 8] * beep_vol; j = (j + f) & 0xffff; } beep_hz_cache = hz; - beep_volume_cache = beep_volume; + beep_volume_cache = beep_vol; beep_nsamples_cache = nsamples; } @@ -1263,78 +1219,157 @@ save_flags(flags); cli(); if (beep_playing) { /* i.e. haven't been terminated already */ + int count = 300 ; out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); + while ((in_le32(&awacs_txdma->status) & RUN) && count--) + udelay(1); /* timeout > 2 samples at lowest rate*/ + /* FIXME: check this is OK on DACA, Tumbler */ out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00) | (beep_speed << 8)); - out_le32(&awacs->byteswap, 0); + out_le32(&awacs->byteswap, 0); /* force BE */ out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); + (void)in_le32(&awacs_txdma->status); out_le32(&awacs_txdma->control, RUN | (RUN << 16)); } restore_flags(flags); } +/* used in init and for wake-up */ + +static void +load_awacs(void) +{ + awacs_write(awacs_reg[0] + MASK_ADDR0); + awacs_write(awacs_reg[1] + MASK_ADDR1); + awacs_write(awacs_reg[2] + MASK_ADDR2); + awacs_write(awacs_reg[4] + MASK_ADDR4); + + if (awacs_revision == AWACS_SCREAMER) { + awacs_write(awacs_reg[5] + MASK_ADDR5); + wait_ms(100); + awacs_write(awacs_reg[6] + MASK_ADDR6); + wait_ms(2); + awacs_write(awacs_reg[1] + MASK_ADDR1); + awacs_write(awacs_reg[7] + MASK_ADDR7); + } + if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) + out_le32(&awacs->byteswap, BS_VAL); + else + out_le32(&awacs->byteswap, 0); +} + #ifdef CONFIG_PMAC_PBOOK /* * Save state when going to sleep, restore it afterwards. */ +/* FIXME: sort out disabling/re-enabling of read stuff as well */ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) { switch (when) { - case PBOOK_SLEEP_NOW: - /* XXX we should stop any dma in progress when going to sleep - and restart it when we wake. */ + case PBOOK_SLEEP_NOW: + LOCK(); + awacs_sleeping = 1; + /* Tell the rest of the driver we are now going to sleep */ + mb(); + if (awacs_revision == AWACS_SCREAMER || + awacs_revision == AWACS_AWACS) { + awacs_reg1_save = awacs_reg[1]; + awacs_reg[1] |= MASK_AMUTE | MASK_CMUTE; + awacs_write(MASK_ADDR1 | awacs_reg[1]); + } + PMacSilence(); + /* stop rx - if going - a bit of a daft user... but */ + out_le32(&awacs_rxdma->control, (RUN|WAKE|FLUSH << 16)); + /* deny interrupts */ + switch (awacs_revision) { + case AWACS_TUMBLER: + break ; /* dont know how yet */ + case AWACS_DACA: + daca_enter_sleep(); + break ; + case AWACS_BURGUNDY: + break ; + case AWACS_SCREAMER: + case AWACS_AWACS: + default: + out_le32(&awacs->control, 0x11) ; + break ; + } disable_irq(awacs_irq); disable_irq(awacs_tx_irq); - if (is_pbook_G3) { - feature_clear(awacs_node, FEATURE_Sound_CLK_enable); - feature_clear(awacs_node, FEATURE_Sound_power); + disable_irq(awacs_rx_irq); + /* Disable sound clock */ + pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); + /* According to Darwin, we do that after turning off the sound + * chip clock. All this will have to be cleaned up once we properly + * parse the OF sound-objects + */ + if (machine_is_compatible("PowerBook3,1") || + machine_is_compatible("PowerBook3,2")) { + awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; + awacs_write(MASK_ADDR1 | awacs_reg[1]); + wait_ms(200); } break; case PBOOK_WAKE: - /* There is still a problem on wake. Sound seems to work fine - if I launch mpg123 and resumes fine if mpg123 was playing, - but the console beep is dead until I do something with the - mixer. Probably yet another timing issue */ - if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable) - || !feature_test(awacs_node, FEATURE_Sound_power)) { - /* these aren't present on the 3400 AFAIK -- paulus */ - feature_set(awacs_node, FEATURE_Sound_CLK_enable); - feature_set(awacs_node, FEATURE_Sound_power); - mdelay(1000); - } - out_le32(&awacs->control, MASK_IEPC - | (awacs_rate_index << 8) | 0x11 - | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0)); - awacs_write(awacs_reg[0] | MASK_ADDR0); - awacs_write(awacs_reg[1] | MASK_ADDR1); - awacs_write(awacs_reg[2] | MASK_ADDR2); - awacs_write(awacs_reg[4] | MASK_ADDR4); - if (awacs_is_screamer) { - awacs_write(awacs_reg[5] + MASK_ADDR5); - awacs_write(awacs_reg[6] + MASK_ADDR6); - awacs_write(awacs_reg[7] + MASK_ADDR7); - } - out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE); + /* Enable sound clock */ + pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 1); + if (machine_is_compatible("PowerBook3,1") || + machine_is_compatible("PowerBook3,2")) { + wait_ms(100); + awacs_reg[1] &= ~(MASK_PAROUT0 | MASK_PAROUT1); + awacs_write(MASK_ADDR1 | awacs_reg[1]); + wait_ms(300); + } else + wait_ms(1000); + /* restore settings */ + switch (awacs_revision) { + case AWACS_TUMBLER: + headphone_intr(0,0,0); + break; + case AWACS_DACA: + wait_ms(10); /* Check this !!! */ + daca_leave_sleep(); + break ; /* dont know how yet */ + case AWACS_BURGUNDY: + break ; + case AWACS_SCREAMER: + case AWACS_AWACS: + default: + load_awacs() ; + break ; + } + /* Recalibrate chip */ + if (awacs_revision == AWACS_SCREAMER) + awacs_recalibrate(); + /* Make sure dma is stopped */ + PMacSilence(); enable_irq(awacs_irq); enable_irq(awacs_tx_irq); - if (awacs_revision == 3) { - mdelay(100); - awacs_write(0x6000); - mdelay(2); - awacs_write(awacs_reg[1] | MASK_ADDR1); - } - /* enable CD sound input */ - if (macio_base && is_pbook_G3) { + enable_irq(awacs_rx_irq); + /* OK, allow ints back again */ + out_le32(&awacs->control, MASK_IEPC + | (awacs_rate_index << 8) | 0x11 + | (awacs_revision < AWACS_DACA ? MASK_IEE: 0)); + if (macio_base && is_pbook_g3) { + /* FIXME: should restore the setup we had...*/ out_8(macio_base + 0x37, 3); - } else if (is_pbook_3400) { - feature_set(awacs_node, FEATURE_IOBUS_enable); - udelay(10); + } else if (is_pbook_3X00) { in_8(latch_base + 0x190); } + /* Remove mute */ + if (awacs_revision == AWACS_SCREAMER || + awacs_revision == AWACS_AWACS) { + awacs_reg[1] = awacs_reg1_save; + awacs_write(MASK_ADDR1 | awacs_reg[1]); + } + awacs_sleeping = 0; /* Resume pending sounds. */ - PMacPlay(); + /* we don't try to restart input... */ + __PMacPlay(); + UNLOCK(); } return PBOOK_SLEEP_OK; } @@ -1347,17 +1382,20 @@ inline static void awacs_burgundy_busy_wait(void) { - while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) - ; + int count = 50; /* > 2 samples at 44k1 */ + while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--) + udelay(1) ; } inline static void awacs_burgundy_extend_wait(void) { - while (!(in_le32(&awacs->codec_stat) & MASK_EXTEND)) - ; - while (in_le32(&awacs->codec_stat) & MASK_EXTEND) - ; + int count = 50 ; /* > 2 samples at 44k1 */ + while ((!(in_le32(&awacs->codec_stat) & MASK_EXTEND)) && count--) + udelay(1) ; + count = 50; + while ((in_le32(&awacs->codec_stat) & MASK_EXTEND) && count--) + udelay(1); } static void @@ -1447,7 +1485,7 @@ awacs_burgundy_init(void) { if (awacs_burgundy_check()) { - printk(KERN_WARNING "AWACS: disabled by MacOS :-(\n"); + printk(KERN_WARNING "dmasound_pmac: burgundy not working :-(\n"); return 1; } @@ -1515,9 +1553,6 @@ return softvolume > 0 ? softvolume : 0; } - - - static int awacs_burgundy_read_mvolume(unsigned address) { @@ -1533,7 +1568,6 @@ return lvolume + (rvolume << 8); } - static void awacs_burgundy_write_mvolume(unsigned address, int volume) { @@ -1550,21 +1584,23 @@ /* End burgundy functions */ +/* Set up output volumes on machines with the 'perch/whisper' extension card. + * this has an SGS i2c chip (7433) which is accessed using the cuda. + * + * TODO: split this out and make use of the other parts of the SGS chip to + * do Bass, Treble etc. + */ - - - -/* Turn on sound output, needed on G3 desktop powermacs */ static void awacs_enable_amp(int spkr_vol) { +#ifdef CONFIG_ADB_CUDA struct adb_request req; awacs_spkr_vol = spkr_vol; if (sys_ctrler != SYS_CTRLER_CUDA) return; -#ifdef CONFIG_ADB_CUDA /* turn on headphones */ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 4, 0); @@ -1595,146 +1631,229 @@ * /dev/mixer abstraction */ -static int awacs_mixer_ioctl(u_int cmd, u_long arg) +static void do_line_lev(int data) { - int data; - - switch (cmd) { - case SOUND_MIXER_READ_DEVMASK: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER - | SOUND_MASK_LINE | SOUND_MASK_MIC - | SOUND_MASK_CD | SOUND_MASK_RECLEV - | SOUND_MASK_ALTPCM - | SOUND_MASK_MONITOR; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_RECMASK: - data = SOUND_MASK_LINE | SOUND_MASK_MIC - | SOUND_MASK_CD; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_RECSRC: - data = 0; - if (awacs_reg[0] & MASK_MUX_AUDIN) - data |= SOUND_MASK_LINE; - if (awacs_reg[0] & MASK_MUX_MIC) - data |= SOUND_MASK_MIC; - if (awacs_reg[0] & MASK_MUX_CD) - data |= SOUND_MASK_CD; - if (awacs_reg[1] & MASK_LOOPTHRU) - data |= SOUND_MASK_MONITOR; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data &= (SOUND_MASK_LINE - | SOUND_MASK_MIC | SOUND_MASK_CD - | SOUND_MASK_MONITOR); - awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC - | MASK_MUX_AUDIN); - awacs_reg[1] &= ~MASK_LOOPTHRU; - if (data & SOUND_MASK_LINE) + line_lev = data ; + awacs_reg[0] &= ~MASK_MUX_AUDIN; + if ((data & 0xff) >= 50) awacs_reg[0] |= MASK_MUX_AUDIN; - if (data & SOUND_MASK_MIC) - awacs_reg[0] |= MASK_MUX_MIC; - if (data & SOUND_MASK_CD) - awacs_reg[0] |= MASK_MUX_CD; - if (data & SOUND_MASK_MONITOR) + awacs_write(MASK_ADDR0 | awacs_reg[0]); +} + +static void do_ip_gain(int data) +{ + ip_gain = data ; + data &= 0xff; + awacs_reg[0] &= ~MASK_GAINLINE; + if (awacs_revision == AWACS_SCREAMER) { + awacs_reg[6] &= ~MASK_MIC_BOOST ; + if (data >= 33) { + awacs_reg[0] |= MASK_GAINLINE; + if( data >= 66) + awacs_reg[6] |= MASK_MIC_BOOST ; + } + awacs_write(MASK_ADDR6 | awacs_reg[6]) ; + } else { + if (data >= 50) + awacs_reg[0] |= MASK_GAINLINE; + } + awacs_write(MASK_ADDR0 | awacs_reg[0]); +} + +static void do_mic_lev(int data) +{ + mic_lev = data ; + data &= 0xff; + awacs_reg[0] &= ~MASK_MUX_MIC; + if (data >= 50) + awacs_reg[0] |= MASK_MUX_MIC; + awacs_write(MASK_ADDR0 | awacs_reg[0]); +} + +static void do_cd_lev(int data) +{ + cd_lev = data ; + awacs_reg[0] &= ~MASK_MUX_CD; + if ((data & 0xff) >= 50) + awacs_reg[0] |= MASK_MUX_CD; + awacs_write(MASK_ADDR0 | awacs_reg[0]); +} + +static void do_rec_lev(int data) +{ + int left, right ; + rec_lev = data ; + /* need to fudge this to use the volume setter routine */ + left = 100 - (data & 0xff) ; if( left < 0 ) left = 0 ; + right = 100 - ((data >> 8) & 0xff) ; if( right < 0 ) right = 0 ; + left |= (right << 8 ); + left = awacs_volume_setter(left, 0, 0, 4); +} + +static void do_passthru_vol(int data) +{ + passthru_vol = data ; + awacs_reg[1] &= ~MASK_LOOPTHRU; + if (awacs_revision == AWACS_SCREAMER) { + if( data ) { /* switch it on for non-zero */ awacs_reg[1] |= MASK_LOOPTHRU; + awacs_write(MASK_ADDR1 | awacs_reg[1]); + } + data = awacs_volume_setter(data, 5, 0, 6) ; + } else { + if ((data & 0xff) >= 50) + awacs_reg[1] |= MASK_LOOPTHRU; + awacs_write(MASK_ADDR1 | awacs_reg[1]); + data = (awacs_reg[1] & MASK_LOOPTHRU)? 100: 0; + } +} + +static int awacs_mixer_ioctl(u_int cmd, u_long arg) +{ + int data; + int rc; + + switch (cmd) { + case SOUND_MIXER_READ_CAPS: + /* say we will allow multiple inputs? prob. wrong + so I'm switching it to single */ + return IOCTL_OUT(arg, 1); + case SOUND_MIXER_READ_DEVMASK: + data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER + | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD + | SOUND_MASK_IGAIN | SOUND_MASK_RECLEV + | SOUND_MASK_ALTPCM + | SOUND_MASK_MONITOR; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_RECMASK: + data = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_RECSRC: + data = 0; + if (awacs_reg[0] & MASK_MUX_AUDIN) + data |= SOUND_MASK_LINE; + if (awacs_reg[0] & MASK_MUX_MIC) + data |= SOUND_MASK_MIC; + if (awacs_reg[0] & MASK_MUX_CD) + data |= SOUND_MASK_CD; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_WRITE_RECSRC: + IOCTL_IN(arg, data); + data &= (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD); + awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC + | MASK_MUX_AUDIN); + if (data & SOUND_MASK_LINE) + awacs_reg[0] |= MASK_MUX_AUDIN; + if (data & SOUND_MASK_MIC) + awacs_reg[0] |= MASK_MUX_MIC; + if (data & SOUND_MASK_CD) + awacs_reg[0] |= MASK_MUX_CD; awacs_write(awacs_reg[0] | MASK_ADDR0); - awacs_write(awacs_reg[1] | MASK_ADDR1); - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_READ_STEREODEVS: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER - | SOUND_MASK_RECLEV; - return IOCTL_OUT(arg, data); - case SOUND_MIXER_READ_CAPS: - return IOCTL_OUT(arg, 0); - case SOUND_MIXER_READ_VOLUME: - data = (awacs_reg[1] & MASK_AMUTE)? 0: - awacs_get_volume(awacs_reg[2], 6); - return IOCTL_OUT(arg, data); + data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER| SOUND_MASK_RECLEV ; + if (awacs_revision == AWACS_SCREAMER) + data |= SOUND_MASK_MONITOR ; + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_WRITE_VOLUME: IOCTL_IN(arg, data); - return IOCTL_OUT(arg, PMacSetVolume(data)); - case SOUND_MIXER_READ_SPEAKER: - if (awacs_revision == 3 - && sys_ctrler == SYS_CTRLER_CUDA) - data = awacs_spkr_vol; - else - data = (awacs_reg[1] & MASK_CMUTE)? 0: - awacs_get_volume(awacs_reg[4], 6); - return IOCTL_OUT(arg, data); + line_vol = data ; + awacs_volume_setter(data, 2, 0, 6); + /* fall through */ + case SOUND_MIXER_READ_VOLUME: + rc = IOCTL_OUT(arg, line_vol); + break; case SOUND_MIXER_WRITE_SPEAKER: IOCTL_IN(arg, data); - if (awacs_revision == 3 - && sys_ctrler == SYS_CTRLER_CUDA) + spk_vol = data ; + if (has_perch) awacs_enable_amp(data); else - data = awacs_volume_setter(data, 4, MASK_CMUTE, 6); - return IOCTL_OUT(arg, data); + (void)awacs_volume_setter(data, 4, MASK_CMUTE, 6); + /* fall though */ + case SOUND_MIXER_READ_SPEAKER: + rc = IOCTL_OUT(arg, spk_vol); + break; case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ IOCTL_IN(arg, data); - beep_volume = data & 0xff; - /* fall through */ + beep_vol = data & 0xff; + /* fall through */ case SOUND_MIXER_READ_ALTPCM: - return IOCTL_OUT(arg, beep_volume); + rc = IOCTL_OUT(arg, beep_vol); + break; case SOUND_MIXER_WRITE_LINE: IOCTL_IN(arg, data); - awacs_reg[0] &= ~MASK_MUX_AUDIN; - if ((data & 0xff) >= 50) - awacs_reg[0] |= MASK_MUX_AUDIN; - awacs_write(MASK_ADDR0 | awacs_reg[0]); - /* fall through */ + do_line_lev(data) ; + /* fall through */ case SOUND_MIXER_READ_LINE: - data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0; - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, line_lev); + break; + case SOUND_MIXER_WRITE_IGAIN: + IOCTL_IN(arg, data); + do_ip_gain(data) ; + /* fall through */ + case SOUND_MIXER_READ_IGAIN: + rc = IOCTL_OUT(arg, ip_gain); + break; case SOUND_MIXER_WRITE_MIC: IOCTL_IN(arg, data); - data &= 0xff; - awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE); - if (data >= 25) { - awacs_reg[0] |= MASK_MUX_MIC; - if (data >= 75) - awacs_reg[0] |= MASK_GAINLINE; - } - awacs_write(MASK_ADDR0 | awacs_reg[0]); - /* fall through */ + do_mic_lev(data); + /* fall through */ case SOUND_MIXER_READ_MIC: - data = (awacs_reg[0] & MASK_MUX_MIC)? - (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0; - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, mic_lev); + break; case SOUND_MIXER_WRITE_CD: IOCTL_IN(arg, data); - awacs_reg[0] &= ~MASK_MUX_CD; - if ((data & 0xff) >= 50) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(MASK_ADDR0 | awacs_reg[0]); - /* fall through */ + do_cd_lev(data); + /* fall through */ case SOUND_MIXER_READ_CD: - data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0; - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, cd_lev); + break; case SOUND_MIXER_WRITE_RECLEV: IOCTL_IN(arg, data); - data = awacs_volume_setter(data, 0, 0, 4); - return IOCTL_OUT(arg, data); + do_rec_lev(data) ; + /* fall through */ case SOUND_MIXER_READ_RECLEV: - data = awacs_get_volume(awacs_reg[0], 4); - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, rec_lev); + break; case MIXER_WRITE(SOUND_MIXER_MONITOR): IOCTL_IN(arg, data); - awacs_reg[1] &= ~MASK_LOOPTHRU; - if ((data & 0xff) >= 50) - awacs_reg[1] |= MASK_LOOPTHRU; - awacs_write(MASK_ADDR1 | awacs_reg[1]); + do_passthru_vol(data) ; /* fall through */ case MIXER_READ(SOUND_MIXER_MONITOR): - data = (awacs_reg[1] & MASK_LOOPTHRU)? 100: 0; - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, passthru_vol); + break; + default: + rc = -EINVAL; } - return -EINVAL; + + return rc; +} + +static void awacs_mixer_init(void) +{ + awacs_volume_setter(line_vol, 2, 0, 6); + if (has_perch) + awacs_enable_amp(spk_vol); + else + (void)awacs_volume_setter(spk_vol, 4, MASK_CMUTE, 6); + do_line_lev(line_lev) ; + do_ip_gain(ip_gain) ; + do_mic_lev(mic_lev) ; + do_cd_lev(cd_lev) ; + do_rec_lev(rec_lev) ; + do_passthru_vol(passthru_vol) ; } static int burgundy_mixer_ioctl(u_int cmd, u_long arg) { int data; + int rc; /* We are, we are, we are... Burgundy or better */ switch(cmd) { @@ -1742,11 +1861,13 @@ data = SOUND_MASK_VOLUME | SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM; - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_READ_RECMASK: data = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD; - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_READ_RECSRC: data = 0; if (awacs_reg[0] & MASK_MUX_AUDIN) @@ -1755,7 +1876,8 @@ data |= SOUND_MASK_MIC; if (awacs_reg[0] & MASK_MUX_CD) data |= SOUND_MASK_CD; - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_WRITE_RECSRC: IOCTL_IN(arg, data); data &= (SOUND_MASK_LINE @@ -1769,23 +1891,26 @@ if (data & SOUND_MASK_CD) awacs_reg[0] |= MASK_MUX_CD; awacs_write(awacs_reg[0] | MASK_ADDR0); - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_READ_STEREODEVS: data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER | SOUND_MASK_RECLEV | SOUND_MASK_CD | SOUND_MASK_LINE; - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_READ_CAPS: - return IOCTL_OUT(arg, 0); + rc = IOCTL_OUT(arg, 0); + break; case SOUND_MIXER_WRITE_VOLUME: IOCTL_IN(arg, data); awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data); /* Fall through */ case SOUND_MIXER_READ_VOLUME: - return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME)); + rc = IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME)); + break; case SOUND_MIXER_WRITE_SPEAKER: IOCTL_IN(arg, data); - if (!(data & 0xff)) { /* Mute the left speaker */ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, @@ -1806,7 +1931,7 @@ } data = (((data&0xff)*16)/100 > 0xf ? 0xf : - (((data&0xff)*16)/100)) + + (((data&0xff)*16)/100)) + ((((data>>8)*16)/100 > 0xf ? 0xf : ((((data>>8)*16)/100)))<<4); @@ -1815,21 +1940,24 @@ case SOUND_MIXER_READ_SPEAKER: data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER); data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8); - return IOCTL_OUT(arg, ~data); + rc = IOCTL_OUT(arg, ~data); + break; case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ IOCTL_IN(arg, data); - beep_volume = data & 0xff; + beep_vol = data & 0xff; /* fall through */ case SOUND_MIXER_READ_ALTPCM: - return IOCTL_OUT(arg, beep_volume); + rc = IOCTL_OUT(arg, beep_vol); + break; case SOUND_MIXER_WRITE_LINE: IOCTL_IN(arg, data); awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data); /* fall through */ case SOUND_MIXER_READ_LINE: - data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE); - return IOCTL_OUT(arg, data); + data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_WRITE_MIC: IOCTL_IN(arg, data); /* Mic is mono device */ @@ -1837,66 +1965,330 @@ awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data); /* fall through */ case SOUND_MIXER_READ_MIC: - data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC); + data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC); data <<= 24; - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_WRITE_CD: IOCTL_IN(arg, data); awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data); /* fall through */ case SOUND_MIXER_READ_CD: data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD); - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_WRITE_RECLEV: IOCTL_IN(arg, data); data = awacs_volume_setter(data, 0, 0, 4); - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_READ_RECLEV: data = awacs_get_volume(awacs_reg[0], 4); - return IOCTL_OUT(arg, data); + rc = IOCTL_OUT(arg, data); + break; case SOUND_MIXER_OUTMASK: + case SOUND_MIXER_OUTSRC: + default: + rc = -EINVAL; + } + + return rc; +} + +static int tumbler_mixer_ioctl(u_int cmd, u_long arg) +{ + int data; + int rc; + + /* We are, we are, we are... Tumbler (and very dumb) */ + /* Ok, we're not THAT dumb anymore, but still pretty dumb :-) */ + + switch(cmd) { + case SOUND_MIXER_READ_DEVMASK: + data = SOUND_MASK_VOLUME | SOUND_MASK_ALTPCM | + SOUND_MASK_BASS | SOUND_MASK_TREBLE | + SOUND_MASK_PCM; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_RECMASK: + data = 0; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_RECSRC: + data = 0; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_WRITE_RECSRC: + IOCTL_IN(arg, data); + data =0; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_STEREODEVS: + data = SOUND_MASK_VOLUME; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_CAPS: + rc = IOCTL_OUT(arg, 0); + break; + case SOUND_MIXER_WRITE_BASS: + IOCTL_IN(arg, data); + tumbler_set_bass(data); + case SOUND_MIXER_READ_BASS: + tumbler_get_bass(&data); + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_WRITE_TREBLE: + IOCTL_IN(arg, data); + tumbler_set_treble(data); + /* Fall through */ + case SOUND_MIXER_READ_TREBLE: + tumbler_get_treble(&data); + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_WRITE_PCM: + IOCTL_IN(arg, data); + tumbler_set_pcm_lvl(data); + /* Fall through */ + case SOUND_MIXER_READ_PCM: + tumbler_get_pcm_lvl(&data); + IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + tumbler_set_volume(data, data); + /* Fall through */ + case SOUND_MIXER_READ_VOLUME: + tumbler_get_volume(& data, &data); + rc = IOCTL_OUT(arg, data); break; + case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ + IOCTL_IN(arg, data); + beep_vol = data & 0xff; + /* fall through */ + case SOUND_MIXER_READ_ALTPCM: + rc = IOCTL_OUT(arg, beep_vol); + break; + case SOUND_MIXER_OUTMASK: case SOUND_MIXER_OUTSRC: + default: + rc = -EINVAL; + } + + return rc; +} + +static int daca_mixer_ioctl(u_int cmd, u_long arg) +{ + int data; + int rc; + + /* And the DACA's no genius either! */ + + switch(cmd) { + case SOUND_MIXER_READ_DEVMASK: + data = SOUND_MASK_VOLUME; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_RECMASK: + data = 0; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_RECSRC: + data = 0; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_WRITE_RECSRC: + IOCTL_IN(arg, data); + data =0; + rc = IOCTL_OUT(arg, data); break; + case SOUND_MIXER_READ_STEREODEVS: + data = SOUND_MASK_VOLUME; + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_READ_CAPS: + rc = IOCTL_OUT(arg, 0); + break; + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + daca_set_volume(data, data); + /* Fall through */ + case SOUND_MIXER_READ_VOLUME: + daca_get_volume(& data, &data); + rc = IOCTL_OUT(arg, data); + break; + case SOUND_MIXER_OUTMASK: + case SOUND_MIXER_OUTSRC: + default: + rc = -EINVAL; } - return -EINVAL; + return rc; } static int PMacMixerIoctl(u_int cmd, u_long arg) { - /* Different IOCTLS for burgundy*/ - if (awacs_revision >= AWACS_BURGUNDY) - return burgundy_mixer_ioctl(cmd, arg); - return awacs_mixer_ioctl(cmd, arg); + int rc; + + /* Different IOCTLS for burgundy and, eventually, DACA & Tumbler */ + + TRY_LOCK(); + + switch (awacs_revision){ + case AWACS_BURGUNDY: + rc = burgundy_mixer_ioctl(cmd, arg); + break ; + case AWACS_DACA: + rc = daca_mixer_ioctl(cmd, arg); + break; + case AWACS_TUMBLER: + rc = tumbler_mixer_ioctl(cmd, arg); + break ; + default: /* ;-)) */ + rc = awacs_mixer_ioctl(cmd, arg); + } + + UNLOCK(); + + return rc; +} + +static void PMacMixerInit(void) +{ + switch (awacs_revision) { + case AWACS_TUMBLER: + printk("AE-Init tumbler mixer\n"); + break ; + + case AWACS_DACA: + case AWACS_BURGUNDY: + break ; /* don't know yet */ + case AWACS_AWACS: + case AWACS_SCREAMER: + default: + awacs_mixer_init() ; + break ; + } } +/* Write/Read sq setup functions: + Check to see if we have enough (or any) dbdma cmd buffers for the + user's fragment settings. If not, allocate some. If this fails we will + point at the beep buffer - as an emergency provision - to stop dma tromping + on some random bit of memory (if someone lets it go anyway). + The command buffers are then set up to point to the fragment buffers + (allocated elsewhere). We need n+1 commands the last of which holds + a NOP + loop to start. +*/ -static void PMacWriteSqSetup(void) +static int PMacWriteSqSetup(void) { - int i; + int i, count = 600 ; volatile struct dbdma_cmd *cp; + LOCK(); + + /* stop the controller from doing any output - if it isn't already. + it _should_ be before this is called anyway */ + + out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + while ((in_le32(&awacs_txdma->status) & RUN) && count--) + udelay(1); +#ifdef DEBUG_DMASOUND +if (count <= 0) + printk("dmasound_pmac: write sq setup: timeout waiting for dma to stop\n"); +#endif + + if ((write_sq.max_count + 1) > number_of_tx_cmd_buffers) { + if (awacs_tx_cmd_space) + kfree(awacs_tx_cmd_space); + number_of_tx_cmd_buffers = 0; + + /* we need nbufs + 1 (for the loop) and we should request + 1 + again because the DBDMA_ALIGN might pull the start up by up + to sizeof(struct dbdma_cmd) - 4. + */ + + awacs_tx_cmd_space = kmalloc + ((write_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd), + GFP_KERNEL); + if (awacs_tx_cmd_space == NULL) { + /* don't leave it dangling - nasty but better than a + random address */ + out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); + printk(KERN_ERR + "dmasound_pmac: can't allocate dbdma cmd buffers" + ", driver disabled\n"); + UNLOCK(); + return -ENOMEM; + } + awacs_tx_cmds = (volatile struct dbdma_cmd *) + DBDMA_ALIGN(awacs_tx_cmd_space); + number_of_tx_cmd_buffers = write_sq.max_count + 1; + } + cp = awacs_tx_cmds; - memset((void *)cp, 0, (write_sq.numBufs+1) * sizeof(struct dbdma_cmd)); - for (i = 0; i < write_sq.numBufs; ++i, ++cp) { + memset((void *)cp, 0, (write_sq.max_count+1) * sizeof(struct dbdma_cmd)); + for (i = 0; i < write_sq.max_count; ++i, ++cp) { st_le32(&cp->phy_addr, virt_to_bus(write_sq.buffers[i])); } st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS); st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds)); - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + /* point the controller at the command stack - ready to go */ out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds)); + UNLOCK(); + return 0; } -static void PMacReadSqSetup(void) +static int PMacReadSqSetup(void) { - int i; + int i, count = 600; volatile struct dbdma_cmd *cp; + LOCK(); + + /* stop the controller from doing any input - if it isn't already. + it _should_ be before this is called anyway */ + + out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + while ((in_le32(&awacs_rxdma->status) & RUN) && count--) + udelay(1); +#ifdef DEBUG_DMASOUND +if (count <= 0) + printk("dmasound_pmac: read sq setup: timeout waiting for dma to stop\n"); +#endif + + if ((read_sq.max_count+1) > number_of_rx_cmd_buffers ) { + if (awacs_rx_cmd_space) + kfree(awacs_rx_cmd_space); + number_of_rx_cmd_buffers = 0; + + /* we need nbufs + 1 (for the loop) and we should request + 1 again + because the DBDMA_ALIGN might pull the start up by up to + sizeof(struct dbdma_cmd) - 4 (assuming kmalloc aligns 32 bits). + */ + + awacs_rx_cmd_space = kmalloc + ((read_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd), + GFP_KERNEL); + if (awacs_rx_cmd_space == NULL) { + /* don't leave it dangling - nasty but better than a + random address */ + out_le32(&awacs_rxdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); + printk(KERN_ERR + "dmasound_pmac: can't allocate dbdma cmd buffers" + ", driver disabled\n"); + UNLOCK(); + return -ENOMEM; + } + awacs_rx_cmds = (volatile struct dbdma_cmd *) + DBDMA_ALIGN(awacs_rx_cmd_space); + number_of_rx_cmd_buffers = read_sq.max_count + 1 ; + } cp = awacs_rx_cmds; - memset((void *)cp, 0, (read_sq.numBufs+1) * sizeof(struct dbdma_cmd)); + memset((void *)cp, 0, (read_sq.max_count+1) * sizeof(struct dbdma_cmd)); /* Set dma buffers up in a loop */ - for (i = 0; i < read_sq.numBufs; i++,cp++) { + for (i = 0; i < read_sq.max_count; i++,cp++) { st_le32(&cp->phy_addr, virt_to_bus(read_sq.buffers[i])); st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS); st_le16(&cp->req_count, read_sq.block_size); @@ -1907,37 +2299,105 @@ */ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS); st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds)); - - /* Don't start until the first read is done. - * This will also abort any operations in progress if the DMA - * happens to be running (and it shouldn't). - */ - out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + /* point the controller at the command stack - ready to go */ out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds)); + UNLOCK(); + return 0; } +/* TODO: this needs work to guarantee that when it returns DMA has stopped + but in a more elegant way than is done here.... +*/ + static void PMacAbortRead(void) { int i; volatile struct dbdma_cmd *cp; + LOCK(); + /* give it a chance to update the output and provide the IRQ + that is expected. + */ + + out_le32(&awacs_rxdma->control, ((FLUSH) << 16) + FLUSH ); + cp = awacs_rx_cmds; - for (i = 0; i < read_sq.numBufs; i++,cp++) + for (i = 0; i < read_sq.max_count; i++,cp++) st_le16(&cp->command, DBDMA_STOP); /* * We should probably wait for the thing to stop before we - * release the memory + * release the memory. */ + + wait_ms(100) ; /* give it a (small) chance to act */ + + /* apply the sledgehammer approach - just stop it now */ + + out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + UNLOCK(); } +extern char *get_afmt_string(int); +static int PMacStateInfo(char *b, size_t sp) +{ + int i, len = 0; + len = sprintf(b,"HW rates: "); + switch (awacs_revision){ + case AWACS_DACA: + case AWACS_BURGUNDY: + len += sprintf(b,"44100 ") ; + break ; + case AWACS_TUMBLER: + for (i=0; i<2; i++){ + if (tumbler_freqs_ok[i]) + len += sprintf(b+len,"%d ", tumbler_freqs[i]) ; + } + break ; + + case AWACS_AWACS: + case AWACS_SCREAMER: + default: + for (i=0; i<8; i++){ + if (awacs_freqs_ok[i]) + len += sprintf(b+len,"%d ", awacs_freqs[i]) ; + } + break ; + } + len += sprintf(b+len,"s/sec\n") ; + if (len < sp) { + len += sprintf(b+len,"HW AFMTS: "); + i = AFMT_U16_BE ; + while (i) { + if (i & dmasound.mach.hardware_afmts) + len += sprintf(b+len,"%s ", + get_afmt_string(i & dmasound.mach.hardware_afmts)); + i >>= 1 ; + } + len += sprintf(b+len,"\n") ; + } + return len ; +} /*** Machine definitions *****************************************************/ +static SETTINGS def_hard = { + format: AFMT_S16_BE, + stereo: 1, + size: 16, + speed: 44100 +} ; + +static SETTINGS def_soft = { + format: AFMT_S16_BE, + stereo: 1, + size: 16, + speed: 44100 +} ; static MACHINE machPMac = { name: awacs_name, - name2: "AWACS", + name2: "PowerMac Built-in Sound", open: PMacOpen, release: PMacRelease, dma_alloc: PMacAlloc, @@ -1951,233 +2411,669 @@ setFormat: PMacSetFormat, setVolume: PMacSetVolume, play: PMacPlay, - record: PMacRecord, + record: NULL, /* default to no record */ + mixer_init: PMacMixerInit, mixer_ioctl: PMacMixerIoctl, write_sq_setup: PMacWriteSqSetup, read_sq_setup: PMacReadSqSetup, + state_info: PMacStateInfo, abort_read: PMacAbortRead, - min_dsp_speed: 8000 + min_dsp_speed: 7350, + max_dsp_speed: 44100, + version: ((DMASOUND_AWACS_REVISION<<8) + DMASOUND_AWACS_EDITION) }; /*** Config & Setup **********************************************************/ +/* Check for pmac models that we care about in terms of special actions. +*/ -int __init dmasound_awacs_init(void) +void __init +set_model(void) { - struct device_node *np; + /* portables/lap-tops */ - if (_machine != _MACH_Pmac) - return -ENODEV; + if (machine_is_compatible("AAPL,3400/2400") || + machine_is_compatible("AAPL,3500")) { + is_pbook_3X00 = 1 ; + } + if (machine_is_compatible("PowerBook1,1") || /* lombard */ + machine_is_compatible("AAPL,PowerBook1998")){ /* wallstreet */ + is_pbook_g3 = 1 ; + return ; + } +} - awacs_subframe = 0; - awacs_revision = 0; - np = find_devices("awacs"); - if (np == 0) { - /* - * powermac G3 models have a node called "davbus" - * with a child called "sound". - */ - struct device_node *sound; - np = find_devices("davbus"); - sound = find_devices("sound"); - if (sound != 0 && sound->parent == np) { - unsigned int *prop, l, i; - prop = (unsigned int *) - get_property(sound, "sub-frame", 0); - if (prop != 0 && *prop >= 0 && *prop < 16) - awacs_subframe = *prop; - if (device_is_compatible(sound, "burgundy")) - awacs_revision = AWACS_BURGUNDY; - /* This should be verified on older screamers */ - if (device_is_compatible(sound, "screamer")) - awacs_is_screamer = 1; - prop = (unsigned int *)get_property(sound, "device-id", 0); - if (prop != 0) - awacs_device_id = *prop; - awacs_has_iic = (find_devices("perch") != NULL); - - /* look for a property saying what sample rates - are available */ - for (i = 0; i < 8; ++i) - awacs_freqs_ok[i] = 0; - prop = (unsigned int *) get_property - (sound, "sample-rates", &l); - if (prop == 0) - prop = (unsigned int *) get_property - (sound, "output-frame-rates", &l); - if (prop != 0) { - for (l /= sizeof(int); l > 0; --l) { - /* sometimes the rate is in the - high-order 16 bits (?) */ - unsigned int r = *prop++; - if (r >= 0x10000) - r >>= 16; - for (i = 0; i < 8; ++i) { - if (r == awacs_freqs[i]) { - awacs_freqs_ok[i] = 1; - break; - } - } +/* Get the OF node that tells us about the registers, interrupts etc. to use + for sound IO. + + On most machines the sound IO OF node is the 'davbus' node. On newer pmacs + with DACA (& Tumbler) the node to use is i2s-a. On much older machines i.e. + before 9500 there is no davbus node and we have to use the 'awacs' property. + + In the latter case we signal this by setting the codec value - so that the + code that looks for chip properties knows how to go about it. +*/ + +static struct device_node +__init *get_snd_io_node(void) +{ + struct device_node *np = NULL; + + /* set up awacs_node for early OF which doesn't have a full set of + * properties on davbus + */ + + awacs_node = find_devices("awacs"); + if (awacs_node) + awacs_revision = AWACS_AWACS; + + /* powermac models after 9500 (other than those which use DACA or + * Tumbler) have a node called "davbus". + */ + np = find_devices("davbus"); + /* + * if we didn't find a davbus device, try 'i2s-a' since + * this seems to be what iBooks (& Tumbler) have. + */ + if (np == NULL) + np = find_devices("i2s-a"); + + /* if we didn't find this - perhaps we are on an early model + * which _only_ has an 'awacs' node + */ + if (np == NULL && awacs_node) + np = awacs_node ; + + /* if we failed all these return null - this will cause the + * driver to give up... + */ + return np ; +} + +/* Get the OF node that contains the info about the sound chip, inputs s-rates + etc. + This node does not exist (or contains much reduced info) on earlier machines + we have to deduce the info other ways for these. +*/ + +static struct device_node +__init *get_snd_info_node(struct device_node *io) +{ + struct device_node *info; + + info = find_devices("sound"); + while (info != 0 && info->parent != io) + info = info->next; + + return info ; +} + +/* Find out what type of codec we have. +*/ + +static int +__init get_codec_type(struct device_node *info) +{ + /* already set if pre-davbus model and info will be NULL */ + int codec = awacs_revision ; + + if (info) { + /* must do awacs first to allow screamer to overide it */ + if (device_is_compatible(info, "awacs")) + codec = AWACS_AWACS ; + if (device_is_compatible(info, "screamer")) + codec = AWACS_SCREAMER; + if (device_is_compatible(info, "burgundy")) + codec = AWACS_BURGUNDY ; + if (device_is_compatible(info, "daca")) + codec = AWACS_DACA; + if (device_is_compatible(info, "tumbler")) + codec = AWACS_TUMBLER; + } + return codec ; +} + +/* find out what type, if any, of expansion card we have +*/ +static void +__init get_expansion_type(void) +{ + if (find_devices("perch") != NULL) + has_perch = 1; + + if (find_devices("pb-ziva-pc") != NULL) + has_ziva = 1; + /* need to work out how we deal with iMac SRS module */ +} + +/* set up frame rates. + * I suspect that these routines don't quite go about it the right way: + * - where there is more than one rate - I think that the first property + * value is the number of rates. + * TODO: check some more device trees and modify accordingly + * Set dmasound.mach.max_dsp_rate on the basis of these routines. +*/ + +static void +__init init_awacs_frame_rates(unsigned int *prop, unsigned int l) +{ + int i ; + if (prop) { + for (i=0; i<8; i++) + awacs_freqs_ok[i] = 0 ; + for (l /= sizeof(int); l > 0; --l) { + unsigned int r = *prop++; + /* Apple 'Fixed' format */ + if (r >= 0x10000) + r >>= 16; + for (i = 0; i < 8; ++i) { + if (r == awacs_freqs[i]) { + awacs_freqs_ok[i] = 1; + break; } - } else { - /* assume just 44.1k is OK */ - awacs_freqs_ok[0] = 1; } } } - if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) { - int vol; - dmasound.mach = machPMac; - - awacs = (volatile struct awacs_regs *) - ioremap(np->addrs[0].address, 0x80); - awacs_txdma = (volatile struct dbdma_regs *) - ioremap(np->addrs[1].address, 0x100); - awacs_rxdma = (volatile struct dbdma_regs *) - ioremap(np->addrs[2].address, 0x100); - - awacs_irq = np->intrs[0].line; - awacs_tx_irq = np->intrs[1].line; - awacs_rx_irq = np->intrs[2].line; + /* else we assume that all the rates are available */ +} - awacs_tx_cmd_space = kmalloc((write_sq.numBufs + 4) * sizeof(struct dbdma_cmd), - GFP_KERNEL); - if (awacs_tx_cmd_space == NULL) { - printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n"); - return -ENOMEM; +static void +__init init_tumbler_frame_rates(unsigned int *prop, unsigned int l) +{ + int i ; + if (prop) { + for (i=0; i<2; i++) + tumbler_freqs_ok[i] = 0; + for (l /= sizeof(int); l > 0; --l) { + unsigned int r = *prop++; + /* Apple 'Fixed' format */ + if (r >= 0x10000) + r >>= 16; + for (i = 0; i < 2; ++i) { + if (r == tumbler_freqs[i]) { + tumbler_freqs_ok[i] = 1; + break; + } + } } - awacs_node = np; -#ifdef CONFIG_PMAC_PBOOK - if (machine_is_compatible("PowerBook1,1") - || machine_is_compatible("AAPL,PowerBook1998")) { - pmu_suspend(); - feature_set(np, FEATURE_Sound_CLK_enable); - feature_set(np, FEATURE_Sound_power); - /* Shorter delay will not work */ - mdelay(1000); - pmu_resume(); + } + /* else we assume that all the rates are available */ +} + +static void +__init init_burgundy_frame_rates(unsigned int *prop, unsigned int l) +{ + int temp[9] ; + int i = 0 ; + if (prop) { + for (l /= sizeof(int); l > 0; --l) { + unsigned int r = *prop++; + /* Apple 'Fixed' format */ + if (r >= 0x10000) + r >>= 16; + temp[i] = r ; + i++ ; if(i>=9) i=8; + } + } +#ifdef DEBUG_DMASOUND +if (i > 1){ + int j; + printk("dmasound_pmac: burgundy with multiple frame rates\n"); + for(j=0; j<i; j++) + printk("%d ", temp[j]) ; + printk("\n") ; +} +#endif +} + +static void +__init init_daca_frame_rates(unsigned int *prop, unsigned int l) +{ + int temp[9] ; + int i = 0 ; + if (prop) { + for (l /= sizeof(int); l > 0; --l) { + unsigned int r = *prop++; + /* Apple 'Fixed' format */ + if (r >= 0x10000) + r >>= 16; + temp[i] = r ; + i++ ; if(i>=9) i=8; + + } + } +#ifdef DEBUG_DMASOUND +if (i > 1){ + int j; + printk("dmasound_pmac: DACA with multiple frame rates\n"); + for(j=0; j<i; j++) + printk("%d ", temp[j]) ; + printk("\n") ; +} +#endif +} + +static void +__init init_frame_rates(unsigned int *prop, unsigned int l) +{ + switch (awacs_revision){ + case AWACS_TUMBLER: + init_tumbler_frame_rates(prop, l); + break ; + case AWACS_DACA: + init_daca_frame_rates(prop, l); + break ; + case AWACS_BURGUNDY: + init_burgundy_frame_rates(prop, l); + break ; + default: /* ;-))) */ + init_awacs_frame_rates(prop, l); + break ; + } +} + +/* find things/machines that can't do mac-io byteswap +*/ + +static void +__init set_hw_byteswap(struct device_node *io) +{ + struct device_node *mio ; + unsigned int *p, rev = 0 ; + + /* if seems that Keylargo (at least rev2) can't byte-swap */ + + for (mio = io->parent; mio ; mio = mio->parent) { + if (strcmp(mio->name, "mac-io") == 0) { + if (device_is_compatible(mio, "Keylargo")){ + p = (unsigned int *) + get_property(mio, "revision-id", 0); + if (p) + rev = *p ; + } + break; } + } + if (rev >= 2) { + hw_can_byteswap = 0; +#ifdef DEBUG_DMASOUND +printk("dmasound_pmac: found Keylargo rev 2 or later - H/W byte-swap disabled\n") ; #endif - awacs_tx_cmds = (volatile struct dbdma_cmd *) - DBDMA_ALIGN(awacs_tx_cmd_space); + } +} +/* Allocate the resources necessary for beep generation. This cannot be (quite) + done statically (yet) because we cannot do virt_to_bus() on static vars when + the code is loaded as a module. + + for the sake of saving the possibility that two allocations will incur the + overhead of two pull-ups in DBDMA_ALIGN() we allocate the 'emergency' dmdma + command here as well... even tho' it is not part of the beep process. +*/ + +int32_t +__init setup_beep(void) +{ + /* Initialize beep stuff */ + /* want one cmd buffer for beeps, and a second one for emergencies + - i.e. dbdma error conditions. + ask for three to allow for pull up in DBDMA_ALIGN(). + */ + beep_dbdma_cmd_space = + kmalloc((2 + 1) * sizeof(struct dbdma_cmd), GFP_KERNEL); + if(beep_dbdma_cmd_space == NULL) { + printk(KERN_ERR "dmasound_pmac: no beep dbdma cmd space\n") ; + return -ENOMEM ; + } + beep_dbdma_cmd = (volatile struct dbdma_cmd *) + DBDMA_ALIGN(beep_dbdma_cmd_space); + /* set up emergency dbdma cmd */ + emergency_dbdma_cmd = beep_dbdma_cmd+1 ; + beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); + if (beep_buf == NULL) { + printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n"); + if( beep_dbdma_cmd_space ) kfree(beep_dbdma_cmd_space) ; + return -ENOMEM ; + } + /* OK, we should be safe to claim the mksound vector now */ + orig_mksound = kd_mksound; + kd_mksound = awacs_mksound; + return 0 ; +} - awacs_rx_cmd_space = kmalloc((read_sq.numBufs + 4) * sizeof(struct dbdma_cmd), - GFP_KERNEL); - if (awacs_rx_cmd_space == NULL) { - printk("DMA sound driver: No memory for input"); +int __init dmasound_awacs_init(void) +{ + struct device_node *io = NULL, *info = NULL; + int vol, res; + + if (_machine != _MACH_Pmac) + return -ENODEV; + + awacs_subframe = 0; + awacs_revision = 0; + hw_can_byteswap = 1 ; /* most can */ + + /* look for models we need to handle specially */ + set_model() ; + + /* find the OF node that tells us about the dbdma stuff + */ + io = get_snd_io_node(); + if (io == NULL) { +#ifdef DEBUG_DMASOUND +printk("dmasound_pmac: couldn't find sound io OF node\n"); +#endif + return -ENODEV ; + } + + /* find the OF node that tells us about the sound sub-system + * this doesn't exist on pre-davbus machines (earlier than 9500) + */ + if (awacs_revision != AWACS_AWACS) { /* set for pre-davbus */ + info = get_snd_info_node(io) ; + if (info == NULL){ +#ifdef DEBUG_DMASOUND +printk("dmasound_pmac: couldn't find 'sound' OF node\n"); +#endif + return -ENODEV ; } - awacs_rx_cmds = (volatile struct dbdma_cmd *) - DBDMA_ALIGN(awacs_rx_cmd_space); + } + awacs_revision = get_codec_type(info) ; + if (awacs_revision == 0) { +#ifdef DEBUG_DMASOUND +printk("dmasound_pmac: couldn't find a Codec we can handle\n"); +#endif + return -ENODEV ; /* we don't know this type of h/w */ + } + /* set up perch, ziva, SRS or whatever else we have as sound + * expansion. + */ + get_expansion_type(); - awacs_reg[0] = MASK_MUX_CD; - /* FIXME: Only machines with external SRS module need MASK_PAROUT */ - awacs_reg[1] = MASK_LOOPTHRU; - if (awacs_has_iic || awacs_device_id == 0x5 || /*awacs_device_id == 0x8 - || */awacs_device_id == 0xb) - awacs_reg[1] |= MASK_PAROUT; - /* get default volume from nvram */ - vol = (~nvram_read_byte(0x1308) & 7) << 1; - awacs_reg[2] = vol + (vol << 6); - awacs_reg[4] = vol + (vol << 6); - awacs_reg[5] = 0; - awacs_reg[6] = 0; - awacs_reg[7] = 0; - out_le32(&awacs->control, 0x11); - awacs_write(awacs_reg[0] + MASK_ADDR0); - awacs_write(awacs_reg[1] + MASK_ADDR1); - awacs_write(awacs_reg[2] + MASK_ADDR2); - awacs_write(awacs_reg[4] + MASK_ADDR4); - if (awacs_is_screamer) { - awacs_write(awacs_reg[5] + MASK_ADDR5); - awacs_write(awacs_reg[6] + MASK_ADDR6); - awacs_write(awacs_reg[7] + MASK_ADDR7); - } - - /* Initialize recent versions of the awacs */ - if (awacs_revision == 0) { - awacs_revision = - (in_le32(&awacs->codec_stat) >> 12) & 0xf; - if (awacs_revision == 3) { - mdelay(100); - awacs_write(0x6000); - mdelay(2); - awacs_write(awacs_reg[1] + MASK_ADDR1); - awacs_enable_amp(100 * 0x101); + /* we've now got enough information to make up the audio topology. + * we will map the sound part of mac-io now so that we can probe for + * other info if necessary (early AWACS we want to read chip ids) + */ + + if (io->n_addrs < 3 || io->n_intrs < 3) { + /* OK - maybe we need to use the 'awacs' node (on earlier + * machines). + */ + if (awacs_node) { + io = awacs_node ; + if (io->n_addrs < 3 || io->n_intrs < 3) { + printk("dmasound_pmac: can't use %s" + " (%d addrs, %d intrs)\n", + io->full_name, io->n_addrs, io->n_intrs); + return -ENODEV; } + } else { + printk("dmasound_pmac: can't use %s (%d addrs, %d intrs)\n", + io->full_name, io->n_addrs, io->n_intrs); } - if (awacs_revision >= AWACS_BURGUNDY) + } + + if (!request_OF_resource(io, 0, NULL)) { + printk(KERN_ERR "dmasound: can't request IO resource !\n"); + return -ENODEV; + } + if (!request_OF_resource(io, 1, " (tx dma)")) { + release_OF_resource(io, 0); + printk(KERN_ERR "dmasound: can't request TX DMA resource !\n"); + return -ENODEV; + } + + if (!request_OF_resource(io, 2, " (rx dma)")) { + release_OF_resource(io, 0); + release_OF_resource(io, 1); + printk(KERN_ERR "dmasound: can't request RX DMA resource !\n"); + return -ENODEV; + } + + /* all OF versions I've seen use this value */ + awacs = (volatile struct awacs_regs *) + ioremap(io->addrs[0].address, 0x1000); + awacs_txdma = (volatile struct dbdma_regs *) + ioremap(io->addrs[1].address, 0x100); + awacs_rxdma = (volatile struct dbdma_regs *) + ioremap(io->addrs[2].address, 0x100); + +#ifdef CONFIG_PMAC_PBOOK + /* first of all make sure that the chip is powered up....*/ + pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1); + if (awacs_revision == AWACS_SCREAMER) + awacs_recalibrate(); +#endif + awacs_irq = io->intrs[0].line; + awacs_tx_irq = io->intrs[1].line; + awacs_rx_irq = io->intrs[2].line; + + awacs_node = io; + + /* if we have an awacs or screamer - probe the chip to make + * sure we have the right revision. + */ + + if (awacs_revision <= AWACS_SCREAMER){ + uint32_t temp, rev, mfg ; + /* find out the awacs revision from the chip */ + temp = in_le32(&awacs->codec_stat); + rev = (temp >> 12) & 0xf; + mfg = (temp >> 8) & 0xf; +#ifdef DEBUG_DMASOUND +printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev); +#endif + if (rev >= AWACS_SCREAMER) + awacs_revision = AWACS_SCREAMER ; + else + awacs_revision = rev ; + } + + dmasound.mach = machPMac; + + /* find out other bits & pieces from OF, these may be present + only on some models ... so be careful. + */ + + /* in the absence of a frame rates property we will use the defaults + */ + + if (info) { + unsigned int *prop, l; + + sound_device_id = 0; + /* device ID appears post g3 b&w */ + prop = (unsigned int *)get_property(info, "device-id", 0); + if (prop != 0) + sound_device_id = *prop; + + /* look for a property saying what sample rates + are available */ + + prop = (unsigned int *)get_property(info, "sample-rates", &l); + if (prop == 0) + prop = (unsigned int *) get_property + (info, "output-frame-rates", &l); + + /* if it's there use it to set up frame rates */ + init_frame_rates(prop, l) ; + } + + out_le32(&awacs->control, 0x11); /* set everything quiesent */ + + set_hw_byteswap(io) ; /* figure out if the h/w can do it */ + + /* get default volume from nvram + * vol = (~nvram_read_byte(0x1308) & 7) << 1; + */ + vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 ); + /* set up tracking values */ + spk_vol = vol * 100 ; + spk_vol /= 7 ; /* get set value to a percentage */ + spk_vol |= (spk_vol << 8) ; /* equal left & right */ + line_vol = passthru_vol = spk_vol ; + + /* fill regs that are shared between AWACS & Burgundy */ + + awacs_reg[2] = vol + (vol << 6); + awacs_reg[4] = vol + (vol << 6); + awacs_reg[5] = vol + (vol << 6); /* screamer has loopthru vol control */ + awacs_reg[6] = 0; /* maybe should be vol << 3 for PCMCIA speaker */ + awacs_reg[7] = 0; + + awacs_reg[0] = MASK_MUX_CD; + awacs_reg[1] = MASK_LOOPTHRU; + + /* FIXME: Only machines with external SRS module need MASK_PAROUT */ + if (has_perch || sound_device_id == 0x5 + || /*sound_device_id == 0x8 ||*/ sound_device_id == 0xb) + awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; + + switch (awacs_revision) { + case AWACS_TUMBLER: +#ifdef CONFIG_KMOD + request_module("i2c-keywest"); +#endif /* CONFIG_KMOD */ + awacs_tumbler_init(); + tas_init(); + break ; + case AWACS_DACA: +#ifdef CONFIG_KMOD + request_module("i2c-keywest"); +#endif /* CONFIG_KMOD */ + daca_init(); + break ; /* dont know how yet */ + case AWACS_BURGUNDY: awacs_burgundy_init(); + break ; + case AWACS_SCREAMER: + case AWACS_AWACS: + default: + load_awacs() ; + break ; + } + + /* enable/set-up external modules - when we know how */ + + if (has_perch) + awacs_enable_amp(100 * 0x101); + + /* Reset dbdma channels */ + out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); + while (in_le32(&awacs_txdma->status) & RUN) + udelay(1); + out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); + while (in_le32(&awacs_rxdma->status) & RUN) + udelay(1); + + /* Initialize beep stuff */ + if ((res=setup_beep())) + return res ; - /* Initialize beep stuff */ - beep_dbdma_cmd = awacs_tx_cmds + (write_sq.numBufs + 1); - orig_mksound = kd_mksound; - kd_mksound = awacs_mksound; - beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); - if (beep_buf == NULL) - printk(KERN_WARNING "dmasound: no memory for " - "beep buffer\n"); #ifdef CONFIG_PMAC_PBOOK - pmu_register_sleep_notifier(&awacs_sleep_notifier); + pmu_register_sleep_notifier(&awacs_sleep_notifier); #endif /* CONFIG_PMAC_PBOOK */ - /* Powerbooks have odd ways of enabling inputs such as - an expansion-bay CD or sound from an internal modem - or a PC-card modem. */ - if (machine_is_compatible("AAPL,3400/2400") - || machine_is_compatible("AAPL,3500")) { - is_pbook_3400 = 1; - /* - * Enable CD and PC-card sound inputs. - * This is done by reading from address - * f301a000, + 0x10 to enable the expansion-bay - * CD sound input, + 0x80 to enable the PC-card - * sound input. The 0x100 enables the SCSI bus - * terminator power. - */ - latch_base = (unsigned char *) ioremap - (0xf301a000, 0x1000); - in_8(latch_base + 0x190); - } else if (machine_is_compatible("PowerBook1,1") - || machine_is_compatible("AAPL,PowerBook1998")) { - struct device_node* mio; - macio_base = 0; - is_pbook_G3 = 1; - for (mio = np->parent; mio; mio = mio->parent) { - if (strcmp(mio->name, "mac-io") == 0 - && mio->n_addrs > 0) { - macio_base = (unsigned char *) ioremap - (mio->addrs[0].address, 0x40); - break; - } + /* Powerbooks have odd ways of enabling inputs such as + an expansion-bay CD or sound from an internal modem + or a PC-card modem. */ + if (is_pbook_3X00) { + /* + * Enable CD and PC-card sound inputs. + * This is done by reading from address + * f301a000, + 0x10 to enable the expansion-bay + * CD sound input, + 0x80 to enable the PC-card + * sound input. The 0x100 enables the SCSI bus + * terminator power. + */ + latch_base = (unsigned char *) ioremap (0xf301a000, 0x1000); + in_8(latch_base + 0x190); + + } else if (is_pbook_g3) { + struct device_node* mio; + macio_base = 0; + for (mio = io->parent; mio; mio = mio->parent) { + if (strcmp(mio->name, "mac-io") == 0 + && mio->n_addrs > 0) { + macio_base = (unsigned char *) ioremap + (mio->addrs[0].address, 0x40); + break; } - /* - * Enable CD sound input. - * The relevant bits for writing to this byte are 0x8f. - * I haven't found out what the 0x80 bit does. - * For the 0xf bits, writing 3 or 7 enables the CD - * input, any other value disables it. Values - * 1, 3, 5, 7 enable the microphone. Values 0, 2, - * 4, 6, 8 - f enable the input from the modem. - */ - if (macio_base) - out_8(macio_base + 0x37, 3); - } - sprintf(awacs_name, "PowerMac (AWACS rev %d) ", - awacs_revision); - return dmasound_init(); + } + /* + * Enable CD sound input. + * The relevant bits for writing to this byte are 0x8f. + * I haven't found out what the 0x80 bit does. + * For the 0xf bits, writing 3 or 7 enables the CD + * input, any other value disables it. Values + * 1, 3, 5, 7 enable the microphone. Values 0, 2, + * 4, 6, 8 - f enable the input from the modem. + * -- paulus. + */ + if (macio_base) + out_8(macio_base + 0x37, 3); + } + + if (hw_can_byteswap) + dmasound.mach.hardware_afmts = (AFMT_S16_BE | AFMT_S16_LE) ; + else + dmasound.mach.hardware_afmts = AFMT_S16_BE ; + + /* shut out chips that do output only. + may need to extend this to machines which have no inputs - even tho' + they use screamer - IIRC one of the powerbooks is like this. + */ + + if (awacs_revision != AWACS_TUMBLER && awacs_revision != AWACS_DACA) { + dmasound.mach.capabilities = DSP_CAP_DUPLEX ; + dmasound.mach.record = PMacRecord ; + } + + dmasound.mach.default_hard = def_hard ; + dmasound.mach.default_soft = def_soft ; + + switch (awacs_revision) { + case AWACS_BURGUNDY: + sprintf(awacs_name, "PowerMac Burgundy ") ; + break ; + case AWACS_DACA: + sprintf(awacs_name, "PowerMac DACA ") ; + break ; + case AWACS_TUMBLER: + sprintf(awacs_name, "PowerMac Tumbler ") ; + break ; + case AWACS_SCREAMER: + sprintf(awacs_name, "PowerMac Screamer ") ; + break ; + case AWACS_AWACS: + default: + sprintf(awacs_name, "PowerMac AWACS rev %d ", awacs_revision) ; + break ; } - return -ENODEV; + + return dmasound_init(); } static void __exit dmasound_awacs_cleanup(void) { + switch (awacs_revision) { + case AWACS_TUMBLER: + awacs_tumbler_cleanup(); + tas_cleanup(); + break ; + case AWACS_DACA: + daca_cleanup(); + break; + } dmasound_deinit(); } +MODULE_DESCRIPTION("PowerMac built-in audio driver."); +MODULE_LICENSE("GPL"); + module_init(dmasound_awacs_init); module_exit(dmasound_awacs_cleanup); -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/dmasound_core.c linux-2.5/drivers/sound/dmasound/dmasound_core.c --- linux-2.5.1/drivers/sound/dmasound/dmasound_core.c Thu Oct 25 20:53:52 2001 +++ linux-2.5/drivers/sound/dmasound/dmasound_core.c Thu Dec 27 16:32:31 2001 @@ -1,4 +1,3 @@ - /* * linux/drivers/sound/dmasound/dmasound_core.c * @@ -103,38 +102,113 @@ * 2000/3/25 Geert Uytterhoeven: * - Integration of dmasound_q40 * - Small clean ups + * + * 2001/01/26 [1.0] Iain Sandoe + * - make /dev/sndstat show revision & edition info. + * - since dmasound.mach.sq_setup() can fail on pmac + * its type has been changed to int and the returns + * are checked. + * [1.1] - stop missing translations from being called. + * 2001/02/08 [1.2] - remove unused translation tables & move machine- + * specific tables to low-level. + * - return correct info. for SNDCTL_DSP_GETFMTS. + * [1.3] - implement SNDCTL_DSP_GETCAPS fully. + * [1.4] - make /dev/sndstat text length usage deterministic. + * - make /dev/sndstat call to low-level + * dmasound.mach.state_info() pass max space to ll driver. + * - tidy startup banners and output info. + * [1.5] - tidy up a little (removed some unused #defines in + * dmasound.h) + * - fix up HAS_RECORD conditionalisation. + * - add record code in places it is missing... + * - change buf-sizes to bytes to allow < 1kb for pmac + * if user param entry is < 256 the value is taken to + * be in kb > 256 is taken to be in bytes. + * - make default buff/frag params conditional on + * machine to allow smaller values for pmac. + * - made the ioctls, read & write comply with the OSS + * rules on setting params. + * - added parsing of _setup() params for record. + * 2001/04/04 [1.6] - fix bug where sample rates higher than maximum were + * being reported as OK. + * - fix open() to return -EBUSY as per OSS doc. when + * audio is in use - this is independent of O_NOBLOCK. + * - fix bug where SNDCTL_DSP_POST was blocking. */ + /* Record capability notes 30/01/2001: + * At present these observations apply only to pmac LL driver (the only one + * that can do record, at present). However, if other LL drivers for machines + * with record are added they may apply. + * + * The fragment parameters for the record and play channels are separate. + * However, if the driver is opened O_RDWR there is no way (in the current OSS + * API) to specify their values independently for the record and playback + * channels. Since the only common factor between the input & output is the + * sample rate (on pmac) it should be possible to open /dev/dspX O_WRONLY and + * /dev/dspY O_RDONLY. The input & output channels could then have different + * characteristics (other than the first that sets sample rate claiming the + * right to set it for ever). As it stands, the format, channels, number of + * bits & sample rate are assumed to be common. In the future perhaps these + * should be the responsibility of the LL driver - and then if a card really + * does not share items between record & playback they can be specified + * separately. +*/ + +/* Thread-safeness of shared_resources notes: 31/01/2001 + * If the user opens O_RDWR and then splits record & play between two threads + * both of which inherit the fd - and then starts changing things from both + * - we will have difficulty telling. + * + * It's bad application coding - but ... + * TODO: think about how to sort this out... without bogging everything down in + * semaphores. + * + * Similarly, the OSS spec says "all changes to parameters must be between + * open() and the first read() or write(). - and a bit later on (by + * implication) "between SNDCTL_DSP_RESET and the first read() or write() after + * it". If the app is multi-threaded and this rule is broken between threads + * we will have trouble spotting it - and the fault will be rather obscure :-( + * + * We will try and put out at least a kmsg if we see it happen... but I think + * it will be quite hard to trap it with an -EXXX return... because we can't + * see the fault until after the damage is done. +*/ #include <linux/module.h> #include <linux/slab.h> #include <linux/sound.h> #include <linux/init.h> #include <linux/soundcard.h> +#include <linux/poll.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> #include "dmasound.h" +#define DMASOUND_CORE_REVISION 1 +#define DMASOUND_CORE_EDITION 6 /* * Declarations */ int dmasound_catchRadius = 0; -static unsigned int numWriteBufs = 4; -static unsigned int writeBufSize = 32; /* in KB! */ +static unsigned int numWriteBufs = DEFAULT_N_BUFFERS; +static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ; /* in bytes */ #ifdef HAS_RECORD -static unsigned int numReadBufs = 4; -static unsigned int readBufSize = 32; /* in KB! */ +static unsigned int numReadBufs = DEFAULT_N_BUFFERS; +static unsigned int readBufSize = DEFAULT_BUFF_SIZE; /* in bytes */ #endif MODULE_PARM(dmasound_catchRadius, "i"); MODULE_PARM(numWriteBufs, "i"); MODULE_PARM(writeBufSize, "i"); +#ifdef HAS_RECORD MODULE_PARM(numReadBufs, "i"); MODULE_PARM(readBufSize, "i"); +#endif MODULE_LICENSE("GPL"); #ifdef MODULE @@ -144,246 +218,18 @@ static int irq_installed = 0; #endif /* MODULE */ +/* control over who can modify resources shared between play/record */ +static mode_t shared_resource_owner = 0 ; +static int shared_resources_initialised = 0 ; /* - * Conversion tables + * Common stuff */ -#ifdef HAS_8BIT_TABLES -/* 8 bit mu-law */ - -char dmasound_ulaw2dma8[] = { - -126, -122, -118, -114, -110, -106, -102, -98, - -94, -90, -86, -82, -78, -74, -70, -66, - -63, -61, -59, -57, -55, -53, -51, -49, - -47, -45, -43, -41, -39, -37, -35, -33, - -31, -30, -29, -28, -27, -26, -25, -24, - -23, -22, -21, -20, -19, -18, -17, -16, - -16, -15, -15, -14, -14, -13, -13, -12, - -12, -11, -11, -10, -10, -9, -9, -8, - -8, -8, -7, -7, -7, -7, -6, -6, - -6, -6, -5, -5, -5, -5, -4, -4, - -4, -4, -4, -4, -3, -3, -3, -3, - -3, -3, -3, -3, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 0, - 125, 121, 117, 113, 109, 105, 101, 97, - 93, 89, 85, 81, 77, 73, 69, 65, - 62, 60, 58, 56, 54, 52, 50, 48, - 46, 44, 42, 40, 38, 36, 34, 32, - 30, 29, 28, 27, 26, 25, 24, 23, - 22, 21, 20, 19, 18, 17, 16, 15, - 15, 14, 14, 13, 13, 12, 12, 11, - 11, 10, 10, 9, 9, 8, 8, 7, - 7, 7, 6, 6, 6, 6, 5, 5, - 5, 5, 4, 4, 4, 4, 3, 3, - 3, 3, 3, 3, 2, 2, 2, 2, - 2, 2, 2, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* 8 bit A-law */ - -char dmasound_alaw2dma8[] = { - -22, -21, -24, -23, -18, -17, -20, -19, - -30, -29, -32, -31, -26, -25, -28, -27, - -11, -11, -12, -12, -9, -9, -10, -10, - -15, -15, -16, -16, -13, -13, -14, -14, - -86, -82, -94, -90, -70, -66, -78, -74, - -118, -114, -126, -122, -102, -98, -110, -106, - -43, -41, -47, -45, -35, -33, -39, -37, - -59, -57, -63, -61, -51, -49, -55, -53, - -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -6, -6, -6, -6, -5, -5, -5, -5, - -8, -8, -8, -8, -7, -7, -7, -7, - -3, -3, -3, -3, -3, -3, -3, -3, - -4, -4, -4, -4, -4, -4, -4, -4, - 21, 20, 23, 22, 17, 16, 19, 18, - 29, 28, 31, 30, 25, 24, 27, 26, - 10, 10, 11, 11, 8, 8, 9, 9, - 14, 14, 15, 15, 12, 12, 13, 13, - 86, 82, 94, 90, 70, 66, 78, 74, - 118, 114, 126, 122, 102, 98, 110, 106, - 43, 41, 47, 45, 35, 33, 39, 37, - 59, 57, 63, 61, 51, 49, 55, 53, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 4, 4, 4, 4, - 7, 7, 7, 7, 6, 6, 6, 6, - 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3 -}; -#endif /* HAS_8BIT_TABLES */ - -#ifdef HAS_16BIT_TABLES - -/* 16 bit mu-law */ - -short dmasound_ulaw2dma16[] = { - -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, - -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, - -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, - -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, - -876, -844, -812, -780, -748, -716, -684, -652, - -620, -588, -556, -524, -492, -460, -428, -396, - -372, -356, -340, -324, -308, -292, -276, -260, - -244, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, - 876, 844, 812, 780, 748, 716, 684, 652, - 620, 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, 260, - 244, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0, -}; - -/* 16 bit A-law */ - -short dmasound_alaw2dma16[] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, - -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, - -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, - -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848, -}; -#endif /* HAS_16BIT_TABLES */ - - -#ifdef HAS_14BIT_TABLES - - /* - * Unused for now. Where are the MSB parts anyway?? - */ - -/* 14 bit mu-law (LSB) */ - -char dmasound_ulaw2dma14l[] = { - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 49, 17, 49, 17, 49, 17, 49, 17, - 49, 17, 49, 17, 49, 17, 49, 17, - 41, 57, 9, 25, 41, 57, 9, 25, - 41, 57, 9, 25, 41, 57, 9, 25, - 37, 45, 53, 61, 5, 13, 21, 29, - 37, 45, 53, 61, 5, 13, 21, 29, - 35, 39, 43, 47, 51, 55, 59, 63, - 3, 7, 11, 15, 19, 23, 27, 31, - 34, 36, 38, 40, 42, 44, 46, 48, - 50, 52, 54, 56, 58, 60, 62, 0, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 15, 47, 15, 47, 15, 47, 15, 47, - 15, 47, 15, 47, 15, 47, 15, 47, - 23, 7, 55, 39, 23, 7, 55, 39, - 23, 7, 55, 39, 23, 7, 55, 39, - 27, 19, 11, 3, 59, 51, 43, 35, - 27, 19, 11, 3, 59, 51, 43, 35, - 29, 25, 21, 17, 13, 9, 5, 1, - 61, 57, 53, 49, 45, 41, 37, 33, - 30, 28, 26, 24, 22, 20, 18, 16, - 14, 12, 10, 8, 6, 4, 2, 0 -}; - -/* 14 bit A-law (LSB) */ - -char dmasound_alaw2dma14l[] = { - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 16, 48, 16, 48, 16, 48, 16, 48, - 16, 48, 16, 48, 16, 48, 16, 48, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 42, 46, 34, 38, 58, 62, 50, 54, - 10, 14, 2, 6, 26, 30, 18, 22, - 42, 46, 34, 38, 58, 62, 50, 54, - 10, 14, 2, 6, 26, 30, 18, 22, - 40, 56, 8, 24, 40, 56, 8, 24, - 40, 56, 8, 24, 40, 56, 8, 24, - 20, 28, 4, 12, 52, 60, 36, 44, - 20, 28, 4, 12, 52, 60, 36, 44, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 48, 16, 48, 16, 48, 16, 48, 16, - 48, 16, 48, 16, 48, 16, 48, 16, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 22, 18, 30, 26, 6, 2, 14, 10, - 54, 50, 62, 58, 38, 34, 46, 42, - 22, 18, 30, 26, 6, 2, 14, 10, - 54, 50, 62, 58, 38, 34, 46, 42, - 24, 8, 56, 40, 24, 8, 56, 40, - 24, 8, 56, 40, 24, 8, 56, 40, - 44, 36, 60, 52, 12, 4, 28, 20, - 44, 36, 60, 52, 12, 4, 28, 20 -}; -#endif /* HAS_14BIT_TABLES */ - +static long long sound_lseek(struct file *file, long long offset, int orig) +{ + return -ESPIPE; +} /* * Mid level stuff @@ -393,15 +239,7 @@ static inline void sound_silence(void) { - /* update hardware settings one more */ - dmasound.mach.init(); - - dmasound.mach.silence(); -} - -static inline void sound_init(void) -{ - dmasound.mach.init(); + dmasound.mach.silence(); /* _MUST_ stop DMA */ } static inline int sound_set_format(int format) @@ -414,8 +252,17 @@ if (speed < 0) return dmasound.soft.speed; + /* trap out-of-range speed settings. + at present we allow (arbitrarily) low rates - using soft + up-conversion - but we can't allow > max because there is + no soft down-conversion. + */ + if (dmasound.mach.max_dsp_speed && + (speed > dmasound.mach.max_dsp_speed)) + speed = dmasound.mach.max_dsp_speed ; + dmasound.soft.speed = speed; - dmasound.mach.init(); + if (dmasound.minDev == SND_DEV_DSP) dmasound.dsp.speed = dmasound.soft.speed; @@ -432,7 +279,6 @@ dmasound.soft.stereo = stereo; if (dmasound.minDev == SND_DEV_DSP) dmasound.dsp.stereo = stereo; - dmasound.mach.init(); return stereo; } @@ -471,10 +317,14 @@ default: return 0; } - return ct_func(userPtr, userCount, frame, frameUsed, frameLeft); + /* if the user has requested a non-existent translation don't try + to call it but just return 0 bytes moved + */ + if (ct_func) + return ct_func(userPtr, userCount, frame, frameUsed, frameLeft); + return 0; } - /* * /dev/mixer abstraction */ @@ -559,6 +409,11 @@ struct sound_queue dmasound_read_sq; #endif +static void sq_reset_output(void) ; +#ifdef HAS_RECORD +static void sq_reset_input(void) ; +#endif + static int sq_allocate_buffers(struct sound_queue *sq, int num, int size) { int i; @@ -588,8 +443,6 @@ int i; if (sq->buffers) { - if (sq != &write_sq && dmasound.mach.abort_read) - dmasound.mach.abort_read(); for (i = 0; i < sq->numBufs; i++) dmasound.mach.dma_free(sq->buffers[i], sq->bufSize); kfree(sq->buffers); @@ -597,15 +450,84 @@ } } -static void sq_setup(struct sound_queue *sq, int max_count, int max_active, - int block_size) + +static int sq_setup(struct sound_queue *sq) { - void (*setup_func)(void); + int (*setup_func)(void); + int hard_frame ; + + if (sq->locked) { /* are we already set? - and not changeable */ +#ifdef DEBUG_DMASOUND +printk("dmasound_core: tried to sq_setup a locked queue\n") ; +#endif + return -EINVAL ; + } + sq->locked = 1 ; /* don't think we have a race prob. here _check_ */ - sq->max_count = max_count; - sq->max_active = max_active; - sq->block_size = block_size; + /* make sure that the parameters are set up + This should have been done already... + */ + + dmasound.mach.init(); + /* OK. If the user has set fragment parameters explicitly, then we + should leave them alone... as long as they are valid. + Invalid user fragment params can occur if we allow the whole buffer + to be used when the user requests the fragments sizes (with no soft + x-lation) and then the user subsequently sets a soft x-lation that + requires increased internal buffering. + + Othwerwise (if the user did not set them) OSS says that we should + select frag params on the basis of 0.5 s output & 0.1 s input + latency. (TODO. For now we will copy in the defaults.) + */ + + if (sq->user_frags <= 0) { + sq->max_count = sq->numBufs ; + sq->max_active = sq->numBufs ; + sq->block_size = sq->bufSize; + /* set up the user info */ + sq->user_frags = sq->numBufs ; + sq->user_frag_size = sq->bufSize ; + sq->user_frag_size *= + (dmasound.soft.size * (dmasound.soft.stereo+1) ) ; + sq->user_frag_size /= + (dmasound.hard.size * (dmasound.hard.stereo+1) ) ; + } else { + /* work out requested block size */ + sq->block_size = sq->user_frag_size ; + sq->block_size *= + (dmasound.hard.size * (dmasound.hard.stereo+1) ) ; + sq->block_size /= + (dmasound.soft.size * (dmasound.soft.stereo+1) ) ; + /* the user wants to write frag-size chunks */ + sq->block_size *= dmasound.hard.speed ; + sq->block_size /= dmasound.soft.speed ; + /* this only works for size values which are powers of 2 */ + hard_frame = + (dmasound.hard.size * (dmasound.hard.stereo+1))/8 ; + sq->block_size += (hard_frame - 1) ; + sq->block_size &= ~(hard_frame - 1) ; /* make sure we are aligned */ + /* let's just check for obvious mistakes */ + if ( sq->block_size <= 0 || sq->block_size > sq->bufSize) { +#ifdef DEBUG_DMASOUND +printk("dmasound_core: invalid frag size (user set %d)\n", sq->user_frag_size) ; +#endif + sq->block_size = sq->bufSize ; + } + if ( sq->user_frags <= sq->numBufs ) { + sq->max_count = sq->user_frags ; + /* if user has set max_active - then use it */ + sq->max_active = (sq->max_active <= sq->max_count) ? + sq->max_active : sq->max_count ; + } else { +#ifdef DEBUG_DMASOUND +printk("dmasound_core: invalid frag count (user set %d)\n", sq->user_frags) ; +#endif + sq->max_count = + sq->max_active = sq->numBufs ; + } + } sq->front = sq->count = sq->rear_size = 0; sq->syncing = 0; sq->active = 0; @@ -613,12 +535,16 @@ if (sq == &write_sq) { sq->rear = -1; setup_func = dmasound.mach.write_sq_setup; - } else { + } +#ifdef HAS_RECORD + else { sq->rear = 0; setup_func = dmasound.mach.read_sq_setup; } +#endif if (setup_func) - setup_func(); + return setup_func(); + return 0 ; } static inline void sq_play(void) @@ -632,6 +558,7 @@ ssize_t uWritten = 0; u_char *dest; ssize_t uUsed, bUsed, bLeft; + unsigned long flags ; /* ++TeSche: Is something like this necessary? * Hey, that's an honest question! Or does any other part of the @@ -640,11 +567,52 @@ if (uLeft == 0) return 0; + /* implement any changes we have made to the soft/hard params. + this is not satisfactory really, all we have done up to now is to + say what we would like - there hasn't been any real checking of capability + */ + + if (shared_resources_initialised == 0) { + dmasound.mach.init() ; + shared_resources_initialised = 1 ; + } + + /* set up the sq if it is not already done. This may seem a dumb place + to do it - but it is what OSS requires. It means that write() can + return memory allocation errors. To avoid this possibility use the + GETBLKSIZE or GETOSPACE ioctls (after you've fiddled with all the + params you want to change) - these ioctls also force the setup. + */ + + if (write_sq.locked == 0) { + if ((uWritten = sq_setup(&write_sq)) < 0) return uWritten ; + uWritten = 0 ; + } + +/* FIXME: I think that this may be the wrong behaviour when we get strapped + for time and the cpu is close to being (or actually) behind in sending data. + - because we've lost the time that the N samples, already in the buffer, + would have given us to get here with the next lot from the user. +*/ /* The interrupt doesn't start to play the last, incomplete frame. * Thus we can append to it without disabling the interrupts! (Note * also that write_sq.rear isn't affected by the interrupt.) */ + /* as of 1.6 this behaviour changes if SNDCTL_DSP_POST has been issued: + this will mimic the behaviour of syncing and allow the sq_play() to + queue a partial fragment. Since sq_play() may/will be called from + the IRQ handler - at least on Pmac we have to deal with it. + The strategy - possibly not optimum - is to kill _POST status if we + get here. This seems, at least, reasonable - in the sense that POST + is supposed to indicate that we might not write before the queue + is drained - and if we get here in time then it does not apply. + */ + + save_flags(flags) ; cli() ; + write_sq.syncing &= ~2 ; /* take out POST status */ + restore_flags(flags) ; + if (write_sq.count > 0 && (bLeft = write_sq.block_size-write_sq.rear_size) > 0) { dest = write_sq.buffers[write_sq.rear]; @@ -655,12 +623,12 @@ return uUsed; src += uUsed; uWritten += uUsed; - uLeft -= uUsed; + uLeft = (uUsed <= uLeft) ? (uLeft - uUsed) : 0 ; /* paranoia */ write_sq.rear_size = bUsed; } - do { - while (write_sq.count == write_sq.max_active) { + while (uLeft) { + while (write_sq.count >= write_sq.max_active) { sq_play(); if (write_sq.open_mode & O_NONBLOCK) return uWritten > 0 ? uWritten : -EAGAIN; @@ -685,19 +653,45 @@ break; src += uUsed; uWritten += uUsed; - uLeft -= uUsed; + uLeft = (uUsed <= uLeft) ? (uLeft - uUsed) : 0 ; /* paranoia */ if (bUsed) { write_sq.rear = (write_sq.rear+1) % write_sq.max_count; write_sq.rear_size = bUsed; write_sq.count++; } - } while (bUsed); /* uUsed may have been 0 */ + } /* uUsed may have been 0 */ sq_play(); return uUsed < 0? uUsed: uWritten; } +static unsigned int sq_poll(struct file *file, struct poll_table_struct *wait) +{ + unsigned int mask = 0; + int retVal; + + if (write_sq.locked == 0) { + if ((retVal = sq_setup(&write_sq)) < 0) + return retVal; + return 0; + } + if (file->f_mode & FMODE_WRITE ) + poll_wait(file, &write_sq.action_queue, wait); +#ifdef HAS_RECORD + if (file->f_mode & FMODE_READ) + poll_wait(file, &read_sq.action_queue, wait); + if (file->f_mode & FMODE_READ) + if (read_sq.block_size - read_sq.rear_size > 0) + mask |= POLLIN | POLLRDNORM; +#endif + if (file->f_mode & FMODE_WRITE) + if (write_sq.count < write_sq.max_active || write_sq.block_size - write_sq.rear_size > 0) + mask |= POLLOUT | POLLWRNORM; + return mask; + +} + #ifdef HAS_RECORD /* * Here is how the values are used for reading. @@ -707,9 +701,12 @@ * The value 'rear' indicates the buffer the DMA is currently filling. * When 'front' == 'rear' the buffer "ring" is empty (we always have an * empty available). The 'rear_size' is used to track partial offsets - * into the current buffer. Right now, I just keep the DMA running. If - * the reader can't keep up, the interrupt tosses the oldest buffer. We - * could also shut down the DMA in this case. + * into the buffer we are currently returning to the user. + + * This level (> [1.5]) doesn't care what strategy the LL driver uses with + * DMA on over-run. It can leave it running (and keep active == 1) or it + * can kill it and set active == 0 in which case this routine will spot + * it and restart the DMA. */ static ssize_t sq_read(struct file *file, char *dst, size_t uLeft, @@ -721,8 +718,25 @@ if (uLeft == 0) return 0; - if (!read_sq.active && dmasound.mach.record) - dmasound.mach.record(); /* Kick off the record process. */ + /* cater for the compatibility mode - record compiled in but no LL */ + if (dmasound.mach.record == NULL) + return -EINVAL ; + + /* see comment in sq_write() + */ + + if( shared_resources_initialised == 0) { + dmasound.mach.init() ; + shared_resources_initialised = 1 ; + } + + /* set up the sq if it is not already done. see comments in sq_write(). + */ + + if (read_sq.locked == 0) { + if ((uRead = sq_setup(&read_sq)) < 0) + return uRead ; + } uRead = 0; @@ -730,6 +744,13 @@ */ while (uLeft > 0) { + /* we happened to get behind and the LL driver killed DMA + then we should set it going again. This also sets it + going the first time through. + */ + if ( !read_sq.active ) + dmasound.mach.record(); + /* When front == rear, the DMA is not done yet. */ while (read_sq.front == read_sq.rear) { @@ -774,14 +795,16 @@ sq->busy = 0; } +#if 0 /* blocking open() */ static inline void sq_wake_up(struct sound_queue *sq, struct file *file, mode_t mode) { if (file->f_mode & mode) { - sq->busy = 0; + sq->busy = 0; /* CHECK: IS THIS OK??? */ WAKE_UP(sq->open_queue); } } +#endif static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode, int numbufs, int bufsize) @@ -790,6 +813,7 @@ if (file->f_mode & mode) { if (sq->busy) { +#if 0 /* blocking open() */ rc = -EBUSY; if (file->f_flags & O_NONBLOCK) return rc; @@ -800,84 +824,188 @@ return rc; } rc = 0; +#else + /* OSS manual says we will return EBUSY regardless + of O_NOBLOCK. + */ + return -EBUSY ; +#endif } sq->busy = 1; /* Let's play spot-the-race-condition */ - if (sq_allocate_buffers(sq, numbufs, bufsize)) { + /* allocate the default number & size of buffers. + (i.e. specified in _setup() or as module params) + can't be changed at the moment - but _could_ be perhaps + in the setfragments ioctl. + */ + if (( rc = sq_allocate_buffers(sq, numbufs, bufsize))) { +#if 0 /* blocking open() */ sq_wake_up(sq, file, mode); +#else + sq->busy = 0 ; +#endif return rc; } - sq_setup(sq, numbufs, numbufs, bufsize); sq->open_mode = file->f_mode; } return rc; } #define write_sq_init_waitqueue() sq_init_waitqueue(&write_sq) +#if 0 /* blocking open() */ #define write_sq_wake_up(file) sq_wake_up(&write_sq, file, FMODE_WRITE) +#endif #define write_sq_release_buffers() sq_release_buffers(&write_sq) #define write_sq_open(file) \ - sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize << 10) + sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize ) #ifdef HAS_RECORD #define read_sq_init_waitqueue() sq_init_waitqueue(&read_sq) +#if 0 /* blocking open() */ #define read_sq_wake_up(file) sq_wake_up(&read_sq, file, FMODE_READ) +#endif #define read_sq_release_buffers() sq_release_buffers(&read_sq) #define read_sq_open(file) \ - sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize << 10) -#else /* !HAS_RECORD */ -#define read_sq_init_waitqueue() do {} while (0) -#define read_sq_wake_up(file) do {} while (0) -#define read_sq_release_buffers() do {} while (0) -#define read_sq_open(file) (0) -#endif /* !HAS_RECORD */ + sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize ) +#endif static int sq_open(struct inode *inode, struct file *file) { int rc; dmasound.mach.open(); - if ((rc = write_sq_open(file)) || (rc = read_sq_open(file))) { + + if ((rc = write_sq_open(file))) { /* checks the f_mode */ dmasound.mach.release(); return rc; } +#ifdef HAS_RECORD + if (dmasound.mach.record) { + if ((rc = read_sq_open(file))) { /* checks the f_mode */ + dmasound.mach.release(); + return rc; + } + } else { /* no record function installed; in compat mode */ + if (file->f_mode & FMODE_READ) { + /* TODO: if O_RDWR, release any resources grabbed by write part */ + dmasound.mach.release() ; + /* I think this is what is required by open(2) */ + return -ENXIO ; + } + } +#else /* !HAS_RECORD */ + if (file->f_mode & FMODE_READ) { + /* TODO: if O_RDWR, release any resources grabbed by write part */ + dmasound.mach.release() ; + return -ENXIO ; /* I think this is what is required by open(2) */ + } +#endif /* HAS_RECORD */ if (dmasound.mach.sq_open) - dmasound.mach.sq_open(); + dmasound.mach.sq_open(file->f_mode); + + /* CHECK whether this is sensible - in the case that dsp0 could be opened + O_RDONLY and dsp1 could be opened O_WRONLY + */ + dmasound.minDev = MINOR(inode->i_rdev) & 0x0f; - dmasound.soft = dmasound.dsp; - dmasound.hard = dmasound.dsp; - sound_init(); - if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) { + + /* OK. - we should make some attempt at consistency. At least the H'ware + options should be set with a valid mode. We will make it that the LL + driver must supply defaults for hard & soft params. + */ + + if (shared_resource_owner == 0) { + /* you can make this AFMT_U8/mono/8K if you want to mimic old + OSS behaviour - while we still have soft translations ;-) */ + dmasound.soft = dmasound.mach.default_soft ; + dmasound.dsp = dmasound.mach.default_soft ; + dmasound.hard = dmasound.mach.default_hard ; + } + +#ifndef DMASOUND_STRICT_OSS_COMPLIANCE + /* none of the current LL drivers can actually do this "native" at the moment + OSS does not really require us to supply /dev/audio if we can't do it. + */ + if (dmasound.minDev == SND_DEV_AUDIO) { sound_set_speed(8000); sound_set_stereo(0); sound_set_format(AFMT_MU_LAW); } - -#if 0 - if (file->f_mode == FMODE_READ && dmasound.mach.record) { - /* Start dma'ing straight away */ - dmasound.mach.record(); - } #endif return 0; } -static void sq_reset(void) +static void sq_reset_output(void) { - sound_silence(); + sound_silence(); /* this _must_ stop DMA, we might be about to lose the buffers */ write_sq.active = 0; write_sq.count = 0; - write_sq.front = (write_sq.rear+1) % write_sq.max_count; + write_sq.rear_size = 0; + /* write_sq.front = (write_sq.rear+1) % write_sq.max_count;*/ + write_sq.front = 0 ; + write_sq.rear = -1 ; /* same as for set-up */ + + /* OK - we can unlock the parameters and fragment settings */ + write_sq.locked = 0 ; + write_sq.user_frags = 0 ; + write_sq.user_frag_size = 0 ; +} + +#ifdef HAS_RECORD + +static void sq_reset_input(void) +{ + if (dmasound.mach.record && read_sq.active) { + if (dmasound.mach.abort_read) { /* this routine must really be present */ + read_sq.syncing = 1 ; + /* this can use the read_sq.sync_queue to sleep if + necessary - it should not return until DMA + is really stopped - because we might deallocate + the buffers as the next action... + */ + dmasound.mach.abort_read() ; + } else { + printk(KERN_ERR + "dmasound_core: %s has no abort_read()!! all bets are off\n", + dmasound.mach.name) ; + } + } + read_sq.syncing = + read_sq.active = + read_sq.front = + read_sq.count = + read_sq.rear = 0 ; + + /* OK - we can unlock the parameters and fragment settings */ + read_sq.locked = 0 ; + read_sq.user_frags = 0 ; + read_sq.user_frag_size = 0 ; +} + +#endif + +static void sq_reset(void) +{ + sq_reset_output() ; +#ifdef HAS_RECORD + sq_reset_input() ; +#endif + /* we could consider resetting the shared_resources_owner here... but I + think it is probably still rather non-obvious to application writer + */ + + /* we release everything else though */ + shared_resources_initialised = 0 ; } static int sq_fsync(struct file *filp, struct dentry *dentry) { int rc = 0; - write_sq.syncing = 1; + write_sq.syncing |= 1; sq_play(); /* there may be an incomplete frame waiting */ while (write_sq.active) { @@ -886,13 +1014,14 @@ /* While waiting for audio output to drain, an * interrupt occurred. Stop audio output immediately * and clear the queue. */ - sq_reset(); + sq_reset_output(); rc = -EINTR; break; } } - write_sq.syncing = 0; + /* flag no sync regardless of whether we had a DSP_POST or not */ + write_sq.syncing = 0 ; return rc; } @@ -901,33 +1030,132 @@ int rc = 0; lock_kernel(); - if (write_sq.busy) - rc = sq_fsync(file, file->f_dentry); - dmasound.soft = dmasound.dsp; - dmasound.hard = dmasound.dsp; - sound_silence(); - write_sq_release_buffers(); - read_sq_release_buffers(); - dmasound.mach.release(); +#ifdef HAS_RECORD + /* probably best to do the read side first - so that time taken to do it + overlaps with playing any remaining output samples. + */ + if (file->f_mode & FMODE_READ) { + sq_reset_input() ; /* make sure dma is stopped and all is quiet */ + read_sq_release_buffers(); + read_sq.busy = 0; + } +#endif - /* There is probably a DOS atack here. They change the mode flag. */ - /* XXX add check here */ - read_sq_wake_up(file); - write_sq_wake_up(file); + if (file->f_mode & FMODE_WRITE) { + if (write_sq.busy) + rc = sq_fsync(file, file->f_dentry); + + sq_reset_output() ; /* make sure dma is stopped and all is quiet */ + write_sq_release_buffers(); + write_sq.busy = 0; + } + + if (file->f_mode & shared_resource_owner) { /* it's us that has them */ + shared_resource_owner = 0 ; + shared_resources_initialised = 0 ; + dmasound.hard = dmasound.mach.default_hard ; + } + + dmasound.mach.release(); +#if 0 /* blocking open() */ /* Wake up a process waiting for the queue being released. * Note: There may be several processes waiting for a call * to open() returning. */ + + /* Iain: hmm I don't understand this next comment ... */ + /* There is probably a DOS atack here. They change the mode flag. */ + /* XXX add check here,*/ +#ifdef HAS_RECORD + read_sq_wake_up(file); /* checks f_mode */ +#endif + write_sq_wake_up(file); /* checks f_mode */ +#endif /* blocking open() */ + unlock_kernel(); return rc; } +/* here we see if we have a right to modify format, channels, size and so on + if no-one else has claimed it already then we do... + + TODO: We might change this to mask O_RDWR such that only one or the other channel + is the owner - if we have problems. +*/ + +static int shared_resources_are_mine(mode_t md) +{ + if (shared_resource_owner) + return (shared_resource_owner & md ) ; + else { + shared_resource_owner = md ; + return 1 ; + } +} + +/* if either queue is locked we must deny the right to change shared params +*/ + +static int queues_are_quiescent(void) +{ +#ifdef HAS_RECORD + if (dmasound.mach.record) + if (read_sq.locked) + return 0 ; +#endif + if (write_sq.locked) + return 0 ; + return 1 ; +} + +/* check and set a queue's fragments per user's wishes... + we will check against the pre-defined literals and the actual sizes. + This is a bit fraught - because soft translations can mess with our + buffer requirements *after* this call - OSS says "call setfrags first" +*/ + +/* It is possible to replace all the -EINVAL returns with an override that + just puts the allowable value in. This may be what many OSS apps require +*/ + +static int set_queue_frags(struct sound_queue *sq, int bufs, int size) +{ + if (sq->locked) { +#ifdef DEBUG_DMASOUND +printk("dmasound_core: tried to set_queue_frags on a locked queue\n") ; +#endif + return -EINVAL ; + } + + if ((size < MIN_FRAG_SIZE) || (size > MAX_FRAG_SIZE)) + return -EINVAL ; + size = (1<<size) ; /* now in bytes */ + if (size > sq->bufSize) + return -EINVAL ; /* this might still not work */ + + if (bufs <= 0) + return -EINVAL ; + if (bufs > sq->numBufs) /* the user is allowed say "don't care" with 0x7fff */ + bufs = sq->numBufs ; + + /* there is, currently, no way to specify max_active separately + from max_count. This could be a LL driver issue - I guess + if there is a requirement for these values to be different then + we will have to pass that info. up to this level. + */ + sq->user_frags = + sq->max_active = bufs ; + sq->user_frag_size = size ; + + return 0 ; +} + static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { - int val; + int val, result; u_long fmt; int data; int size, nbufs; @@ -937,85 +1165,167 @@ case SNDCTL_DSP_RESET: sq_reset(); return 0; + break ; + case SNDCTL_DSP_GETFMTS: + fmt = dmasound.mach.hardware_afmts ; /* this is what OSS says.. */ + return IOCTL_OUT(arg, fmt); + break ; + case SNDCTL_DSP_GETBLKSIZE: + /* this should tell the caller about bytes that the app can + read/write - the app doesn't care about our internal buffers. + We force sq_setup() here as per OSS 1.1 (which should + compute the values necessary). + Since there is no mechanism to specify read/write separately, for + fds opened O_RDWR, the write_sq values will, arbitrarily, overwrite + the read_sq ones. + */ + size = 0 ; +#ifdef HAS_RECORD + if (dmasound.mach.record && (file->f_mode & FMODE_READ)) { + if ( !read_sq.locked ) + sq_setup(&read_sq) ; /* set params */ + size = read_sq.user_frag_size ; + } +#endif + if (file->f_mode & FMODE_WRITE) { + if ( !write_sq.locked ) + sq_setup(&write_sq) ; + size = write_sq.user_frag_size ; + } + return IOCTL_OUT(arg, size); + break ; case SNDCTL_DSP_POST: + /* all we are going to do is to tell the LL that any + partial frags can be queued for output. + The LL will have to clear this flag when last output + is queued. + */ + write_sq.syncing |= 0x2 ; + sq_play() ; + return 0 ; case SNDCTL_DSP_SYNC: - return sq_fsync(file, file->f_dentry); - - /* ++TeSche: before changing any of these it's - * probably wise to wait until sound playing has - * settled down. */ + /* This call, effectively, has the same behaviour as SNDCTL_DSP_RESET + except that it waits for output to finish before resetting + everything - read, however, is killed imediately. + */ + result = 0 ; +#ifdef HAS_RECORD + if ((file->f_mode & FMODE_READ) && dmasound.mach.record) + sq_reset_input() ; +#endif + if (file->f_mode & FMODE_WRITE) { + result = sq_fsync(file, file->f_dentry); + sq_reset_output() ; + } + /* if we are the shared resource owner then release them */ + if (file->f_mode & shared_resource_owner) + shared_resources_initialised = 0 ; + return result ; + break ; case SNDCTL_DSP_SPEED: - sq_fsync(file, file->f_dentry); - IOCTL_IN(arg, data); - return IOCTL_OUT(arg, sound_set_speed(data)); + /* changing this on the fly will have wierd effects on the sound. + Where there are rate conversions implemented in soft form - it + will cause the _ctx_xxx() functions to be substituted. + However, there doesn't appear to be any reason to dis-allow it from + a driver pov. + */ + if (shared_resources_are_mine(file->f_mode)) { + IOCTL_IN(arg, data); + data = sound_set_speed(data) ; + shared_resources_initialised = 0 ; + return IOCTL_OUT(arg, data); + } else + return -EINVAL ; + break ; + /* OSS says these next 4 actions are undefined when the device is + busy/active - we will just return -EINVAL. + To be allowed to change one - (a) you have to own the right + (b) the queue(s) must be quiescent + */ case SNDCTL_DSP_STEREO: - sq_fsync(file, file->f_dentry); - IOCTL_IN(arg, data); - return IOCTL_OUT(arg, sound_set_stereo(data)); + if (shared_resources_are_mine(file->f_mode) && + queues_are_quiescent()) { + IOCTL_IN(arg, data); + shared_resources_initialised = 0 ; + return IOCTL_OUT(arg, sound_set_stereo(data)); + } else + return -EINVAL ; + break ; case SOUND_PCM_WRITE_CHANNELS: - sq_fsync(file, file->f_dentry); - IOCTL_IN(arg, data); - return IOCTL_OUT(arg, sound_set_stereo(data-1)+1); + if (shared_resources_are_mine(file->f_mode) && + queues_are_quiescent()) { + IOCTL_IN(arg, data); + /* the user might ask for 20 channels, we will return 1 or 2 */ + shared_resources_initialised = 0 ; + return IOCTL_OUT(arg, sound_set_stereo(data-1)+1); + } else + return -EINVAL ; + break ; case SNDCTL_DSP_SETFMT: - sq_fsync(file, file->f_dentry); - IOCTL_IN(arg, data); - return IOCTL_OUT(arg, sound_set_format(data)); - case SNDCTL_DSP_GETFMTS: - fmt = 0; - if (dmasound.trans_write) { - if (dmasound.trans_write->ct_ulaw) - fmt |= AFMT_MU_LAW; - if (dmasound.trans_write->ct_alaw) - fmt |= AFMT_A_LAW; - if (dmasound.trans_write->ct_s8) - fmt |= AFMT_S8; - if (dmasound.trans_write->ct_u8) - fmt |= AFMT_U8; - if (dmasound.trans_write->ct_s16be) - fmt |= AFMT_S16_BE; - if (dmasound.trans_write->ct_u16be) - fmt |= AFMT_U16_BE; - if (dmasound.trans_write->ct_s16le) - fmt |= AFMT_S16_LE; - if (dmasound.trans_write->ct_u16le) - fmt |= AFMT_U16_LE; - } - return IOCTL_OUT(arg, fmt); - case SNDCTL_DSP_GETBLKSIZE: - size = write_sq.block_size - * dmasound.soft.size * (dmasound.soft.stereo + 1) - / (dmasound.hard.size * (dmasound.hard.stereo + 1)); - return IOCTL_OUT(arg, size); + if (shared_resources_are_mine(file->f_mode) && + queues_are_quiescent()) { + int format; + IOCTL_IN(arg, data); + shared_resources_initialised = 0 ; + format = sound_set_format(data); + result = IOCTL_OUT(arg, format); + if (result < 0) + return result; + if (format != data) + return -EINVAL; + return 0; + } else + return -EINVAL ; + break ; case SNDCTL_DSP_SUBDIVIDE: + return -EINVAL ; break; case SNDCTL_DSP_SETFRAGMENT: - if (write_sq.count || write_sq.active || write_sq.syncing) - return -EINVAL; - IOCTL_IN(arg, size); - nbufs = size >> 16; - if (nbufs < 2 || nbufs > write_sq.numBufs) - nbufs = write_sq.numBufs; - size &= 0xffff; - if (size >= 8 && size <= 29) { - size = 1 << size; - size *= dmasound.hard.size * (dmasound.hard.stereo + 1); - size /= dmasound.soft.size * (dmasound.soft.stereo + 1); - if (size > write_sq.bufSize) - size = write_sq.bufSize; - } else - size = write_sq.bufSize; - sq_setup(&write_sq, write_sq.numBufs, nbufs, size); - return IOCTL_OUT(arg,write_sq.bufSize | write_sq.numBufs << 16); + /* we can do this independently for the two queues - with the + proviso that for fds opened O_RDWR we cannot separate the + actions and both queues will be set per the last call. + NOTE: this does *NOT* actually set the queue up - merely + registers our intentions. + */ + IOCTL_IN(arg, data); + result = 0 ; + nbufs = (data >> 16) & 0x7fff ; /* 0x7fff is 'use maximum' */ + size = data & 0xffff; +#ifdef HAS_RECORD + if ((file->f_mode & FMODE_READ) && dmasound.mach.record) { + result = set_queue_frags(&read_sq, nbufs, size) ; + if (result) + return result ; + } +#endif + if (file->f_mode & FMODE_WRITE) { + result = set_queue_frags(&write_sq, nbufs, size) ; + if (result) + return result ; + } + /* NOTE: this return value is irrelevant - OSS specifically says that + the value is 'random' and that the user _must_ check the actual + frags values using SNDCTL_DSP_GETBLKSIZE or similar */ + return IOCTL_OUT(arg, data); + break ; case SNDCTL_DSP_GETOSPACE: - info.fragments = write_sq.max_active - write_sq.count; - info.fragstotal = write_sq.max_active; - info.fragsize = write_sq.block_size; - info.bytes = info.fragments * info.fragsize; - if (copy_to_user((void *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; + /* + */ + if (file->f_mode & FMODE_WRITE) { + if ( !write_sq.locked ) + sq_setup(&write_sq) ; + info.fragments = write_sq.max_active - write_sq.count; + info.fragstotal = write_sq.max_active; + info.fragsize = write_sq.user_frag_size; + info.bytes = info.fragments * info.fragsize; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } else + return -EINVAL ; + break ; case SNDCTL_DSP_GETCAPS: - val = 1; /* Revision level of this ioctl() */ + val = dmasound.mach.capabilities & 0xffffff00; return IOCTL_OUT(arg,val); default: @@ -1029,42 +1339,48 @@ owner: THIS_MODULE, llseek: no_llseek, write: sq_write, + poll: sq_poll, ioctl: sq_ioctl, open: sq_open, release: sq_release, #ifdef HAS_RECORD - read: sq_read, + read: NULL /* default to no read for compat mode */ #endif }; -static void __init sq_init(void) +static int __init sq_init(void) { #ifndef MODULE int sq_unit; #endif + +#ifdef HAS_RECORD + if (dmasound.mach.record) + sq_fops.read = sq_read ; +#endif sq_unit = register_sound_dsp(&sq_fops, -1); - if (sq_unit < 0) - return; + if (sq_unit < 0) { + printk(KERN_ERR "dmasound_core: couldn't register fops\n") ; + return sq_unit ; + } write_sq_init_waitqueue(); +#ifdef HAS_RECORD read_sq_init_waitqueue(); +#endif - /* whatever you like as startup mode for /dev/dsp, - * (/dev/audio hasn't got a startup mode). note that - * once changed a new open() will *not* restore these! + /* These parameters will be restored for every clean open() + * in the case of multiple open()s (e.g. dsp0 & dsp1) they + * will be set so long as the shared resources have no owner. */ - dmasound.dsp.format = AFMT_U8; - dmasound.dsp.stereo = 0; - dmasound.dsp.size = 8; - - /* set minimum rate possible without expanding */ - dmasound.dsp.speed = dmasound.mach.min_dsp_speed; - - /* before the first open to /dev/dsp this wouldn't be set */ - dmasound.soft = dmasound.dsp; - dmasound.hard = dmasound.dsp; - sound_silence(); + if (shared_resource_owner == 0) { + dmasound.soft = dmasound.mach.default_soft ; + dmasound.hard = dmasound.mach.default_hard ; + dmasound.dsp = dmasound.mach.default_soft ; + shared_resources_initialised = 0 ; + } + return 0 ; } @@ -1072,12 +1388,68 @@ * /dev/sndstat */ +/* we allow more space for record-enabled because there are extra output lines. + the number here must include the amount we are prepared to give to the low-level + driver. +*/ + +#ifdef HAS_RECORD +#define STAT_BUFF_LEN 1024 +#else +#define STAT_BUFF_LEN 768 +#endif + +/* this is how much space we will allow the low-level driver to use + in the stat buffer. Currently, 2 * (80 character line + <NL>). + We do not police this (it is up to the ll driver to be honest). +*/ + +#define LOW_LEVEL_STAT_ALLOC 162 + static struct { int busy; - char buf[512]; /* state.buf should not overflow! */ + char buf[STAT_BUFF_LEN]; /* state.buf should not overflow! */ int len, ptr; } state; +/* publish this function for use by low-level code, if required */ + +char *get_afmt_string(int afmt) +{ + switch(afmt) { + case AFMT_MU_LAW: + return "mu-law"; + break; + case AFMT_A_LAW: + return "A-law"; + break; + case AFMT_U8: + return "unsigned 8 bit"; + break; + case AFMT_S8: + return "signed 8 bit"; + break; + case AFMT_S16_BE: + return "signed 16 bit BE"; + break; + case AFMT_U16_BE: + return "unsigned 16 bit BE"; + break; + case AFMT_S16_LE: + return "signed 16 bit LE"; + break; + case AFMT_U16_LE: + return "unsigned 16 bit LE"; + break; + case 0: + return "format not set" ; + break ; + default: + break ; + } + return "ERROR: Unsupported AFMT_XXXX code" ; +} + static int state_open(struct inode *inode, struct file *file) { char *buffer = state.buf; @@ -1090,52 +1462,76 @@ state.ptr = 0; state.busy = 1; - len += sprintf(buffer+len, "%sDMA sound driver:\n", dmasound.mach.name); + len += sprintf(buffer+len, "%sDMA sound driver rev %03d :\n", + dmasound.mach.name, (DMASOUND_CORE_REVISION<<4) + + ((dmasound.mach.version>>8) & 0x0f)); + len += sprintf(buffer+len, + "Core driver edition %02d.%02d : %s driver edition %02d.%02d\n", + DMASOUND_CORE_REVISION, DMASOUND_CORE_EDITION, dmasound.mach.name2, + (dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ; + + /* call the low-level module to fill in any stat info. that it has + if present. Maximum buffer usage is specified. + */ - len += sprintf(buffer+len, "\tsound.format = 0x%x", - dmasound.soft.format); - switch (dmasound.soft.format) { - case AFMT_MU_LAW: - len += sprintf(buffer+len, " (mu-law)"); - break; - case AFMT_A_LAW: - len += sprintf(buffer+len, " (A-law)"); - break; - case AFMT_U8: - len += sprintf(buffer+len, " (unsigned 8 bit)"); - break; - case AFMT_S8: - len += sprintf(buffer+len, " (signed 8 bit)"); - break; - case AFMT_S16_BE: - len += sprintf(buffer+len, " (signed 16 bit big)"); - break; - case AFMT_U16_BE: - len += sprintf(buffer+len, " (unsigned 16 bit big)"); - break; - case AFMT_S16_LE: - len += sprintf(buffer+len, " (signed 16 bit little)"); - break; - case AFMT_U16_LE: - len += sprintf(buffer+len, " (unsigned 16 bit little)"); - break; - } - len += sprintf(buffer+len, "\n"); - len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n", - dmasound.soft.speed, dmasound.hard.speed); - len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n", - dmasound.soft.stereo, - dmasound.soft.stereo ? "stereo" : "mono"); if (dmasound.mach.state_info) - len += dmasound.mach.state_info(buffer); - len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d" - " sq.max_active = %d\n", - write_sq.block_size, write_sq.max_count, - write_sq.max_active); - len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", - write_sq.count, write_sq.rear_size); - len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n", - write_sq.active, write_sq.syncing); + len += dmasound.mach.state_info(buffer+len, + (size_t) LOW_LEVEL_STAT_ALLOC) ; + + /* make usage of the state buffer as deterministic as poss. + exceptional conditions could cause overrun - and this is flagged as + a kernel error. + */ + + /* formats and settings */ + + len += sprintf(buffer+len,"\t\t === Formats & settings ===\n") ; + len += sprintf(buffer+len,"Parameter %20s%20s\n","soft","hard") ; + len += sprintf(buffer+len,"Format :%20s%20s\n", + get_afmt_string(dmasound.soft.format), + get_afmt_string(dmasound.hard.format)); + + len += sprintf(buffer+len,"Samp Rate:%14d s/sec%14d s/sec\n", + dmasound.soft.speed, dmasound.hard.speed); + + len += sprintf(buffer+len,"Channels :%20s%20s\n", + dmasound.soft.stereo ? "stereo" : "mono", + dmasound.hard.stereo ? "stereo" : "mono" ); + + /* sound queue status */ + + len += sprintf(buffer+len,"\t\t === Sound Queue status ===\n"); + len += sprintf(buffer+len,"Allocated:%8s%6s\n","Buffers","Size") ; + len += sprintf(buffer+len,"%9s:%8d%6d\n", + "write", write_sq.numBufs, write_sq.bufSize) ; +#ifdef HAS_RECORD + if (dmasound.mach.record) + len += sprintf(buffer+len,"%9s:%8d%6d\n", + "read", read_sq.numBufs, read_sq.bufSize) ; +#endif + len += sprintf(buffer+len, + "Current : MaxFrg FragSiz MaxAct Frnt Rear " + "Cnt RrSize A B S L xruns\n") ; + len += sprintf(buffer+len,"%9s:%7d%8d%7d%5d%5d%4d%7d%2d%2d%2d%2d%7d\n", + "write", write_sq.max_count, write_sq.block_size, + write_sq.max_active, write_sq.front, write_sq.rear, + write_sq.count, write_sq.rear_size, write_sq.active, + write_sq.busy, write_sq.syncing, write_sq.locked, write_sq.xruns) ; +#ifdef HAS_RECORD + if (dmasound.mach.record) + len += sprintf(buffer+len,"%9s:%7d%8d%7d%5d%5d%4d%7d%2d%2d%2d%2d%7d\n", + "read", read_sq.max_count, read_sq.block_size, + read_sq.max_active, read_sq.front, read_sq.rear, + read_sq.count, read_sq.rear_size, read_sq.active, + read_sq.busy, read_sq.syncing, read_sq.locked, read_sq.xruns) ; +#endif +#ifdef DEBUG_DMASOUND +printk("dmasound: stat buffer used %d bytes\n", len) ; +#endif + + if (len >= STAT_BUFF_LEN) + printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n"); + state.len = len; return 0; } @@ -1171,15 +1567,16 @@ release: state_release, }; -static void __init state_init(void) +static int __init state_init(void) { #ifndef MODULE int state_unit; #endif state_unit = register_sound_special(&state_fops, SND_DEV_STATUS); if (state_unit < 0) - return; + return state_unit ; state.busy = 0; + return 0 ; } @@ -1191,6 +1588,7 @@ int __init dmasound_init(void) { + int res ; #ifdef MODULE if (irq_installed) return -EBUSY; @@ -1199,10 +1597,12 @@ /* Set up sound queue, /dev/audio and /dev/dsp. */ /* Set default settings. */ - sq_init(); + if ((res = sq_init()) < 0) + return res ; /* Set up /dev/sndstat. */ - state_init(); + if ((res = state_init()) < 0) + return res ; /* Set up /dev/mixer. */ mixer_init(); @@ -1215,8 +1615,21 @@ irq_installed = 1; #endif - printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n", - numWriteBufs, writeBufSize); + printk(KERN_INFO "%s DMA sound driver rev %03d installed\n", + dmasound.mach.name, (DMASOUND_CORE_REVISION<<4) + + ((dmasound.mach.version>>8) & 0x0f)); + printk(KERN_INFO + "Core driver edition %02d.%02d : %s driver edition %02d.%02d\n", + DMASOUND_CORE_REVISION, DMASOUND_CORE_EDITION, dmasound.mach.name2, + (dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ; + printk(KERN_INFO "Write will use %4d fragments of %7d bytes as default\n", + numWriteBufs, writeBufSize) ; +#ifdef HAS_RECORD + if (dmasound.mach.record) + printk(KERN_INFO + "Read will use %4d fragments of %7d bytes as default\n", + numReadBufs, readBufSize) ; +#endif return 0; } @@ -1228,6 +1641,7 @@ if (irq_installed) { sound_silence(); dmasound.mach.irqcleanup(); + irq_installed = 0; } write_sq_release_buffers(); @@ -1245,29 +1659,60 @@ static int __init dmasound_setup(char *str) { - int ints[6]; + int ints[6], size; str = get_options(str, ARRAY_SIZE(ints), ints); /* check the bootstrap parameter for "dmasound=" */ + /* FIXME: other than in the most naive of cases there is no sense in these + * buffers being other than powers of two. This is not checked yet. + */ + switch (ints[0]) { +#ifdef HAS_RECORD + case 5: + if ((ints[5] < 0) || (ints[5] > MAX_CATCH_RADIUS)) + printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); + else + catchRadius = ints[5]; + /* fall through */ + case 4: + if (ints[4] < MIN_BUFFERS) + printk("dmasound_setup: illegal number of read buffers, using default = %d\n", + numReadBufs); + else + numReadBufs = ints[4]; + /* fall through */ + case 3: + if ((size = ints[3]) < 256) /* check for small buffer specs */ + size <<= 10 ; + if (size < MIN_BUFSIZE || size > MAX_BUFSIZE) + printk("dmasound_setup: illegal read buffer size, using default = %d\n", readBufSize); + else + readBufSize = size; + /* fall through */ +#else case 3: if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); else catchRadius = ints[3]; /* fall through */ +#endif case 2: if (ints[1] < MIN_BUFFERS) printk("dmasound_setup: illegal number of buffers, using default = %d\n", numWriteBufs); else numWriteBufs = ints[1]; - if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) - printk("dmasound_setup: illegal buffer size, using default = %dK\n", writeBufSize); - else - writeBufSize = ints[2]; - break; + /* fall through */ + case 1: + if ((size = ints[2]) < 256) /* check for small buffer specs */ + size <<= 10 ; + if (size < MIN_BUFSIZE || size > MAX_BUFSIZE) + printk("dmasound_setup: illegal write buffer size, using default = %d\n", writeBufSize); + else + writeBufSize = size; case 0: break; default: @@ -1281,6 +1726,85 @@ #endif /* !MODULE */ + /* + * Conversion tables + */ + +#ifdef HAS_8BIT_TABLES +/* 8 bit mu-law */ + +char dmasound_ulaw2dma8[] = { + -126, -122, -118, -114, -110, -106, -102, -98, + -94, -90, -86, -82, -78, -74, -70, -66, + -63, -61, -59, -57, -55, -53, -51, -49, + -47, -45, -43, -41, -39, -37, -35, -33, + -31, -30, -29, -28, -27, -26, -25, -24, + -23, -22, -21, -20, -19, -18, -17, -16, + -16, -15, -15, -14, -14, -13, -13, -12, + -12, -11, -11, -10, -10, -9, -9, -8, + -8, -8, -7, -7, -7, -7, -6, -6, + -6, -6, -5, -5, -5, -5, -4, -4, + -4, -4, -4, -4, -3, -3, -3, -3, + -3, -3, -3, -3, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 0, + 125, 121, 117, 113, 109, 105, 101, 97, + 93, 89, 85, 81, 77, 73, 69, 65, + 62, 60, 58, 56, 54, 52, 50, 48, + 46, 44, 42, 40, 38, 36, 34, 32, + 30, 29, 28, 27, 26, 25, 24, 23, + 22, 21, 20, 19, 18, 17, 16, 15, + 15, 14, 14, 13, 13, 12, 12, 11, + 11, 10, 10, 9, 9, 8, 8, 7, + 7, 7, 6, 6, 6, 6, 5, 5, + 5, 5, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* 8 bit A-law */ + +char dmasound_alaw2dma8[] = { + -22, -21, -24, -23, -18, -17, -20, -19, + -30, -29, -32, -31, -26, -25, -28, -27, + -11, -11, -12, -12, -9, -9, -10, -10, + -15, -15, -16, -16, -13, -13, -14, -14, + -86, -82, -94, -90, -70, -66, -78, -74, + -118, -114, -126, -122, -102, -98, -110, -106, + -43, -41, -47, -45, -35, -33, -39, -37, + -59, -57, -63, -61, -51, -49, -55, -53, + -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -6, -6, -6, -6, -5, -5, -5, -5, + -8, -8, -8, -8, -7, -7, -7, -7, + -3, -3, -3, -3, -3, -3, -3, -3, + -4, -4, -4, -4, -4, -4, -4, -4, + 21, 20, 23, 22, 17, 16, 19, 18, + 29, 28, 31, 30, 25, 24, 27, 26, + 10, 10, 11, 11, 8, 8, 9, 9, + 14, 14, 15, 15, 12, 12, 13, 13, + 86, 82, 94, 90, 70, 66, 78, 74, + 118, 114, 126, 122, 102, 98, 110, 106, + 43, 41, 47, 45, 35, 33, 39, 37, + 59, 57, 63, 61, 51, 49, 55, 53, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 4, 4, 4, 4, + 7, 7, 7, 7, 6, 6, 6, 6, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 +}; +#endif /* HAS_8BIT_TABLES */ /* * Visible symbols for modules @@ -1300,14 +1824,4 @@ EXPORT_SYMBOL(dmasound_ulaw2dma8); EXPORT_SYMBOL(dmasound_alaw2dma8); #endif -#ifdef HAS_16BIT_TABLES -EXPORT_SYMBOL(dmasound_ulaw2dma16); -EXPORT_SYMBOL(dmasound_alaw2dma16); -#endif -#ifdef HAS_14BIT_TABLES -EXPORT_SYMBOL(dmasound_ulaw2dma14l); -EXPORT_SYMBOL(dmasound_ulaw2dma14h); -EXPORT_SYMBOL(dmasound_alaw2dma14l); -EXPORT_SYMBOL(dmasound_alaw2dma14h); -#endif - +EXPORT_SYMBOL(get_afmt_string) ; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/dmasound_paula.c linux-2.5/drivers/sound/dmasound/dmasound_paula.c --- linux-2.5.1/drivers/sound/dmasound/dmasound_paula.c Thu Oct 25 20:53:52 2001 +++ linux-2.5/drivers/sound/dmasound/dmasound_paula.c Thu Dec 27 16:32:31 2001 @@ -1,11 +1,18 @@ - /* * linux/drivers/sound/dmasound/dmasound_paula.c * * Amiga `Paula' DMA Sound Driver * * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits - */ + * prior to 28/01/2001 + * + * 28/01/2001 [0.1] Iain Sandoe + * - added versioning + * - put in and populated the hardware_afmts field. + * [0.2] - put in SNDCTL_DSP_GETCAPS value. + * [0.3] - put in constraint on state buffer usage. + * [0.4] - put in default hard/soft settings +*/ #include <linux/module.h> @@ -23,6 +30,8 @@ #include "dmasound.h" +#define DMASOUND_PAULA_REVISION 0 +#define DMASOUND_PAULA_EDITION 4 /* * The minimum period for audio depends on htotal (for OCS/ECS/AGA) @@ -114,7 +123,7 @@ static void AmiMixerInit(void); static int AmiMixerIoctl(u_int cmd, u_long arg); static void AmiWriteSqSetup(void); -static int AmiStateInfo(char *buffer); +static int AmiStateInfo(char *buffer, size_t space); /*** Translations ************************************************************/ @@ -653,19 +662,36 @@ } -static int AmiStateInfo(char *buffer) +static int AmiStateInfo(char *buffer, size_t space) { int len = 0; len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n", dmasound.volume_left); len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n", dmasound.volume_right); + if (len >= space) { + printk(KERN_ERR "dmasound_paula: overlowed state buffer alloc.\n") ; + len = space ; + } return len; } /*** Machine definitions *****************************************************/ +static SETTINGS def_hard = { + format: AFMT_S8, + stereo: 0, + size: 8, + speed: 8000 +} ; + +static SETTINGS def_soft = { + format: AFMT_U8, + stereo: 0, + size: 8, + speed: 8000 +} ; static MACHINE machAmiga = { name: "Amiga", @@ -688,7 +714,10 @@ mixer_ioctl: AmiMixerIoctl, write_sq_setup: AmiWriteSqSetup, state_info: AmiStateInfo, - min_dsp_speed: 8000 + min_dsp_speed: 8000, + version: ((DMASOUND_PAULA_REVISION<<8) | DMASOUND_PAULA_EDITION), + hardware_afmts: (AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */ + capabilities: DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */ }; @@ -704,6 +733,8 @@ "dmasound [Paula]")) return -EBUSY; dmasound.mach = machAmiga; + dmasound.mach.default_hard = def_hard ; + dmasound.mach.default_soft = def_soft ; err = dmasound_init(); if (err) release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/dmasound_q40.c linux-2.5/drivers/sound/dmasound/dmasound_q40.c --- linux-2.5.1/drivers/sound/dmasound/dmasound_q40.c Thu Oct 25 20:53:52 2001 +++ linux-2.5/drivers/sound/dmasound/dmasound_q40.c Thu Dec 27 16:32:31 2001 @@ -1,10 +1,16 @@ - /* * linux/drivers/sound/dmasound/dmasound_q40.c * * Q40 DMA Sound Driver * * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits + * prior to 28/01/2001 + * + * 28/01/2001 [0.1] Iain Sandoe + * - added versioning + * - put in and populated the hardware_afmts field. + * [0.2] - put in SNDCTL_DSP_GETCAPS value. + * [0.3] - put in default hard/soft settings. */ @@ -18,6 +24,8 @@ #include "dmasound.h" +#define DMASOUND_Q40_REVISION 0 +#define DMASOUND_Q40_EDITION 3 static int expand_bal; /* Balance factor for expanding (not volume!) */ static int expand_data; /* Data for expanding */ @@ -216,7 +224,7 @@ int bal = expand_bal; int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; int utotal, ftotal; - + ftotal = frameLeft; utotal = userCount; while (frameLeft) { @@ -390,7 +398,7 @@ q40_pp=start; q40_sc=size; - + write_sq.front = (write_sq.front+1) % write_sq.max_count; write_sq.active++; @@ -446,7 +454,7 @@ *DAC_LEFT=*q40_pp; *DAC_RIGHT=*q40_pp++; q40_sc --; - master_outb(1,SAMPLE_CLEAR_REG); + master_outb(1,SAMPLE_CLEAR_REG); }else Q40Interrupt(); } static void Q40Interrupt(void) @@ -546,6 +554,19 @@ /*** Machine definitions *****************************************************/ +static SETTINGS def_hard = { + format: AFMT_U8, + stereo: 0, + size: 8, + speed: 10000 +} ; + +static SETTINGS def_soft = { + format: AFMT_U8, + stereo: 0, + size: 8, + speed: 8000 +} ; static MACHINE machQ40 = { name: "Q40", @@ -559,10 +580,13 @@ irqcleanup: Q40IrqCleanUp, #endif /* MODULE */ init: Q40Init, - silence: Q40Silence, - setFormat: Q40SetFormat, + silence: Q40Silence, + setFormat: Q40SetFormat, setVolume: Q40SetVolume, - play: Q40Play + play: Q40Play, + version: ((DMASOUND_Q40_REVISION<<8) | DMASOUND_Q40_EDITION), + hardware_afmts: AFMT_U8, /* h'ware-supported formats *only* here */ + capabilities: DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */ }; @@ -573,6 +597,8 @@ { if (MACH_IS_Q40) { dmasound.mach = machQ40; + dmasound.mach.default_hard = def_hard ; + dmasound.mach.default_soft = def_soft ; return dmasound_init(); } else return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/tas3001c.c linux-2.5/drivers/sound/dmasound/tas3001c.c --- linux-2.5.1/drivers/sound/dmasound/tas3001c.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/sound/dmasound/tas3001c.c Thu Dec 27 16:32:31 2001 @@ -0,0 +1,370 @@ +/* + * Driver for the i2c/i2s based TA3001C sound chip used + * on some Apple hardware. Also known as "tumbler". + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * Modified by Christopher C. Chimelis <chris@debian.org>: + * + * TODO: + * ----- + * * Enable DRC since the TiBook speakers are less than good + * * Enable control over input line 2 (is this connected?) + * * Play with the dual six-stage cascading biquad filtering to see how + * we can use it to our advantage (currently not implemented) + * + * Version 0.3: + * ------------ + * * Fixed volume control + * * Added bass and treble control + * * Added PCM line level control (mixer 1 in the TAS manual) + * + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include <linux/ioport.h> +#include <linux/sysctl.h> +#include <linux/types.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/prom.h> + +#include "dmasound.h" +#include "tas3001c.h" + +#define I2C_DRIVERID_TAS (0xFEBA) + +#define TAS_VERSION "0.3" +#define TAS_DATE "20011214" + +#define TAS_SETTING_MAX 100 + +#define VOL_DEFAULT (((TAS_SETTING_MAX*4)/5)<<0) +#define INPUT_DEFAULT (((TAS_SETTING_MAX*4)/5)<<0) +#define BASS_DEFAULT ((TAS_SETTING_MAX/2)<<0) +#define TREBLE_DEFAULT ((TAS_SETTING_MAX/2)<<0) + +static uint cur_left_vol; +static uint cur_right_vol; +static uint cur_pcm_lvl; +static uint cur_treble; +static uint cur_bass; + +static struct i2c_client * tumbler_client = NULL; + +static int tas_attach_adapter(struct i2c_adapter *adapter); + +static int tas_attach_adapter(struct i2c_adapter *adapter); +static int tas_detect_client(struct i2c_adapter *adapter, int address); +static int tas_detach_client(struct i2c_client *client); + +/* Unique ID allocation */ +static int tas_id; +static int tas_initialized; + +static struct device_node* tas_node; +static u8 tas_i2c_address = 0x34; + + +struct tas_data { + int arf; /* place holder for future use */ +}; + +struct i2c_driver tas_driver = { + name: "TAS3001C driver V 0.3", + id: I2C_DRIVERID_TAS, + flags: I2C_DF_NOTIFY, + attach_adapter: &tas_attach_adapter, + detach_client: &tas_detach_client, + command: NULL, + inc_use: NULL, /* &tas_inc_use, */ + dec_use: NULL /* &tas_dev_use */ +}; + +void +tumbler_get_volume(uint * left_vol, uint *right_vol) +{ + *left_vol = cur_left_vol; + *right_vol = cur_right_vol; +} + +int +tumbler_set_register(uint reg, uint size, char *block) +{ + if (i2c_smbus_write_block_data(tumbler_client, reg, size, block) < 0) { + printk("tas3001c: I2C write failed \n"); + return -1; + } + return 0; +} + +void +tumbler_get_pcm_lvl(uint *pcm_lvl) +{ + *pcm_lvl = cur_pcm_lvl; +} + +void +tumbler_get_treble(uint *treble) +{ + *treble = cur_treble; +} + +void +tumbler_get_bass(uint *bass) +{ + *bass = cur_bass; +} + +int +tumbler_set_bass(uint bass) +{ + uint cur_bass_pers = bass; + char block; + + if (!tumbler_client) + return -1; + + bass &= 0xff; + if (bass > TAS_SETTING_MAX) + bass = TAS_SETTING_MAX; + bass = ((bass * 72) / TAS_SETTING_MAX) << 0; + bass = tas_bass_table[bass]; + block = (bass >> 0) & 0xff; + + if (tumbler_set_register(TAS_SET_BASS, &block) < 0) { + printk("tas3001c: failed to set bass \n"); + return -1; + } + cur_bass = cur_bass_pers; + return 0; +} + +int +tumbler_set_treble(uint treble) +{ + uint cur_treble_pers = treble; + char block; + + if (!tumbler_client) + return -1; + + treble &= 0xff; + if (treble > TAS_SETTING_MAX) + treble = TAS_SETTING_MAX; + treble = ((treble * 72) / TAS_SETTING_MAX) << 0; + treble = tas_treble_table[treble]; + block = (treble >> 0) & 0xff; + + if (tumbler_set_register(TAS_SET_TREBLE, &block) < 0) { + printk("tas3001c: failed to set treble \n"); + return -1; + } + cur_treble = cur_treble_pers; + return 0; +} + +int +tumbler_set_pcm_lvl(uint pcm_lvl) +{ + uint pcm_lvl_pers = pcm_lvl; + unsigned char block[3]; + + if (!tumbler_client) + return -1; + + pcm_lvl &= 0xff; + if (pcm_lvl > TAS_SETTING_MAX) + pcm_lvl = TAS_SETTING_MAX; + pcm_lvl = ((pcm_lvl * 176) / TAS_SETTING_MAX) << 0; + + pcm_lvl = tas_input_table[pcm_lvl]; + + block[0] = (pcm_lvl >> 16) & 0xff; + block[1] = (pcm_lvl >> 8) & 0xff; + block[2] = (pcm_lvl >> 0) & 0xff; + + if (tumbler_set_register(TAS_SET_MIXER1, block) < 0) { + printk("tas3001c: failed to set input level \n"); + return -1; + } + cur_pcm_lvl = pcm_lvl_pers; + + return 0; +} + +int +tumbler_set_volume(uint left_vol, uint right_vol) +{ + uint left_vol_pers = left_vol; + uint right_vol_pers = right_vol; + unsigned char block[6]; + + if (!tumbler_client) + return -1; + + left_vol &= 0xff; + if (left_vol > TAS_SETTING_MAX) + left_vol = TAS_SETTING_MAX; + right_vol &= 0xff; + if (right_vol > TAS_SETTING_MAX) + right_vol = TAS_SETTING_MAX; + left_vol = ((left_vol * 176) / TAS_SETTING_MAX) << 0; + right_vol = ((right_vol * 176) / TAS_SETTING_MAX) << 0; + + left_vol = tas_volume_table[left_vol]; + right_vol = tas_volume_table[right_vol]; + + block[0] = (left_vol >> 16) & 0xff; + block[1] = (left_vol >> 8) & 0xff; + block[2] = (left_vol >> 0) & 0xff; + + block[3] = (right_vol >> 16) & 0xff; + block[4] = (right_vol >> 8) & 0xff; + block[5] = (right_vol >> 0) & 0xff; + + if (tumbler_set_register(TAS_SET_VOLUME, block) < 0) { + printk("tas3001c: failed to set volume \n"); + return -1; + } + cur_left_vol = left_vol_pers; + cur_right_vol = right_vol_pers; + + return 0; +} + +static int +tas_attach_adapter(struct i2c_adapter *adapter) +{ + if (!strncmp(adapter->name, "mac-io", 6)) + tas_detect_client(adapter, tas_i2c_address); + + return 0; +} + +static int +tas_init_client(struct i2c_client * new_client) +{ + /* Make sure something answers on the i2c bus + */ + + if (i2c_smbus_write_byte_data(new_client, 1, (1<<6)+(2<<4)+(2<<2)+0) < 0) + return -1; + + tumbler_client = new_client; + + tumbler_set_volume(VOL_DEFAULT, VOL_DEFAULT); + tumbler_set_pcm_lvl(INPUT_DEFAULT); + tumbler_set_bass(BASS_DEFAULT); + tumbler_set_treble(TREBLE_DEFAULT); + + return 0; +} + +static int +tas_detect_client(struct i2c_adapter *adapter, int address) +{ + int rc = 0; + struct i2c_client *new_client; + struct tas_data *data; + const char *client_name = "tas 3001c Digital Equalizer"; + + new_client = kmalloc( + sizeof(struct i2c_client) + sizeof(struct tas_data), + GFP_KERNEL); + if (!new_client) { + rc = -ENOMEM; + goto bail; + } + + /* This is tricky, but it will set the data to the right value. */ + new_client->data = new_client + 1; + data = (struct tas_data *) (new_client->data); + + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &tas_driver; + new_client->flags = 0; + + strcpy(new_client->name,client_name); + + new_client->id = tas_id++; /* Automatically unique */ + + if (tas_init_client(new_client)) { + rc = -ENODEV; + goto bail; + } + + /* Tell the i2c layer a new client has arrived */ + if (i2c_attach_client(new_client)) { + rc = -ENODEV; + goto bail; + } +bail: + if (rc && new_client) + kfree(new_client); + return rc; +} + +static int +tas_detach_client(struct i2c_client *client) +{ + if (client == tumbler_client) + tumbler_client = NULL; + + i2c_detach_client(client); + kfree(client); + + return 0; +} + +int +tas_cleanup(void) +{ + if (!tas_initialized) + return -ENODEV; + i2c_del_driver(&tas_driver); + tas_initialized = 0; + + return 0; +} + +int +tas_init(void) +{ + int rc; + u32* paddr; + + if (tas_initialized) + return 0; + + tas_node = find_devices("deq"); + if (tas_node == NULL) + return -ENODEV; + + printk(KERN_INFO "tas3001c driver version %s (%s)\n",TAS_VERSION,TAS_DATE); + paddr = (u32 *)get_property(tas_node, "i2c-address", NULL); + if (paddr) { + tas_i2c_address = (*paddr) >> 1; + printk(KERN_INFO "using i2c address: 0x%x from device-tree\n", + tas_i2c_address); + } else + printk(KERN_INFO "using i2c address: 0x%x (default)\n", tas_i2c_address); + + if ((rc = i2c_add_driver(&tas_driver))) { + printk("tas3001c: Driver registration failed, module not inserted.\n"); + tas_cleanup(); + return rc; + } + tas_initialized = 1; + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/tas3001c.h linux-2.5/drivers/sound/dmasound/tas3001c.h --- linux-2.5.1/drivers/sound/dmasound/tas3001c.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/sound/dmasound/tas3001c.h Thu Dec 27 16:32:31 2001 @@ -0,0 +1,248 @@ +/* + * Header file for the i2c/i2s based TA3001C sound chip used + * on some Apple hardware. Also known as "tumbler". + * + * 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. + * + * Written by Christopher C. Chimelis <chris@debian.org> + */ + +#ifndef _tas3001c_h_ +#define _tas3001c_h_ + +/* + * Macros that correspond to the registers that we write to + * when setting the various values. + */ +#define TAS_DRC 0x02 /* DRC */ +#define TAS_VOLUME 0x04 /* Volume */ +#define TAS_TREBLE 0x05 /* Treble */ +#define TAS_BASS 0x06 /* Bass */ +#define TAS_MIXER1 0x07 /* PCM line */ +#define TAS_MIXER2 0x08 /* Input (Unk) */ + +/* + * Macros that define various arguments to tas_set_register() + */ +#define TAS_SET_DRC TAS_DRC, 2 +#define TAS_SET_VOLUME TAS_VOLUME, 6 +#define TAS_SET_TREBLE TAS_TREBLE, 1 +#define TAS_SET_BASS TAS_BASS, 1 +#define TAS_SET_MIXER1 TAS_MIXER1, 3 +#define TAS_SET_MIXER2 TAS_MIXER2, 3 + + +/* + * tas_volume_table contains lookup values for the volume settings + * for tumbler. This is straight from the programming manual + * for the chip, however, it's zero-sourced for your shopping pleasure + * (meaning, you'll have to compute the difference between the desired + * dB and the index value of the proper setting. + * + * This table should've been replaced by the formula: + * dB = 20 log(x) + * but, since there's no log() or supporting functions like exp(), + * my implementation of the above won't work. Yeah, I could do it + * the hard way, but this table is just easier :-) + * + * For reference, -70 dB = tas_volume_table[0] + */ + +static unsigned int tas_volume_table[] = { + 0x00000015, 0x00000016, 0x00000017, /* -70.0, -69.5, -69.0 */ + 0x00000019, 0x0000001a, 0x0000001c, /* -68.5, -68.0, -67.5 */ + 0x0000001d, 0x0000001f, 0x00000021, /* -67.0, -66.5, -66.0 */ + 0x00000023, 0x00000025, 0x00000027, /* -65.5, -65.0, -64.5 */ + 0x00000029, 0x0000002c, 0x0000002e, /* -64.0, -63.5, -63.0 */ + 0x00000031, 0x00000034, 0x00000037, /* -62.5, -62.0, -61.5 */ + 0x0000003a, 0x0000003e, 0x00000042, /* -61.0, -60.5, -60.0 */ + 0x00000045, 0x0000004a, 0x0000004e, /* -59.5, -59.0, -58.5 */ + 0x00000053, 0x00000057, 0x0000005d, /* -58.0, -57.5, -57.0 */ + 0x00000062, 0x00000068, 0x0000006e, /* -56.5, -56.0, -55.5 */ + 0x00000075, 0x0000007b, 0x00000083, /* -55.0, -54.5, -54.0 */ + 0x0000008b, 0x00000093, 0x0000009b, /* -53.5, -53.0, -52.5 */ + 0x000000a5, 0x000000ae, 0x000000b9, /* -52.0, -51.5, -51.0 */ + 0x000000c4, 0x000000cf, 0x000000dc, /* -50.5, -50.0, -49.5 */ + 0x000000e9, 0x000000f6, 0x00000105, /* -49.0, -48.5, -48.0 */ + 0x00000114, 0x00000125, 0x00000136, /* -47.5, -47.0, -46.5 */ + 0x00000148, 0x0000015c, 0x00000171, /* -46.0, -45.5, -45.0 */ + 0x00000186, 0x0000019e, 0x000001b6, /* -44.5, -44.0, -43.5 */ + 0x000001d0, 0x000001eb, 0x00000209, /* -43.0, -42.5, -42.0 */ + 0x00000227, 0x00000248, 0x0000026b, /* -41.5, -41.0, -40.5 */ + 0x0000028f, 0x000002b6, 0x000002df, /* -40.0, -39.5, -39.0 */ + 0x0000030b, 0x00000339, 0x0000036a, /* -38.5, -38.0, -37.5 */ + 0x0000039e, 0x000003d5, 0x0000040f, /* -37.0, -36.5, -36.0 */ + 0x0000044c, 0x0000048d, 0x000004d2, /* -35.5, -35.0, -34.5 */ + 0x0000051c, 0x00000569, 0x000005bb, /* -34.0, -33.5, -33.0 */ + 0x00000612, 0x0000066e, 0x000006d0, /* -32.5, -32.0, -31.5 */ + 0x00000737, 0x000007a5, 0x00000818, /* -31.0, -30.5, -30.0 */ + 0x00000893, 0x00000915, 0x0000099f, /* -29.5, -29.0, -28.5 */ + 0x00000a31, 0x00000acc, 0x00000b6f, /* -28.0, -27.5, -27.0 */ + 0x00000c1d, 0x00000cd5, 0x00000d97, /* -26.5, -26.0, -25.5 */ + 0x00000e65, 0x00000f40, 0x00001027, /* -25.0, -24.5, -24.0 */ + 0x0000111c, 0x00001220, 0x00001333, /* -23.5, -23.0, -22.5 */ + 0x00001456, 0x0000158a, 0x000016d1, /* -22.0, -21.5, -21.0 */ + 0x0000182b, 0x0000199a, 0x00001b1e, /* -20.5, -20.0, -19.5 */ + 0x00001cb9, 0x00001e6d, 0x0000203a, /* -19.0, -18.5, -18.0 */ + 0x00002223, 0x00002429, 0x0000264e, /* -17.5, -17.0, -16.5 */ + 0x00002893, 0x00002afa, 0x00002d86, /* -16.0, -15.5, -15.0 */ + 0x00003039, 0x00003314, 0x0000361b, /* -14.5, -14.0, -13.5 */ + 0x00003950, 0x00003cb5, 0x0000404e, /* -13.0, -12.5, -12.0 */ + 0x0000441d, 0x00004827, 0x00004c6d, /* -11.5, -11.0, -10.5 */ + 0x000050f4, 0x000055c0, 0x00005ad5, /* -10.0, -09.5, -09.0 */ + 0x00006037, 0x000065ea, 0x00006bf4, /* -08.5, -08.0, -07.5 */ + 0x0000725a, 0x00007920, 0x0000804e, /* -07.0, -06.5, -06.0 */ + 0x000087e8, 0x00008ff6, 0x0000987d, /* -05.5, -05.0, -04.5 */ + 0x0000a186, 0x0000ab19, 0x0000b53c, /* -04.0, -03.5, -03.0 */ + 0x0000bff9, 0x0000cb59, 0x0000d766, /* -02.5, -02.0, -01.5 */ + 0x0000e429, 0x0000f1ae, 0x00010000, /* -01.0, -00.5, 00.0 */ + 0x00010f2b, 0x00011f3d, 0x00013042, /* +00.5, +01.0, +01.5 */ + 0x00014249, 0x00015562, 0x0001699c, /* +02.0, +02.5, +03.0 */ + 0x00017f09, 0x000195bc, 0x0001adc6, /* +03.5, +04.0, +04.5 */ + 0x0001c73d, 0x0001e237, 0x0001feca, /* +05.0, +05.5, +06.0 */ + 0x00021d0e, 0x00023d1d, 0x00025f12, /* +06.5, +07.0, +07.5 */ + 0x0002830b, 0x0002a925, 0x0002d182, /* +08.0, +08.5, +09.0 */ + 0x0002fc42, 0x0003298b, 0x00035983, /* +09.5, +10.0, +10.5 */ + 0x00038c53, 0x0003c225, 0x0003fb28, /* +11.0, +11.5, +12.0 */ + 0x0004378b, 0x00047783, 0x0004bb44, /* +12.5, +13.0, +13.5 */ + 0x0005030a, 0x00054f10, 0x00059f98, /* +14.0, +14.5, +15.0 */ + 0x0005f4e5, 0x00064f40, 0x0006aef6, /* +15.5, +16.0, +16.5 */ + 0x00071457, 0x00077fbb, 0x0007f17b /* +17.0, +17.5, +18.0 */ +}; + +/* tas_treble_table[] is a lookup table that holds the values to drop into + * the treble setting register on the TAS. Again, there is a formula for + * this one, but we use this instead due to lack of real math functions + * in the kernel. + */ +static char tas_treble_table[] = { + 0x96, 0x95, 0x94, /* -18.0, -17.5, -17.0 */ + 0x93, 0x92, 0x91, /* -16.5, -16.0, -15.5 */ + 0x90, 0x8f, 0x8e, /* -15.0, -14.5, -14.0 */ + 0x8d, 0x8c, 0x8b, /* -13.5, -13.0, -12.5 */ + 0x8a, 0x89, 0x88, /* -12.0, -11.5, -11.0 */ + 0x87, 0x86, 0x85, /* -10.5, -10.0, -09.5 */ + 0x84, 0x83, 0x82, /* -09.0, -08.5, -08.0 */ + 0x81, 0x80, 0x7f, /* -07.5, -07.0, -06.5 */ + 0x7e, 0x7d, 0x7c, /* -06.0, -05.5, -05.0 */ + 0x7b, 0x7a, 0x79, /* -04.5, -04.0, -03.5 */ + 0x78, 0x77, 0x76, /* -03.0, -02.5, -02.0 */ + 0x75, 0x74, 0x73, /* -01.5, -01.0, -00.5 */ + 0x72, 0x71, 0x70, /* 00.0, +00.5, +01.0 */ + 0x6e, 0x6d, 0x6c, /* +01.5, +02.0, +02.5 */ + 0x6b, 0x69, 0x68, /* +03.0, +03.5, +04.0 */ + 0x66, 0x65, 0x63, /* +04.5, +05.0, +05.5 */ + 0x62, 0x60, 0x5e, /* +06.0, +06.5, +07.0 */ + 0x5c, 0x5a, 0x57, /* +07.5, +08.0, +08.5 */ + 0x55, 0x52, 0x4f, /* +09.0, +09.5, +10.0 */ + 0x4c, 0x49, 0x45, /* +10.5, +11.0, +11.5 */ + 0x42, 0x3e, 0x3a, /* +12.0, +12.5, +13.0 */ + 0x36, 0x32, 0x2d, /* +13.5, +14.0, +14.5 */ + 0x28, 0x22, 0x1c, /* +15.0, +15.5, +16.0 */ + 0x16, 0x10, 0x09, /* +16.5, +17.0, +17.5 */ + 0x01 /* +18.0 */ +}; + +/* tas_bass_table[] is a lookup table that holds the values to drop into + * the bass setting register on the TAS. Again, there is a formula for + * this one, but we use this instead due to lack of real math functions + * in the kernel. + */ +static char tas_bass_table[] = { + 0x86, 0x82, 0x7f, /* -18.0, -17.5, -17.0 */ + 0x7d, 0x7a, 0x78, /* -16.5, -16.0, -15.5 */ + 0x76, 0x74, 0x72, /* -15.0, -14.5, -14.0 */ + 0x70, 0x6e, 0x6d, /* -13.5, -13.0, -12.5 */ + 0x6b, 0x69, 0x66, /* -12.0, -11.5, -11.0 */ + 0x64, 0x61, 0x5f, /* -10.5, -10.0, -09.5 */ + 0x5d, 0x5c, 0x5a, /* -09.0, -08.5, -08.0 */ + 0x59, 0x58, 0x56, /* -07.5, -07.0, -06.5 */ + 0x55, 0x54, 0x53, /* -06.0, -05.5, -05.0 */ + 0x51, 0x4f, 0x4d, /* -04.5, -04.0, -03.5 */ + 0x4b, 0x49, 0x46, /* -03.0, -02.5, -02.0 */ + 0x44, 0x42, 0x40, /* -01.5, -01.0, -00.5 */ + 0x3e, 0x3c, 0x3b, /* 00.0, +00.5, +01.0 */ + 0x39, 0x38, 0x36, /* +01.5, +02.0, +02.5 */ + 0x35, 0x33, 0x31, /* +03.0, +03.5, +04.0 */ + 0x30, 0x2e, 0x2c, /* +04.5, +05.0, +05.5 */ + 0x2b, 0x29, 0x28, /* +06.0, +06.5, +07.0 */ + 0x26, 0x25, 0x23, /* +07.5, +08.0, +08.5 */ + 0x21, 0x1f, 0x1c, /* +09.0, +09.5, +10.0 */ + 0x19, 0x18, 0x17, /* +10.5, +11.0, +11.5 */ + 0x16, 0x14, 0x13, /* +12.0, +12.5, +13.0 */ + 0x12, 0x10, 0x0f, /* +13.5, +14.0, +14.5 */ + 0x0d, 0x0b, 0x0a, /* +15.0, +15.5, +16.0 */ + 0x08, 0x06, 0x03, /* +16.5, +17.0, +17.5 */ + 0x01 /* +18.0 */ +}; + +/* tas_input_table[] is a lookup table that holds the values to drop into + * the setting registers on the TAS for "mixers 1 & 2" (which are the input + * lines). Again, there is a formula for these, but we use this instead + * due to lack of real math functions in the kernel. + */ +static unsigned int tas_input_table[] = { + 0x00014b, 0x00015f, 0x000174, /* -70.0, -69.5, -69.0 */ + 0x00018a, 0x0001a1, 0x0001ba, /* -68.5, -68.0, -67.5 */ + 0x0001d4, 0x0001f0, 0x00020d, /* -67.0, -66.5, -66.0 */ + 0x00022c, 0x00024d, 0x000270, /* -65.5, -65.0, -64.5 */ + 0x000295, 0x0002bc, 0x0002e6, /* -64.0, -63.5, -63.0 */ + 0x000312, 0x000340, 0x000372, /* -62.5, -62.0, -61.5 */ + 0x0003a6, 0x0003dd, 0x000418, /* -61.0, -60.5, -60.0 */ + 0x000456, 0x000498, 0x0004de, /* -59.5, -59.0, -58.5 */ + 0x000528, 0x000576, 0x0005c9, /* -58.0, -57.5, -57.0 */ + 0x000620, 0x00067d, 0x0006e0, /* -56.5, -56.0, -55.5 */ + 0x000748, 0x0007b7, 0x00082c, /* -55.0, -54.5, -54.0 */ + 0x0008a8, 0x00092b, 0x0009b6, /* -53.5, -53.0, -52.5 */ + 0x000a49, 0x000ae5, 0x000b8b, /* -52.0, -51.5, -51.0 */ + 0x000c3a, 0x000cf3, 0x000db8, /* -50.5, -50.0, -49.5 */ + 0x000e88, 0x000f64, 0x00104e, /* -49.0, -48.5, -48.0 */ + 0x001145, 0x00124b, 0x001361, /* -47.5, -47.0, -46.5 */ + 0x001487, 0x0015be, 0x001708, /* -46.0, -45.5, -45.0 */ + 0x001865, 0x0019d8, 0x001b60, /* -44.5, -44.0, -43.5 */ + 0x001cff, 0x001eb7, 0x002089, /* -43.0, -42.5, -42.0 */ + 0x002276, 0x002481, 0x0026ab, /* -41.5, -41.0, -40.5 */ + 0x0028f5, 0x002b63, 0x002df5, /* -40.0, -39.5, -39.0 */ + 0x0030ae, 0x003390, 0x00369e, /* -38.5, -38.0, -37.5 */ + 0x0039db, 0x003d49, 0x0040ea, /* -37.0, -36.5, -36.0 */ + 0x0044c3, 0x0048d6, 0x004d27, /* -35.5, -35.0, -34.5 */ + 0x0051b9, 0x005691, 0x005bb2, /* -34.0, -33.5, -33.0 */ + 0x006121, 0x0066e3, 0x006cfb, /* -32.5, -32.0, -31.5 */ + 0x007370, 0x007a48, 0x008186, /* -31.0, -30.5, -30.0 */ + 0x008933, 0x009154, 0x0099f1, /* -29.5, -29.0, -28.5 */ + 0x00a310, 0x00acba, 0x00b6f6, /* -28.0, -27.5, -27.0 */ + 0x00c1cd, 0x00cd49, 0x00d973, /* -26.5, -26.0, -25.5 */ + 0x00e655, 0x00f3fb, 0x010270, /* -25.0, -24.5, -24.0 */ + 0x0111c0, 0x0121f9, 0x013328, /* -23.5, -23.0, -22.5 */ + 0x01455b, 0x0158a2, 0x016d0e, /* -22.0, -21.5, -21.0 */ + 0x0182af, 0x019999, 0x01b1de, /* -20.5, -20.0, -19.5 */ + 0x01cb94, 0x01e6cf, 0x0203a7, /* -19.0, -18.5, -18.0 */ + 0x022235, 0x024293, 0x0264db, /* -17.5, -17.0, -16.5 */ + 0x02892c, 0x02afa3, 0x02d862, /* -16.0, -15.5, -15.0 */ + 0x03038a, 0x033142, 0x0361af, /* -14.5, -14.0, -13.5 */ + 0x0394fa, 0x03cb50, 0x0404de, /* -13.0, -12.5, -12.0 */ + 0x0441d5, 0x048268, 0x04c6d0, /* -11.5, -11.0, -10.5 */ + 0x050f44, 0x055c04, 0x05ad50, /* -10.0, -09.5, -09.0 */ + 0x06036e, 0x065ea5, 0x06bf44, /* -08.5, -08.0, -07.5 */ + 0x07259d, 0x079207, 0x0804dc, /* -07.0, -06.5, -06.0 */ + 0x087e80, 0x08ff59, 0x0987d5, /* -05.5, -05.0, -04.5 */ + 0x0a1866, 0x0ab189, 0x0b53be, /* -04.0, -03.5, -03.0 */ + 0x0bff91, 0x0cb591, 0x0d765a, /* -02.5, -02.0, -01.5 */ + 0x0e4290, 0x0f1adf, 0x100000, /* -01.0, -00.5, 00.0 */ + 0x10f2b4, 0x11f3c9, 0x13041a, /* +00.5, +01.0, +01.5 */ + 0x14248e, 0x15561a, 0x1699c0, /* +02.0, +02.5, +03.0 */ + 0x17f094, 0x195bb8, 0x1adc61, /* +03.5, +04.0, +04.5 */ + 0x1c73d5, 0x1e236d, 0x1fec98, /* +05.0, +05.5, +06.0 */ + 0x21d0d9, 0x23d1cd, 0x25f125, /* +06.5, +07.0, +07.5 */ + 0x2830af, 0x2a9254, 0x2d1818, /* +08.0, +08.5, +09.0 */ + 0x2fc420, 0x3298b0, 0x35982f, /* +09.5, +10.0, +10.5 */ + 0x38c528, 0x3c224c, 0x3fb278, /* +11.0, +11.5, +12.0 */ + 0x437880, 0x477828, 0x4bb446, /* +12.5, +13.0, +13.5 */ + 0x5030a1, 0x54f106, 0x59f980, /* +14.0, +14.5, +15.0 */ + 0x5f4e52, 0x64f403, 0x6aef5d, /* +15.5, +16.0, +16.5 */ + 0x714575, 0x77fbaa, 0x7f17af /* +17.0, +17.5, +18.0 */ +}; + +#endif /* _tas3001c_h_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/dmasound/trans_16.c linux-2.5/drivers/sound/dmasound/trans_16.c --- linux-2.5.1/drivers/sound/dmasound/trans_16.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/sound/dmasound/trans_16.c Thu Dec 27 16:32:31 2001 @@ -0,0 +1,679 @@ +/* + * linux/drivers/sound/dmasound/trans_16.c + * + * 16 bit translation routines. Only used by Power mac at present. + * + * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and + * history prior to 08/02/2001. + * + * 08/02/2001 Iain Sandoe + * split from dmasound_awacs.c + */ + +#include <linux/soundcard.h> +#include <asm/uaccess.h> +#include "dmasound.h" + +static short dmasound_alaw2dma16[] ; +static short dmasound_ulaw2dma16[] ; + +static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); + +static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); + +static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); + +/*** Translations ************************************************************/ + +extern int expand_bal; /* Balance factor for expanding (not volume!) */ +static int expand_data; /* Data for expanding */ + +static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + short *table = dmasound.soft.format == AFMT_MU_LAW + ? dmasound_ulaw2dma16 : dmasound_alaw2dma16; + ssize_t count, used; + short *p = (short *) &frame[*frameUsed]; + int val, stereo = dmasound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + used = count = min_t(unsigned long, userCount, frameLeft); + while (count > 0) { + u_char data; + if (get_user(data, userPtr++)) + return -EFAULT; + val = table[data]; + *p++ = val; + if (stereo) { + if (get_user(data, userPtr++)) + return -EFAULT; + val = table[data]; + } + *p++ = val; + count--; + } + *frameUsed += used * 4; + return stereo? used * 2: used; +} + + +static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + short *p = (short *) &frame[*frameUsed]; + int val, stereo = dmasound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + used = count = min_t(unsigned long, userCount, frameLeft); + while (count > 0) { + u_char data; + if (get_user(data, userPtr++)) + return -EFAULT; + val = data << 8; + *p++ = val; + if (stereo) { + if (get_user(data, userPtr++)) + return -EFAULT; + val = data << 8; + } + *p++ = val; + count--; + } + *frameUsed += used * 4; + return stereo? used * 2: used; +} + + +static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + short *p = (short *) &frame[*frameUsed]; + int val, stereo = dmasound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + used = count = min_t(unsigned long, userCount, frameLeft); + while (count > 0) { + u_char data; + if (get_user(data, userPtr++)) + return -EFAULT; + val = (data ^ 0x80) << 8; + *p++ = val; + if (stereo) { + if (get_user(data, userPtr++)) + return -EFAULT; + val = (data ^ 0x80) << 8; + } + *p++ = val; + count--; + } + *frameUsed += used * 4; + return stereo? used * 2: used; +} + + +static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + int stereo = dmasound.soft.stereo; + short *fp = (short *) &frame[*frameUsed]; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + used = count = min_t(unsigned long, userCount, frameLeft); + if (!stereo) { + short *up = (short *) userPtr; + while (count > 0) { + short data; + if (get_user(data, up++)) + return -EFAULT; + *fp++ = data; + *fp++ = data; + count--; + } + } else { + if (copy_from_user(fp, userPtr, count * 4)) + return -EFAULT; + } + *frameUsed += used * 4; + return stereo? used * 4: used * 2; +} + +static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); + int stereo = dmasound.soft.stereo; + short *fp = (short *) &frame[*frameUsed]; + short *up = (short *) userPtr; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + used = count = min_t(unsigned long, userCount, frameLeft); + while (count > 0) { + short data; + if (get_user(data, up++)) + return -EFAULT; + data ^= mask; + *fp++ = data; + if (stereo) { + if (get_user(data, up++)) + return -EFAULT; + data ^= mask; + } + *fp++ = data; + count--; + } + *frameUsed += used * 4; + return stereo? used * 4: used * 2; +} + + +static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + unsigned short *table = (unsigned short *) + (dmasound.soft.format == AFMT_MU_LAW + ? dmasound_ulaw2dma16 : dmasound_alaw2dma16); + unsigned int data = expand_data; + unsigned int *p = (unsigned int *) &frame[*frameUsed]; + int bal = expand_bal; + int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; + int utotal, ftotal; + int stereo = dmasound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + u_char c; + if (bal < 0) { + if (userCount == 0) + break; + if (get_user(c, userPtr++)) + return -EFAULT; + data = table[c]; + if (stereo) { + if (get_user(c, userPtr++)) + return -EFAULT; + data = (data << 16) + table[c]; + } else + data = (data << 16) + data; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) * 4; + utotal -= userCount; + return stereo? utotal * 2: utotal; +} + +static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + unsigned int *p = (unsigned int *) &frame[*frameUsed]; + unsigned int data = expand_data; + int bal = expand_bal; + int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; + int stereo = dmasound.soft.stereo; + int utotal, ftotal; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + u_char c; + if (bal < 0) { + if (userCount == 0) + break; + if (get_user(c, userPtr++)) + return -EFAULT; + data = c << 8; + if (stereo) { + if (get_user(c, userPtr++)) + return -EFAULT; + data = (data << 16) + (c << 8); + } else + data = (data << 16) + data; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) * 4; + utotal -= userCount; + return stereo? utotal * 2: utotal; +} + + +static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + unsigned int *p = (unsigned int *) &frame[*frameUsed]; + unsigned int data = expand_data; + int bal = expand_bal; + int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; + int stereo = dmasound.soft.stereo; + int utotal, ftotal; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + u_char c; + if (bal < 0) { + if (userCount == 0) + break; + if (get_user(c, userPtr++)) + return -EFAULT; + data = (c ^ 0x80) << 8; + if (stereo) { + if (get_user(c, userPtr++)) + return -EFAULT; + data = (data << 16) + ((c ^ 0x80) << 8); + } else + data = (data << 16) + data; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) * 4; + utotal -= userCount; + return stereo? utotal * 2: utotal; +} + + +static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + unsigned int *p = (unsigned int *) &frame[*frameUsed]; + unsigned int data = expand_data; + unsigned short *up = (unsigned short *) userPtr; + int bal = expand_bal; + int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; + int stereo = dmasound.soft.stereo; + int utotal, ftotal; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + unsigned short c; + if (bal < 0) { + if (userCount == 0) + break; + if (get_user(data, up++)) + return -EFAULT; + if (stereo) { + if (get_user(c, up++)) + return -EFAULT; + data = (data << 16) + c; + } else + data = (data << 16) + data; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) * 4; + utotal -= userCount; + return stereo? utotal * 4: utotal * 2; +} + + +static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); + unsigned int *p = (unsigned int *) &frame[*frameUsed]; + unsigned int data = expand_data; + unsigned short *up = (unsigned short *) userPtr; + int bal = expand_bal; + int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; + int stereo = dmasound.soft.stereo; + int utotal, ftotal; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + ftotal = frameLeft; + utotal = userCount; + while (frameLeft) { + unsigned short c; + if (bal < 0) { + if (userCount == 0) + break; + if (get_user(data, up++)) + return -EFAULT; + data ^= mask; + if (stereo) { + if (get_user(c, up++)) + return -EFAULT; + data = (data << 16) + (c ^ mask); + } else + data = (data << 16) + data; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + expand_bal = bal; + expand_data = data; + *frameUsed += (ftotal - frameLeft) * 4; + utotal -= userCount; + return stereo? utotal * 4: utotal * 2; +} + +/* data in routines... */ + +static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + short *p = (short *) &frame[*frameUsed]; + int val, stereo = dmasound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + used = count = min_t(unsigned long, userCount, frameLeft); + while (count > 0) { + u_char data; + + val = *p++; + data = val >> 8; + if (put_user(data, (u_char *)userPtr++)) + return -EFAULT; + if (stereo) { + val = *p; + data = val >> 8; + if (put_user(data, (u_char *)userPtr++)) + return -EFAULT; + } + p++; + count--; + } + *frameUsed += used * 4; + return stereo? used * 2: used; +} + + +static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + short *p = (short *) &frame[*frameUsed]; + int val, stereo = dmasound.soft.stereo; + + frameLeft >>= 2; + if (stereo) + userCount >>= 1; + used = count = min_t(unsigned long, userCount, frameLeft); + while (count > 0) { + u_char data; + + val = *p++; + data = (val >> 8) ^ 0x80; + if (put_user(data, (u_char *)userPtr++)) + return -EFAULT; + if (stereo) { + val = *p; + data = (val >> 8) ^ 0x80; + if (put_user(data, (u_char *)userPtr++)) + return -EFAULT; + } + p++; + count--; + } + *frameUsed += used * 4; + return stereo? used * 2: used; +} + +static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + int stereo = dmasound.soft.stereo; + short *fp = (short *) &frame[*frameUsed]; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + used = count = min_t(unsigned long, userCount, frameLeft); + if (!stereo) { + short *up = (short *) userPtr; + while (count > 0) { + short data; + data = *fp; + if (put_user(data, up++)) + return -EFAULT; + fp+=2; + count--; + } + } else { + if (copy_to_user((u_char *)userPtr, fp, count * 4)) + return -EFAULT; + } + *frameUsed += used * 4; + return stereo? used * 4: used * 2; +} + +static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) +{ + ssize_t count, used; + int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); + int stereo = dmasound.soft.stereo; + short *fp = (short *) &frame[*frameUsed]; + short *up = (short *) userPtr; + + frameLeft >>= 2; + userCount >>= (stereo? 2: 1); + used = count = min_t(unsigned long, userCount, frameLeft); + while (count > 0) { + int data; + + data = *fp++; + data ^= mask; + if (put_user(data, up++)) + return -EFAULT; + if (stereo) { + data = *fp; + data ^= mask; + if (put_user(data, up++)) + return -EFAULT; + } + fp++; + count--; + } + *frameUsed += used * 4; + return stereo? used * 4: used * 2; +} + +TRANS transAwacsNormal = { + ct_ulaw: pmac_ct_law, + ct_alaw: pmac_ct_law, + ct_s8: pmac_ct_s8, + ct_u8: pmac_ct_u8, + ct_s16be: pmac_ct_s16, + ct_u16be: pmac_ct_u16, + ct_s16le: pmac_ct_s16, + ct_u16le: pmac_ct_u16, +}; + +TRANS transAwacsExpand = { + ct_ulaw: pmac_ctx_law, + ct_alaw: pmac_ctx_law, + ct_s8: pmac_ctx_s8, + ct_u8: pmac_ctx_u8, + ct_s16be: pmac_ctx_s16, + ct_u16be: pmac_ctx_u16, + ct_s16le: pmac_ctx_s16, + ct_u16le: pmac_ctx_u16, +}; + +TRANS transAwacsNormalRead = { + ct_s8: pmac_ct_s8_read, + ct_u8: pmac_ct_u8_read, + ct_s16be: pmac_ct_s16_read, + ct_u16be: pmac_ct_u16_read, + ct_s16le: pmac_ct_s16_read, + ct_u16le: pmac_ct_u16_read, +}; + +/* translation tables */ +/* 16 bit mu-law */ + +static short dmasound_ulaw2dma16[] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, + -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, + -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, + -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0, +}; + +/* 16 bit A-law */ + +static short dmasound_alaw2dma16[] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, + -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, + -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848, +}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/emu10k1/audio.c linux-2.5/drivers/sound/emu10k1/audio.c --- linux-2.5.1/drivers/sound/emu10k1/audio.c Tue Oct 9 17:53:17 2001 +++ linux-2.5/drivers/sound/emu10k1/audio.c Wed Jan 2 01:30:12 2002 @@ -1098,7 +1098,7 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct emu10k1_card *card = NULL; struct list_head *entry; struct emu10k1_wavedevice *wave_dev; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/emu10k1/main.c linux-2.5/drivers/sound/emu10k1/main.c --- linux-2.5.1/drivers/sound/emu10k1/main.c Tue Oct 9 17:53:18 2001 +++ linux-2.5/drivers/sound/emu10k1/main.c Thu Dec 13 16:32:36 2001 @@ -1127,7 +1127,7 @@ name: "emu10k1", id_table: emu10k1_pci_tbl, probe: emu10k1_probe, - remove: emu10k1_remove, + remove: __devexit_p(emu10k1_remove), }; static int __init emu10k1_init_module(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/emu10k1/midi.c linux-2.5/drivers/sound/emu10k1/midi.c --- linux-2.5.1/drivers/sound/emu10k1/midi.c Tue Oct 9 17:53:18 2001 +++ linux-2.5/drivers/sound/emu10k1/midi.c Wed Jan 2 02:54:51 2002 @@ -87,7 +87,7 @@ static int emu10k1_midi_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct emu10k1_card *card = NULL; struct emu10k1_mididevice *midi_dev; struct list_head *entry; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/emu10k1/mixer.c linux-2.5/drivers/sound/emu10k1/mixer.c --- linux-2.5.1/drivers/sound/emu10k1/mixer.c Tue Oct 9 17:53:18 2001 +++ linux-2.5/drivers/sound/emu10k1/mixer.c Wed Jan 2 02:54:51 2002 @@ -640,7 +640,7 @@ static int emu10k1_mixer_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct emu10k1_card *card = NULL; struct list_head *entry; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/es1370.c linux-2.5/drivers/sound/es1370.c --- linux-2.5.1/drivers/sound/es1370.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/sound/es1370.c Mon Jan 14 22:39:45 2002 @@ -1029,7 +1029,7 @@ static int es1370_open_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct list_head *list; struct es1370_state *s; @@ -1729,7 +1729,7 @@ static int es1370_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; @@ -2165,7 +2165,7 @@ static int es1370_open_dac(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; @@ -2408,7 +2408,7 @@ static int es1370_midi_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; @@ -2484,12 +2484,8 @@ break; if (signal_pending(current)) break; - if (file->f_flags & O_NONBLOCK) { - remove_wait_queue(&s->midi.owait, &wait); - set_current_state(TASK_RUNNING); - unlock_kernel(); - return -EBUSY; - } + if (file->f_flags & O_NONBLOCK) + break; tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/es1371.c linux-2.5/drivers/sound/es1371.c --- linux-2.5.1/drivers/sound/es1371.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/sound/es1371.c Mon Jan 14 22:39:45 2002 @@ -1213,7 +1213,7 @@ static int es1371_open_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct list_head *list; struct es1371_state *s; @@ -1913,7 +1913,7 @@ static int es1371_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; @@ -2342,7 +2342,7 @@ static int es1371_open_dac(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; @@ -2584,7 +2584,7 @@ static int es1371_midi_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; @@ -2660,10 +2660,7 @@ if (signal_pending(current)) break; if (file->f_flags & O_NONBLOCK) { - remove_wait_queue(&s->midi.owait, &wait); - set_current_state(TASK_RUNNING); - unlock_kernel(); - return -EBUSY; + break; } tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/esssolo1.c linux-2.5/drivers/sound/esssolo1.c --- linux-2.5.1/drivers/sound/esssolo1.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/sound/esssolo1.c Mon Jan 14 22:39:45 2002 @@ -913,7 +913,7 @@ static int solo1_open_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct solo1_state *s = NULL; struct pci_dev *pci_dev; @@ -1590,7 +1590,7 @@ static int solo1_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); struct solo1_state *s = NULL; struct pci_dev *pci_dev; @@ -1879,7 +1879,7 @@ static int solo1_midi_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct solo1_state *s = NULL; @@ -1967,12 +1967,8 @@ break; if (signal_pending(current)) break; - if (file->f_flags & O_NONBLOCK) { - remove_wait_queue(&s->midi.owait, &wait); - set_current_state(TASK_RUNNING); - unlock_kernel(); - return -EBUSY; - } + if (file->f_flags & O_NONBLOCK) + break; tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "solo1: midi timed out??\n"); @@ -2105,7 +2101,7 @@ static int solo1_dmfm_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); struct solo1_state *s = NULL; struct pci_dev *pci_dev; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/i810_audio.c linux-2.5/drivers/sound/i810_audio.c --- linux-2.5.1/drivers/sound/i810_audio.c Fri Nov 9 22:07:41 2001 +++ linux-2.5/drivers/sound/i810_audio.c Wed Jan 2 17:23:52 2002 @@ -1405,10 +1405,9 @@ if (dmabuf->count < 0) { dmabuf->count = 0; } - cnt = dmabuf->dmasize - dmabuf->fragsize - dmabuf->count; - // this is to make the copy_from_user simpler below - if(cnt > (dmabuf->dmasize - swptr)) - cnt = dmabuf->dmasize - swptr; + cnt = dmabuf->dmasize - swptr; + if(cnt > (dmabuf->dmasize - dmabuf->count)) + cnt = dmabuf->dmasize - dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); #ifdef DEBUG2 @@ -1419,16 +1418,13 @@ if (cnt <= 0) { unsigned long tmo; // 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); } - // Update the LVI pointer in case we have already - // written data in this syscall and are just waiting - // on the tail bit of data - i810_update_lvi(state,0); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; goto ret; @@ -1860,7 +1856,7 @@ if(dmabuf->mapped) abinfo.bytes = dmabuf->count; else - abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.bytes = dmabuf->dmasize - dmabuf->fragsize - dmabuf->count; abinfo.fragments = abinfo.bytes / dmabuf->userfragsize; spin_unlock_irqrestore(&state->card->lock, flags); #ifdef DEBUG @@ -2345,7 +2341,7 @@ static int i810_open_mixdev(struct inode *inode, struct file *file) { int i; - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct i810_card *card = devs; for (card = devs; card != NULL; card = card->next) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/maestro.c linux-2.5/drivers/sound/maestro.c --- linux-2.5.1/drivers/sound/maestro.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/sound/maestro.c Wed Jan 2 17:23:52 2002 @@ -2126,7 +2126,7 @@ /* --------------------------------------------------------------------- */ static int ess_open_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct ess_card *card = NULL; struct pci_dev *pdev; struct pci_driver *drvr; @@ -2967,7 +2967,7 @@ static int ess_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct ess_state *s = NULL; unsigned char fmtm = ~0, fmts = 0; struct pci_dev *pdev; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/maestro3.c linux-2.5/drivers/sound/maestro3.c --- linux-2.5.1/drivers/sound/maestro3.c Sun Nov 25 18:17:47 2001 +++ linux-2.5/drivers/sound/maestro3.c Wed Jan 2 17:23:52 2002 @@ -1969,7 +1969,7 @@ static int m3_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct m3_card *c; struct m3_state *s = NULL; int i; @@ -2137,7 +2137,7 @@ /* OSS /dev/mixer file operation methods */ static int m3_open_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct m3_card *card = devs; for (card = devs; card != NULL; card = card->next) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/opl3sa2.c linux-2.5/drivers/sound/opl3sa2.c --- linux-2.5.1/drivers/sound/opl3sa2.c Sun Nov 25 17:43:42 2001 +++ linux-2.5/drivers/sound/opl3sa2.c Fri Dec 28 11:21:15 2001 @@ -55,6 +55,7 @@ * sb_card.c and awe_wave.c. (Dec 12, 2000) * Scott Murray Some small cleanups to the init code output. * (Jan 7, 2001) + * Zwane Mwaikambo Added PM support. (Dec 4 2001) * */ @@ -62,13 +63,16 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/isapnp.h> - +#include <linux/pm.h> #include "sound_config.h" #include "ad1848.h" #include "mpu401.h" +#define OPL3SA2_MODULE_NAME "opl3sa2" + /* Useful control port indexes: */ +#define OPL3SA2_PM 0x01 #define OPL3SA2_SYS_CTRL 0x02 #define OPL3SA2_IRQ_CONFIG 0x03 #define OPL3SA2_DMA_CONFIG 0x06 @@ -86,6 +90,11 @@ #define DEFAULT_MIC 50 #define DEFAULT_TIMBRE 0 +/* Power saving modes */ +#define OPL3SA2_PM_MODE1 0x05 +#define OPL3SA2_PM_MODE2 0x04 +#define OPL3SA2_PM_MODE3 0x03 + /* For checking against what the card returns: */ #define VERSION_UNKNOWN 0 #define VERSION_YMF711 1 @@ -121,6 +130,10 @@ typedef struct opl3sa2_mixerdata_tag { unsigned short cfg_port; unsigned short padding; + unsigned char pm_reg; + unsigned int in_suspend; + struct pm_dev *pmdev; + unsigned int card; unsigned int volume_l; unsigned int volume_r; unsigned int mic; @@ -328,6 +341,20 @@ } +static void opl3sa2_mixer_restore(opl3sa2_mixerdata* devc, int card) +{ + if (devc) { + opl3sa2_set_volume(devc, devc->volume_l, devc->volume_r); + opl3sa2_set_mic(devc, devc->mic); + + if (chipset[card] == CHIPSET_OPL3SA3) { + opl3sa3_set_bass(devc, devc->bass_l, devc->bass_r); + opl3sa3_set_treble(devc, devc->treble_l, devc->treble_r); + } + } +} + + static inline void arg_to_vol_mono(unsigned int vol, int* value) { int left; @@ -608,9 +635,9 @@ char tag; /* - * Verify that the I/O port range is free. + * Try and allocate our I/O port range. */ - if(check_region(hw_config->io_base, 2)) { + if(!request_region(hw_config->io_base, 2, OPL3SA2_MODULE_NAME)) { printk(KERN_ERR "opl3sa2: Control I/O port %#x not free\n", hw_config->io_base); return 0; @@ -699,7 +726,6 @@ static void __init attach_opl3sa2(struct address_info* hw_config, int card) { - request_region(hw_config->io_base, 2, chipset_name[card]); /* Initialize IRQ configuration to IRQ-B: -, IRQ-A: WSS+MPU+OPL3 */ opl3sa2_write(hw_config->io_base, OPL3SA2_IRQ_CONFIG, 0x0d); @@ -892,6 +918,81 @@ /* End of component functions */ +/* Power Management support functions */ +static int opl3sa2_suspend(struct pm_dev *pdev, unsigned char pm_mode) +{ + unsigned long flags; + opl3sa2_mixerdata *p; + + if (!pdev) + return -EINVAL; + + save_flags(flags); + cli(); + + p = (opl3sa2_mixerdata *) pdev->data; + + switch (pm_mode) { + case 1: + pm_mode = OPL3SA2_PM_MODE1; + break; + case 2: + pm_mode = OPL3SA2_PM_MODE2; + break; + case 3: + pm_mode = OPL3SA2_PM_MODE3; + break; + default: + /* we don't know howto handle this... */ + restore_flags(flags); + return -EBUSY; + } + + p->in_suspend = 1; + /* its supposed to automute before suspending, so we wont bother */ + opl3sa2_read(p->cfg_port, OPL3SA2_PM, &p->pm_reg); + opl3sa2_write(p->cfg_port, OPL3SA2_PM, p->pm_reg | pm_mode); + /* wait a while for the clock oscillator to stabilise */ + mdelay(10); + + restore_flags(flags); + return 0; +} + +static int opl3sa2_resume(struct pm_dev *pdev) +{ + unsigned long flags; + opl3sa2_mixerdata *p; + + if (!pdev) + return -EINVAL; + + p = (opl3sa2_mixerdata *) pdev->data; + save_flags(flags); + cli(); + + /* I don't think this is necessary */ + opl3sa2_write(p->cfg_port, OPL3SA2_PM, p->pm_reg); + opl3sa2_mixer_restore(p, p->card); + p->in_suspend = 0; + + restore_flags(flags); + return 0; +} + +static int opl3sa2_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data) +{ + unsigned char mode = (unsigned char)data; + + switch (rqst) { + case PM_SUSPEND: + return opl3sa2_suspend(pdev, mode); + + case PM_RESUME: + return opl3sa2_resume(pdev); + } + return 0; +} /* * Install OPL3-SA2 based card(s). @@ -989,6 +1090,12 @@ attach_opl3sa2_mss(&cfg_mss[card]); attach_opl3sa2_mixer(&cfg[card], card); + opl3sa2_data[card].card = card; + /* register our power management capabilities */ + opl3sa2_data[card].pmdev = pm_register(PM_ISA_DEV, card, opl3sa2_pm_callback); + if (opl3sa2_data[card].pmdev) + opl3sa2_data[card].pmdev->data = &opl3sa2_data[card]; + /* * Set the Yamaha 3D enhancement mode (aka Ymersion) if asked to and * it's supported. @@ -1033,6 +1140,9 @@ int card; for(card = 0; card < opl3sa2_cards_num; card++) { + if (opl3sa2_data[card].pmdev) + pm_unregister(opl3sa2_data[card].pmdev); + if(cfg_mpu[card].slots[1] != -1) { unload_opl3sa2_mpu(&cfg_mpu[card]); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/sb_audio.c linux-2.5/drivers/sound/sb_audio.c --- linux-2.5.1/drivers/sound/sb_audio.c Sat Feb 17 00:02:37 2001 +++ linux-2.5/drivers/sound/sb_audio.c Mon Jan 14 22:39:45 2002 @@ -602,8 +602,8 @@ if (speed > 0) { - if (speed < 5000) /* which of these */ - speed = 4000; /* is correct ??? */ + if (speed < 5000) + speed = 5000; if (speed > max_speed) speed = max_speed; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/sb_card.c linux-2.5/drivers/sound/sb_card.c --- linux-2.5.1/drivers/sound/sb_card.c Sun Nov 25 17:43:42 2001 +++ linux-2.5/drivers/sound/sb_card.c Thu Dec 13 16:32:36 2001 @@ -378,6 +378,11 @@ 0,0,0,0, 0,1,1,-1}, {"Sound Blaster AWE 32", + ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0047), + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), + 0,0,0,0, + 0,1,1,-1}, + {"Sound Blaster AWE 32", ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0,0,0,0, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/sonicvibes.c linux-2.5/drivers/sound/sonicvibes.c --- linux-2.5.1/drivers/sound/sonicvibes.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/sound/sonicvibes.c Mon Jan 14 22:39:45 2002 @@ -2226,12 +2226,8 @@ break; if (signal_pending(current)) break; - if (file->f_flags & O_NONBLOCK) { - remove_wait_queue(&s->midi.owait, &wait); - set_current_state(TASK_RUNNING); - unlock_kernel(); - return -EBUSY; - } + if (file->f_flags & O_NONBLOCK) + break; tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "sv: midi timed out??\n"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/sound_core.c linux-2.5/drivers/sound/sound_core.c --- linux-2.5.1/drivers/sound/sound_core.c Sun Nov 25 18:17:47 2001 +++ linux-2.5/drivers/sound/sound_core.c Thu Jan 10 15:50:04 2002 @@ -17,7 +17,7 @@ * plug into this. The fact they dont all go via OSS doesn't mean * they don't have to implement the OSS API. There is a lot of logic * to keeping much of the OSS weight out of the code in a compatibility - * module, but its up to the driver to rember to load it... + * module, but it's up to the driver to remember to load it... * * The code provides a set of functions for registration of devices * by type. This is done rather than providing a single call so that @@ -171,10 +171,10 @@ return r; } - if (r == low) + if ( r < SOUND_STEP ) sprintf (name_buf, "%s", name); else - sprintf (name_buf, "%s%d", name, (r - low) / SOUND_STEP); + sprintf (name_buf, "%s%d", name, (r / SOUND_STEP)); s->de = devfs_register (devfs_handle, name_buf, DEVFS_FL_NONE, SOUND_MAJOR, s->unit_minor, S_IFCHR | mode, fops, NULL); @@ -229,17 +229,21 @@ int register_sound_special(struct file_operations *fops, int unit) { - char *name; + const int chain = (unit & 0x0F); + int max_unit = chain + 128; + const char *name; - switch (unit) { + switch (chain) { case 0: name = "mixer"; break; case 1: name = "sequencer"; + unit = chain; + max_unit = chain + 1; break; case 2: - name = "midi00"; + name = "midi"; break; case 3: name = "dsp"; @@ -258,6 +262,8 @@ break; case 8: name = "sequencer2"; + unit = chain; + max_unit = chain + 1; break; case 9: name = "dmmidi"; @@ -278,10 +284,10 @@ name = "admmidi"; break; default: - name = "unknown"; + name = "unknownX"; break; } - return sound_insert_unit(&chains[unit&15], fops, -1, unit, unit+1, + return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit, name, S_IRUSR | S_IWUSR); } @@ -478,7 +484,7 @@ int soundcore_open(struct inode *inode, struct file *file) { int chain; - int unit=MINOR(inode->i_rdev); + int unit = minor(inode->i_rdev); struct sound_unit *s; struct file_operations *new_fops = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/soundcard.c linux-2.5/drivers/sound/soundcard.c --- linux-2.5.1/drivers/sound/soundcard.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/sound/soundcard.c Thu Jan 3 22:55:32 2002 @@ -35,7 +35,6 @@ #include <linux/kmod.h> #include <asm/dma.h> #include <asm/io.h> -#include <asm/segment.h> #include <linux/wait.h> #include <linux/slab.h> #include <linux/ioport.h> @@ -145,7 +144,7 @@ static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - int dev = MINOR(file->f_dentry->d_inode->i_rdev); + int dev = minor(file->f_dentry->d_inode->i_rdev); int ret = -EINVAL; /* @@ -178,7 +177,7 @@ static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - int dev = MINOR(file->f_dentry->d_inode->i_rdev); + int dev = minor(file->f_dentry->d_inode->i_rdev); int ret = -EINVAL; lock_kernel(); @@ -205,7 +204,7 @@ static int sound_open(struct inode *inode, struct file *file) { - int dev = MINOR(inode->i_rdev); + int dev = minor(inode->i_rdev); int retval; DEB(printk("sound_open(dev=%d)\n", dev)); @@ -256,7 +255,7 @@ static int sound_release(struct inode *inode, struct file *file) { - int dev = MINOR(inode->i_rdev); + int dev = minor(inode->i_rdev); lock_kernel(); DEB(printk("sound_release(dev=%d)\n", dev)); @@ -342,7 +341,7 @@ unsigned int cmd, unsigned long arg) { int err, len = 0, dtype; - int dev = MINOR(inode->i_rdev); + int dev = minor(inode->i_rdev); if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { /* @@ -405,7 +404,7 @@ static unsigned int sound_poll(struct file *file, poll_table * wait) { struct inode *inode = file->f_dentry->d_inode; - int dev = MINOR(inode->i_rdev); + int dev = minor(inode->i_rdev); DEB(printk("sound_poll(dev=%d)\n", dev)); switch (dev & 0x0f) { @@ -429,7 +428,7 @@ int dev_class; unsigned long size; struct dma_buffparms *dmap = NULL; - int dev = MINOR(file->f_dentry->d_inode->i_rdev); + int dev = minor(file->f_dentry->d_inode->i_rdev); dev_class = dev & 0x0f; dev >>= 4; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/sscape.c linux-2.5/drivers/sound/sscape.c --- linux-2.5.1/drivers/sound/sscape.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/sound/sscape.c Sun Dec 30 21:17:30 2001 @@ -34,7 +34,6 @@ #include <linux/kmod.h> #include <asm/dma.h> #include <asm/io.h> -#include <asm/segment.h> #include <linux/wait.h> #include <linux/slab.h> #include <linux/ioport.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/via82cxxx_audio.c linux-2.5/drivers/sound/via82cxxx_audio.c --- linux-2.5.1/drivers/sound/via82cxxx_audio.c Mon Dec 10 18:39:20 2001 +++ linux-2.5/drivers/sound/via82cxxx_audio.c Mon Jan 7 14:02:21 2002 @@ -365,7 +365,7 @@ name: VIA_MODULE_NAME, id_table: via_pci_tbl, probe: via_init_one, - remove: via_remove_one, + remove: __devexit_p(via_remove_one), }; @@ -1358,7 +1358,7 @@ static int via_mixer_open (struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct via_info *card; struct pci_dev *pdev; struct pci_driver *drvr; @@ -2974,7 +2974,7 @@ static int via_dsp_open (struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct via_info *card; struct pci_dev *pdev; struct via_channel *chan; @@ -3271,7 +3271,7 @@ } -static void __exit via_remove_one (struct pci_dev *pdev) +static void __devexit via_remove_one (struct pci_dev *pdev) { struct via_info *card; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/sound/ymfpci.c linux-2.5/drivers/sound/ymfpci.c --- linux-2.5.1/drivers/sound/ymfpci.c Sun Nov 25 18:17:47 2001 +++ linux-2.5/drivers/sound/ymfpci.c Sat Jan 5 16:38:08 2002 @@ -39,6 +39,7 @@ * native synthesizer through a playback slot. * - Use new 2.3.x cache coherent PCI DMA routines instead of virt_to_bus. * - Make the thing big endian compatible. ALSA has it done. + * - 2001/11/29 ac97_save_state */ #include <linux/config.h> @@ -155,7 +156,7 @@ schedule_timeout(1); } } while (end_time - (signed long)jiffies >= 0); - printk("ymfpci_codec_ready: codec %i is not ready [0x%x]\n", + printk(KERN_ERR "ymfpci_codec_ready: codec %i is not ready [0x%x]\n", secondary, ymfpci_readw(codec, reg)); return -EBUSY; } @@ -173,19 +174,19 @@ static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg) { - ymfpci_t *codec = dev->private_data; + ymfpci_t *unit = dev->private_data; + int i; - if (ymfpci_codec_ready(codec, 0, 0)) + if (ymfpci_codec_ready(unit, 0, 0)) return ~0; - ymfpci_writew(codec, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg); - if (ymfpci_codec_ready(codec, 0, 0)) + ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg); + if (ymfpci_codec_ready(unit, 0, 0)) return ~0; - if (codec->pci->device == PCI_DEVICE_ID_YAMAHA_744 && codec->rev < 2) { - int i; + if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) { for (i = 0; i < 600; i++) - ymfpci_readw(codec, YDSXGR_PRISTATUSDATA); + ymfpci_readw(unit, YDSXGR_PRISTATUSDATA); } - return ymfpci_readw(codec, YDSXGR_PRISTATUSDATA); + return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA); } /* @@ -404,7 +405,7 @@ dmabuf->ready = 1; #if 0 - printk("prog_dmabuf: rate %d format 0x%x," + printk(KERN_DEBUG "prog_dmabuf: rate %d format 0x%x," " numfrag %d fragsize %d dmasize %d\n", state->format.rate, state->format.format, dmabuf->numfrag, dmabuf->fragsize, dmabuf->dmasize); @@ -615,7 +616,7 @@ dmabuf->hwptr = pos; if (dmabuf->count == 0) { - printk("ymfpci%d: %d: strain: hwptr %d\n", + printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n", codec->dev_audio, voice->number, dmabuf->hwptr); ymf_playback_trigger(codec, ypcm, 0); } @@ -633,7 +634,7 @@ /* * Lost interrupt or other screwage. */ - printk("ymfpci%d: %d: lost: delta %d" + printk(KERN_ERR "ymfpci%d: %d: lost: delta %d" " hwptr %d swptr %d distance %d count %d\n", codec->dev_audio, voice->number, delta, dmabuf->hwptr, swptr, distance, dmabuf->count); @@ -641,10 +642,10 @@ /* * Normal end of DMA. */ -// printk("ymfpci%d: %d: done: delta %d" -// " hwptr %d swptr %d distance %d count %d\n", -// codec->dev_audio, voice->number, delta, -// dmabuf->hwptr, swptr, distance, dmabuf->count); + YMFDBGI("ymfpci%d: %d: done: delta %d" + " hwptr %d swptr %d distance %d count %d\n", + codec->dev_audio, voice->number, delta, + dmabuf->hwptr, swptr, distance, dmabuf->count); } played = dmabuf->count; if (ypcm->running) { @@ -1442,13 +1443,14 @@ { struct ymf_state *state = (struct ymf_state *)file->private_data; struct ymf_dmabuf *dmabuf; + int redzone; unsigned long flags; unsigned int mask = 0; if (file->f_mode & FMODE_WRITE) poll_wait(file, &state->wpcm.dmabuf.wait, wait); - // if (file->f_mode & FMODE_READ) - // poll_wait(file, &dmabuf->wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &state->rpcm.dmabuf.wait, wait); spin_lock_irqsave(&state->unit->reg_lock, flags); if (file->f_mode & FMODE_READ) { @@ -1457,12 +1459,21 @@ mask |= POLLIN | POLLRDNORM; } if (file->f_mode & FMODE_WRITE) { + redzone = ymf_calc_lend(state->format.rate); + redzone <<= state->format.shift; + redzone *= 3; + dmabuf = &state->wpcm.dmabuf; if (dmabuf->mapped) { if (dmabuf->count >= (signed)dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; } else { - if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize) + /* + * Don't select unless a full fragment is available. + * Otherwise artsd does GETOSPACE, sees 0, and loops. + */ + if (dmabuf->count + redzone + dmabuf->fragsize + <= dmabuf->dmasize) mask |= POLLOUT | POLLWRNORM; } } @@ -1497,6 +1508,7 @@ return -EAGAIN; dmabuf->mapped = 1; +/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n"); return 0; } @@ -1508,13 +1520,16 @@ unsigned long flags; audio_buf_info abinfo; count_info cinfo; + int redzone; int val; switch (cmd) { case OSS_GETVERSION: + YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg); return put_user(SOUND_VERSION, (int *)arg); case SNDCTL_DSP_RESET: + YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd); if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); dmabuf = &state->wpcm.dmabuf; @@ -1536,6 +1551,7 @@ return 0; case SNDCTL_DSP_SYNC: + YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd); if (file->f_mode & FMODE_WRITE) { dmabuf = &state->wpcm.dmabuf; if (file->f_flags & O_NONBLOCK) { @@ -1554,6 +1570,7 @@ case SNDCTL_DSP_SPEED: /* set smaple rate */ if (get_user(val, (int *)arg)) return -EFAULT; + YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val); if (val >= 8000 && val <= 48000) { if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); @@ -1585,6 +1602,7 @@ case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ if (get_user(val, (int *)arg)) return -EFAULT; + YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val); if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); dmabuf = &state->wpcm.dmabuf; @@ -1606,24 +1624,31 @@ return 0; case SNDCTL_DSP_GETBLKSIZE: + YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd); if (file->f_mode & FMODE_WRITE) { if ((val = prog_dmabuf(state, 0))) return val; - return put_user(state->wpcm.dmabuf.fragsize, (int *)arg); + val = state->wpcm.dmabuf.fragsize; + YMFDBGX("ymf_ioctl: GETBLK w %d\n", val); + return put_user(val, (int *)arg); } if (file->f_mode & FMODE_READ) { if ((val = prog_dmabuf(state, 1))) return val; - return put_user(state->rpcm.dmabuf.fragsize, (int *)arg); + val = state->rpcm.dmabuf.fragsize; + YMFDBGX("ymf_ioctl: GETBLK r %d\n", val); + return put_user(val, (int *)arg); } return -EINVAL; case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ + YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd); return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Select sample format */ if (get_user(val, (int *)arg)) return -EFAULT; + YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val); if (val == AFMT_S16_LE || val == AFMT_U8) { if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); @@ -1649,6 +1674,7 @@ case SNDCTL_DSP_CHANNELS: if (get_user(val, (int *)arg)) return -EFAULT; + YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val); if (val != 0) { if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); @@ -1676,6 +1702,7 @@ return put_user(state->format.voices, (int *)arg); case SNDCTL_DSP_POST: + YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd); /* * Quoting OSS PG: * The ioctl SNDCTL_DSP_POST is a lightweight version of @@ -1697,6 +1724,10 @@ case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (int *)arg)) return -EFAULT; + YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n", + cmd, + (val >> 16) & 0xFFFF, val & 0xFFFF, + (val >> 16) & 0xFFFF, val & 0xFFFF); dmabuf = &state->wpcm.dmabuf; dmabuf->ossfragshift = val & 0xffff; dmabuf->ossmaxfrags = (val >> 16) & 0xffff; @@ -1707,20 +1738,25 @@ return 0; case SNDCTL_DSP_GETOSPACE: + YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd); if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; dmabuf = &state->wpcm.dmabuf; if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) return val; + redzone = ymf_calc_lend(state->format.rate); + redzone <<= state->format.shift; + redzone *= 3; spin_lock_irqsave(&state->unit->reg_lock, flags); abinfo.fragsize = dmabuf->fragsize; - abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone; abinfo.fragstotal = dmabuf->numfrag; abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->unit->reg_lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETISPACE: + YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd); if (!(file->f_mode & FMODE_READ)) return -EINVAL; dmabuf = &state->rpcm.dmabuf; @@ -1735,15 +1771,18 @@ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_NONBLOCK: + YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd); file->f_flags |= O_NONBLOCK; return 0; case SNDCTL_DSP_GETCAPS: + YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd); /* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, (int *)arg); */ return put_user(0, (int *)arg); case SNDCTL_DSP_GETIPTR: + YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd); if (!(file->f_mode & FMODE_READ)) return -EINVAL; dmabuf = &state->rpcm.dmabuf; @@ -1751,13 +1790,13 @@ cinfo.bytes = dmabuf->total_bytes; cinfo.blocks = dmabuf->count >> dmabuf->fragshift; cinfo.ptr = dmabuf->hwptr; - /* XXX fishy - breaks invariant count=hwptr-swptr */ - if (dmabuf->mapped) - dmabuf->count &= dmabuf->fragsize-1; spin_unlock_irqrestore(&state->unit->reg_lock, flags); + YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n", + cinfo.ptr, cinfo.bytes); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETOPTR: + YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd); if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; dmabuf = &state->wpcm.dmabuf; @@ -1765,22 +1804,25 @@ cinfo.bytes = dmabuf->total_bytes; cinfo.blocks = dmabuf->count >> dmabuf->fragshift; cinfo.ptr = dmabuf->hwptr; - /* XXX fishy - breaks invariant count=swptr-hwptr */ - if (dmabuf->mapped) - dmabuf->count &= dmabuf->fragsize-1; spin_unlock_irqrestore(&state->unit->reg_lock, flags); + YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n", + cinfo.ptr, cinfo.bytes); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; case SNDCTL_DSP_SETDUPLEX: /* XXX TODO */ + YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd); return -EINVAL; case SOUND_PCM_READ_RATE: + YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd); return put_user(state->format.rate, (int *)arg); case SOUND_PCM_READ_CHANNELS: + YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd); return put_user(state->format.voices, (int *)arg); case SOUND_PCM_READ_BITS: + YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd); return put_user(AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_MAPINBUF: @@ -1816,7 +1858,7 @@ struct ymf_state *state; int err; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); if ((minor & 0x0F) == 3) { /* /dev/dspN */ ; } else { @@ -1866,8 +1908,8 @@ } #if 0 /* test if interrupts work */ - ymfpci_writew(codec, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */ - ymfpci_writeb(codec, YDSXGR_TIMERCTRL, + ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */ + ymfpci_writeb(unit, YDSXGR_TIMERCTRL, (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN)); #endif up(&unit->open_sem); @@ -1895,13 +1937,13 @@ static int ymf_release(struct inode *inode, struct file *file) { struct ymf_state *state = (struct ymf_state *)file->private_data; - ymfpci_t *codec = state->unit; + ymfpci_t *unit = state->unit; #if 0 /* test if interrupts work */ - ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0); + ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0); #endif - down(&codec->open_sem); + down(&unit->open_sem); /* * XXX Solve the case of O_NONBLOCK close - don't deallocate here. @@ -1918,7 +1960,7 @@ file->private_data = NULL; /* Can you tell I programmed Solaris */ kfree(state); - up(&codec->open_sem); + up(&unit->open_sem); return 0; } @@ -1928,10 +1970,10 @@ */ static int ymf_open_mixdev(struct inode *inode, struct file *file) { - int i; - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct list_head *list; ymfpci_t *unit; + int i; list_for_each(list, &ymf_devs) { unit = list_entry(list, ymfpci_t, ymf_devs); @@ -1988,23 +2030,26 @@ static int ymf_suspend(struct pci_dev *pcidev, u32 unused) { - int i; struct ymf_unit *unit = pci_get_drvdata(pcidev); unsigned long flags; struct ymf_dmabuf *dmabuf; struct list_head *p; struct ymf_state *state; struct ac97_codec *codec; + int i; spin_lock_irqsave(&unit->reg_lock, flags); unit->suspended = 1; + /* + * XXX Talk to Kai to remove ac97_save_state before it's too late! + * Other drivers call ac97_reset, which does not have + * a save counterpart. Current ac97_save_state is empty. + */ for (i = 0; i < NR_AC97; i++) { - codec = unit->ac97_codec[i]; - if (!codec) - continue; - ac97_save_state(codec); + if ((codec = unit->ac97_codec[i]) != NULL) + ac97_save_state(codec); } list_for_each(p, &unit->states) { @@ -2031,12 +2076,12 @@ static int ymf_resume(struct pci_dev *pcidev) { - int i; struct ymf_unit *unit = pci_get_drvdata(pcidev); unsigned long flags; struct list_head *p; struct ymf_state *state; struct ac97_codec *codec; + int i; ymfpci_aclink_reset(unit->pci); ymfpci_codec_ready(unit, 0, 1); /* prints diag if not ready. */ @@ -2063,6 +2108,11 @@ ac97_restore_state(codec); } + for (i = 0; i < NR_AC97; i++) { + if ((codec = unit->ac97_codec[i]) != NULL) + ac97_restore_state(codec); + } + unit->suspended = 0; list_for_each(p, &unit->states) { state = list_entry(p, struct ymf_state, chain); @@ -2160,12 +2210,15 @@ { u8 cmd; + /* + * In the 744, 754 only 0x01 exists, 0x02 is undefined. + * It does not seem to hurt to trip both regardless of revision. + */ pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd); - if (cmd & 0x03) { - pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc); - pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03); - pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc); - } + pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc); + pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03); + pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc); + pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0); pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0); } @@ -2357,7 +2410,7 @@ codec->codec_write = ymfpci_codec_write; if (ac97_probe_codec(codec) == 0) { - printk("ymfpci: ac97_probe_codec failed\n"); + printk(KERN_ERR "ymfpci: ac97_probe_codec failed\n"); goto out_kfree; } @@ -2398,6 +2451,7 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent) { u16 ctrl; + unsigned long base; ymfpci_t *codec; int err; @@ -2406,6 +2460,7 @@ printk(KERN_ERR "ymfpci: pci_enable_device failed\n"); return err; } + base = pci_resource_start(pcidev, 0); if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) { printk(KERN_ERR "ymfpci: no core\n"); @@ -2420,16 +2475,21 @@ codec->pci = pcidev; pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev); - codec->reg_area_virt = ioremap(pci_resource_start(pcidev, 0), 0x8000); - if (codec->reg_area_virt == NULL) { - printk(KERN_ERR "ymfpci: unable to map registers\n"); + + if (request_mem_region(base, 0x8000, "ymfpci") == NULL) { + printk(KERN_ERR "ymfpci: unable to request mem region\n"); goto out_free; } + if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) { + printk(KERN_ERR "ymfpci: unable to map registers\n"); + goto out_release_region; + } + pci_set_master(pcidev); printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n", - (char *)ent->driver_data, pci_resource_start(pcidev, 0), pcidev->irq); + (char *)ent->driver_data, base, pcidev->irq); ymfpci_aclink_reset(pcidev); if (ymfpci_codec_ready(codec, 0, 1) < 0) @@ -2459,8 +2519,7 @@ /* register /dev/dsp */ if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) { - printk(KERN_ERR "ymfpci%d: unable to register dsp\n", - codec->dev_audio); + printk(KERN_ERR "ymfpci: unable to register dsp\n"); goto out_free_irq; } @@ -2506,6 +2565,8 @@ ymfpci_writel(codec, YDSXGR_STATUS, ~0); out_unmap: iounmap(codec->reg_area_virt); + out_release_region: + release_mem_region(pci_resource_start(pcidev, 0), 0x8000); out_free: kfree(codec); return -ENODEV; @@ -2529,6 +2590,7 @@ ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL); ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); iounmap(codec->reg_area_virt); + release_mem_region(pci_resource_start(pcidev, 0), 0x8000); #ifdef CONFIG_SOUND_YMFPCI_LEGACY if (codec->iomidi) { unload_uart401(&codec->mpu_data); @@ -2545,7 +2607,7 @@ name: "ymfpci", id_table: ymf_id_tbl, probe: ymf_probe_one, - remove: ymf_remove_one, + remove: __devexit_p(ymf_remove_one), suspend: ymf_suspend, resume: ymf_resume }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/tc/zs.c linux-2.5/drivers/tc/zs.c --- linux-2.5.1/drivers/tc/zs.c Mon Aug 27 15:56:31 2001 +++ linux-2.5/drivers/tc/zs.c Sun Dec 30 21:17:30 2001 @@ -64,7 +64,6 @@ #include <asm/pgtable.h> #include <asm/irq.h> #include <asm/system.h> -#include <asm/segment.h> #include <asm/bitops.h> #include <asm/uaccess.h> #include <asm/wbflush.h> @@ -1893,7 +1892,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -2125,18 +2126,6 @@ } } -/* - * Receive character from the serial port - */ -static int serial_console_wait_key(struct console *co) -{ - struct dec_serial *info; - - info = zs_soft + co->index; - - return zs_poll_rx_char(info); -} - static kdev_t serial_console_device(struct console *c) { return MKDEV(TTY_MAJOR, 64 + c->index); @@ -2271,7 +2260,6 @@ name: "ttyS", write: serial_console_write, device: serial_console_device, - wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: -1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/telephony/ixj.c linux-2.5/drivers/telephony/ixj.c --- linux-2.5.1/drivers/telephony/ixj.c Thu Oct 25 20:53:52 2001 +++ linux-2.5/drivers/telephony/ixj.c Sun Dec 30 21:17:30 2001 @@ -268,7 +268,6 @@ #include <linux/pci.h> #include <asm/io.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/isapnp.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/Config.in linux-2.5/drivers/usb/Config.in --- linux-2.5.1/drivers/usb/Config.in Sun Dec 9 04:28:44 2001 +++ linux-2.5/drivers/usb/Config.in Tue Jan 8 00:44:24 2002 @@ -18,7 +18,8 @@ bool ' Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT fi -comment 'USB Controllers' +comment 'USB Host Controller Drivers' +source drivers/usb/hcd/Config.in if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB fi @@ -32,6 +33,9 @@ comment 'USB Device Class drivers' dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL +if [ "$CONFIG_SCSI" = "n" ]; then + comment ' SCSI support is needed for USB Storage' +fi dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI dep_mbool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE dep_mbool ' Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL @@ -72,6 +76,8 @@ dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV + dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB fi @@ -93,5 +99,6 @@ comment 'USB Miscellaneous drivers' dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL +dep_tristate ' USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/Makefile linux-2.5/drivers/usb/Makefile --- linux-2.5.1/drivers/usb/Makefile Fri Oct 5 19:04:51 2001 +++ linux-2.5/drivers/usb/Makefile Tue Jan 8 00:44:24 2002 @@ -10,19 +10,13 @@ # Objects that export symbols. -export-objs := usb.o +export-objs := usb.o hcd.o ov511.o pwc-uncompress.o # Multipart objects. -list-multi := usbcore.o hid.o -usbcore-objs := usb.o usb-debug.o hub.o +list-multi := usbcore.o hid.o pwc.o +usbcore-objs := usb.o usb-debug.o hub.o hcd.o hid-objs := hid-core.o hid-input.o - -ifneq ($(CONFIG_USB_PWC),n) - export-objs += pwc-uncompress.o - list-multi += pwc.o -endif - pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o @@ -46,6 +40,12 @@ # Each configuration option enables a list of files. obj-$(CONFIG_USB) += usbcore.o + +# EHCI needs to be linked before the other HCD drivers +ifeq ($(CONFIG_USB_EHCI_HCD),y) + obj-y += hcd/ehci-hcd.o +endif + obj-$(CONFIG_USB_UHCI) += usb-uhci.o obj-$(CONFIG_USB_UHCI_ALT) += uhci.o obj-$(CONFIG_USB_OHCI) += usb-ohci.o @@ -65,8 +65,10 @@ obj-$(CONFIG_USB_MDC800) += mdc800.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_DABUSB) += dabusb.o +obj-$(CONFIG_USB_VICAM) += vicam.o obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_SE401) += se401.o +obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_CATC) += catc.o obj-$(CONFIG_USB_KAWETH) += kaweth.o @@ -77,9 +79,12 @@ obj-$(CONFIG_USB_HPUSBSCSI) += hpusbscsi.o obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o obj-$(CONFIG_USB_USBNET) += usbnet.o +obj-$(CONFIG_USB_AUERSWALD) += auerswald.o # Object files in subdirectories +mod-subdirs := serial hcd +subdir-$(CONFIG_USB_EHCI_HCD) += hcd subdir-$(CONFIG_USB_SERIAL) += serial subdir-$(CONFIG_USB_STORAGE) += storage diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/acm.c linux-2.5/drivers/usb/acm.c --- linux-2.5.1/drivers/usb/acm.c Fri Oct 5 19:06:08 2001 +++ linux-2.5/drivers/usb/acm.c Tue Jan 8 00:44:24 2002 @@ -184,7 +184,7 @@ static void acm_ctrl_irq(struct urb *urb) { struct acm *acm = urb->context; - devrequest *dr = urb->transfer_buffer; + struct usb_ctrlrequest *dr = urb->transfer_buffer; unsigned char *data = (unsigned char *)(dr + 1); int newctrl; @@ -195,7 +195,7 @@ return; } - switch (dr->request) { + switch (dr->bRequest) { case ACM_IRQ_NETWORK: @@ -223,7 +223,7 @@ default: dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d", - dr->request, dr->index, dr->length, data[0], data[1]); + dr->bRequest, dr->wIndex, dr->wLength, data[0], data[1]); return; } } @@ -297,7 +297,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) { - struct acm *acm = acm_table[MINOR(tty->device)]; + struct acm *acm = acm_table[minor(tty->device)]; if (!acm || !acm->dev) return -EINVAL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/audio.c linux-2.5/drivers/usb/audio.c --- linux-2.5.1/drivers/usb/audio.c Sun Dec 9 04:28:44 2001 +++ linux-2.5/drivers/usb/audio.c Wed Jan 2 17:23:52 2002 @@ -833,7 +833,7 @@ } } -static int usbin_prepare_desc(struct usbin *u, purb_t urb) +static int usbin_prepare_desc(struct usbin *u, struct urb *urb) { unsigned int i, maxsize, offs; @@ -850,7 +850,7 @@ * return value: 0 if descriptor should be restarted, -1 otherwise * convert sample format on the fly if necessary */ -static int usbin_retire_desc(struct usbin *u, purb_t urb) +static int usbin_retire_desc(struct usbin *u, struct urb *urb) { unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree; unsigned char *cp; @@ -930,7 +930,7 @@ /* * we output sync data */ -static int usbin_sync_prepare_desc(struct usbin *u, purb_t urb) +static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb) { unsigned char *cp = urb->transfer_buffer; unsigned int i, offs; @@ -948,7 +948,7 @@ /* * return value: 0 if descriptor should be restarted, -1 otherwise */ -static int usbin_sync_retire_desc(struct usbin *u, purb_t urb) +static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb) { unsigned int i; @@ -996,7 +996,7 @@ { struct usb_device *dev = as->state->usbdev; struct usbin *u = &as->usbin; - purb_t urb; + struct urb *urb; unsigned long flags; unsigned int maxsze, bufsz; @@ -1186,7 +1186,7 @@ } } -static int usbout_prepare_desc(struct usbout *u, purb_t urb) +static int usbout_prepare_desc(struct usbout *u, struct urb *urb) { unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs; unsigned char *cp = urb->transfer_buffer; @@ -1238,7 +1238,7 @@ /* * return value: 0 if descriptor should be restarted, -1 otherwise */ -static int usbout_retire_desc(struct usbout *u, purb_t urb) +static int usbout_retire_desc(struct usbout *u, struct urb *urb) { unsigned int i; @@ -1285,7 +1285,7 @@ spin_unlock_irqrestore(&as->lock, flags); } -static int usbout_sync_prepare_desc(struct usbout *u, purb_t urb) +static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb) { unsigned int i, offs; @@ -1299,7 +1299,7 @@ /* * return value: 0 if descriptor should be restarted, -1 otherwise */ -static int usbout_sync_retire_desc(struct usbout *u, purb_t urb) +static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb) { unsigned char *cp = urb->transfer_buffer; unsigned int f, i; @@ -1361,7 +1361,7 @@ { struct usb_device *dev = as->state->usbdev; struct usbout *u = &as->usbout; - purb_t urb; + struct urb *urb; unsigned long flags; unsigned int maxsze, bufsz; @@ -1947,7 +1947,7 @@ static int usb_audio_open_mixdev(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct list_head *devs, *mdevs; struct usb_mixerdev *ms; struct usb_audio_state *s; @@ -2621,7 +2621,7 @@ static int usb_audio_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); struct list_head *devs, *adevs; struct usb_audiodev *as; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/auerswald.c linux-2.5/drivers/usb/auerswald.c --- linux-2.5.1/drivers/usb/auerswald.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/auerswald.c Thu Jan 10 13:32:21 2002 @@ -0,0 +1,2156 @@ +/*****************************************************************************/ +/* + * auerswald.c -- Auerswald PBX/System Telephone usb driver. + * + * Copyright (C) 2001 Wolfgang Mües (wmues@nexgo.de) + * + * Very much code of this driver is borrowed from dabusb.c (Deti Fliegl) + * and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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. + */ + /*****************************************************************************/ + +/* Standard Linux module include files */ +#include <asm/uaccess.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/devfs_fs_kernel.h> +#undef DEBUG /* include debug macros until it's done */ +#include <linux/usb.h> + +/*-------------------------------------------------------------------*/ +/* Debug support */ +#ifdef DEBUG +#define dump( adr, len) \ +do { \ + unsigned int u; \ + printk (KERN_DEBUG); \ + for (u = 0; u < len; u++) \ + printk (" %02X", adr[u] & 0xFF); \ + printk ("\n"); \ +} while (0) +#else +#define dump( adr, len) +#endif + +/*-------------------------------------------------------------------*/ +/* Version Information */ +#define DRIVER_VERSION "0.9.9" +#define DRIVER_AUTHOR "Wolfgang Mües <wmues@nexgo.de>" +#define DRIVER_DESC "Auerswald PBX/System Telephone usb driver" + +/*-------------------------------------------------------------------*/ +/* Private declarations for Auerswald USB driver */ + +/* Auerswald Vendor ID */ +#define ID_AUERSWALD 0x09BF + +#ifndef AUER_MINOR_BASE /* allow external override */ +#define AUER_MINOR_BASE 80 /* auerswald driver minor number */ +#endif + +/* we can have up to this number of device plugged in at once */ +#define AUER_MAX_DEVICES 16 + +/* prefix for the device descriptors in /dev/usb */ +#define AU_PREFIX "auer" + +/* Number of read buffers for each device */ +#define AU_RBUFFERS 10 + +/* Number of chain elements for each control chain */ +#define AUCH_ELEMENTS 20 + +/* Number of retries in communication */ +#define AU_RETRIES 10 + +/*-------------------------------------------------------------------*/ +/* vendor specific protocol */ +/* Header Byte */ +#define AUH_INDIRMASK 0x80 /* mask for direct/indirect bit */ +#define AUH_DIRECT 0x00 /* data is for USB device */ +#define AUH_INDIRECT 0x80 /* USB device is relay */ + +#define AUH_SPLITMASK 0x40 /* mask for split bit */ +#define AUH_UNSPLIT 0x00 /* data block is full-size */ +#define AUH_SPLIT 0x40 /* data block is part of a larger one, + split-byte follows */ + +#define AUH_TYPEMASK 0x3F /* mask for type of data transfer */ +#define AUH_TYPESIZE 0x40 /* different types */ +#define AUH_DCHANNEL 0x00 /* D channel data */ +#define AUH_B1CHANNEL 0x01 /* B1 channel transparent */ +#define AUH_B2CHANNEL 0x02 /* B2 channel transparent */ +/* 0x03..0x0F reserved for driver internal use */ +#define AUH_COMMAND 0x10 /* Command channel */ +#define AUH_BPROT 0x11 /* Configuration block protocol */ +#define AUH_DPROTANA 0x12 /* D channel protocol analyzer */ +#define AUH_TAPI 0x13 /* telephone api data (ATD) */ +/* 0x14..0x3F reserved for other protocols */ +#define AUH_UNASSIGNED 0xFF /* if char device has no assigned service */ +#define AUH_FIRSTUSERCH 0x11 /* first channel which is available for driver users */ + +#define AUH_SIZE 1 /* Size of Header Byte */ + +/* Split Byte. Only present if split bit in header byte set.*/ +#define AUS_STARTMASK 0x80 /* mask for first block of splitted frame */ +#define AUS_FIRST 0x80 /* first block */ +#define AUS_FOLLOW 0x00 /* following block */ + +#define AUS_ENDMASK 0x40 /* mask for last block of splitted frame */ +#define AUS_END 0x40 /* last block */ +#define AUS_NOEND 0x00 /* not the last block */ + +#define AUS_LENMASK 0x3F /* mask for block length information */ + +/* Request types */ +#define AUT_RREQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER) /* Read Request */ +#define AUT_WREQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER) /* Write Request */ + +/* Vendor Requests */ +#define AUV_GETINFO 0x00 /* GetDeviceInfo */ +#define AUV_WBLOCK 0x01 /* Write Block */ +#define AUV_RBLOCK 0x02 /* Read Block */ +#define AUV_CHANNELCTL 0x03 /* Channel Control */ +#define AUV_DUMMY 0x04 /* Dummy Out for retry */ + +/* Device Info Types */ +#define AUDI_NUMBCH 0x0000 /* Number of supported B channels */ +#define AUDI_OUTFSIZE 0x0001 /* Size of OUT B channel fifos */ +#define AUDI_MBCTRANS 0x0002 /* max. Blocklength of control transfer */ + +/* Interrupt endpoint definitions */ +#define AU_IRQENDP 1 /* Endpoint number */ +#define AU_IRQCMDID 16 /* Command-block ID */ +#define AU_BLOCKRDY 0 /* Command: Block data ready on ctl endpoint */ +#define AU_IRQMINSIZE 5 /* Nr. of bytes decoded in this driver */ + +/* Device String Descriptors */ +#define AUSI_VENDOR 1 /* "Auerswald GmbH & Co. KG" */ +#define AUSI_DEVICE 2 /* Name of the Device */ +#define AUSI_SERIALNR 3 /* Serial Number */ +#define AUSI_MSN 4 /* "MSN ..." (first) Multiple Subscriber Number */ + +#define AUSI_DLEN 100 /* Max. Length of Device Description */ + +#define AUV_RETRY 0x101 /* First Firmware version which can do control retries */ + +/*-------------------------------------------------------------------*/ +/* External data structures / Interface */ +typedef struct +{ + char *buf; /* return buffer for string contents */ + unsigned int bsize; /* size of return buffer */ +} audevinfo_t,*paudevinfo_t; + +/* IO controls */ +#define IOCTL_AU_SLEN _IOR( 'U', 0xF0, int) /* return the max. string descriptor length */ +#define IOCTL_AU_DEVINFO _IOWR('U', 0xF1, audevinfo_t) /* get name of a specific device */ +#define IOCTL_AU_SERVREQ _IOW( 'U', 0xF2, int) /* request a service channel */ +#define IOCTL_AU_BUFLEN _IOR( 'U', 0xF3, int) /* return the max. buffer length for the device */ +#define IOCTL_AU_RXAVAIL _IOR( 'U', 0xF4, int) /* return != 0 if Receive Data available */ +#define IOCTL_AU_CONNECT _IOR( 'U', 0xF5, int) /* return != 0 if connected to a service channel */ +#define IOCTL_AU_TXREADY _IOR( 'U', 0xF6, int) /* return != 0 if Transmitt channel ready to send */ +/* 'U' 0xF7..0xFF reseved */ + +/*-------------------------------------------------------------------*/ +/* Internal data structures */ + +/* ..................................................................*/ +/* urb chain element */ +struct auerchain; /* forward for circular reference */ +typedef struct +{ + struct auerchain *chain; /* pointer to the chain to which this element belongs */ + urb_t * urbp; /* pointer to attached urb */ + void *context; /* saved URB context */ + usb_complete_t complete; /* saved URB completion function */ + struct list_head list; /* to include element into a list */ +} auerchainelement_t,*pauerchainelement_t; + +/* urb chain */ +typedef struct auerchain +{ + pauerchainelement_t active; /* element which is submitted to urb */ + spinlock_t lock; /* protection agains interrupts */ + struct list_head waiting_list; /* list of waiting elements */ + struct list_head free_list; /* list of available elements */ +} auerchain_t,*pauerchain_t; + +/* ...................................................................*/ +/* buffer element */ +struct auerbufctl; /* forward */ +typedef struct +{ + char *bufp; /* reference to allocated data buffer */ + unsigned int len; /* number of characters in data buffer */ + unsigned int retries; /* for urb retries */ + struct usb_ctrlrequest *dr; /* for setup data in control messages */ + urb_t * urbp; /* USB urb */ + struct auerbufctl *list; /* pointer to list */ + struct list_head buff_list; /* reference to next buffer in list */ +} auerbuf_t,*pauerbuf_t; + +/* buffer list control block */ +typedef struct auerbufctl +{ + spinlock_t lock; /* protection in interrupt */ + struct list_head free_buff_list;/* free buffers */ + struct list_head rec_buff_list; /* buffers with receive data */ +} auerbufctl_t,*pauerbufctl_t; + +/* ...................................................................*/ +/* service context */ +struct auerscon; /* forward */ +typedef void (*auer_dispatch_t)(struct auerscon*, pauerbuf_t); +typedef void (*auer_disconn_t) (struct auerscon*); +typedef struct auerscon +{ + unsigned int id; /* protocol service id AUH_xxxx */ + auer_dispatch_t dispatch; /* dispatch read buffer */ + auer_disconn_t disconnect; /* disconnect from device, wake up all char readers */ +} auerscon_t,*pauerscon_t; + +/* ...................................................................*/ +/* USB device context */ +typedef struct +{ + struct semaphore mutex; /* protection in user context */ + char name[16]; /* name of the /dev/usb entry */ + unsigned int dtindex; /* index in the device table */ + devfs_handle_t devfs; /* devfs device node */ + struct usb_device * usbdev; /* USB device handle */ + int open_count; /* count the number of open character channels */ + char dev_desc[AUSI_DLEN];/* for storing a textual description */ + unsigned int maxControlLength; /* max. Length of control paket (without header) */ + urb_t * inturbp; /* interrupt urb */ + char * intbufp; /* data buffer for interrupt urb */ + unsigned int irqsize; /* size of interrupt endpoint 1 */ + struct auerchain controlchain; /* for chaining of control messages */ + auerbufctl_t bufctl; /* Buffer control for control transfers */ + pauerscon_t services[AUH_TYPESIZE];/* context pointers for each service */ + unsigned int version; /* Version of the device */ + wait_queue_head_t bufferwait; /* wait for a control buffer */ +} auerswald_t,*pauerswald_t; + +/* the global usb devfs handle */ +extern devfs_handle_t usb_devfs_handle; + +/* array of pointers to our devices that are currently connected */ +static pauerswald_t dev_table[AUER_MAX_DEVICES]; + +/* lock to protect the dev_table structure */ +static struct semaphore dev_table_mutex; + +/* ................................................................... */ +/* character device context */ +typedef struct +{ + struct semaphore mutex; /* protection in user context */ + pauerswald_t auerdev; /* context pointer of assigned device */ + auerbufctl_t bufctl; /* controls the buffer chain */ + auerscon_t scontext; /* service context */ + wait_queue_head_t readwait; /* for synchronous reading */ + struct semaphore readmutex; /* protection against multiple reads */ + pauerbuf_t readbuf; /* buffer held for partial reading */ + unsigned int readoffset; /* current offset in readbuf */ + unsigned int removed; /* is != 0 if device is removed */ +} auerchar_t,*pauerchar_t; + + +/*-------------------------------------------------------------------*/ +/* Forwards */ +static void auerswald_ctrlread_complete (urb_t * urb); +static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp); + + +/*-------------------------------------------------------------------*/ +/* USB chain helper functions */ +/* -------------------------- */ + +/* completion function for chained urbs */ +static void auerchain_complete (urb_t * urb) +{ + unsigned long flags; + int result; + + /* get pointer to element and to chain */ + pauerchainelement_t acep = (pauerchainelement_t) urb->context; + pauerchain_t acp = acep->chain; + + /* restore original entries in urb */ + urb->context = acep->context; + urb->complete = acep->complete; + + dbg ("auerchain_complete called"); + + /* call original completion function + NOTE: this function may lead to more urbs submitted into the chain. + (no chain lock at calling complete()!) + acp->active != NULL is protecting us against recursion.*/ + urb->complete (urb); + + /* detach element from chain data structure */ + spin_lock_irqsave (&acp->lock, flags); + if (acp->active != acep) /* paranoia debug check */ + dbg ("auerchain_complete: completion on non-active element called!"); + else + acp->active = NULL; + + /* add the used chain element to the list of free elements */ + list_add_tail (&acep->list, &acp->free_list); + acep = NULL; + + /* is there a new element waiting in the chain? */ + if (!acp->active && !list_empty (&acp->waiting_list)) { + /* yes: get the entry */ + struct list_head *tmp = acp->waiting_list.next; + list_del (tmp); + acep = list_entry (tmp, auerchainelement_t, list); + acp->active = acep; + } + spin_unlock_irqrestore (&acp->lock, flags); + + /* submit the new urb */ + if (acep) { + urb = acep->urbp; + dbg ("auerchain_complete: submitting next urb from chain"); + urb->status = 0; /* needed! */ + result = usb_submit_urb( urb); + + /* check for submit errors */ + if (result) { + urb->status = result; + dbg("auerchain_complete: usb_submit_urb with error code %d", result); + /* and do error handling via *this* completion function (recursive) */ + auerchain_complete( urb); + } + } else { + /* simple return without submitting a new urb. + The empty chain is detected with acp->active == NULL. */ + }; +} + + +/* submit function for chained urbs + this function may be called from completion context or from user space! + early = 1 -> submit in front of chain +*/ +static int auerchain_submit_urb_list (pauerchain_t acp, urb_t * urb, int early) +{ + int result; + unsigned long flags; + pauerchainelement_t acep = NULL; + + dbg ("auerchain_submit_urb called"); + + /* try to get a chain element */ + spin_lock_irqsave (&acp->lock, flags); + if (!list_empty (&acp->free_list)) { + /* yes: get the entry */ + struct list_head *tmp = acp->free_list.next; + list_del (tmp); + acep = list_entry (tmp, auerchainelement_t, list); + } + spin_unlock_irqrestore (&acp->lock, flags); + + /* if no chain element available: return with error */ + if (!acep) { + return -ENOMEM; + } + + /* fill in the new chain element values */ + acep->chain = acp; + acep->context = urb->context; + acep->complete = urb->complete; + acep->urbp = urb; + INIT_LIST_HEAD (&acep->list); + + /* modify urb */ + urb->context = acep; + urb->complete = auerchain_complete; + urb->status = -EINPROGRESS; /* usb_submit_urb does this, too */ + + /* add element to chain - or start it immediately */ + spin_lock_irqsave (&acp->lock, flags); + if (acp->active) { + /* there is traffic in the chain, simple add element to chain */ + if (early) { + dbg ("adding new urb to head of chain"); + list_add (&acep->list, &acp->waiting_list); + } else { + dbg ("adding new urb to end of chain"); + list_add_tail (&acep->list, &acp->waiting_list); + } + acep = NULL; + } else { + /* the chain is empty. Prepare restart */ + acp->active = acep; + } + /* Spin has to be removed before usb_submit_urb! */ + spin_unlock_irqrestore (&acp->lock, flags); + + /* Submit urb if immediate restart */ + if (acep) { + dbg("submitting urb immediate"); + urb->status = 0; /* needed! */ + result = usb_submit_urb( urb); + /* check for submit errors */ + if (result) { + urb->status = result; + dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result); + /* and do error handling via completion function */ + auerchain_complete( urb); + } + } + + return 0; +} + +/* submit function for chained urbs + this function may be called from completion context or from user space! +*/ +static int auerchain_submit_urb (pauerchain_t acp, urb_t * urb) +{ + return auerchain_submit_urb_list (acp, urb, 0); +} + +/* cancel an urb which is submitted to the chain + the result is 0 if the urb is cancelled, or -EINPROGRESS if + USB_ASYNC_UNLINK is set and the function is successfully started. +*/ +static int auerchain_unlink_urb (pauerchain_t acp, urb_t * urb) +{ + unsigned long flags; + urb_t * urbp; + pauerchainelement_t acep; + struct list_head *tmp; + + dbg ("auerchain_unlink_urb called"); + + /* search the chain of waiting elements */ + spin_lock_irqsave (&acp->lock, flags); + list_for_each (tmp, &acp->waiting_list) { + acep = list_entry (tmp, auerchainelement_t, list); + if (acep->urbp == urb) { + list_del (tmp); + urb->context = acep->context; + urb->complete = acep->complete; + list_add_tail (&acep->list, &acp->free_list); + spin_unlock_irqrestore (&acp->lock, flags); + dbg ("unlink waiting urb"); + urb->status = -ENOENT; + urb->complete (urb); + return 0; + } + } + /* not found. */ + spin_unlock_irqrestore (&acp->lock, flags); + + /* get the active urb */ + acep = acp->active; + if (acep) { + urbp = acep->urbp; + + /* check if we have to cancel the active urb */ + if (urbp == urb) { + /* note that there is a race condition between the check above + and the unlink() call because of no lock. This race is harmless, + because the usb module will detect the unlink() after completion. + We can't use the acp->lock here because the completion function + wants to grab it. + */ + dbg ("unlink active urb"); + return usb_unlink_urb (urbp); + } + } + + /* not found anyway + ... is some kind of success + */ + dbg ("urb to unlink not found in chain"); + return 0; +} + +/* cancel all urbs which are in the chain. + this function must not be called from interrupt or completion handler. +*/ +static void auerchain_unlink_all (pauerchain_t acp) +{ + unsigned long flags; + urb_t * urbp; + pauerchainelement_t acep; + + dbg ("auerchain_unlink_all called"); + + /* clear the chain of waiting elements */ + spin_lock_irqsave (&acp->lock, flags); + while (!list_empty (&acp->waiting_list)) { + /* get the next entry */ + struct list_head *tmp = acp->waiting_list.next; + list_del (tmp); + acep = list_entry (tmp, auerchainelement_t, list); + urbp = acep->urbp; + urbp->context = acep->context; + urbp->complete = acep->complete; + list_add_tail (&acep->list, &acp->free_list); + spin_unlock_irqrestore (&acp->lock, flags); + dbg ("unlink waiting urb"); + urbp->status = -ENOENT; + urbp->complete (urbp); + spin_lock_irqsave (&acp->lock, flags); + } + spin_unlock_irqrestore (&acp->lock, flags); + + /* clear the active urb */ + acep = acp->active; + if (acep) { + urbp = acep->urbp; + urbp->transfer_flags &= ~USB_ASYNC_UNLINK; + dbg ("unlink active urb"); + usb_unlink_urb (urbp); + } +} + + +/* free the chain. + this function must not be called from interrupt or completion handler. +*/ +static void auerchain_free (pauerchain_t acp) +{ + unsigned long flags; + pauerchainelement_t acep; + + dbg ("auerchain_free called"); + + /* first, cancel all pending urbs */ + auerchain_unlink_all (acp); + + /* free the elements */ + spin_lock_irqsave (&acp->lock, flags); + while (!list_empty (&acp->free_list)) { + /* get the next entry */ + struct list_head *tmp = acp->free_list.next; + list_del (tmp); + spin_unlock_irqrestore (&acp->lock, flags); + acep = list_entry (tmp, auerchainelement_t, list); + kfree (acep); + spin_lock_irqsave (&acp->lock, flags); + } + spin_unlock_irqrestore (&acp->lock, flags); +} + + +/* Init the chain control structure */ +static void auerchain_init (pauerchain_t acp) +{ + /* init the chain data structure */ + acp->active = NULL; + spin_lock_init (&acp->lock); + INIT_LIST_HEAD (&acp->waiting_list); + INIT_LIST_HEAD (&acp->free_list); +} + +/* setup a chain. + It is assumed that there is no concurrency while setting up the chain + requirement: auerchain_init() +*/ +static int auerchain_setup (pauerchain_t acp, unsigned int numElements) +{ + pauerchainelement_t acep; + + dbg ("auerchain_setup called with %d elements", numElements); + + /* fill the list of free elements */ + for (;numElements; numElements--) { + acep = (pauerchainelement_t) kmalloc (sizeof (auerchainelement_t), GFP_KERNEL); + if (!acep) goto ac_fail; + memset (acep, 0, sizeof (auerchainelement_t)); + INIT_LIST_HEAD (&acep->list); + list_add_tail (&acep->list, &acp->free_list); + } + return 0; + +ac_fail:/* free the elements */ + while (!list_empty (&acp->free_list)) { + /* get the next entry */ + struct list_head *tmp = acp->free_list.next; + list_del (tmp); + acep = list_entry (tmp, auerchainelement_t, list); + kfree (acep); + } + return -ENOMEM; +} + + +/* completion handler for synchronous chained URBs */ +static void auerchain_blocking_completion (urb_t *urb) +{ + wait_queue_head_t *wakeup = (wait_queue_head_t *)urb->context; + wake_up (wakeup); +} + + +/* Starts chained urb and waits for completion or timeout */ +static int auerchain_start_wait_urb (pauerchain_t acp, urb_t *urb, int timeout, int* actual_length) +{ + DECLARE_WAITQUEUE (wait, current); + DECLARE_WAIT_QUEUE_HEAD (wqh); + int status; + + dbg ("auerchain_start_wait_urb called"); + init_waitqueue_head (&wqh); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue (&wqh, &wait); + urb->context = &wqh; + status = auerchain_submit_urb ( acp, urb); + if (status) { + /* something went wrong */ + 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 */ + dbg ("auerchain_start_wait_urb: timeout"); + auerchain_unlink_urb (acp, urb); /* remove urb safely */ + status = -ETIMEDOUT; + } else + status = urb->status; + + if (actual_length) + *actual_length = urb->actual_length; + + return status; +} + + +/* auerchain_control_msg - Builds a control urb, sends it off and waits for completion + acp: pointer to the auerchain + dev: pointer to the usb device to send the message to + pipe: endpoint "pipe" to send the message to + request: USB message request value + requesttype: USB message request type value + value: USB message value + index: USB message index value + data: pointer to the data to send + size: length in bytes of the data to send + timeout: time to wait for the message to complete before timing out (if 0 the wait is forever) + + This function sends a simple control message to a specified endpoint + and waits for the message to complete, or timeout. + + If successful, it returns the transfered length, othwise a negative error number. + + Don't use this function from within an interrupt context, like a + bottom half handler. If you need a asyncronous message, or need to send + a message from within interrupt context, use auerchain_submit_urb() +*/ +static int auerchain_control_msg (pauerchain_t acp, struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, + __u16 value, __u16 index, void *data, __u16 size, int timeout) +{ + int ret; + struct usb_ctrlrequest *dr; + urb_t *urb; + int length; + + dbg ("auerchain_control_msg"); + dr = kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL); + if (!dr) + return -ENOMEM; + urb = usb_alloc_urb (0); + if (!urb) { + kfree (dr); + return -ENOMEM; + } + + dr->bRequestType = requesttype; + dr->bRequest = request; + dr->wValue = cpu_to_le16 (value); + dr->wIndex = cpu_to_le16 (index); + dr->wLength = cpu_to_le16 (size); + + FILL_CONTROL_URB (urb, dev, pipe, (unsigned char*)dr, data, size, /* build urb */ + (usb_complete_t)auerchain_blocking_completion,0); + ret = auerchain_start_wait_urb (acp, urb, timeout, &length); + + usb_free_urb (urb); + kfree (dr); + + if (ret < 0) + return ret; + else + return length; +} + + +/*-------------------------------------------------------------------*/ +/* Buffer List helper functions */ + +/* free a single auerbuf */ +static void auerbuf_free (pauerbuf_t bp) +{ + if (bp->bufp) { + kfree (bp->bufp); + } + if (bp->dr) { + kfree (bp->dr); + } + if (bp->urbp) { + usb_free_urb (bp->urbp); + } + kfree (bp); +} + +/* free the buffers from an auerbuf list */ +static void auerbuf_free_list (struct list_head *q) +{ + struct list_head *tmp; + struct list_head *p; + pauerbuf_t bp; + + dbg ("auerbuf_free_list"); + for (p = q->next; p != q;) { + bp = list_entry (p, auerbuf_t, buff_list); + tmp = p->next; + list_del (p); + p = tmp; + auerbuf_free (bp); + } +} + +/* init the members of a list control block */ +static void auerbuf_init (pauerbufctl_t bcp) +{ + dbg ("auerbuf_init"); + spin_lock_init (&bcp->lock); + INIT_LIST_HEAD (&bcp->free_buff_list); + INIT_LIST_HEAD (&bcp->rec_buff_list); +} + +/* free all buffers from an auerbuf chain */ +static void auerbuf_free_buffers (pauerbufctl_t bcp) +{ + unsigned long flags; + dbg ("auerbuf_free_buffers"); + + spin_lock_irqsave (&bcp->lock, flags); + + auerbuf_free_list (&bcp->free_buff_list); + auerbuf_free_list (&bcp->rec_buff_list); + + spin_unlock_irqrestore (&bcp->lock, flags); +} + +/* setup a list of buffers */ +/* requirement: auerbuf_init() */ +static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned int bufsize) +{ + pauerbuf_t bep; + + dbg ("auerbuf_setup called with %d elements of %d bytes", numElements, bufsize); + + /* fill the list of free elements */ + for (;numElements; numElements--) { + bep = (pauerbuf_t) kmalloc (sizeof (auerbuf_t), GFP_KERNEL); + if (!bep) goto bl_fail; + memset (bep, 0, sizeof (auerbuf_t)); + bep->list = bcp; + INIT_LIST_HEAD (&bep->buff_list); + bep->bufp = (char *) kmalloc (bufsize, GFP_KERNEL); + if (!bep->bufp) goto bl_fail; + bep->dr = (struct usb_ctrlrequest *) kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL); + if (!bep->dr) goto bl_fail; + bep->urbp = usb_alloc_urb (0); + if (!bep->urbp) goto bl_fail; + list_add_tail (&bep->buff_list, &bcp->free_buff_list); + } + return 0; + +bl_fail:/* not enought memory. Free allocated elements */ + dbg ("auerbuf_setup: no more memory"); + auerbuf_free_buffers (bcp); + return -ENOMEM; +} + +/* insert a used buffer into the free list */ +static void auerbuf_releasebuf( pauerbuf_t bp) +{ + unsigned long flags; + pauerbufctl_t bcp = bp->list; + bp->retries = 0; + + dbg ("auerbuf_releasebuf called"); + spin_lock_irqsave (&bcp->lock, flags); + list_add_tail (&bp->buff_list, &bcp->free_buff_list); + spin_unlock_irqrestore (&bcp->lock, flags); +} + + +/*-------------------------------------------------------------------*/ +/* Completion handlers */ + +/* Values of urb->status or results of usb_submit_urb(): +0 Initial, OK +-EINPROGRESS during submission until end +-ENOENT if urb is unlinked +-ETIMEDOUT Transfer timed out, NAK +-ENOMEM Memory Overflow +-ENODEV Specified USB-device or bus doesn't exist +-ENXIO URB already queued +-EINVAL a) Invalid transfer type specified (or not supported) + b) Invalid interrupt interval (0n256) +-EAGAIN a) Specified ISO start frame too early + b) (using ISO-ASAP) Too much scheduled for the future wait some time and try again. +-EFBIG Too much ISO frames requested (currently uhci900) +-EPIPE Specified pipe-handle/Endpoint is already stalled +-EMSGSIZE Endpoint message size is zero, do interface/alternate setting +-EPROTO a) Bitstuff error + b) Unknown USB error +-EILSEQ CRC mismatch +-ENOSR Buffer error +-EREMOTEIO Short packet detected +-EXDEV ISO transfer only partially completed look at individual frame status for details +-EINVAL ISO madness, if this happens: Log off and go home +-EOVERFLOW babble +*/ + +/* check if a status code allows a retry */ +static int auerswald_status_retry (int status) +{ + switch (status) { + case 0: + case -ETIMEDOUT: + case -EOVERFLOW: + case -EAGAIN: + case -EPIPE: + case -EPROTO: + case -EILSEQ: + case -ENOSR: + case -EREMOTEIO: + return 1; /* do a retry */ + } + return 0; /* no retry possible */ +} + +/* Completion of asynchronous write block */ +static void auerchar_ctrlwrite_complete (urb_t * urb) +{ + pauerbuf_t bp = (pauerbuf_t) urb->context; + pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); + dbg ("auerchar_ctrlwrite_complete called"); + + /* reuse the buffer */ + auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); +} + +/* Completion handler for dummy retry packet */ +static void auerswald_ctrlread_wretcomplete (urb_t * urb) +{ + pauerbuf_t bp = (pauerbuf_t) urb->context; + pauerswald_t cp; + int ret; + dbg ("auerswald_ctrlread_wretcomplete called"); + dbg ("complete with status: %d", urb->status); + cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); + + /* check if it is possible to advance */ + if (!auerswald_status_retry (urb->status) || !cp->usbdev) { + /* reuse the buffer */ + err ("control dummy: transmission error %d, can not retry", urb->status); + auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); + return; + } + + /* fill the control message */ + bp->dr->bRequestType = AUT_RREQ; + bp->dr->bRequest = AUV_RBLOCK; + bp->dr->wLength = bp->dr->wValue; /* temporary stored */ + bp->dr->wValue = cpu_to_le16 (1); /* Retry Flag */ + /* bp->dr->index = channel id; remains */ + FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0), + (unsigned char*)bp->dr, bp->bufp, le16_to_cpu (bp->dr->wLength), + (usb_complete_t)auerswald_ctrlread_complete,bp); + + /* submit the control msg as next paket */ + ret = auerchain_submit_urb_list (&cp->controlchain, bp->urbp, 1); + if (ret) { + dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret); + bp->urbp->status = ret; + auerswald_ctrlread_complete (bp->urbp); + } +} + +/* completion handler for receiving of control messages */ +static void auerswald_ctrlread_complete (urb_t * urb) +{ + unsigned int serviceid; + pauerswald_t cp; + pauerscon_t scp; + pauerbuf_t bp = (pauerbuf_t) urb->context; + int ret; + dbg ("auerswald_ctrlread_complete called"); + + cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl))); + + /* check if there is valid data in this urb */ + if (urb->status) { + dbg ("complete with non-zero status: %d", urb->status); + /* should we do a retry? */ + if (!auerswald_status_retry (urb->status) + || !cp->usbdev + || (cp->version < AUV_RETRY) + || (bp->retries >= AU_RETRIES)) { + /* reuse the buffer */ + err ("control read: transmission error %d, can not retry", urb->status); + auerbuf_releasebuf (bp); + return; + } + bp->retries++; + dbg ("Retry count = %d", bp->retries); + /* send a long dummy control-write-message to allow device firmware to react */ + bp->dr->bRequestType = AUT_WREQ; + bp->dr->bRequest = AUV_DUMMY; + bp->dr->wValue = bp->dr->wLength; /* temporary storage */ + // bp->dr->wIndex channel ID remains + bp->dr->wLength = cpu_to_le16 (32); /* >= 8 bytes */ + FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0), + (unsigned char*)bp->dr, bp->bufp, 32, + (usb_complete_t)auerswald_ctrlread_wretcomplete,bp); + + /* submit the control msg as next paket */ + ret = auerchain_submit_urb_list (&cp->controlchain, bp->urbp, 1); + if (ret) { + dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret); + bp->urbp->status = ret; + auerswald_ctrlread_wretcomplete (bp->urbp); + } + return; + } + + /* get the actual bytecount (incl. headerbyte) */ + bp->len = urb->actual_length; + serviceid = bp->bufp[0] & AUH_TYPEMASK; + dbg ("Paket with serviceid %d and %d bytes received", serviceid, bp->len); + + /* dispatch the paket */ + scp = cp->services[serviceid]; + if (scp) { + /* look, Ma, a listener! */ + scp->dispatch (scp, bp); + } + + /* release the paket */ + auerbuf_releasebuf (bp); + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); +} + +/*-------------------------------------------------------------------*/ +/* Handling of Interrupt Endpoint */ +/* This interrupt Endpoint is used to inform the host about waiting + messages from the USB device. +*/ +/* int completion handler. */ +static void auerswald_int_complete (urb_t * urb) +{ + unsigned long flags; + unsigned int channelid; + unsigned int bytecount; + int ret; + pauerbuf_t bp = NULL; + pauerswald_t cp = (pauerswald_t) urb->context; + + dbg ("auerswald_int_complete called"); + + /* do not respond to an error condition */ + if (urb->status != 0) { + dbg ("nonzero URB status = %d", urb->status); + return; + } + + /* check if all needed data was received */ + if (urb->actual_length < AU_IRQMINSIZE) { + dbg ("invalid data length received: %d bytes", urb->actual_length); + return; + } + + /* check the command code */ + if (cp->intbufp[0] != AU_IRQCMDID) { + dbg ("invalid command received: %d", cp->intbufp[0]); + return; + } + + /* check the command type */ + if (cp->intbufp[1] != AU_BLOCKRDY) { + dbg ("invalid command type received: %d", cp->intbufp[1]); + return; + } + + /* now extract the information */ + channelid = cp->intbufp[2]; + bytecount = le16_to_cpup (&cp->intbufp[3]); + + /* check the channel id */ + if (channelid >= AUH_TYPESIZE) { + dbg ("invalid channel id received: %d", channelid); + return; + } + + /* check the byte count */ + if (bytecount > (cp->maxControlLength+AUH_SIZE)) { + dbg ("invalid byte count received: %d", bytecount); + return; + } + dbg ("Service Channel = %d", channelid); + dbg ("Byte Count = %d", bytecount); + + /* get a buffer for the next data paket */ + spin_lock_irqsave (&cp->bufctl.lock, flags); + if (!list_empty (&cp->bufctl.free_buff_list)) { + /* yes: get the entry */ + struct list_head *tmp = cp->bufctl.free_buff_list.next; + list_del (tmp); + bp = list_entry (tmp, auerbuf_t, buff_list); + } + spin_unlock_irqrestore (&cp->bufctl.lock, flags); + + /* if no buffer available: skip it */ + if (!bp) { + dbg ("auerswald_int_complete: no data buffer available"); + /* can we do something more? + This is a big problem: if this int packet is ignored, the + device will wait forever and not signal any more data. + The only real solution is: having enought buffers! + Or perhaps temporary disabling the int endpoint? + */ + return; + } + + /* fill the control message */ + bp->dr->bRequestType = AUT_RREQ; + bp->dr->bRequest = AUV_RBLOCK; + bp->dr->wValue = cpu_to_le16 (0); + bp->dr->wIndex = cpu_to_le16 (channelid | AUH_DIRECT | AUH_UNSPLIT); + bp->dr->wLength = cpu_to_le16 (bytecount); + FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0), + (unsigned char*)bp->dr, bp->bufp, bytecount, + (usb_complete_t)auerswald_ctrlread_complete,bp); + + /* submit the control msg */ + ret = auerchain_submit_urb (&cp->controlchain, bp->urbp); + if (ret) { + dbg ("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret); + bp->urbp->status = ret; + auerswald_ctrlread_complete( bp->urbp); + /* here applies the same problem as above: device locking! */ + } +} + +/* int memory deallocation + NOTE: no mutex please! +*/ +static void auerswald_int_free (pauerswald_t cp) +{ + if (cp->inturbp) { + usb_free_urb (cp->inturbp); + cp->inturbp = NULL; + } + if (cp->intbufp) { + kfree (cp->intbufp); + cp->intbufp = NULL; + } +} + +/* This function is called to activate the interrupt + endpoint. This function returns 0 if successfull or an error code. + NOTE: no mutex please! +*/ +static int auerswald_int_open (pauerswald_t cp) +{ + int ret; + struct usb_endpoint_descriptor *ep; + int irqsize; + dbg ("auerswald_int_open"); + + ep = usb_epnum_to_ep_desc (cp->usbdev, USB_DIR_IN | AU_IRQENDP); + if (!ep) { + ret = -EFAULT; + goto intoend; + } + irqsize = ep->wMaxPacketSize; + cp->irqsize = irqsize; + + /* allocate the urb and data buffer */ + if (!cp->inturbp) { + cp->inturbp = usb_alloc_urb (0); + if (!cp->inturbp) { + ret = -ENOMEM; + goto intoend; + } + } + if (!cp->intbufp) { + cp->intbufp = (char *) kmalloc (irqsize, GFP_KERNEL); + if (!cp->intbufp) { + ret = -ENOMEM; + goto intoend; + } + } + /* setup urb */ + FILL_INT_URB (cp->inturbp, cp->usbdev, usb_rcvintpipe (cp->usbdev,AU_IRQENDP), cp->intbufp, irqsize, auerswald_int_complete, cp, ep->bInterval); + /* start the urb */ + cp->inturbp->status = 0; /* needed! */ + ret = usb_submit_urb (cp->inturbp); + +intoend: + if (ret < 0) { + /* activation of interrupt endpoint has failed. Now clean up. */ + dbg ("auerswald_int_open: activation of int endpoint failed"); + + /* deallocate memory */ + auerswald_int_free (cp); + } + return ret; +} + +/* This function is called to deactivate the interrupt + endpoint. This function returns 0 if successfull or an error code. + NOTE: no mutex please! +*/ +static int auerswald_int_release (pauerswald_t cp) +{ + int ret = 0; + dbg ("auerswald_int_release"); + + /* stop the int endpoint */ + if (cp->inturbp) { + ret = usb_unlink_urb (cp->inturbp); + if (ret) + dbg ("nonzero int unlink result received: %d", ret); + } + + /* deallocate memory */ + auerswald_int_free (cp); + + return ret; +} + +/* --------------------------------------------------------------------- */ +/* Helper functions */ + +/* wake up waiting readers */ +static void auerchar_disconnect (pauerscon_t scp) +{ + pauerchar_t ccp = ((pauerchar_t)((char *)(scp)-(unsigned long)(&((pauerchar_t)0)->scontext))); + dbg ("auerchar_disconnect called"); + ccp->removed = 1; + wake_up (&ccp->readwait); +} + + +/* dispatch a read paket to a waiting character device */ +static void auerchar_ctrlread_dispatch (pauerscon_t scp, pauerbuf_t bp) +{ + unsigned long flags; + pauerchar_t ccp; + pauerbuf_t newbp = NULL; + char * charp; + dbg ("auerchar_ctrlread_dispatch called"); + ccp = ((pauerchar_t)((char *)(scp)-(unsigned long)(&((pauerchar_t)0)->scontext))); + + /* get a read buffer from character device context */ + spin_lock_irqsave (&ccp->bufctl.lock, flags); + if (!list_empty (&ccp->bufctl.free_buff_list)) { + /* yes: get the entry */ + struct list_head *tmp = ccp->bufctl.free_buff_list.next; + list_del (tmp); + newbp = list_entry (tmp, auerbuf_t, buff_list); + } + spin_unlock_irqrestore (&ccp->bufctl.lock, flags); + + if (!newbp) { + dbg ("No read buffer available, discard paket!"); + return; /* no buffer, no dispatch */ + } + + /* copy information to new buffer element + (all buffers have the same length) */ + charp = newbp->bufp; + newbp->bufp = bp->bufp; + bp->bufp = charp; + newbp->len = bp->len; + + /* insert new buffer in read list */ + spin_lock_irqsave (&ccp->bufctl.lock, flags); + list_add_tail (&newbp->buff_list, &ccp->bufctl.rec_buff_list); + spin_unlock_irqrestore (&ccp->bufctl.lock, flags); + dbg ("read buffer appended to rec_list"); + + /* wake up pending synchronous reads */ + wake_up (&ccp->readwait); +} + + +/* Delete an auerswald driver context */ +static void auerswald_delete( pauerswald_t cp) +{ + dbg( "auerswald_delete"); + if (cp == NULL) return; + + /* Wake up all processes waiting for a buffer */ + wake_up (&cp->bufferwait); + + /* Cleaning up */ + auerswald_int_release (cp); + auerchain_free (&cp->controlchain); + auerbuf_free_buffers (&cp->bufctl); + + /* release the memory */ + kfree( cp); +} + + +/* Delete an auerswald character context */ +static void auerchar_delete( pauerchar_t ccp) +{ + dbg ("auerchar_delete"); + if (ccp == NULL) return; + + /* wake up pending synchronous reads */ + ccp->removed = 1; + wake_up (&ccp->readwait); + + /* remove the read buffer */ + if (ccp->readbuf) { + auerbuf_releasebuf (ccp->readbuf); + ccp->readbuf = NULL; + } + + /* remove the character buffers */ + auerbuf_free_buffers (&ccp->bufctl); + + /* release the memory */ + kfree( ccp); +} + + +/* add a new service to the device + scp->id must be set! + return: 0 if OK, else error code +*/ +static int auerswald_addservice (pauerswald_t cp, pauerscon_t scp) +{ + int ret; + + /* is the device available? */ + if (!cp->usbdev) { + dbg ("usbdev == NULL"); + return -EIO; /*no: can not add a service, sorry*/ + } + + /* is the service available? */ + if (cp->services[scp->id]) { + dbg ("service is busy"); + return -EBUSY; + } + + /* device is available, service is free */ + cp->services[scp->id] = scp; + + /* register service in device */ + ret = auerchain_control_msg( + &cp->controlchain, /* pointer to control chain */ + cp->usbdev, /* pointer to device */ + usb_sndctrlpipe (cp->usbdev, 0), /* pipe to control endpoint */ + AUV_CHANNELCTL, /* USB message request value */ + AUT_WREQ, /* USB message request type value */ + 0x01, /* open USB message value */ + scp->id, /* USB message index value */ + NULL, /* pointer to the data to send */ + 0, /* length in bytes of the data to send */ + HZ * 2); /* time to wait for the message to complete before timing out */ + if (ret < 0) { + dbg ("auerswald_addservice: auerchain_control_msg returned error code %d", ret); + /* undo above actions */ + cp->services[scp->id] = NULL; + return ret; + } + + dbg ("auerswald_addservice: channel open OK"); + return 0; +} + + +/* remove a service from the the device + scp->id must be set! */ +static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp) +{ + dbg ("auerswald_removeservice called"); + + /* check if we have a service allocated */ + if (scp->id == AUH_UNASSIGNED) return; + + /* If there is a device: close the channel */ + if (cp->usbdev) { + /* Close the service channel inside the device */ + int ret = auerchain_control_msg( + &cp->controlchain, /* pointer to control chain */ + cp->usbdev, /* pointer to device */ + usb_sndctrlpipe (cp->usbdev, 0), /* pipe to control endpoint */ + AUV_CHANNELCTL, /* USB message request value */ + AUT_WREQ, /* USB message request type value */ + 0x00, // close /* USB message value */ + scp->id, /* USB message index value */ + NULL, /* pointer to the data to send */ + 0, /* length in bytes of the data to send */ + HZ * 2); /* time to wait for the message to complete before timing out */ + if (ret < 0) { + dbg ("auerswald_removeservice: auerchain_control_msg returned error code %d", ret); + } + else { + dbg ("auerswald_removeservice: channel close OK"); + } + } + + /* remove the service from the device */ + cp->services[scp->id] = NULL; + scp->id = AUH_UNASSIGNED; +} + + +/* --------------------------------------------------------------------- */ +/* Char device functions */ + +/* Open a new character device */ +static int auerchar_open (struct inode *inode, struct file *file) +{ + int dtindex = minor(inode->i_rdev) - AUER_MINOR_BASE; + pauerswald_t cp = NULL; + pauerchar_t ccp = NULL; + int ret; + + /* minor number in range? */ + if ((dtindex < 0) || (dtindex >= AUER_MAX_DEVICES)) { + return -ENODEV; + } + /* usb device available? */ + if (down_interruptible (&dev_table_mutex)) { + return -ERESTARTSYS; + } + cp = dev_table[dtindex]; + if (cp == NULL) { + up (&dev_table_mutex); + return -ENODEV; + } + if (down_interruptible (&cp->mutex)) { + up (&dev_table_mutex); + return -ERESTARTSYS; + } + up (&dev_table_mutex); + + /* prevent module unloading */ + MOD_INC_USE_COUNT; + + /* we have access to the device. Now lets allocate memory */ + ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL); + if (ccp == NULL) { + err ("out of memory"); + ret = -ENOMEM; + goto ofail; + } + + /* Initialize device descriptor */ + memset( ccp, 0, sizeof(auerchar_t)); + init_MUTEX( &ccp->mutex); + init_MUTEX( &ccp->readmutex); + auerbuf_init (&ccp->bufctl); + ccp->scontext.id = AUH_UNASSIGNED; + ccp->scontext.dispatch = auerchar_ctrlread_dispatch; + ccp->scontext.disconnect = auerchar_disconnect; + init_waitqueue_head (&ccp->readwait); + + ret = auerbuf_setup (&ccp->bufctl, AU_RBUFFERS, cp->maxControlLength+AUH_SIZE); + if (ret) { + goto ofail; + } + + cp->open_count++; + ccp->auerdev = cp; + dbg("open %s as /dev/usb/%s", cp->dev_desc, cp->name); + up (&cp->mutex); + + /* file IO stuff */ + file->f_pos = 0; + file->private_data = ccp; + return 0; + + /* Error exit */ +ofail: up (&cp->mutex); + auerchar_delete (ccp); + MOD_DEC_USE_COUNT; + return ret; +} + + +/* IOCTL functions */ +static int auerchar_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + pauerchar_t ccp = (pauerchar_t) file->private_data; + int ret = 0; + audevinfo_t devinfo; + pauerswald_t cp = NULL; + unsigned int u; + dbg ("ioctl"); + + /* get the mutexes */ + if (down_interruptible (&ccp->mutex)) { + return -ERESTARTSYS; + } + cp = ccp->auerdev; + if (!cp) { + up (&ccp->mutex); + return -ENODEV; + } + if (down_interruptible (&cp->mutex)) { + up(&ccp->mutex); + return -ERESTARTSYS; + } + + /* Check for removal */ + if (!cp->usbdev) { + up(&cp->mutex); + up(&ccp->mutex); + return -ENODEV; + } + + switch (cmd) { + + /* return != 0 if Transmitt channel ready to send */ + case IOCTL_AU_TXREADY: + dbg ("IOCTL_AU_TXREADY"); + u = ccp->auerdev + && (ccp->scontext.id != AUH_UNASSIGNED) + && !list_empty (&cp->bufctl.free_buff_list); + ret = put_user (u, (unsigned int *) arg); + break; + + /* return != 0 if connected to a service channel */ + case IOCTL_AU_CONNECT: + dbg ("IOCTL_AU_CONNECT"); + u = (ccp->scontext.id != AUH_UNASSIGNED); + ret = put_user (u, (unsigned int *) arg); + break; + + /* return != 0 if Receive Data available */ + case IOCTL_AU_RXAVAIL: + dbg ("IOCTL_AU_RXAVAIL"); + if (ccp->scontext.id == AUH_UNASSIGNED) { + ret = -EIO; + break; + } + u = 0; /* no data */ + if (ccp->readbuf) { + int restlen = ccp->readbuf->len - ccp->readoffset; + if (restlen > 0) u = 1; + } + if (!u) { + if (!list_empty (&ccp->bufctl.rec_buff_list)) { + u = 1; + } + } + ret = put_user (u, (unsigned int *) arg); + break; + + /* return the max. buffer length for the device */ + case IOCTL_AU_BUFLEN: + dbg ("IOCTL_AU_BUFLEN"); + u = cp->maxControlLength; + ret = put_user (u, (unsigned int *) arg); + break; + + /* requesting a service channel */ + case IOCTL_AU_SERVREQ: + dbg ("IOCTL_AU_SERVREQ"); + /* requesting a service means: release the previous one first */ + auerswald_removeservice (cp, &ccp->scontext); + /* get the channel number */ + ret = get_user (u, (unsigned int *) arg); + if (ret) { + break; + } + if ((u < AUH_FIRSTUSERCH) || (u >= AUH_TYPESIZE)) { + ret = -EIO; + break; + } + dbg ("auerchar service request parameters are ok"); + ccp->scontext.id = u; + + /* request the service now */ + ret = auerswald_addservice (cp, &ccp->scontext); + if (ret) { + /* no: revert service entry */ + ccp->scontext.id = AUH_UNASSIGNED; + } + break; + + /* get a string descriptor for the device */ + case IOCTL_AU_DEVINFO: + dbg ("IOCTL_AU_DEVINFO"); + if (copy_from_user (&devinfo, (void *) arg, sizeof (audevinfo_t))) { + ret = -EFAULT; + break; + } + u = strlen(cp->dev_desc)+1; + if (u > devinfo.bsize) { + u = devinfo.bsize; + } + ret = copy_to_user(devinfo.buf, cp->dev_desc, u); + break; + + /* get the max. string descriptor length */ + case IOCTL_AU_SLEN: + dbg ("IOCTL_AU_SLEN"); + u = AUSI_DLEN; + ret = put_user (u, (unsigned int *) arg); + break; + + default: + dbg ("IOCTL_AU_UNKNOWN"); + ret = -ENOIOCTLCMD; + break; + } + /* release the mutexes */ + up(&cp->mutex); + up(&ccp->mutex); + return ret; +} + + +/* Seek is not supported */ +static loff_t auerchar_llseek (struct file *file, loff_t offset, int origin) +{ + dbg ("auerchar_seek"); + return -ESPIPE; +} + + +/* Read data from the device */ +static ssize_t auerchar_read (struct file *file, char *buf, size_t count, loff_t * ppos) +{ + unsigned long flags; + pauerchar_t ccp = (pauerchar_t) file->private_data; + pauerbuf_t bp = NULL; + dbg ("auerchar_read"); + + /* Error checking */ + if (!ccp) + return -EIO; + if (*ppos) + return -ESPIPE; + if (count == 0) + return 0; + + /* get the mutex */ + if (down_interruptible (&ccp->mutex)) + return -ERESTARTSYS; + + /* Can we expect to read something? */ + if (ccp->scontext.id == AUH_UNASSIGNED) { + up (&ccp->mutex); + return -EIO; + } + + /* only one reader per device allowed */ + if (down_interruptible (&ccp->readmutex)) { + up (&ccp->mutex); + return -ERESTARTSYS; + } + + /* read data from readbuf, if available */ +doreadbuf: + bp = ccp->readbuf; + if (bp) { + /* read the maximum bytes */ + int restlen = bp->len - ccp->readoffset; + if (restlen < 0) + restlen = 0; + if (count > restlen) + count = restlen; + if (count) { + if (copy_to_user (buf, bp->bufp+ccp->readoffset, count)) { + dbg ("auerswald_read: copy_to_user failed"); + up (&ccp->readmutex); + up (&ccp->mutex); + return -EFAULT; + } + } + /* advance the read offset */ + ccp->readoffset += count; + restlen -= count; + // reuse the read buffer + if (restlen <= 0) { + auerbuf_releasebuf (bp); + ccp->readbuf = NULL; + } + /* return with number of bytes read */ + if (count) { + up (&ccp->readmutex); + up (&ccp->mutex); + return count; + } + } + + /* a read buffer is not available. Try to get the next data block. */ +doreadlist: + bp = NULL; + spin_lock_irqsave (&ccp->bufctl.lock, flags); + if (!list_empty (&ccp->bufctl.rec_buff_list)) { + /* yes: get the entry */ + struct list_head *tmp = ccp->bufctl.rec_buff_list.next; + list_del (tmp); + bp = list_entry (tmp, auerbuf_t, buff_list); + } + spin_unlock_irqrestore (&ccp->bufctl.lock, flags); + + /* have we got data? */ + if (bp) { + ccp->readbuf = bp; + ccp->readoffset = AUH_SIZE; /* for headerbyte */ + goto doreadbuf; /* now we can read! */ + } + + /* no data available. Should we wait? */ + if (file->f_flags & O_NONBLOCK) { + dbg ("No read buffer available, returning -EAGAIN"); + up (&ccp->readmutex); + up (&ccp->mutex); + return -EAGAIN; /* nonblocking, no data available */ + } + + /* yes, we should wait! */ + up (&ccp->mutex); /* allow other operations while we wait */ + interruptible_sleep_on (&ccp->readwait); + if (signal_pending (current)) { + /* waked up by a signal */ + up (&ccp->readmutex); + return -ERESTARTSYS; + } + + /* Anything left to read? */ + if ((ccp->scontext.id == AUH_UNASSIGNED) || ccp->removed) { + up (&ccp->readmutex); + return -EIO; + } + + if (down_interruptible (&ccp->mutex)) { + up (&ccp->readmutex); + return -ERESTARTSYS; + } + + /* try to read the incomming data again */ + goto doreadlist; +} + + +/* Write a data block into the right service channel of the device */ +static ssize_t auerchar_write (struct file *file, const char *buf, size_t len, loff_t *ppos) +{ + pauerchar_t ccp = (pauerchar_t) file->private_data; + pauerswald_t cp = NULL; + pauerbuf_t bp; + unsigned long flags; + int ret; + + dbg ("auerchar_write %d bytes", len); + + /* Error checking */ + if (!ccp) + return -EIO; + if (*ppos) + return -ESPIPE; + if (len == 0) + return 0; + +write_again: + /* get the mutex */ + if (down_interruptible (&ccp->mutex)) + return -ERESTARTSYS; + + /* Can we expect to write something? */ + if (ccp->scontext.id == AUH_UNASSIGNED) { + up (&ccp->mutex); + return -EIO; + } + + cp = ccp->auerdev; + if (!cp) { + up (&ccp->mutex); + return -ERESTARTSYS; + } + if (down_interruptible (&cp->mutex)) { + up (&ccp->mutex); + return -ERESTARTSYS; + } + if (!cp->usbdev) { + up (&cp->mutex); + up (&ccp->mutex); + return -EIO; + } + /* Try to get a buffer from the device pool. + We can't use a buffer from ccp->bufctl because the write + command will last beond a release() */ + bp = NULL; + spin_lock_irqsave (&cp->bufctl.lock, flags); + if (!list_empty (&cp->bufctl.free_buff_list)) { + /* yes: get the entry */ + struct list_head *tmp = cp->bufctl.free_buff_list.next; + list_del (tmp); + bp = list_entry (tmp, auerbuf_t, buff_list); + } + spin_unlock_irqrestore (&cp->bufctl.lock, flags); + + /* are there any buffers left? */ + if (!bp) { + up (&cp->mutex); + up (&ccp->mutex); + + /* NONBLOCK: don't wait */ + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + + /* BLOCKING: wait */ + interruptible_sleep_on (&cp->bufferwait); + if (signal_pending (current)) { + /* waked up by a signal */ + return -ERESTARTSYS; + } + goto write_again; + } + + /* protect against too big write requests */ + if (len > cp->maxControlLength) len = cp->maxControlLength; + + /* Fill the buffer */ + if (copy_from_user ( bp->bufp+AUH_SIZE, buf, len)) { + dbg ("copy_from_user failed"); + auerbuf_releasebuf (bp); + up (&cp->mutex); + up (&ccp->mutex); + return -EIO; + } + + /* set the header byte */ + *(bp->bufp) = ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT; + + /* Set the transfer Parameters */ + bp->len = len+AUH_SIZE; + bp->dr->bRequestType = AUT_WREQ; + bp->dr->bRequest = AUV_WBLOCK; + bp->dr->wValue = cpu_to_le16 (0); + bp->dr->wIndex = cpu_to_le16 (ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT); + bp->dr->wLength = cpu_to_le16 (len+AUH_SIZE); + FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0), + (unsigned char*)bp->dr, bp->bufp, len+AUH_SIZE, + auerchar_ctrlwrite_complete, bp); + /* up we go */ + ret = auerchain_submit_urb (&cp->controlchain, bp->urbp); + up (&cp->mutex); + if (ret) { + dbg ("auerchar_write: nonzero result of auerchain_submit_urb %d", ret); + auerbuf_releasebuf (bp); + up (&ccp->mutex); + return -EIO; + } + else { + dbg ("auerchar_write: Write OK"); + up (&ccp->mutex); + return len; + } +} + + +/* Close a character device */ +static int auerchar_release (struct inode *inode, struct file *file) +{ + pauerchar_t ccp = (pauerchar_t) file->private_data; + pauerswald_t cp; + dbg("release"); + + /* get the mutexes */ + if (down_interruptible (&ccp->mutex)) { + return -ERESTARTSYS; + } + cp = ccp->auerdev; + if (cp) { + if (down_interruptible (&cp->mutex)) { + up (&ccp->mutex); + return -ERESTARTSYS; + } + /* remove an open service */ + auerswald_removeservice (cp, &ccp->scontext); + /* detach from device */ + if ((--cp->open_count <= 0) && (cp->usbdev == NULL)) { + /* usb device waits for removal */ + up (&cp->mutex); + auerswald_delete (cp); + } else { + up (&cp->mutex); + } + cp = NULL; + ccp->auerdev = NULL; + } + up (&ccp->mutex); + auerchar_delete (ccp); + + /* release the module */ + MOD_DEC_USE_COUNT; + + return 0; +} + + +/*----------------------------------------------------------------------*/ +/* File operation structure */ +static struct file_operations auerswald_fops = +{ + owner: THIS_MODULE, + llseek: auerchar_llseek, + read: auerchar_read, + write: auerchar_write, + ioctl: auerchar_ioctl, + open: auerchar_open, + release: auerchar_release, +}; + + +/* --------------------------------------------------------------------- */ +/* Special USB driver functions */ + +/* Probe if this driver wants to serve an USB device + + This entry point is called whenever a new device is attached to the bus. + Then the device driver has to create a new instance of its internal data + structures for the new device. + + The dev argument specifies the device context, which contains pointers + to all USB descriptors. The interface argument specifies the interface + number. If a USB driver wants to bind itself to a particular device and + interface it has to return a pointer. This pointer normally references + the device driver's context structure. + + Probing normally is done by checking the vendor and product identifications + or the class and subclass definitions. If they match the interface number + is compared with the ones supported by the driver. When probing is done + class based it might be necessary to parse some more USB descriptors because + the device properties can differ in a wide range. +*/ +static void *auerswald_probe (struct usb_device *usbdev, unsigned int ifnum, + const struct usb_device_id *id) +{ + pauerswald_t cp = NULL; + DECLARE_WAIT_QUEUE_HEAD (wqh); + unsigned int dtindex; + unsigned int u = 0; + char *pbuf; + int ret; + + dbg ("probe: vendor id 0x%x, device id 0x%x ifnum:%d", + usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum); + + /* See if the device offered us matches that we can accept */ + if (usbdev->descriptor.idVendor != ID_AUERSWALD) return NULL; + + /* we use only the first -and only- interface */ + if (ifnum != 0) return NULL; + + /* prevent module unloading while sleeping */ + MOD_INC_USE_COUNT; + + /* allocate memory for our device and intialize it */ + cp = kmalloc (sizeof(auerswald_t), GFP_KERNEL); + if (cp == NULL) { + err ("out of memory"); + goto pfail; + } + + /* Initialize device descriptor */ + memset (cp, 0, sizeof(auerswald_t)); + init_MUTEX (&cp->mutex); + cp->usbdev = usbdev; + auerchain_init (&cp->controlchain); + auerbuf_init (&cp->bufctl); + init_waitqueue_head (&cp->bufferwait); + + /* find a free slot in the device table */ + down (&dev_table_mutex); + for (dtindex = 0; dtindex < AUER_MAX_DEVICES; ++dtindex) { + if (dev_table[dtindex] == NULL) + break; + } + if ( dtindex >= AUER_MAX_DEVICES) { + err ("more than %d devices plugged in, can not handle this device", AUER_MAX_DEVICES); + up (&dev_table_mutex); + goto pfail; + } + + /* Give the device a name */ + sprintf (cp->name, AU_PREFIX "%d", dtindex); + + /* Store the index */ + cp->dtindex = dtindex; + dev_table[dtindex] = cp; + up (&dev_table_mutex); + + /* initialize the devfs node for this device and register it */ + cp->devfs = devfs_register (usb_devfs_handle, cp->name, + DEVFS_FL_DEFAULT, USB_MAJOR, + AUER_MINOR_BASE + dtindex, + S_IFCHR | S_IRUGO | S_IWUGO, + &auerswald_fops, NULL); + + /* Get the usb version of the device */ + cp->version = cp->usbdev->descriptor.bcdDevice; + dbg ("Version is %X", cp->version); + + /* allow some time to settle the device */ + sleep_on_timeout (&wqh, HZ / 3 ); + + /* Try to get a suitable textual description of the device */ + /* Device name:*/ + ret = usb_string( cp->usbdev, AUSI_DEVICE, cp->dev_desc, AUSI_DLEN-1); + if (ret >= 0) { + u += ret; + /* Append Serial Number */ + memcpy(&cp->dev_desc[u], ",Ser# ", 6); + u += 6; + ret = usb_string( cp->usbdev, AUSI_SERIALNR, &cp->dev_desc[u], AUSI_DLEN-u-1); + if (ret >= 0) { + u += ret; + /* Append subscriber number */ + memcpy(&cp->dev_desc[u], ", ", 2); + u += 2; + ret = usb_string( cp->usbdev, AUSI_MSN, &cp->dev_desc[u], AUSI_DLEN-u-1); + if (ret >= 0) { + u += ret; + } + } + } + cp->dev_desc[u] = '\0'; + info("device is a %s", cp->dev_desc); + + /* get the maximum allowed control transfer length */ + pbuf = (char *) kmalloc (2, GFP_KERNEL); /* use an allocated buffer because of urb target */ + if (!pbuf) { + err( "out of memory"); + goto pfail; + } + ret = usb_control_msg(cp->usbdev, /* pointer to device */ + usb_rcvctrlpipe( cp->usbdev, 0 ), /* pipe to control endpoint */ + AUV_GETINFO, /* USB message request value */ + AUT_RREQ, /* USB message request type value */ + 0, /* USB message value */ + AUDI_MBCTRANS, /* USB message index value */ + pbuf, /* pointer to the receive buffer */ + 2, /* length of the buffer */ + HZ * 2); /* time to wait for the message to complete before timing out */ + if (ret == 2) { + cp->maxControlLength = le16_to_cpup(pbuf); + kfree(pbuf); + dbg("setup: max. allowed control transfersize is %d bytes", cp->maxControlLength); + } else { + kfree(pbuf); + err("setup: getting max. allowed control transfer length failed with error %d", ret); + goto pfail; + } + + /* allocate a chain for the control messages */ + if (auerchain_setup (&cp->controlchain, AUCH_ELEMENTS)) { + err ("out of memory"); + goto pfail; + } + + /* allocate buffers for control messages */ + if (auerbuf_setup (&cp->bufctl, AU_RBUFFERS, cp->maxControlLength+AUH_SIZE)) { + err ("out of memory"); + goto pfail; + } + + /* start the interrupt endpoint */ + if (auerswald_int_open (cp)) { + err ("int endpoint failed"); + goto pfail; + } + + /* all OK */ + return cp; + + /* Error exit: clean up the memory */ +pfail: auerswald_delete (cp); + MOD_DEC_USE_COUNT; + return NULL; +} + + +/* Disconnect driver from a served device + + This function is called whenever a device which was served by this driver + is disconnected. + + The argument dev specifies the device context and the driver_context + returns a pointer to the previously registered driver_context of the + probe function. After returning from the disconnect function the USB + framework completly deallocates all data structures associated with + this device. So especially the usb_device structure must not be used + any longer by the usb driver. +*/ +static void auerswald_disconnect (struct usb_device *usbdev, void *driver_context) +{ + pauerswald_t cp = (pauerswald_t) driver_context; + unsigned int u; + + down (&cp->mutex); + info ("device /dev/usb/%s now disconnecting", cp->name); + + /* remove from device table */ + /* Nobody can open() this device any more */ + down (&dev_table_mutex); + dev_table[cp->dtindex] = NULL; + up (&dev_table_mutex); + + /* remove our devfs node */ + /* Nobody can see this device any more */ + devfs_unregister (cp->devfs); + + /* Stop the interrupt endpoint */ + auerswald_int_release (cp); + + /* remove the control chain allocated in auerswald_probe + This has the benefit of + a) all pending (a)synchronous urbs are unlinked + b) all buffers dealing with urbs are reclaimed + */ + auerchain_free (&cp->controlchain); + + if (cp->open_count == 0) { + /* nobody is using this device. So we can clean up now */ + up (&cp->mutex);/* up() is possible here because no other task + can open the device (see above). I don't want + to kfree() a locked mutex. */ + auerswald_delete (cp); + } else { + /* device is used. Remove the pointer to the + usb device (it's not valid any more). The last + release() will do the clean up */ + cp->usbdev = NULL; + up (&cp->mutex); + /* Terminate waiting writers */ + wake_up (&cp->bufferwait); + /* Inform all waiting readers */ + for ( u = 0; u < AUH_TYPESIZE; u++) { + pauerscon_t scp = cp->services[u]; + if (scp) scp->disconnect( scp); + } + } + + /* The device releases this module */ + MOD_DEC_USE_COUNT; +} + +/* Descriptor for the devices which are served by this driver. + NOTE: this struct is parsed by the usbmanager install scripts. + Don't change without caution! +*/ +static struct usb_device_id auerswald_ids [] = { + { USB_DEVICE (ID_AUERSWALD, 0x00C0) }, /* COMpact 2104 USB */ + { USB_DEVICE (ID_AUERSWALD, 0x00DB) }, /* COMpact 4410/2206 USB */ + { USB_DEVICE (ID_AUERSWALD, 0x00F1) }, /* Comfort 2000 System Telephone */ + { USB_DEVICE (ID_AUERSWALD, 0x00F2) }, /* Comfort 1200 System Telephone */ + { } /* Terminating entry */ +}; + +/* Standard module device table */ +MODULE_DEVICE_TABLE (usb, auerswald_ids); + +/* Standard usb driver struct */ +static struct usb_driver auerswald_driver = { + name: "auerswald", + probe: auerswald_probe, + disconnect: auerswald_disconnect, + fops: &auerswald_fops, + minor: AUER_MINOR_BASE, + id_table: auerswald_ids, +}; + + +/* --------------------------------------------------------------------- */ +/* Module loading/unloading */ + +/* Driver initialisation. Called after module loading. + NOTE: there is no concurrency at _init +*/ +static int __init auerswald_init (void) +{ + int result; + dbg ("init"); + + /* initialize the device table */ + memset (&dev_table, 0, sizeof(dev_table)); + init_MUTEX (&dev_table_mutex); + + /* register driver at the USB subsystem */ + result = usb_register (&auerswald_driver); + if (result < 0) { + err ("driver could not be registered"); + return -1; + } + return 0; +} + +/* Driver deinit. Called before module removal. + NOTE: there is no concurrency at _cleanup +*/ +static void __exit auerswald_cleanup (void) +{ + dbg ("cleanup"); + usb_deregister (&auerswald_driver); +} + +/* --------------------------------------------------------------------- */ +/* Linux device driver module description */ + +MODULE_AUTHOR (DRIVER_AUTHOR); +MODULE_DESCRIPTION (DRIVER_DESC); + +module_init (auerswald_init); +module_exit (auerswald_cleanup); + +/* --------------------------------------------------------------------- */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/bluetooth.c linux-2.5/drivers/usb/bluetooth.c --- linux-2.5.1/drivers/usb/bluetooth.c Sun Dec 9 04:28:44 2001 +++ linux-2.5/drivers/usb/bluetooth.c Tue Jan 8 00:44:24 2002 @@ -179,7 +179,7 @@ __u8 control_out_bInterfaceNum; struct urb * control_urb_pool[NUM_CONTROL_URBS]; - devrequest dr[NUM_CONTROL_URBS]; + struct usb_ctrlrequest dr[NUM_CONTROL_URBS]; unsigned char * interrupt_in_buffer; struct urb * interrupt_in_urb; @@ -288,7 +288,7 @@ static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, const unsigned char *buf, int len) { struct urb *urb = NULL; - devrequest *dr = NULL; + struct usb_ctrlrequest *dr = NULL; int i; int status; @@ -325,11 +325,11 @@ } memcpy (urb->transfer_buffer, buf, len); - dr->requesttype = BLUETOOTH_CONTROL_REQUEST_TYPE; - dr->request = request; - dr->value = cpu_to_le16((u16) value); - dr->index = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum); - dr->length = cpu_to_le16((u16) len); + dr->bRequestType= BLUETOOTH_CONTROL_REQUEST_TYPE; + dr->bRequest = request; + dr->wValue = cpu_to_le16((u16) value); + dr->wIndex = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum); + dr->wLength = cpu_to_le16((u16) len); FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0), (unsigned char*)dr, urb->transfer_buffer, len, bluetooth_ctrl_callback, bluetooth); @@ -360,7 +360,7 @@ tty->driver_data = NULL; /* get the bluetooth object associated with this tty pointer */ - bluetooth = get_bluetooth_by_minor (MINOR(tty->device)); + bluetooth = get_bluetooth_by_minor (minor(tty->device)); if (bluetooth_paranoia_check (bluetooth, __FUNCTION__)) { return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/catc.c linux-2.5/drivers/usb/catc.c --- linux-2.5.1/drivers/usb/catc.c Tue Nov 13 17:19:41 2001 +++ linux-2.5/drivers/usb/catc.c Tue Jan 8 00:44:24 2002 @@ -38,7 +38,9 @@ #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/spinlock.h> +#include <linux/ethtool.h> #include <asm/bitops.h> +#include <asm/uaccess.h> #undef DEBUG @@ -48,9 +50,10 @@ * Version information. */ -#define DRIVER_VERSION "v2.7" +#define DRIVER_VERSION "v2.8" #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>" #define DRIVER_DESC "CATC EL1210A NetMate USB Ethernet driver" +#define SHORT_DRIVER_DESC "EL1210A NetMate USB Ethernet" MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -156,7 +159,7 @@ u8 rx_buf[RX_MAX_BURST * (PKT_SZ + 2)]; u8 irq_buf[2]; u8 ctrl_buf[64]; - devrequest ctrl_dr; + struct usb_ctrlrequest ctrl_dr; struct timer_list timer; u8 stats_buf[8]; @@ -259,11 +262,15 @@ } } - if (data[1] & 0x40) + if (data[1] & 0x40) { + netif_carrier_on(catc->netdev); dbg("link ok"); + } - if (data[1] & 0x20) + if (data[1] & 0x20) { + netif_carrier_off(catc->netdev); dbg("link bad"); + } } /* @@ -376,14 +383,14 @@ struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail; struct usb_device *usbdev = catc->usbdev; struct urb *urb = &catc->ctrl_urb; - devrequest *dr = &catc->ctrl_dr; + struct usb_ctrlrequest *dr = &catc->ctrl_dr; int status; - dr->request = q->request; - dr->requesttype = 0x40 | q->dir; - dr->value = cpu_to_le16(q->value); - dr->index = cpu_to_le16(q->index); - dr->length = cpu_to_le16(q->len); + dr->bRequest = q->request; + dr->bRequestType = 0x40 | q->dir; + dr->wValue = cpu_to_le16(q->value); + dr->wIndex = cpu_to_le16(q->index); + dr->wLength = cpu_to_le16(q->len); urb->pipe = q->dir ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0); urb->transfer_buffer_length = q->len; @@ -564,6 +571,54 @@ } /* + * ioctl's + */ +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct catc *catc = dev->priv; + u32 cmd; + char tmp[40]; + + if (get_user(cmd, (u32 *)useraddr)) + return -EFAULT; + + switch (cmd) { + /* get driver info */ + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, SHORT_DRIVER_DESC, ETHTOOL_BUSINFO_LEN); + strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); + sprintf(tmp, "usb%d:%d", catc->usbdev->bus->busnum, catc->usbdev->devnum); + strncpy(info.bus_info, tmp,ETHTOOL_BUSINFO_LEN); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + edata.data = netif_carrier_ok(dev); + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + } + + return -EOPNOTSUPP; +} + +static int catc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + switch(cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + default: + return -EOPNOTSUPP; + } +} + + +/* * Open, close. */ @@ -629,6 +684,7 @@ netdev->tx_timeout = catc_tx_timeout; netdev->watchdog_timeo = TX_TIMEOUT; netdev->set_multicast_list = catc_set_multicast_list; + netdev->do_ioctl = catc_ioctl; netdev->priv = catc; catc->usbdev = usbdev; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/dabusb.c linux-2.5/drivers/usb/dabusb.c --- linux-2.5.1/drivers/usb/dabusb.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/usb/dabusb.c Thu Jan 3 22:56:46 2002 @@ -83,24 +83,24 @@ } /*-------------------------------------------------------------------*/ #ifdef DEBUG -static void dump_urb (purb_t purb) +static void dump_urb (struct urb *urb) { - dbg("urb :%p", purb); - dbg("next :%p", purb->next); - dbg("dev :%p", purb->dev); - dbg("pipe :%08X", purb->pipe); - dbg("status :%d", purb->status); - dbg("transfer_flags :%08X", purb->transfer_flags); - dbg("transfer_buffer :%p", purb->transfer_buffer); - dbg("transfer_buffer_length:%d", purb->transfer_buffer_length); - dbg("actual_length :%d", purb->actual_length); - dbg("setup_packet :%p", purb->setup_packet); - dbg("start_frame :%d", purb->start_frame); - dbg("number_of_packets :%d", purb->number_of_packets); - dbg("interval :%d", purb->interval); - dbg("error_count :%d", purb->error_count); - dbg("context :%p", purb->context); - dbg("complete :%p", purb->complete); + dbg("urb :%p", urb); + dbg("next :%p", urb->next); + dbg("dev :%p", urb->dev); + dbg("pipe :%08X", urb->pipe); + dbg("status :%d", urb->status); + dbg("transfer_flags :%08X", urb->transfer_flags); + dbg("transfer_buffer :%p", urb->transfer_buffer); + dbg("transfer_buffer_length:%d", urb->transfer_buffer_length); + dbg("actual_length :%d", urb->actual_length); + dbg("setup_packet :%p", urb->setup_packet); + dbg("start_frame :%d", urb->start_frame); + dbg("number_of_packets :%d", urb->number_of_packets); + dbg("interval :%d", urb->interval); + dbg("error_count :%d", urb->error_count); + dbg("context :%p", urb->context); + dbg("complete :%p", urb->complete); } #endif /*-------------------------------------------------------------------*/ @@ -167,7 +167,7 @@ return 0; } /*-------------------------------------------------------------------*/ -static void dabusb_iso_complete (purb_t purb) +static void dabusb_iso_complete (struct urb *purb) { pbuff_t b = purb->context; pdabusb_t s = b->s; @@ -482,7 +482,7 @@ int rem; int cnt; pbuff_t b; - purb_t purb = NULL; + struct urb *purb = NULL; dbg("dabusb_read"); @@ -579,7 +579,7 @@ static int dabusb_open (struct inode *inode, struct file *file) { - int devnum = MINOR (inode->i_rdev); + int devnum = minor(inode->i_rdev); pdabusb_t s; if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/dabusb.h linux-2.5/drivers/usb/dabusb.h --- linux-2.5.1/drivers/usb/dabusb.h Tue Oct 3 16:24:40 2000 +++ linux-2.5/drivers/usb/dabusb.h Tue Jan 1 23:42:42 2002 @@ -38,7 +38,7 @@ typedef struct { pdabusb_t s; - purb_t purb; + struct urb *purb; struct list_head buff_list; } buff_t,*pbuff_t; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/dc2xx.c linux-2.5/drivers/usb/dc2xx.c --- linux-2.5.1/drivers/usb/dc2xx.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/dc2xx.c Wed Jan 2 17:23:52 2002 @@ -294,11 +294,11 @@ static int camera_open (struct inode *inode, struct file *file) { struct camera_state *camera = NULL; - int subminor; + unsigned int subminor; int value = 0; down (&state_table_mutex); - subminor = MINOR (inode->i_rdev) - USB_CAMERA_MINOR_BASE; + subminor = minor(inode->i_rdev) - USB_CAMERA_MINOR_BASE; if (subminor < 0 || subminor >= MAX_CAMERAS || !(camera = minor_data [subminor])) { up (&state_table_mutex); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/devio.c linux-2.5/drivers/usb/devio.c --- linux-2.5.1/drivers/usb/devio.c Sun Dec 9 04:28:44 2001 +++ linux-2.5/drivers/usb/devio.c Tue Jan 8 00:44:24 2002 @@ -40,6 +40,7 @@ #include <linux/smp_lock.h> #include <linux/signal.h> #include <linux/poll.h> +#include <linux/module.h> #include <linux/usb.h> #include <linux/usbdevice_fs.h> #include <asm/uaccess.h> @@ -245,7 +246,7 @@ return NULL; } -static void async_completed(purb_t urb) +static void async_completed(struct urb *urb) { struct async *as = (struct async *)urb->context; struct dev_state *ps = as->ps; @@ -471,9 +472,7 @@ */ lock_kernel(); ret = -ENOENT; - if (ITYPE(inode->i_ino) != IDEVICE) - goto out; - dev = inode->u.usbdev_i.p.dev; + dev = inode->u.generic_ip; if (!dev) goto out; ret = -ENOMEM; @@ -528,40 +527,40 @@ if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) return -EFAULT; - if ((ret = check_ctrlrecip(ps, ctrl.requesttype, ctrl.index))) + if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex))) return ret; - if (ctrl.length > PAGE_SIZE) + if (ctrl.wLength > PAGE_SIZE) return -EINVAL; if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; tmo = (ctrl.timeout * HZ + 999) / 1000; - if (ctrl.requesttype & 0x80) { - if (ctrl.length && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.length)) { + if (ctrl.bRequestType & 0x80) { + if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { free_page((unsigned long)tbuf); return -EINVAL; } - i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, - ctrl.value, ctrl.index, tbuf, ctrl.length, tmo); - if ((i > 0) && ctrl.length) { - if (copy_to_user(ctrl.data, tbuf, ctrl.length)) { + i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, + ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + if ((i > 0) && ctrl.wLength) { + if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) { free_page((unsigned long)tbuf); return -EFAULT; } } } else { - if (ctrl.length) { - if (copy_from_user(tbuf, ctrl.data, ctrl.length)) { + if (ctrl.wLength) { + if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { free_page((unsigned long)tbuf); return -EFAULT; } } - i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, - ctrl.value, ctrl.index, tbuf, ctrl.length, tmo); + i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, + ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); } free_page((unsigned long)tbuf); if (i<0) { printk(KERN_DEBUG "usbdevfs: USBDEVFS_CONTROL failed dev %d rqt %u rq %u len %u ret %d\n", - dev->devnum, ctrl.requesttype, ctrl.request, ctrl.length, i); + dev->devnum, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i); } return i; } @@ -758,7 +757,7 @@ struct usbdevfs_iso_packet_desc *isopkt = NULL; struct usb_endpoint_descriptor *ep_desc; struct async *as; - devrequest *dr = NULL; + struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret; @@ -788,23 +787,23 @@ /* min 8 byte setup packet, max arbitrary */ if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE) return -EINVAL; - if (!(dr = kmalloc(sizeof(devrequest), GFP_KERNEL))) + if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) return -ENOMEM; if (copy_from_user(dr, (unsigned char*)uurb.buffer, 8)) { kfree(dr); return -EFAULT; } - if (uurb.buffer_length < (le16_to_cpup(&dr->length) + 8)) { + if (uurb.buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { kfree(dr); return -EINVAL; } - if ((ret = check_ctrlrecip(ps, dr->requesttype, le16_to_cpup(&dr->index)))) { + if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) { kfree(dr); return ret; } - uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->requesttype & USB_ENDPOINT_DIR_MASK); + uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK); uurb.number_of_packets = 0; - uurb.buffer_length = le16_to_cpup(&dr->length); + uurb.buffer_length = le16_to_cpup(&dr->wLength); uurb.buffer += 8; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) { kfree(dr); @@ -1088,10 +1087,15 @@ else if (ifp->driver == 0 || ifp->driver->ioctl == 0) retval = -ENOSYS; } - if (retval == 0) + if (retval == 0) { + if (ifp->driver->owner) + __MOD_INC_USE_COUNT(ifp->driver->owner); /* ifno might usefully be passed ... */ retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf); /* size = min_t(int, size, retval)? */ + if (ifp->driver->owner) + __MOD_DEC_USE_COUNT(ifp->driver->owner); + } } /* cleanup and return */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd/Config.in linux-2.5/drivers/usb/hcd/Config.in --- linux-2.5.1/drivers/usb/hcd/Config.in Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd/Config.in Thu Jan 3 23:04:40 2002 @@ -0,0 +1,7 @@ +# +# USB Host Controller Drivers +# +dep_tristate ' EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL +# dep_tristate ' OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL +# dep_tristate ' UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd/Makefile linux-2.5/drivers/usb/hcd/Makefile --- linux-2.5.1/drivers/usb/hcd/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd/Makefile Thu Jan 10 13:32:21 2002 @@ -0,0 +1,27 @@ +# +# Makefile for USB Host Controller Driver +# framework and drivers +# + +O_TARGET := + +obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o +# obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o +# obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Take multi-part drivers out of obj-y and put components in. +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. +OX_OBJS := $(obj-y) +MX_OBJS := $(obj-m) +MIX_OBJS := $(int-m) + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd/ehci-dbg.c linux-2.5/drivers/usb/hcd/ehci-dbg.c --- linux-2.5.1/drivers/usb/hcd/ehci-dbg.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd/ehci-dbg.c Tue Jan 1 23:42:42 2002 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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 file is part of ehci-hcd.c */ + +#ifdef EHCI_VERBOSE_DEBUG +# define vdbg dbg +#else + static inline void vdbg (char *fmt, ...) { } +#endif + +#ifdef DEBUG + +/* check the values in the HCSPARAMS register - host controller structural parameters */ +/* see EHCI 0.95 Spec, Table 2-4 for each value */ +static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) +{ + u32 params = readl (&ehci->caps->hcs_params); + + dbg ("%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d", + label, params, + HCS_DEBUG_PORT (params), + HCS_INDICATOR (params) ? " ind" : "", + HCS_N_CC (params), + HCS_N_PCC (params), + HCS_PORTROUTED (params) ? "" : " ordered", + HCS_PPC (params) ? "" : " !ppc", + HCS_N_PORTS (params) + ); + /* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */ + if (HCS_PORTROUTED (params)) { + int i; + char buf [46], tmp [7], byte; + + buf[0] = 0; + for (i = 0; i < HCS_N_PORTS (params); i++) { + byte = readb (&ehci->caps->portroute[(i>>1)]); + sprintf(tmp, "%d ", + ((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf))); + strcat(buf, tmp); + } + dbg ("%s: %s portroute %s", + ehci->hcd.bus_name, label, + buf); + } +} +#else + +static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {} + +#endif + +#ifdef DEBUG + +/* check the values in the HCCPARAMS register - host controller capability parameters */ +/* see EHCI 0.95 Spec, Table 2-5 for each value */ +static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) +{ + u32 params = readl (&ehci->caps->hcc_params); + + if (HCC_EXT_CAPS (params)) { + // EHCI 0.96 ... could interpret these (legacy?) + dbg ("%s extended capabilities at pci %d", + label, HCC_EXT_CAPS (params)); + } + if (HCC_ISOC_CACHE (params)) { + dbg ("%s hcc_params 0x%04x caching frame %s%s%s", + label, params, + HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024", + HCC_CANPARK (params) ? " park" : "", + HCC_64BIT_ADDR (params) ? " 64 bit addr" : ""); + } else { + dbg ("%s hcc_params 0x%04x caching %d uframes %s%s%s", + label, + params, + HCC_ISOC_THRES (params), + HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024", + HCC_CANPARK (params) ? " park" : "", + HCC_64BIT_ADDR (params) ? " 64 bit addr" : ""); + } +} +#else + +static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {} + +#endif + +#ifdef DEBUG + +#if 0 +static void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label, + qh, qh->hw_info1, qh->hw_info2, + qh->hw_current, qh->hw_qtd_next); + dbg (" alt+errs= %x, token= %x, page0= %x, page1= %x", + qh->hw_alt_next, qh->hw_token, + qh->hw_buf [0], qh->hw_buf [1]); + if (qh->hw_buf [2]) { + dbg (" page2= %x, page3= %x, page4= %x", + qh->hw_buf [2], qh->hw_buf [3], + qh->hw_buf [4]); + } +} +#endif + +static const char *const fls_strings [] = + { "1024", "512", "256", "??" }; + +#else +#if 0 +static inline void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {} +#endif +#endif /* DEBUG */ + +/* functions have the "wrong" filename when they're output... */ + +#define dbg_status(ehci, label, status) \ + dbg ("%s status 0x%x%s%s%s%s%s%s%s%s%s%s", \ + label, status, \ + (status & STS_ASS) ? " Async" : "", \ + (status & STS_PSS) ? " Periodic" : "", \ + (status & STS_RECL) ? " Recl" : "", \ + (status & STS_HALT) ? " Halt" : "", \ + (status & STS_IAA) ? " IAA" : "", \ + (status & STS_FATAL) ? " FATAL" : "", \ + (status & STS_FLR) ? " FLR" : "", \ + (status & STS_PCD) ? " PCD" : "", \ + (status & STS_ERR) ? " ERR" : "", \ + (status & STS_INT) ? " INT" : "" \ + ) + +#define dbg_cmd(ehci, label, command) \ + dbg ("%s %x cmd %s=%d ithresh=%d%s%s%s%s period=%s%s %s", \ + label, command, \ + (command & CMD_PARK) ? "park" : "(park)", \ + CMD_PARK_CNT (command), \ + (command >> 16) & 0x3f, \ + (command & CMD_LRESET) ? " LReset" : "", \ + (command & CMD_IAAD) ? " IAAD" : "", \ + (command & CMD_ASE) ? " Async" : "", \ + (command & CMD_PSE) ? " Periodic" : "", \ + fls_strings [(command >> 2) & 0x3], \ + (command & CMD_RESET) ? " Reset" : "", \ + (command & CMD_RUN) ? "RUN" : "HALT" \ + ) + +#define dbg_port(hcd, label, port, status) \ + dbg ("%s port %d status 0x%x%s%s speed=%d%s%s%s%s%s%s%s%s%s", \ + label, port, status, \ + (status & PORT_OWNER) ? " OWNER" : "", \ + (status & PORT_POWER) ? " POWER" : "", \ + (status >> 10) & 3, \ + (status & PORT_RESET) ? " RESET" : "", \ + (status & PORT_SUSPEND) ? " SUSPEND" : "", \ + (status & PORT_RESUME) ? " RESUME" : "", \ + (status & PORT_OCC) ? " OCC" : "", \ + (status & PORT_OC) ? " OC" : "", \ + (status & PORT_PEC) ? " PEC" : "", \ + (status & PORT_PE) ? " PE" : "", \ + (status & PORT_CSC) ? " CSC" : "", \ + (status & PORT_CONNECT) ? " CONNECT" : "" \ + ) + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd/ehci-hcd.c linux-2.5/drivers/usb/hcd/ehci-hcd.c --- linux-2.5.1/drivers/usb/hcd/ehci-hcd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd/ehci-hcd.c Thu Jan 3 00:47:20 2002 @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2000-2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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/module.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> + +#ifndef CONFIG_USB_DEBUG + #define CONFIG_USB_DEBUG /* this is still experimental! */ +#endif + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include <linux/usb.h> +#include "../hcd.h" + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/unaligned.h> + +//#undef KERN_DEBUG +//#define KERN_DEBUG "" + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI hc_driver implementation ... experimental, incomplete. + * Based on the 0.96 register interface specification. + * + * There are lots of things to help out with here ... notably + * everything "periodic", and of course testing with all sorts + * of usb 2.0 devices and configurations. + * + * USB 2.0 shows up in upcoming www.pcmcia.org technology. + * First was PCMCIA, like ISA; then CardBus, which is PCI. + * Next comes "CardBay", using USB 2.0 signals. + * + * Contains additional contributions by: + * Brad Hards + * Rory Bolt + * ... + */ + +#define DRIVER_VERSION "$Revision: 1.1 $" +#define DRIVER_AUTHOR "David Brownell" +#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" + + +// #define EHCI_VERBOSE_DEBUG +// #define have_iso + +#ifdef DEBUG +# define EHCI_SLAB_FLAGS (SLAB_POISON) +#else +# define EHCI_SLAB_FLAGS 0 +#endif + +/* magic numbers that can affect system performance */ +#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ +#define EHCI_TUNE_RL_HS 0 /* nak throttle; see 4.9 */ +#define EHCI_TUNE_RL_TT 0 +#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ +#define EHCI_TUNE_MULT_TT 1 + +/* Initial IRQ latency: lower than default */ +static int log2_irq_thresh = 0; // 0 to 6 +MODULE_PARM (log2_irq_thresh, "i"); +MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); + +/* Some A steppings of the NEC controller need soft retries */ +//#define EHCI_SOFT_RETRIES 5 /* after CERR-induced fault */ + +#define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT) + +/*-------------------------------------------------------------------------*/ + +#include "ehci.h" +#include "ehci-dbg.c" + +/*-------------------------------------------------------------------------*/ + +/* + * hc states include: unknown, halted, ready, running + * transitional states are messy just now + * trying to avoid "running" unless urbs are active + * a "ready" hc can be finishing prefetched work + */ + +/* halt a non-running controller */ +static void ehci_reset (struct ehci_hcd *ehci) +{ + u32 command = readl (&ehci->regs->command); + + command |= CMD_RESET; + dbg_cmd (ehci, "reset", command); + writel (command, &ehci->regs->command); + while (readl (&ehci->regs->command) & CMD_RESET) + continue; + ehci->hcd.state = USB_STATE_HALT; +} + +/* idle the controller (from running) */ +static void ehci_ready (struct ehci_hcd *ehci) +{ + u32 command; + +#ifdef DEBUG + if (!HCD_IS_RUNNING (ehci->hcd.state)) + BUG (); +#endif + + while (!(readl (&ehci->regs->status) & (STS_ASS | STS_PSS))) + udelay (100); + command = readl (&ehci->regs->command); + command &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); + writel (command, &ehci->regs->command); + + // hardware can take 16 microframes to turn off ... + ehci->hcd.state = USB_STATE_READY; +} + +/*-------------------------------------------------------------------------*/ + +#include "ehci-hub.c" +#include "ehci-mem.c" +#include "ehci-q.c" +#include "ehci-sched.c" + +/*-------------------------------------------------------------------------*/ + +static void ehci_tasklet (unsigned long param); + +/* called by khubd or root hub init threads */ + +static int ehci_start (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 temp; + struct usb_device *udev; + int retval; + u32 hcc_params; + u8 tempbyte; + + // FIXME: given EHCI 0.96 or later, and a controller with + // the USBLEGSUP/USBLEGCTLSTS extended capability, make sure + // the BIOS doesn't still own this controller. + + spin_lock_init (&ehci->lock); + + ehci->caps = (struct ehci_caps *) hcd->regs; + ehci->regs = (struct ehci_regs *) (hcd->regs + ehci->caps->length); + dbg_hcs_params (ehci, "ehci_start"); + dbg_hcc_params (ehci, "ehci_start"); + + /* + * hw default: 1K periodic list heads, one per frame. + * periodic_size can shrink by USBCMD update if hcc_params allows. + */ + ehci->periodic_size = DEFAULT_I_TDPS; + if ((retval = ehci_mem_init (ehci, EHCI_SLAB_FLAGS | SLAB_KERNEL)) < 0) + return retval; + hcc_params = readl (&ehci->caps->hcc_params); + + /* controllers may cache some of the periodic schedule ... */ + if (HCC_ISOC_CACHE (hcc_params)) // full frame cache + ehci->i_thresh = 8; + else // N microframes cached + ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params); + + ehci->async = 0; + ehci->reclaim = 0; + ehci->next_frame = -1; + + /* controller state: unknown --> reset */ + + /* EHCI spec section 4.1 */ + ehci_reset (ehci); + writel (INTR_MASK, &ehci->regs->intr_enable); + writel (ehci->periodic_dma, &ehci->regs->frame_list); + + /* + * hcc_params controls whether ehci->regs->segment must (!!!) + * be used; it constrains QH/ITD/SITD and QTD locations. + * By default, pci_alloc_consistent() won't hand out addresses + * above 4GB (via pdev->dma_mask) so we know this value. + * + * NOTE: that pdev->dma_mask setting means that all DMA mappings + * for I/O buffers will have the same restriction, though it's + * neither necessary nor desirable in that case. + */ + if (HCC_64BIT_ADDR (hcc_params)) { + writel (0, &ehci->regs->segment); + info ("using segment 0 for 64bit DMA addresses ..."); + } + + /* clear interrupt enables, set irq latency */ + temp = readl (&ehci->regs->command) & 0xff; + if (log2_irq_thresh < 0 || log2_irq_thresh > 6) + log2_irq_thresh = 0; + temp |= 1 << (16 + log2_irq_thresh); + // keeping default periodic framelist size + temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE), + writel (temp, &ehci->regs->command); + dbg_cmd (ehci, "init", temp); + + /* set async sleep time = 10 us ... ? */ + + ehci->tasklet.func = ehci_tasklet; + ehci->tasklet.data = (unsigned long) ehci; + + /* wire up the root hub */ + hcd->bus->root_hub = udev = usb_alloc_dev (NULL, hcd->bus); + if (!udev) { +done2: + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + + /* + * Start, enabling full USB 2.0 functionality ... usb 1.1 devices + * are explicitly handed to companion controller(s), so no TT is + * involved with the root hub. + */ + ehci->hcd.state = USB_STATE_READY; + writel (FLAG_CF, &ehci->regs->configured_flag); + readl (&ehci->regs->command); /* unblock posted write */ + + /* PCI Serial Bus Release Number is at 0x60 offset */ + pci_read_config_byte(hcd->pdev, 0x60, &tempbyte); + temp = readw (&ehci->caps->hci_version); + info ("USB %x.%x support enabled, EHCI rev %x.%2x", + ((tempbyte & 0xf0)>>4), + (tempbyte & 0x0f), + temp >> 8, + temp & 0xff); + + /* + * From here on, khubd concurrently accesses the root + * hub; drivers will be talking to enumerated devices. + * + * Before this point the HC was idle/ready. After, khubd + * and device drivers may start it running. + */ + usb_connect (udev); + udev->speed = USB_SPEED_HIGH; + if (usb_new_device (udev) != 0) { + if (hcd->state == USB_STATE_RUNNING) + ehci_ready (ehci); + while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS)) + udelay (100); + ehci_reset (ehci); + // usb_disconnect (udev); + hcd->bus->root_hub = 0; + usb_free_dev (udev); + retval = -ENODEV; + goto done2; + } + + return 0; +} + +/* always called by thread; normally rmmod */ + +static void ehci_stop (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + + dbg ("%s: stop", hcd->bus_name); + + if (hcd->state == USB_STATE_RUNNING) + ehci_ready (ehci); + while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS)) + udelay (100); + ehci_reset (ehci); + + // root hub is shut down separately (first, when possible) + scan_async (ehci); + if (ehci->next_frame != -1) + scan_periodic (ehci); + ehci_mem_cleanup (ehci); + + dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); +} + +static int ehci_get_frame (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_PM + +/* suspend/resume, section 4.3 */ + +static int ehci_suspend (struct usb_hcd *hcd, u32 state) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 params; + int ports; + int i; + + dbg ("%s: suspend to %d", hcd->bus_name, state); + + params = readl (&ehci->caps->hcs_params); + ports = HCS_N_PORTS (params); + + // FIXME: This assumes what's probably a D3 level suspend... + + // FIXME: usb wakeup events on this bus should resume the machine. + // pci config register PORTWAKECAP controls which ports can do it; + // bios may have initted the register... + + /* suspend each port, then stop the hc */ + for (i = 0; i < ports; i++) { + int temp = readl (&ehci->regs->port_status [i]); + + if ((temp & PORT_PE) == 0 + || (temp & PORT_OWNER) != 0) + continue; +dbg ("%s: suspend port %d", hcd->bus_name, i); + temp |= PORT_SUSPEND; + writel (temp, &ehci->regs->port_status [i]); + } + + if (hcd->state == USB_STATE_RUNNING) + ehci_ready (ehci); + while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS)) + udelay (100); + writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command); + +// save pci FLADJ value + + /* who tells PCI to reduce power consumption? */ + + return 0; +} + +static int ehci_resume (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 params; + int ports; + int i; + + dbg ("%s: resume", hcd->bus_name); + + params = readl (&ehci->caps->hcs_params); + ports = HCS_N_PORTS (params); + + // FIXME: if controller didn't retain state, + // return and let generic code clean it up + // test configured_flag ? + + /* resume HC and each port */ +// restore pci FLADJ value + // khubd and drivers will set HC running, if needed; + hcd->state = USB_STATE_READY; + for (i = 0; i < ports; i++) { + int temp = readl (&ehci->regs->port_status [i]); + + if ((temp & PORT_PE) == 0 + || (temp & PORT_SUSPEND) != 0) + continue; +dbg ("%s: resume port %d", hcd->bus_name, i); + temp |= PORT_RESUME; + writel (temp, &ehci->regs->port_status [i]); + readl (&ehci->regs->command); /* unblock posted writes */ + + wait_ms (20); + temp &= ~PORT_RESUME; + writel (temp, &ehci->regs->port_status [i]); + } + readl (&ehci->regs->command); /* unblock posted writes */ + return 0; +} + +#endif + +/*-------------------------------------------------------------------------*/ + +/* + * tasklet scheduled by some interrupts and other events + * calls driver completion functions ... but not in_irq() + */ +static void ehci_tasklet (unsigned long param) +{ + struct ehci_hcd *ehci = (struct ehci_hcd *) param; + + if (ehci->reclaim_ready) + end_unlink_async (ehci); + scan_async (ehci); + if (ehci->next_frame != -1) + scan_periodic (ehci); + + // FIXME: when nothing is connected to the root hub, + // turn off the RUN bit so the host can enter C3 "sleep" power + // saving mode; make root hub code scan memory less often. +} + +/*-------------------------------------------------------------------------*/ + +static void ehci_irq (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 status = readl (&ehci->regs->status); + int bh = 0; + + /* clear (just) interrupts */ + status &= INTR_MASK; + writel (status, &ehci->regs->status); + readl (&ehci->regs->command); /* unblock posted write */ + + if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */ + return; + +#ifdef EHCI_VERBOSE_DEBUG + /* unrequested/ignored: Port Change Detect, Frame List Rollover */ + if (status & INTR_MASK) + dbg_status (ehci, "irq", status); +#endif + + /* INT, ERR, and IAA interrupt rates can be throttled */ + + /* normal [4.15.1.2] or error [4.15.1.1] completion */ + if (likely ((status & (STS_INT|STS_ERR)) != 0)) + bh = 1; + + /* complete the unlinking of some qh [4.15.2.3] */ + if (status & STS_IAA) { + ehci->reclaim_ready = 1; + bh = 1; + } + + /* PCI errors [4.15.2.4] */ + if (unlikely ((status & STS_FATAL) != 0)) { + err ("%s: fatal error, state %x", hcd->bus_name, hcd->state); + ehci_reset (ehci); + // generic layer kills/unlinks all urbs + // then tasklet cleans up the rest + bh = 1; + } + + /* most work doesn't need to be in_irq() */ + if (likely (bh == 1)) + tasklet_schedule (&ehci->tasklet); +} + +/*-------------------------------------------------------------------------*/ + +/* + * non-error returns are a promise to giveback() the urb later + * we drop ownership so next owner (or urb unlink) can get it + * + * urb + dev is in hcd_dev.urb_list + * we're queueing TDs onto software and hardware lists + * + * hcd-specific init for hcpriv hasn't been done yet + * + * NOTE: EHCI queues control and bulk requests transparently, like OHCI. + */ +static int ehci_urb_enqueue ( + struct usb_hcd *hcd, + struct urb *urb, + int mem_flags +) { + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + struct list_head qtd_list; + + urb->transfer_flags &= ~EHCI_STATE_UNLINK; + INIT_LIST_HEAD (&qtd_list); + switch (usb_pipetype (urb->pipe)) { + + case PIPE_CONTROL: + case PIPE_BULK: + if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) + return -ENOMEM; + submit_async (ehci, urb, &qtd_list, mem_flags); + break; + + case PIPE_INTERRUPT: + if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) + return -ENOMEM; + return intr_submit (ehci, urb, &qtd_list, mem_flags); + + case PIPE_ISOCHRONOUS: +#ifdef have_iso + if (urb->dev->speed == USB_SPEED_HIGH) + return itd_submit (ehci, urb); + else + return sitd_submit (ehci, urb); +#else + // FIXME highspeed iso stuff is written but never run/tested. + // and the split iso support isn't even written yet. + dbg ("no iso support yet"); + return -ENOSYS; +#endif /* have_iso */ + + } + return 0; +} + +/* remove from hardware lists + * completions normally happen asynchronously + */ + +static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; + unsigned long flags; + + dbg ("%s urb_dequeue %p qh state %d", + hcd->bus_name, urb, qh->qh_state); + + switch (usb_pipetype (urb->pipe)) { + case PIPE_CONTROL: + case PIPE_BULK: + spin_lock_irqsave (&ehci->lock, flags); + if (ehci->reclaim) { +dbg ("dq: reclaim busy, %s", RUN_CONTEXT); + if (in_interrupt ()) { + spin_unlock_irqrestore (&ehci->lock, flags); + return -EAGAIN; + } + while (qh->qh_state == QH_STATE_LINKED + && ehci->reclaim + && ehci->hcd.state != USB_STATE_HALT + ) { + spin_unlock_irqrestore (&ehci->lock, flags); +// yeech ... this could spin for up to two frames! +dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d", + qh->qh_state, ehci->reclaim, ehci->hcd.state +); + udelay (100); + spin_lock_irqsave (&ehci->lock, flags); + } + } + if (qh->qh_state == QH_STATE_LINKED) + start_unlink_async (ehci, qh); + spin_unlock_irqrestore (&ehci->lock, flags); + return 0; + + case PIPE_INTERRUPT: + intr_deschedule (ehci, urb->start_frame, qh, urb->interval); + if (ehci->hcd.state == USB_STATE_HALT) + urb->status = -ESHUTDOWN; + qh_completions (ehci, &qh->qtd_list, 1); + return 0; + + case PIPE_ISOCHRONOUS: + // itd or sitd ... + + // wait till next completion, do it then. + // completion irqs can wait up to 128 msec, + urb->transfer_flags |= EHCI_STATE_UNLINK; + return 0; + } + return -EINVAL; +} + +/*-------------------------------------------------------------------------*/ + +// bulk qh holds the data toggle + +static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev) +{ + struct hcd_dev *dev = (struct hcd_dev *)udev->hcpriv; + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + int i; + unsigned long flags; + + /* ASSERT: nobody can be submitting urbs for this any more */ + + dbg ("%s: free_config devnum %d", hcd->bus_name, udev->devnum); + + spin_lock_irqsave (&ehci->lock, flags); + for (i = 0; i < 32; i++) { + if (dev->ep [i]) { + struct ehci_qh *qh; + + // FIXME: this might be an itd/sitd too ... + // or an interrupt urb (not on async list) + // can use "union ehci_shadow" + + qh = (struct ehci_qh *) dev->ep [i]; + vdbg ("free_config, ep 0x%02x qh %p", i, qh); + if (!list_empty (&qh->qtd_list)) { + dbg ("ep 0x%02x qh %p not empty!", i, qh); + BUG (); + } + dev->ep [i] = 0; + + /* wait_ms() won't spin here -- we're a thread */ + while (qh->qh_state == QH_STATE_LINKED + && ehci->reclaim + && ehci->hcd.state != USB_STATE_HALT + ) { + spin_unlock_irqrestore (&ehci->lock, flags); + wait_ms (1); + spin_lock_irqsave (&ehci->lock, flags); + } + if (qh->qh_state == QH_STATE_LINKED) { + start_unlink_async (ehci, qh); + while (qh->qh_state != QH_STATE_IDLE) { + spin_unlock_irqrestore (&ehci->lock, + flags); + wait_ms (1); + spin_lock_irqsave (&ehci->lock, flags); + } + } + qh_unput (ehci, qh); + } + } + + spin_unlock_irqrestore (&ehci->lock, flags); +} + +/*-------------------------------------------------------------------------*/ + +static const char hcd_name [] = "ehci-hcd"; + +static const struct hc_driver ehci_driver = { + description: hcd_name, + + /* + * generic hardware linkage + */ + irq: ehci_irq, + flags: HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + start: ehci_start, +#ifdef CONFIG_PM + suspend: ehci_suspend, + resume: ehci_resume, +#endif + stop: ehci_stop, + + /* + * memory lifecycle (except per-request) + */ + hcd_alloc: ehci_hcd_alloc, + hcd_free: ehci_hcd_free, + + /* + * managing i/o requests and associated device resources + */ + urb_enqueue: ehci_urb_enqueue, + urb_dequeue: ehci_urb_dequeue, + free_config: ehci_free_config, + + /* + * scheduling support + */ + get_frame_number: ehci_get_frame, + + /* + * root hub support + */ + hub_status_data: ehci_hub_status_data, + hub_control: ehci_hub_control, +}; + +/*-------------------------------------------------------------------------*/ + +/* EHCI spec says PCI is required. */ + +/* PCI driver selection metadata; PCI hotplugging uses this */ +static const struct pci_device_id __devinitdata pci_ids [] = { { + + /* handle any USB 2.0 EHCI controller */ + + class: ((PCI_CLASS_SERIAL_USB << 8) | 0x20), + class_mask: ~0, + driver_data: (unsigned long) &ehci_driver, + + /* no matter who makes it */ + vendor: PCI_ANY_ID, + device: PCI_ANY_ID, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + +}, { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE (pci, pci_ids); + +/* pci driver glue; this is a "new style" PCI driver module */ +static struct pci_driver ehci_pci_driver = { + name: (char *) hcd_name, + id_table: pci_ids, + + probe: usb_hcd_pci_probe, + remove: usb_hcd_pci_remove, + +#ifdef CONFIG_PM + suspend: usb_hcd_pci_suspend, + resume: usb_hcd_pci_resume, +#endif +}; + +#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC + +EXPORT_NO_SYMBOLS; +MODULE_DESCRIPTION (DRIVER_INFO); +MODULE_AUTHOR (DRIVER_AUTHOR); +MODULE_LICENSE ("GPL"); + +static int __init init (void) +{ + dbg (DRIVER_INFO); + dbg ("block sizes: qh %d qtd %d itd %d sitd %d", + sizeof (struct ehci_qh), sizeof (struct ehci_qtd), + sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); + + return pci_module_init (&ehci_pci_driver); +} +module_init (init); + +static void __exit cleanup (void) +{ + pci_unregister_driver (&ehci_pci_driver); +} +module_exit (cleanup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd/ehci-hub.c linux-2.5/drivers/usb/hcd/ehci-hub.c --- linux-2.5.1/drivers/usb/hcd/ehci-hub.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd/ehci-hub.c Tue Jan 1 23:42:42 2002 @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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 file is part of ehci-hcd.c */ + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Root Hub ... the nonsharable stuff + * + * Registers don't need cpu_to_le32, that happens transparently + */ + +/*-------------------------------------------------------------------------*/ + +static int check_reset_complete ( + struct ehci_hcd *ehci, + int index, + int port_status +) { + if (!(port_status & PORT_CONNECT)) { + ehci->reset_done [index] = 0; + return port_status; + } + + /* if reset finished and it's still not enabled -- handoff */ + if (!(port_status & PORT_PE)) { + dbg ("%s port %d full speed, give to companion, 0x%x", + ehci->hcd.bus_name, index + 1, port_status); + + // what happens if HCS_N_CC(params) == 0 ? + port_status |= PORT_OWNER; + writel (port_status, &ehci->regs->port_status [index]); + + } else + dbg ("%s port %d high speed", ehci->hcd.bus_name, index + 1); + + return port_status; +} + +/*-------------------------------------------------------------------------*/ + + +/* build "status change" packet (one or two bytes) from HC registers */ + +static int +ehci_hub_status_data (struct usb_hcd *hcd, char *buf) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 temp, status = 0; + int ports, i, retval = 1; + unsigned long flags; + + /* init status to no-changes */ + buf [0] = 0; + temp = readl (&ehci->caps->hcs_params); + ports = HCS_N_PORTS (temp); + if (ports > 7) { + buf [1] = 0; + retval++; + } + + /* no hub change reports (bit 0) for now (power, ...) */ + + /* port N changes (bit N)? */ + spin_lock_irqsave (&ehci->lock, flags); + for (i = 0; i < ports; i++) { + temp = readl (&ehci->regs->port_status [i]); + if (temp & PORT_OWNER) { + // get disconnected ports back if no companion driver + if (temp & PORT_CONNECT) + continue; + temp &= ~(PORT_OWNER|PORT_CSC); + writel (temp, &ehci->regs->port_status [i]); + } + if (!(temp & PORT_CONNECT)) + ehci->reset_done [i] = 0; + if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) { + set_bit (i, buf); + status = STS_PCD; + } + } + spin_unlock_irqrestore (&ehci->lock, flags); + return status ? retval : 0; +} + +/*-------------------------------------------------------------------------*/ + +static void +ehci_hub_descriptor ( + struct ehci_hcd *ehci, + struct usb_hub_descriptor *desc +) { + u32 params = readl (&ehci->caps->hcs_params); + int ports = HCS_N_PORTS (params); + u16 temp; + + desc->bDescriptorType = 0x29; + desc->bPwrOn2PwrGood = 0; /* FIXME: f(system power) */ + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = ports; + temp = 1 + (ports / 8); + desc->bDescLength = 7 + 2 * temp; + + /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ + memset (&desc->bitmap [0], 0, temp); + memset (&desc->bitmap [temp], 0xff, temp); + + temp = 0x0008; /* per-port overcurrent reporting */ + if (HCS_PPC (params)) /* per-port power control */ + temp |= 0x0001; + if (HCS_INDICATOR (params)) /* per-port indicators (LEDs) */ + temp |= 0x0080; + desc->wHubCharacteristics = cpu_to_le16 (temp); +} + +/*-------------------------------------------------------------------------*/ + +static int ehci_hub_control ( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength +) { + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 params = readl (&ehci->caps->hcs_params); + int ports = HCS_N_PORTS (params); + u32 temp; + unsigned long flags; + int retval = 0; + + /* + * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. + * HCS_INDICATOR may say we can change LEDs to off/amber/green. + * (track current state ourselves) ... blink for diagnostics, + * power, "this is the one", etc. EHCI spec supports this. + */ + + spin_lock_irqsave (&ehci->lock, flags); + switch (typeReq) { + case ClearHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = readl (&ehci->regs->port_status [wIndex]); + if (temp & PORT_OWNER) + break; + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + writel (temp & ~PORT_PE, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_C_ENABLE: + writel (temp | PORT_PEC, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_SUSPEND: + case USB_PORT_FEAT_C_SUSPEND: + /* ? */ + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC (params)) + writel (temp & ~PORT_POWER, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_C_CONNECTION: + writel (temp | PORT_CSC, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + writel (temp | PORT_OCC, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_C_RESET: + /* GetPortStatus clears reset */ + break; + default: + goto error; + } + readl (&ehci->regs->command); /* unblock posted write */ + break; + case GetHubDescriptor: + ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *) + buf); + break; + case GetHubStatus: + /* no hub-wide feature/status flags */ + memset (buf, 0, 4); + //cpu_to_le32s ((u32 *) buf); + break; + case GetPortStatus: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + memset (buf, 0, 4); + temp = readl (&ehci->regs->port_status [wIndex]); + + // wPortChange bits + if (temp & PORT_CSC) + set_bit (USB_PORT_FEAT_C_CONNECTION, buf); + if (temp & PORT_PEC) + set_bit (USB_PORT_FEAT_C_ENABLE, buf); + // USB_PORT_FEAT_C_SUSPEND + if (temp & PORT_OCC) + set_bit (USB_PORT_FEAT_C_OVER_CURRENT, buf); + + /* whoever resets must GetPortStatus to complete it!! */ + if ((temp & PORT_RESET) + && jiffies > ehci->reset_done [wIndex]) { + set_bit (USB_PORT_FEAT_C_RESET, buf); + + /* force reset to complete */ + writel (temp & ~PORT_RESET, + &ehci->regs->port_status [wIndex]); + do { + temp = readl ( + &ehci->regs->port_status [wIndex]); + udelay (10); + } while (temp & PORT_RESET); + + /* see what we found out */ + temp = check_reset_complete (ehci, wIndex, temp); + } + + // don't show wPortStatus if it's owned by a companion hc + if (!(temp & PORT_OWNER)) { + if (temp & PORT_CONNECT) { + set_bit (USB_PORT_FEAT_CONNECTION, buf); + set_bit (USB_PORT_FEAT_HIGHSPEED, buf); + } + if (temp & PORT_PE) + set_bit (USB_PORT_FEAT_ENABLE, buf); + if (temp & PORT_SUSPEND) + set_bit (USB_PORT_FEAT_SUSPEND, buf); + if (temp & PORT_OC) + set_bit (USB_PORT_FEAT_OVER_CURRENT, buf); + if (temp & PORT_RESET) + set_bit (USB_PORT_FEAT_RESET, buf); + if (temp & PORT_POWER) + set_bit (USB_PORT_FEAT_POWER, buf); + } + +#ifndef EHCI_VERBOSE_DEBUG + if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ +#endif + dbg_port (hcd, "GetStatus", wIndex + 1, temp); + cpu_to_le32s ((u32 *) buf); + break; + case SetHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case SetPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = readl (&ehci->regs->port_status [wIndex]); + if (temp & PORT_OWNER) + break; + + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + writel (temp | PORT_SUSPEND, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC (params)) + writel (temp | PORT_POWER, + &ehci->regs->port_status [wIndex]); + break; + case USB_PORT_FEAT_RESET: + /* line status bits may report this as low speed */ + if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT + && PORT_USB11 (temp)) { + dbg ("%s port %d low speed, give to companion", + hcd->bus_name, wIndex + 1); + temp |= PORT_OWNER; + } else { + vdbg ("%s port %d reset", + hcd->bus_name, wIndex + 1); + temp |= PORT_RESET; + temp &= ~PORT_PE; + + /* + * caller must wait, then call GetPortStatus + * usb 2.0 spec says 50 ms resets on root + */ + ehci->reset_done [wIndex] = jiffies + + ((50 /* msec */ * HZ) / 1000); + } + writel (temp, &ehci->regs->port_status [wIndex]); + break; + default: + goto error; + } + readl (&ehci->regs->command); /* unblock posted writes */ + break; + + default: +error: + /* "stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore (&ehci->lock, flags); + return retval; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd/ehci-mem.c linux-2.5/drivers/usb/hcd/ehci-mem.c --- linux-2.5.1/drivers/usb/hcd/ehci-mem.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd/ehci-mem.c Tue Jan 1 23:42:42 2002 @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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 file is part of ehci-hcd.c */ + +/*-------------------------------------------------------------------------*/ + +/* + * There's basically three types of memory: + * - data used only by the HCD ... kmalloc is fine + * - async and periodic schedules, shared by HC and HCD ... these + * need to use pci_pool or pci_alloc_consistent + * - driver buffers, read/written by HC ... single shot DMA mapped + * + * There's also PCI "register" data, which is memory mapped. + * No memory seen by this driver is pagable. + */ + +/*-------------------------------------------------------------------------*/ +/* + * Allocator / cleanup for the per device structure + * Called by hcd init / removal code + */ +static struct usb_hcd *ehci_hcd_alloc (void) +{ + struct ehci_hcd *ehci; + + ehci = (struct ehci_hcd *) + kmalloc (sizeof (struct ehci_hcd), GFP_KERNEL); + if (ehci != 0) { + memset (ehci, 0, sizeof (struct ehci_hcd)); + return &ehci->hcd; + } + return 0; +} + +static void ehci_hcd_free (struct usb_hcd *hcd) +{ + kfree (hcd_to_ehci (hcd)); +} + +/*-------------------------------------------------------------------------*/ + +/* Allocate the key transfer structures from the previously allocated pool */ + +static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags) +{ + struct ehci_qtd *qtd; + dma_addr_t dma; + + qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma); + if (qtd != 0) { + memset (qtd, 0, sizeof *qtd); + qtd->qtd_dma = dma; + qtd->hw_next = EHCI_LIST_END; + qtd->hw_alt_next = EHCI_LIST_END; + INIT_LIST_HEAD (&qtd->qtd_list); + } + return qtd; +} + +static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd) +{ + pci_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma); +} + + +static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) +{ + struct ehci_qh *qh; + dma_addr_t dma; + + qh = (struct ehci_qh *) + pci_pool_alloc (ehci->qh_pool, flags, &dma); + if (qh) { + memset (qh, 0, sizeof *qh); + atomic_set (&qh->refcount, 1); + qh->qh_dma = dma; + // INIT_LIST_HEAD (&qh->qh_list); + INIT_LIST_HEAD (&qh->qtd_list); + } + return qh; +} + +/* to share a qh (cpu threads, or hc) */ +static inline struct ehci_qh *qh_put (/* ehci, */ struct ehci_qh *qh) +{ + // dbg ("put %p (%d++)", qh, qh->refcount.counter); + atomic_inc (&qh->refcount); + return qh; +} + +static void qh_unput (struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + // dbg ("unput %p (--%d)", qh, qh->refcount.counter); + if (!atomic_dec_and_test (&qh->refcount)) + return; + /* clean qtds first, and know this is not linked */ + if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) { + dbg ("unused qh not empty!"); + BUG (); + } + pci_pool_free (ehci->qh_pool, qh, qh->qh_dma); +} + +/*-------------------------------------------------------------------------*/ + +/* The queue heads and transfer descriptors are managed from pools tied + * to each of the "per device" structures. + * This is the initialisation and cleanup code. + */ + +static void ehci_mem_cleanup (struct ehci_hcd *ehci) +{ + /* PCI consistent memory and pools */ + if (ehci->qtd_pool) + pci_pool_destroy (ehci->qtd_pool); + ehci->qtd_pool = 0; + + if (ehci->qh_pool) { + pci_pool_destroy (ehci->qh_pool); + ehci->qh_pool = 0; + } + + if (ehci->itd_pool) + pci_pool_destroy (ehci->itd_pool); + ehci->itd_pool = 0; + + if (ehci->sitd_pool) + pci_pool_destroy (ehci->sitd_pool); + ehci->sitd_pool = 0; + + if (ehci->periodic) + pci_free_consistent (ehci->hcd.pdev, + ehci->periodic_size * sizeof (u32), + ehci->periodic, ehci->periodic_dma); + ehci->periodic = 0; + + /* shadow periodic table */ + if (ehci->pshadow) + kfree (ehci->pshadow); + ehci->pshadow = 0; +} + +/* remember to add cleanup code (above) if you add anything here */ +static int ehci_mem_init (struct ehci_hcd *ehci, int flags) +{ + int i; + + /* QTDs for control/bulk/intr transfers */ + ehci->qtd_pool = pci_pool_create ("ehci_qtd", ehci->hcd.pdev, + sizeof (struct ehci_qtd), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */, + flags); + if (!ehci->qtd_pool) { + dbg ("no qtd pool"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + + /* QH for control/bulk/intr transfers */ + ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev, + sizeof (struct ehci_qh), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */, + flags); + if (!ehci->qh_pool) { + dbg ("no qh pool"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + + /* ITD for high speed ISO transfers */ + ehci->itd_pool = pci_pool_create ("ehci_itd", ehci->hcd.pdev, + sizeof (struct ehci_itd), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */, + flags); + if (!ehci->itd_pool) { + dbg ("no itd pool"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + + /* SITD for full/low speed split ISO transfers */ + ehci->sitd_pool = pci_pool_create ("ehci_sitd", ehci->hcd.pdev, + sizeof (struct ehci_sitd), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */, + flags); + if (!ehci->sitd_pool) { + dbg ("no sitd pool"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + + /* Hardware periodic table */ + ehci->periodic = (u32 *) + pci_alloc_consistent (ehci->hcd.pdev, + ehci->periodic_size * sizeof (u32), + &ehci->periodic_dma); + if (ehci->periodic == 0) { + dbg ("no hw periodic table"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + for (i = 0; i < ehci->periodic_size; i++) + ehci->periodic [i] = EHCI_LIST_END; + + /* software shadow of hardware table */ + ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), + flags & ~EHCI_SLAB_FLAGS); + if (ehci->pshadow == 0) { + dbg ("no shadow periodic table"); + ehci_mem_cleanup (ehci); + return -ENOMEM; + } + memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *)); + + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd/ehci-q.c linux-2.5/drivers/usb/hcd/ehci-q.c --- linux-2.5.1/drivers/usb/hcd/ehci-q.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd/ehci-q.c Thu Jan 10 13:32:21 2002 @@ -0,0 +1,970 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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 file is part of ehci-hcd.c */ + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI hardware queue manipulation + * + * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd" + * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned + * buffers needed for the larger number). We use one QH per endpoint, queue + * multiple (bulk or control) urbs per endpoint. URBs may need several qtds. + * A scheduled interrupt qh always has one qtd, one urb. + * + * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with + * interrupts) needs careful scheduling. Performance improvements can be + * an ongoing challenge. + * + * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs, + * or otherwise through transaction translators (TTs) in USB 2.0 hubs using + * (b) special fields in qh entries or (c) split iso entries. TTs will + * buffer low/full speed data so the host collects it at high speed. + */ + +/*-------------------------------------------------------------------------*/ + +/* fill a qtd, returning how much of the buffer we were able to queue up */ + +static int +qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token) +{ + int i, count; + + /* one buffer entry per 4K ... first might be short or unaligned */ + qtd->hw_buf [0] = cpu_to_le32 (buf); + count = 0x1000 - (buf & 0x0fff); /* rest of that page */ + if (likely (len < count)) /* ... iff needed */ + count = len; + else { + buf += 0x1000; + buf &= ~0x0fff; + + /* per-qtd limit: from 16K to 20K (best alignment) */ + for (i = 1; count < len && i < 5; i++) { + u64 addr = buf; + qtd->hw_buf [i] = cpu_to_le32 ((u32)addr); + qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32)); + buf += 0x1000; + if ((count + 0x1000) < len) + count += 0x1000; + else + count = len; + } + } + qtd->hw_token = cpu_to_le32 ((count << 16) | token); + qtd->length = count; + +#if 0 + vdbg (" qtd_fill %p, token %8x bytes %d dma %x", + qtd, le32_to_cpu (qtd->hw_token), count, qtd->hw_buf [0]); +#endif + + return count; +} + +/*-------------------------------------------------------------------------*/ + +/* update halted (but potentially linked) qh */ + +static inline void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd) +{ + qh->hw_current = 0; + qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma); + qh->hw_alt_next = EHCI_LIST_END; + + /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ + qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING); +} + +/*-------------------------------------------------------------------------*/ + +static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token) +{ + /* count IN/OUT bytes, not SETUP (even short packets) */ + if (likely (QTD_PID (token) != 2)) + urb->actual_length += length - QTD_LENGTH (token); + + /* don't modify error codes */ + if (unlikely (urb->status == -EINPROGRESS && (token & QTD_STS_HALT))) { + if (token & QTD_STS_BABBLE) { + urb->status = -EOVERFLOW; + } else if (!QTD_CERR (token)) { + if (token & QTD_STS_DBE) + urb->status = (QTD_PID (token) == 1) /* IN ? */ + ? -ENOSR /* hc couldn't read data */ + : -ECOMM; /* hc couldn't write data */ + else if (token & QTD_STS_MMF) /* missed tt uframe */ + urb->status = -EPROTO; + else if (token & QTD_STS_XACT) { + if (QTD_LENGTH (token)) + urb->status = -EPIPE; + else { + dbg ("3strikes"); + urb->status = -EPROTO; + } + } else /* presumably a stall */ + urb->status = -EPIPE; + + /* CERR nonzero + data left + halt --> stall */ + } else if (QTD_LENGTH (token)) + urb->status = -EPIPE; + else /* unknown */ + urb->status = -EPROTO; + dbg ("ep %d-%s qtd token %08x --> status %d", + /* devpath */ + usb_pipeendpoint (urb->pipe), + usb_pipein (urb->pipe) ? "in" : "out", + token, urb->status); + + /* stall indicates some recovery action is needed */ + if (urb->status == -EPIPE) { + int pipe = urb->pipe; + + if (!usb_pipecontrol (pipe)) + usb_endpoint_halt (urb->dev, + usb_pipeendpoint (pipe), + usb_pipeout (pipe)); + if (urb->dev->tt && !usb_pipeint (pipe)) { +err ("must CLEAR_TT_BUFFER, hub port %d%s addr %d ep %d", + urb->dev->ttport, /* devpath */ + urb->dev->tt->multi ? "" : " (all-ports TT)", + urb->dev->devnum, usb_pipeendpoint (urb->pipe)); + // FIXME something (khubd?) should make the hub + // CLEAR_TT_BUFFER ASAP, it's blocking other + // fs/ls requests... hub_tt_clear_buffer() ? + } + } + } +} + +static void ehci_urb_complete ( + struct ehci_hcd *ehci, + dma_addr_t addr, + struct urb *urb +) { + if (urb->transfer_buffer_length && usb_pipein (urb->pipe)) + pci_dma_sync_single (ehci->hcd.pdev, addr, + urb->transfer_buffer_length, + PCI_DMA_FROMDEVICE); + + /* cleanse status if we saw no error */ + if (likely (urb->status == -EINPROGRESS)) { + if (urb->actual_length != urb->transfer_buffer_length + && (urb->transfer_flags & USB_DISABLE_SPD)) + urb->status = -EREMOTEIO; + else + urb->status = 0; + } + + /* only report unlinks once */ + if (likely (urb->status != -ENOENT && urb->status != -ENOTCONN)) + urb->complete (urb); +} + +/* urb->lock ignored from here on (hcd is done with urb) */ + +static void ehci_urb_done ( + struct ehci_hcd *ehci, + dma_addr_t addr, + struct urb *urb +) { + if (urb->transfer_buffer_length) + pci_unmap_single (ehci->hcd.pdev, + addr, + urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); + if (likely (urb->hcpriv != 0)) { + qh_unput (ehci, (struct ehci_qh *) urb->hcpriv); + urb->hcpriv = 0; + } + + if (likely (urb->status == -EINPROGRESS)) { + if (urb->actual_length != urb->transfer_buffer_length + && (urb->transfer_flags & USB_DISABLE_SPD)) + urb->status = -EREMOTEIO; + else + urb->status = 0; + } + + /* hand off urb ownership */ + usb_hcd_giveback_urb (&ehci->hcd, urb); +} + + +/* + * Process completed qtds for a qh, issuing completions if needed. + * When freeing: frees qtds, unmaps buf, returns URB to driver. + * When not freeing (queued periodic qh): retain qtds, mapping, and urb. + * Races up to qh->hw_current; returns number of urb completions. + */ +static int +qh_completions ( + struct ehci_hcd *ehci, + struct list_head *qtd_list, + int freeing +) { + struct ehci_qtd *qtd, *last; + struct list_head *next; + struct ehci_qh *qh = 0; + int unlink = 0, halted = 0; + unsigned long flags; + int retval = 0; + + spin_lock_irqsave (&ehci->lock, flags); + if (unlikely (list_empty (qtd_list))) { + spin_unlock_irqrestore (&ehci->lock, flags); + return retval; + } + + /* scan QTDs till end of list, or we reach an active one */ + for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list), + last = 0, next = 0; + next != qtd_list; + last = qtd, qtd = list_entry (next, + struct ehci_qtd, qtd_list)) { + struct urb *urb = qtd->urb; + u32 token = 0; + + /* qh is non-null iff these qtds were queued to the HC */ + qh = (struct ehci_qh *) urb->hcpriv; + + /* clean up any state from previous QTD ...*/ + if (last) { + if (likely (last->urb != urb)) { + /* complete() can reenter this HCD */ + spin_unlock_irqrestore (&ehci->lock, flags); + if (likely (freeing != 0)) + ehci_urb_done (ehci, last->buf_dma, + last->urb); + else + ehci_urb_complete (ehci, last->buf_dma, + last->urb); + spin_lock_irqsave (&ehci->lock, flags); + retval++; + } + + /* qh overlays can have HC's old cached copies of + * next qtd ptrs, if an URB was queued afterwards. + */ + if (qh && cpu_to_le32 (last->qtd_dma) == qh->hw_current + && last->hw_next != qh->hw_qtd_next) { + qh->hw_alt_next = last->hw_alt_next; + qh->hw_qtd_next = last->hw_next; + } + + if (likely (freeing != 0)) + ehci_qtd_free (ehci, last); + last = 0; + } + next = qtd->qtd_list.next; + + /* if these qtds were queued to the HC, some may be active. + * else we're cleaning up after a failed URB submission. + */ + if (likely (qh != 0)) { + int qh_halted; + + qh_halted = __constant_cpu_to_le32 (QTD_STS_HALT) + & qh->hw_token; + token = le32_to_cpu (qtd->hw_token); + halted = halted + || qh_halted + || (ehci->hcd.state == USB_STATE_HALT) + || (qh->qh_state == QH_STATE_IDLE); + + /* QH halts only because of fault or unlink; in both + * cases, queued URBs get unlinked. But for unlink, + * URBs at the head of the queue can stay linked. + */ + if (unlikely (halted != 0)) { + + /* unlink everything because of HC shutdown? */ + if (ehci->hcd.state == USB_STATE_HALT) { + freeing = unlink = 1; + urb->status = -ESHUTDOWN; + + /* explicit unlink, starting here? */ + } else if (qh->qh_state == QH_STATE_IDLE + && (urb->status == -ECONNRESET + || urb->status == -ENOENT)) { + freeing = unlink = 1; + + /* unlink everything because of error? */ + } else if (qh_halted + && !(token & QTD_STS_HALT)) { + freeing = unlink = 1; + if (urb->status == -EINPROGRESS) + urb->status = -ECONNRESET; + + /* unlink the rest? */ + } else if (unlink) { + urb->status = -ECONNRESET; + + /* QH halted to unlink urbs after this? */ + } else if ((token & QTD_STS_ACTIVE) != 0) { + qtd = 0; + continue; + } + + /* Else QH is active, so we must not modify QTDs + * that HC may be working on. Break from loop. + */ + } else if (unlikely ((token & QTD_STS_ACTIVE) != 0)) { + next = qtd_list; + qtd = 0; + continue; + } + + spin_lock (&urb->lock); + qtd_copy_status (urb, qtd->length, token); + spin_unlock (&urb->lock); + } + + /* + * NOTE: this won't work right with interrupt urbs that + * need multiple qtds ... only the first scan of qh->qtd_list + * starts at the right qtd, yet multiple scans could happen + * for transfers that are scheduled across multiple uframes. + * (Such schedules are not currently allowed!) + */ + if (likely (freeing != 0)) + list_del (&qtd->qtd_list); + else { + /* restore everything the HC could change + * from an interrupt QTD + */ + qtd->hw_token = (qtd->hw_token + & ~__constant_cpu_to_le32 (0x8300)) + | cpu_to_le32 (qtd->length << 16) + | __constant_cpu_to_le32 (QTD_IOC + | (EHCI_TUNE_CERR << 10) + | QTD_STS_ACTIVE); + qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff); + + /* this offset, and the length above, + * are likely wrong on QTDs #2..N + */ + qtd->hw_buf [0] |= cpu_to_le32 (0x0fff & qtd->buf_dma); + } + +#if 0 + if (urb->status == -EINPROGRESS) + vdbg (" qtd %p ok, urb %p, token %8x, len %d", + qtd, urb, token, urb->actual_length); + else + vdbg ("urb %p status %d, qtd %p, token %8x, len %d", + urb, urb->status, qtd, token, + urb->actual_length); +#endif + + /* SETUP for control urb? */ + if (unlikely (QTD_PID (token) == 2)) + pci_unmap_single (ehci->hcd.pdev, + qtd->buf_dma, sizeof (struct usb_ctrlrequest), + PCI_DMA_TODEVICE); + } + + /* patch up list head? */ + if (unlikely (halted && qh && !list_empty (qtd_list))) { + qh_update (qh, list_entry (qtd_list->next, + struct ehci_qtd, qtd_list)); + } + spin_unlock_irqrestore (&ehci->lock, flags); + + /* last urb's completion might still need calling */ + if (likely (last != 0)) { + if (likely (freeing != 0)) { + ehci_urb_done (ehci, last->buf_dma, last->urb); + ehci_qtd_free (ehci, last); + } else + ehci_urb_complete (ehci, last->buf_dma, last->urb); + retval++; + } + return retval; +} + +/*-------------------------------------------------------------------------*/ + +/* + * create a list of filled qtds for this URB; won't link into qh. + */ +static struct list_head * +qh_urb_transaction ( + struct ehci_hcd *ehci, + struct urb *urb, + struct list_head *head, + int flags +) { + struct ehci_qtd *qtd, *qtd_prev; + dma_addr_t buf, map_buf; + int len, maxpacket; + u32 token; + + /* + * URBs map to sequences of QTDs: one logical transaction + */ + qtd = ehci_qtd_alloc (ehci, flags); + if (unlikely (!qtd)) + return 0; + qtd_prev = 0; + list_add_tail (&qtd->qtd_list, head); + qtd->urb = urb; + + token = QTD_STS_ACTIVE; + token |= (EHCI_TUNE_CERR << 10); + /* for split transactions, SplitXState initialized to zero */ + + if (usb_pipecontrol (urb->pipe)) { + /* control request data is passed in the "setup" pid */ + + /* NOTE: this isn't smart about 64bit DMA, since it uses the + * default (32bit) mask rather than using the whole address + * space. we could set pdev->dma_mask to all-ones while + * getting this mapping, locking it and restoring before + * allocating qtd/qh/... or maybe only do that for the main + * data phase (below). + */ + qtd->buf_dma = pci_map_single ( + ehci->hcd.pdev, + urb->setup_packet, + sizeof (struct usb_ctrlrequest), + PCI_DMA_TODEVICE); + if (unlikely (!qtd->buf_dma)) + goto cleanup; + + /* SETUP pid */ + qtd_fill (qtd, qtd->buf_dma, sizeof (struct usb_ctrlrequest), + token | (2 /* "setup" */ << 8)); + + /* ... and always at least one more pid */ + token ^= QTD_TOGGLE; + qtd_prev = qtd; + qtd = ehci_qtd_alloc (ehci, flags); + if (unlikely (!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); + list_add_tail (&qtd->qtd_list, head); + } + + /* + * data transfer stage: buffer setup + */ + len = urb->transfer_buffer_length; + if (likely (len > 0)) { + /* NOTE: sub-optimal mapping with 64bit DMA (see above) */ + buf = map_buf = pci_map_single (ehci->hcd.pdev, + urb->transfer_buffer, len, + usb_pipein (urb->pipe) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); + if (unlikely (!buf)) + goto cleanup; + } else + buf = map_buf = 0; + + if (!buf || usb_pipein (urb->pipe)) + token |= (1 /* "in" */ << 8); + /* else it's already initted to "out" pid (0 << 8) */ + + maxpacket = usb_maxpacket (urb->dev, urb->pipe, + usb_pipeout (urb->pipe)); + + /* + * buffer gets wrapped in one or more qtds; + * last one may be "short" (including zero len) + * and may serve as a control status ack + */ + for (;;) { + int this_qtd_len; + + qtd->urb = urb; + qtd->buf_dma = map_buf; + this_qtd_len = qtd_fill (qtd, buf, len, token); + len -= this_qtd_len; + buf += this_qtd_len; + + /* qh makes control packets use qtd toggle; maybe switch it */ + if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) + token ^= QTD_TOGGLE; + + if (likely (len <= 0)) + break; + + qtd_prev = qtd; + qtd = ehci_qtd_alloc (ehci, flags); + if (unlikely (!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); + list_add_tail (&qtd->qtd_list, head); + } + + /* + * control requests may need a terminating data "status" ack; + * bulk ones may need a terminating short packet (zero length). + */ + if (likely (buf != 0)) { + int one_more = 0; + + if (usb_pipecontrol (urb->pipe)) { + one_more = 1; + token ^= 0x0100; /* "in" <--> "out" */ + token |= QTD_TOGGLE; /* force DATA1 */ + } else if (usb_pipebulk (urb->pipe) + && (urb->transfer_flags & USB_ZERO_PACKET) + && !(urb->transfer_buffer_length % maxpacket)) { + one_more = 1; + } + if (one_more) { + qtd_prev = qtd; + qtd = ehci_qtd_alloc (ehci, flags); + if (unlikely (!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma); + list_add_tail (&qtd->qtd_list, head); + + /* never any data in such packets */ + qtd_fill (qtd, 0, 0, token); + } + } + + /* by default, enable interrupt on urb completion */ + if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT))) + qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC); + return head; + +cleanup: + urb->status = -ENOMEM; + qh_completions (ehci, head, 1); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* + * Hardware maintains data toggle (like OHCI) ... here we (re)initialize + * the hardware data toggle in the QH, and set the pseudo-toggle in udev + * so we can see if usb_clear_halt() was called. NOP for control, since + * we set up qh->hw_info1 to always use the QTD toggle bits. + */ +static inline void +clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh) +{ + vdbg ("clear toggle, dev %d ep 0x%x-%s", + udev->devnum, ep, is_out ? "out" : "in"); + qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE); + usb_settoggle (udev, ep, is_out, 1); +} + +// Would be best to create all qh's from config descriptors, +// when each interface/altsetting is established. Unlink +// any previous qh and cancel its urbs first; endpoints are +// implicitly reset then (data toggle too). +// That'd mean updating how usbcore talks to HCDs. (2.5?) + + +/* + * Each QH holds a qtd list; a QH is used for everything except iso. + * + * For interrupt urbs, the scheduler must set the microframe scheduling + * mask(s) each time the QH gets scheduled. For highspeed, that's + * just one microframe in the s-mask. For split interrupt transactions + * there are additional complications: c-mask, maybe FSTNs. + */ +static struct ehci_qh * +ehci_qh_make ( + struct ehci_hcd *ehci, + struct urb *urb, + struct list_head *qtd_list, + int flags +) { + struct ehci_qh *qh = ehci_qh_alloc (ehci, flags); + u32 info1 = 0, info2 = 0; + + if (!qh) + return qh; + + /* + * init endpoint/device data for this QH + */ + info1 |= usb_pipeendpoint (urb->pipe) << 8; + info1 |= usb_pipedevice (urb->pipe) << 0; + + /* using TT? */ + switch (urb->dev->speed) { + case USB_SPEED_LOW: + info1 |= (1 << 12); /* EPS "low" */ + /* FALL THROUGH */ + + case USB_SPEED_FULL: + /* EPS 0 means "full" */ + info1 |= (EHCI_TUNE_RL_TT << 28); + if (usb_pipecontrol (urb->pipe)) { + info1 |= (1 << 27); /* for TT */ + info1 |= 1 << 14; /* toggle from qtd */ + } + info1 |= usb_maxpacket (urb->dev, urb->pipe, + usb_pipeout (urb->pipe)) << 16; + + info2 |= (EHCI_TUNE_MULT_TT << 30); + info2 |= urb->dev->ttport << 23; + info2 |= urb->dev->tt->hub->devnum << 16; + + /* NOTE: if (usb_pipeint (urb->pipe)) { scheduler sets c-mask } + * ... and a 0.96 scheduler might use FSTN nodes too + */ + break; + + case USB_SPEED_HIGH: /* no TT involved */ + info1 |= (2 << 12); /* EPS "high" */ + info1 |= (EHCI_TUNE_RL_HS << 28); + if (usb_pipecontrol (urb->pipe)) { + info1 |= 64 << 16; /* usb2 fixed maxpacket */ + info1 |= 1 << 14; /* toggle from qtd */ + } else if (usb_pipebulk (urb->pipe)) { + info1 |= 512 << 16; /* usb2 fixed maxpacket */ + info2 |= (EHCI_TUNE_MULT_HS << 30); + } else + info1 |= usb_maxpacket (urb->dev, urb->pipe, + usb_pipeout (urb->pipe)) << 16; + break; + default: +#ifdef DEBUG + BUG (); +#endif + } + + /* NOTE: if (usb_pipeint (urb->pipe)) { scheduler sets s-mask } */ + + qh->qh_state = QH_STATE_IDLE; + qh->hw_info1 = cpu_to_le32 (info1); + qh->hw_info2 = cpu_to_le32 (info2); + + /* initialize sw and hw queues with these qtds */ + list_splice (qtd_list, &qh->qtd_list); + qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list)); + + /* initialize data toggle state */ + if (!usb_pipecontrol (urb->pipe)) + clear_toggle (urb->dev, + usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe), + qh); + + return qh; +} + +/*-------------------------------------------------------------------------*/ + +/* move qh (and its qtds) onto async queue; maybe enable queue. */ + +static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + u32 dma = QH_NEXT (qh->qh_dma); + struct ehci_qh *q; + + if (unlikely (!(q = ehci->async))) { + u32 cmd = readl (&ehci->regs->command); + + /* in case a clear of CMD_ASE didn't take yet */ + while (readl (&ehci->regs->status) & STS_ASS) + udelay (100); + + qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */ + qh->qh_next.qh = qh; + qh->hw_next = dma; + ehci->async = qh; + writel ((u32)qh->qh_dma, &ehci->regs->async_next); + cmd |= CMD_ASE | CMD_RUN; + writel (cmd, &ehci->regs->command); + ehci->hcd.state = USB_STATE_RUNNING; + /* posted write need not be known to HC yet ... */ + } else { + /* splice right after "start" of ring */ + qh->hw_info1 &= ~__constant_cpu_to_le32 (QH_HEAD); /* [4.8] */ + qh->qh_next = q->qh_next; + qh->hw_next = q->hw_next; + q->qh_next.qh = qh; + q->hw_next = dma; + } + qh->qh_state = QH_STATE_LINKED; + /* qtd completions reported later by interrupt */ +} + +/*-------------------------------------------------------------------------*/ + +static void +submit_async ( + struct ehci_hcd *ehci, + struct urb *urb, + struct list_head *qtd_list, + int mem_flags +) { + struct ehci_qtd *qtd; + struct hcd_dev *dev; + int epnum; + unsigned long flags; + struct ehci_qh *qh = 0; + + qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); + dev = (struct hcd_dev *)urb->dev->hcpriv; + epnum = usb_pipeendpoint (urb->pipe); + if (usb_pipein (urb->pipe)) + epnum |= 0x10; + + vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]", + ehci->hcd.bus_name, urb, urb->transfer_buffer_length, + epnum & 0x0f, (epnum & 0x10) ? "in" : "out", + qtd, dev ? dev->ep [epnum] : (void *)~0); + + spin_lock_irqsave (&ehci->lock, flags); + + qh = (struct ehci_qh *) dev->ep [epnum]; + if (likely (qh != 0)) { + u32 hw_next = QTD_NEXT (qtd->qtd_dma); + + /* maybe patch the qh used for set_address */ + if (unlikely (epnum == 0 + && le32_to_cpu (qh->hw_info1 & 0x7f) == 0)) + qh->hw_info1 |= cpu_to_le32 (usb_pipedevice(urb->pipe)); + + /* is an URB is queued to this qh already? */ + if (unlikely (!list_empty (&qh->qtd_list))) { + struct ehci_qtd *last_qtd; + int short_rx = 0; + + /* update the last qtd's "next" pointer */ + // dbg_qh ("non-empty qh", ehci, qh); + last_qtd = list_entry (qh->qtd_list.prev, + struct ehci_qtd, qtd_list); + last_qtd->hw_next = hw_next; + + /* previous urb allows short rx? maybe optimize. */ + if (!(last_qtd->urb->transfer_flags & USB_DISABLE_SPD) + && (epnum & 0x10)) { + // only the last QTD for now + last_qtd->hw_alt_next = hw_next; + short_rx = 1; + } + + /* Adjust any old copies in qh overlay too. + * Interrupt code must cope with case of HC having it + * cached, and clobbering these updates. + * ... complicates getting rid of extra interrupts! + */ + if (qh->hw_current == cpu_to_le32 (last_qtd->qtd_dma)) { + wmb (); + qh->hw_qtd_next = hw_next; + if (short_rx) + qh->hw_alt_next = hw_next + | (qh->hw_alt_next & 0x1e); + vdbg ("queue to qh %p, patch", qh); + } + + /* no URB queued */ + } else { + // dbg_qh ("empty qh", ehci, qh); + +// FIXME: how handle usb_clear_halt() for an EP with queued URBs? +// usbcore may not let us handle that cleanly... +// likely must cancel them all first! + + /* usb_clear_halt() means qh data toggle gets reset */ + if (usb_pipebulk (urb->pipe) + && unlikely (!usb_gettoggle (urb->dev, + (epnum & 0x0f), + !(epnum & 0x10)))) { + clear_toggle (urb->dev, + epnum & 0x0f, !(epnum & 0x10), qh); + } + qh_update (qh, qtd); + } + list_splice (qtd_list, qh->qtd_list.prev); + + } else { + /* can't sleep here, we have ehci->lock... */ + qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC); + if (likely (qh != 0)) { + // dbg_qh ("new qh", ehci, qh); + dev->ep [epnum] = qh; + } else + urb->status = -ENOMEM; + } + + /* Control/bulk operations through TTs don't need scheduling, + * the HC and TT handle it when the TT has a buffer ready. + */ + if (likely (qh != 0)) { + urb->hcpriv = qh_put (qh); + if (likely (qh->qh_state == QH_STATE_IDLE)) + qh_link_async (ehci, qh_put (qh)); + } + spin_unlock_irqrestore (&ehci->lock, flags); + if (unlikely (!qh)) + qh_completions (ehci, qtd_list, 1); +} + +/*-------------------------------------------------------------------------*/ + +/* the async qh for the qtds being reclaimed are now unlinked from the HC */ +/* caller must not own ehci->lock */ + +static void end_unlink_async (struct ehci_hcd *ehci) +{ + struct ehci_qh *qh = ehci->reclaim; + + qh->qh_state = QH_STATE_IDLE; + qh->qh_next.qh = 0; + qh_unput (ehci, qh); // refcount from reclaim + ehci->reclaim = 0; + ehci->reclaim_ready = 0; + + qh_completions (ehci, &qh->qtd_list, 1); + + // unlink any urb should now unlink all following urbs, so that + // relinking only happens for urbs before the unlinked ones. + if (!list_empty (&qh->qtd_list) + && HCD_IS_RUNNING (ehci->hcd.state)) + qh_link_async (ehci, qh); + else + qh_unput (ehci, qh); // refcount from async list +} + + +/* makes sure the async qh will become idle */ +/* caller must own ehci->lock */ + +static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + int cmd = readl (&ehci->regs->command); + struct ehci_qh *prev; + +#ifdef DEBUG + if (ehci->reclaim + || !ehci->async + || qh->qh_state != QH_STATE_LINKED +#ifdef CONFIG_SMP +// this macro lies except on SMP compiles + || !spin_is_locked (&ehci->lock) +#endif + ) + BUG (); +#endif + + qh->qh_state = QH_STATE_UNLINK; + ehci->reclaim = qh = qh_put (qh); + + // dbg_qh ("start unlink", ehci, qh); + + /* Remove the last QH (qhead)? Stop async schedule first. */ + if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) { + /* can't get here without STS_ASS set */ + if (ehci->hcd.state != USB_STATE_HALT) { + if (cmd & CMD_PSE) + writel (cmd & __constant_cpu_to_le32 (~CMD_ASE), + &ehci->regs->command); + else { + ehci_ready (ehci); + while (!(readl (&ehci->regs->status) & STS_ASS)) + udelay (100); + } + } + qh->qh_next.qh = ehci->async = 0; + + ehci->reclaim_ready = 1; + tasklet_schedule (&ehci->tasklet); + return; + } + + if (unlikely (ehci->hcd.state == USB_STATE_HALT)) { + ehci->reclaim_ready = 1; + tasklet_schedule (&ehci->tasklet); + return; + } + + prev = ehci->async; + while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async) + prev = prev->qh_next.qh; +#ifdef DEBUG + if (prev->qh_next.qh != qh) + BUG (); +#endif + + if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) { + ehci->async = prev; + prev->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); + } + prev->hw_next = qh->hw_next; + prev->qh_next = qh->qh_next; + + ehci->reclaim_ready = 0; + cmd |= CMD_IAAD; + writel (cmd, &ehci->regs->command); + /* posted write need not be known to HC yet ... */ +} + +/*-------------------------------------------------------------------------*/ + +static void scan_async (struct ehci_hcd *ehci) +{ + struct ehci_qh *qh; + unsigned long flags; + + spin_lock_irqsave (&ehci->lock, flags); +rescan: + qh = ehci->async; + if (likely (qh != 0)) { + do { + /* clean any finished work for this qh */ + if (!list_empty (&qh->qtd_list)) { + // dbg_qh ("scan_async", ehci, qh); + qh = qh_put (qh); + spin_unlock_irqrestore (&ehci->lock, flags); + + /* concurrent unlink could happen here */ + qh_completions (ehci, &qh->qtd_list, 1); + + spin_lock_irqsave (&ehci->lock, flags); + qh_unput (ehci, qh); + } + + /* unlink idle entries (reduces PCI usage) */ + if (list_empty (&qh->qtd_list) && !ehci->reclaim) { + if (qh->qh_next.qh != qh) { + // dbg ("irq/empty"); + start_unlink_async (ehci, qh); + } else { + // FIXME: arrange to stop + // after it's been idle a while. + } + } + qh = qh->qh_next.qh; + if (!qh) /* unlinked? */ + goto rescan; + } while (qh != ehci->async); + } + + spin_unlock_irqrestore (&ehci->lock, flags); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd/ehci-sched.c linux-2.5/drivers/usb/hcd/ehci-sched.c --- linux-2.5.1/drivers/usb/hcd/ehci-sched.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd/ehci-sched.c Tue Jan 1 23:42:42 2002 @@ -0,0 +1,1053 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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 file is part of ehci-hcd.c */ + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI scheduled transaction support: interrupt, iso, split iso + * These are called "periodic" transactions in the EHCI spec. + */ + +/* + * Ceiling microseconds (typical) for that many bytes at high speed + * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed + * to preallocate bandwidth) + */ +#define EHCI_HOST_DELAY 5 /* nsec, guess */ +#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \ + + ((2083UL * (3167 + BitTime (bytes)))/1000) \ + + EHCI_HOST_DELAY) +#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \ + + ((2083UL * (3167 + BitTime (bytes)))/1000) \ + + EHCI_HOST_DELAY) + +static int ehci_get_frame (struct usb_hcd *hcd); + +/*-------------------------------------------------------------------------*/ + +/* + * periodic_next_shadow - return "next" pointer on shadow list + * @periodic: host pointer to qh/itd/sitd + * @tag: hardware tag for type of this record + */ +static union ehci_shadow * +periodic_next_shadow (union ehci_shadow *periodic, int tag) +{ + switch (tag) { + case Q_TYPE_QH: + return &periodic->qh->qh_next; + case Q_TYPE_FSTN: + return &periodic->fstn->fstn_next; +#ifdef have_iso + case Q_TYPE_ITD: + return &periodic->itd->itd_next; + case Q_TYPE_SITD: + return &periodic->sitd->sitd_next; +#endif /* have_iso */ + } + dbg ("BAD shadow %p tag %d", periodic->ptr, tag); + // BUG (); + return 0; +} + +/* returns true after successful unlink */ +/* caller must hold ehci->lock */ +static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) +{ + union ehci_shadow *prev_p = &ehci->pshadow [frame]; + u32 *hw_p = &ehci->periodic [frame]; + union ehci_shadow here = *prev_p; + union ehci_shadow *next_p; + + /* find predecessor of "ptr"; hw and shadow lists are in sync */ + while (here.ptr && here.ptr != ptr) { + prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p)); + hw_p = &here.qh->hw_next; + here = *prev_p; + } + /* an interrupt entry (at list end) could have been shared */ + if (!here.ptr) { + dbg ("entry %p no longer on frame [%d]", ptr, frame); + return 0; + } + // vdbg ("periodic unlink %p from frame %d", ptr, frame); + + /* update hardware list ... HC may still know the old structure, so + * don't change hw_next until it'll have purged its cache + */ + next_p = periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p)); + *hw_p = here.qh->hw_next; + + /* unlink from shadow list; HCD won't see old structure again */ + *prev_p = *next_p; + next_p->ptr = 0; + + return 1; +} + +/* how many of the uframe's 125 usecs are allocated? */ +static unsigned short +periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) +{ + u32 *hw_p = &ehci->periodic [frame]; + union ehci_shadow *q = &ehci->pshadow [frame]; + unsigned usecs = 0; +#ifdef have_iso + u32 temp = 0; +#endif + + while (q->ptr) { + switch (Q_NEXT_TYPE (*hw_p)) { + case Q_TYPE_QH: + /* is it in the S-mask? */ + if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe)) + usecs += q->qh->usecs; + q = &q->qh->qh_next; + break; + case Q_TYPE_FSTN: + /* for "save place" FSTNs, count the relevant INTR + * bandwidth from the previous frame + */ + if (q->fstn->hw_prev != EHCI_LIST_END) { + dbg ("not counting FSTN bandwidth yet ..."); + } + q = &q->fstn->fstn_next; + break; +#ifdef have_iso + case Q_TYPE_ITD: + temp = le32_to_cpu (q->itd->transaction [uframe]); + temp >>= 16; + temp &= 0x0fff; + if (temp) + usecs += HS_USECS_ISO (temp); + q = &q->itd->itd_next; + break; + case Q_TYPE_SITD: + temp = q->sitd->hw_fullspeed_ep & + __constant_cpu_to_le32 (1 << 31); + + // FIXME: this doesn't count data bytes right... + + /* is it in the S-mask? (count SPLIT, DATA) */ + if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) { + if (temp) + usecs += HS_USECS (188); + else + usecs += HS_USECS (1); + } + + /* ... C-mask? (count CSPLIT, DATA) */ + if (q->sitd->hw_uframe & + cpu_to_le32 (1 << (8 + uframe))) { + if (temp) + usecs += HS_USECS (0); + else + usecs += HS_USECS (188); + } + q = &q->sitd->sitd_next; + break; +#endif /* have_iso */ + default: + BUG (); + } + } +#ifdef DEBUG + if (usecs > 100) + err ("overallocated uframe %d, periodic is %d usecs", + frame * 8 + uframe, usecs); +#endif + return usecs; +} + +/*-------------------------------------------------------------------------*/ + +static void intr_deschedule ( + struct ehci_hcd *ehci, + unsigned frame, + struct ehci_qh *qh, + unsigned period +) { + unsigned long flags; + + spin_lock_irqsave (&ehci->lock, flags); + + do { + periodic_unlink (ehci, frame, qh); + qh_unput (ehci, qh); + frame += period; + } while (frame < ehci->periodic_size); + + qh->qh_state = QH_STATE_UNLINK; + qh->qh_next.ptr = 0; + ehci->periodic_urbs--; + + /* maybe turn off periodic schedule */ + if (!ehci->periodic_urbs) { + u32 cmd = readl (&ehci->regs->command); + + /* did setting PSE not take effect yet? + * takes effect only at frame boundaries... + */ + while (!(readl (&ehci->regs->status) & STS_PSS)) + udelay (20); + + cmd &= ~CMD_PSE; + writel (cmd, &ehci->regs->command); + /* posted write ... */ + + ehci->next_frame = -1; + } else + vdbg ("periodic schedule still enabled"); + + spin_unlock_irqrestore (&ehci->lock, flags); + + /* + * If the hc may be looking at this qh, then delay a uframe + * (yeech!) to be sure it's done. + * No other threads may be mucking with this qh. + */ + if (((ehci_get_frame (&ehci->hcd) - frame) % period) == 0) + udelay (125); + + qh->qh_state = QH_STATE_IDLE; + qh->hw_next = EHCI_LIST_END; + + vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d", + qh, period, frame, + atomic_read (&qh->refcount), ehci->periodic_urbs); +} + +static int intr_submit ( + struct ehci_hcd *ehci, + struct urb *urb, + struct list_head *qtd_list, + int mem_flags +) { + unsigned epnum, period; + unsigned temp; + unsigned short mult, usecs; + unsigned long flags; + struct ehci_qh *qh; + struct hcd_dev *dev; + int status = 0; + + /* get endpoint and transfer data */ + epnum = usb_pipeendpoint (urb->pipe); + if (usb_pipein (urb->pipe)) { + temp = urb->dev->epmaxpacketin [epnum]; + epnum |= 0x10; + } else + temp = urb->dev->epmaxpacketout [epnum]; + mult = 1; + if (urb->dev->speed == USB_SPEED_HIGH) { + /* high speed "high bandwidth" is coded in ep maxpacket */ + mult += (temp >> 11) & 0x03; + temp &= 0x03ff; + } else { + dbg ("no intr/tt scheduling yet"); + status = -ENOSYS; + goto done; + } + + /* + * NOTE: current completion/restart logic doesn't handle more than + * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this. + * such big requests need many periods to transfer. + */ + if (unlikely (qtd_list->next != qtd_list->prev)) { + dbg ("only one intr qtd per urb allowed"); + status = -EINVAL; + goto done; + } + + usecs = HS_USECS (urb->transfer_buffer_length); + + /* + * force a power-of-two (frames) sized polling interval + * + * NOTE: endpoint->bInterval for highspeed is measured in uframes, + * while for full/low speeds it's in frames. Here we "know" that + * urb->interval doesn't give acccess to high interrupt rates. + */ + period = ehci->periodic_size; + temp = period; + if (unlikely (urb->interval < 1)) + urb->interval = 1; + while (temp > urb->interval) + temp >>= 1; + period = urb->interval = temp; + + spin_lock_irqsave (&ehci->lock, flags); + + /* get the qh (must be empty and idle) */ + dev = (struct hcd_dev *)urb->dev->hcpriv; + qh = (struct ehci_qh *) dev->ep [epnum]; + if (qh) { + /* only allow one queued interrupt urb per EP */ + if (unlikely (qh->qh_state != QH_STATE_IDLE + || !list_empty (&qh->qtd_list))) { + dbg ("interrupt urb already queued"); + status = -EBUSY; + } else { + /* maybe reset hardware's data toggle in the qh */ + if (unlikely (!usb_gettoggle (urb->dev, epnum & 0x0f, + !(epnum & 0x10)))) { + qh->hw_token |= + __constant_cpu_to_le32 (QTD_TOGGLE); + usb_settoggle (urb->dev, epnum & 0x0f, + !(epnum & 0x10), 1); + } + /* trust the QH was set up as interrupt ... */ + list_splice (qtd_list, &qh->qtd_list); + qh_update (qh, list_entry (qtd_list->next, + struct ehci_qtd, qtd_list)); + } + } else { + /* can't sleep here, we have ehci->lock... */ + qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC); + qtd_list = &qh->qtd_list; + if (likely (qh != 0)) { + // dbg ("new INTR qh %p", qh); + dev->ep [epnum] = qh; + } else + status = -ENOMEM; + } + + /* Schedule this periodic QH. */ + if (likely (status == 0)) { + unsigned frame = urb->interval; + + qh->hw_next = EHCI_LIST_END; + qh->hw_info2 |= cpu_to_le32 (mult << 30); + qh->usecs = usecs; + + urb->hcpriv = qh_put (qh); + status = -ENOSPC; + + /* pick a set of schedule slots, link the QH into them */ + do { + int uframe; + + /* Select some frame 0..(urb->interval - 1) with a + * microframe that can hold this transaction. + * + * FIXME for TT splits, need uframes for start and end. + * FSTNs can put end into next frame (uframes 0 or 1). + */ + frame--; + for (uframe = 0; uframe < 8; uframe++) { + int claimed; + claimed = periodic_usecs (ehci, frame, uframe); + /* 80% periodic == 100 usec max committed */ + if ((claimed + usecs) <= 100) { + vdbg ("frame %d.%d: %d usecs, plus %d", + frame, uframe, claimed, usecs); + break; + } + } + if (uframe == 8) + continue; +// FIXME delete when code below handles non-empty queues + if (ehci->pshadow [frame].ptr) + continue; + + /* QH will run once each period, starting there */ + urb->start_frame = frame; + status = 0; + + /* set S-frame mask */ + qh->hw_info2 |= cpu_to_le32 (1 << uframe); + // dbg_qh ("Schedule INTR qh", ehci, qh); + + /* stuff into the periodic schedule */ + qh->qh_state = QH_STATE_LINKED; + vdbg ("qh %p usecs %d period %d starting frame %d.%d", + qh, qh->usecs, period, frame, uframe); + do { + if (unlikely ((int)ehci->pshadow [frame].ptr)) { +// FIXME -- just link to the end, before any qh with a shorter period, +// AND handle it already being (implicitly) linked into this frame + BUG (); + } else { + ehci->pshadow [frame].qh = qh_put (qh); + ehci->periodic [frame] = + QH_NEXT (qh->qh_dma); + } + frame += period; + } while (frame < ehci->periodic_size); + + /* maybe enable periodic schedule processing */ + if (!ehci->periodic_urbs++) { + u32 cmd; + + /* did clearing PSE did take effect yet? + * takes effect only at frame boundaries... + */ + while (readl (&ehci->regs->status) & STS_PSS) + udelay (20); + + cmd = readl (&ehci->regs->command) | CMD_PSE; + writel (cmd, &ehci->regs->command); + /* posted write ... PSS happens later */ + ehci->hcd.state = USB_STATE_RUNNING; + + /* make sure tasklet scans these */ + ehci->next_frame = ehci_get_frame (&ehci->hcd); + } + break; + + } while (frame); + } + spin_unlock_irqrestore (&ehci->lock, flags); +done: + if (status) { + usb_complete_t complete = urb->complete; + + urb->complete = 0; + urb->status = status; + qh_completions (ehci, qtd_list, 1); + urb->complete = complete; + } + return status; +} + +static unsigned long +intr_complete ( + struct ehci_hcd *ehci, + unsigned frame, + struct ehci_qh *qh, + unsigned long flags /* caller owns ehci->lock ... */ +) { + struct ehci_qtd *qtd; + struct urb *urb; + int unlinking; + + /* nothing to report? */ + if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE)) + != 0)) + return flags; + + qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list); + urb = qtd->urb; + unlinking = (urb->status == -ENOENT) || (urb->status == -ECONNRESET); + + /* call any completions, after patching for reactivation */ + spin_unlock_irqrestore (&ehci->lock, flags); + /* NOTE: currently restricted to one qtd per qh! */ + if (qh_completions (ehci, &qh->qtd_list, 0) == 0) + urb = 0; + spin_lock_irqsave (&ehci->lock, flags); + + /* never reactivate requests that were unlinked ... */ + if (likely (urb != 0)) { + if (unlinking + || urb->status == -ECONNRESET + || urb->status == -ENOENT + // || (urb->dev == null) + || ehci->hcd.state == USB_STATE_HALT) + urb = 0; + // FIXME look at all those unlink cases ... we always + // need exactly one completion that reports unlink. + // the one above might not have been it! + } + + /* normally reactivate */ + if (likely (urb != 0)) { + if (usb_pipeout (urb->pipe)) + pci_dma_sync_single (ehci->hcd.pdev, + qtd->buf_dma, + urb->transfer_buffer_length, + PCI_DMA_TODEVICE); + urb->status = -EINPROGRESS; + urb->actual_length = 0; + + /* patch qh and restart */ + qh_update (qh, qtd); + } + return flags; +} + +/*-------------------------------------------------------------------------*/ + +#ifdef have_iso + +static inline void itd_free (struct ehci_hcd *ehci, struct ehci_itd *itd) +{ + pci_pool_free (ehci->itd_pool, itd, itd->itd_dma); +} + +/* + * Create itd and allocate into uframes within specified frame. + * Caller must update the resulting uframe links. + */ +static struct ehci_itd * +itd_make ( + struct ehci_hcd *ehci, + struct urb *urb, + unsigned index, // urb->iso_frame_desc [index] + unsigned frame, // scheduled start + dma_addr_t dma, // mapped transfer buffer + int mem_flags +) { + struct ehci_itd *itd; + u64 temp; + u32 buf1; + unsigned epnum, maxp, multi, usecs; + unsigned length; + unsigned i, bufnum; + + /* allocate itd, start to fill it */ + itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &dma); + if (!itd) + return itd; + + itd->hw_next = EHCI_LIST_END; + itd->urb = urb; + itd->index = index; + INIT_LIST_HEAD (&itd->itd_list); + itd->uframe = (frame * 8) % ehci->periodic_size; + + /* tell itd about the buffer its transfers will consume */ + length = urb->iso_frame_desc [index].length; + dma += urb->iso_frame_desc [index].offset; + temp = dma & ~0x0fff; + for (i = 0; i < 7; i++) { + itd->hw_bufp [i] = cpu_to_le32 ((u32) temp); + itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32)); + temp += 0x0fff; + } + + /* + * this might be a "high bandwidth" highspeed endpoint, + * as encoded in the ep descriptor's maxpacket field + */ + epnum = usb_pipeendpoint (urb->pipe); + if (usb_pipein (urb->pipe)) { + maxp = urb->dev->epmaxpacketin [epnum]; + buf1 = (1 << 11) | maxp; + } else { + maxp = urb->dev->epmaxpacketout [epnum]; + buf1 = maxp; + } + multi = 1; + multi += (temp >> 11) & 0x03; + maxp &= 0x03ff; + + /* "plus" info in low order bits of buffer pointers */ + itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum); + itd->hw_bufp [1] |= cpu_to_le32 (buf1); + itd->hw_bufp [2] |= cpu_to_le32 (multi); + + /* schedule as many uframes as needed */ + maxp *= multi; + usecs = HS_USECS_ISO (maxp); + bufnum = 0; + for (i = 0; i < 8; i++) { + unsigned t, offset, scratch; + + if (length <= 0) { + itd->hw_transaction [i] = 0; + continue; + } + + /* don't commit more than 80% periodic == 100 usec */ + if ((periodic_usecs (ehci, itd->uframe, i) + usecs) > 100) + continue; + + /* we'll use this uframe; figure hw_transaction */ + t = EHCI_ISOC_ACTIVE; + t |= bufnum << 12; // which buffer? + offset = temp & 0x0fff; // offset therein + t |= offset; + if ((offset + maxp) >= 4096) // hc auto-wraps end-of-"page" + bufnum++; + if (length <= maxp) { + // interrupt only needed at end-of-urb + if ((index + 1) == urb->number_of_packets) + t |= EHCI_ITD_IOC; + scratch = length; + } else + scratch = maxp; + t |= scratch << 16; + t = cpu_to_le32 (t); + + itd->hw_transaction [i] = itd->transaction [i] = t; + length -= scratch; + } + if (length > 0) { + dbg ("iso frame too big, urb %p [%d], %d extra (of %d)", + urb, index, length, urb->iso_frame_desc [index].length); + itd_free (ehci, itd); + itd = 0; + } + return itd; +} + +static inline void +itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) +{ + u32 ptr; + + ptr = cpu_to_le32 (itd->itd_dma); // type 0 == itd + if (ehci->pshadow [frame].ptr) { + if (!itd->itd_next.ptr) { + itd->itd_next = ehci->pshadow [frame]; + itd->hw_next = ehci->periodic [frame]; + } else if (itd->itd_next.ptr != ehci->pshadow [frame].ptr) { + dbg ("frame %d itd link goof", frame); + BUG (); + } + } + ehci->pshadow [frame].itd = itd; + ehci->periodic [frame] = ptr; +} + +#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR) + +static unsigned long +itd_complete (struct ehci_hcd *ehci, struct ehci_itd *itd, unsigned long flags) +{ + struct urb *urb = itd->urb; + + /* if not unlinking: */ + if (!(urb->transfer_flags & EHCI_STATE_UNLINK) + && ehci->hcd.state != USB_STATE_HALT) { + int i; + iso_packet_descriptor_t *desc; + struct ehci_itd *first_itd = urb->hcpriv; + + /* update status for this frame's transfers */ + desc = &urb->iso_frame_desc [itd->index]; + desc->status = 0; + desc->actual_length = 0; + for (i = 0; i < 8; i++) { + u32 t = itd->hw_transaction [i]; + if (t & (ISO_ERRS | EHCI_ISOC_ACTIVE)) { + if (t & EHCI_ISOC_ACTIVE) + desc->status = -EXDEV; + else if (t & EHCI_ISOC_BUF_ERR) + desc->status = usb_pipein (urb->pipe) + ? -ENOSR /* couldn't read */ + : -ECOMM; /* couldn't write */ + else if (t & EHCI_ISOC_BABBLE) + desc->status = -EOVERFLOW; + else /* (t & EHCI_ISOC_XACTERR) */ + desc->status = -EPROTO; + break; + } + desc->actual_length += EHCI_ITD_LENGTH (t); + } + + /* handle completion now? */ + if ((itd->index + 1) != urb->number_of_packets) + return flags; + + i = usb_pipein (urb->pipe); + if (i) + pci_dma_sync_single (ehci->hcd.pdev, + first_itd->buf_dma, + urb->transfer_buffer_length, + PCI_DMA_FROMDEVICE); + + /* call completion with no locks; it can unlink ... */ + spin_unlock_irqrestore (&ehci->lock, flags); + urb->complete (urb); + spin_lock_irqsave (&ehci->lock, flags); + + /* re-activate this URB? or unlink? */ + if (!(urb->transfer_flags & EHCI_STATE_UNLINK) + && ehci->hcd.state != USB_STATE_HALT) { + if (!i) + pci_dma_sync_single (ehci->hcd.pdev, + first_itd->buf_dma, + urb->transfer_buffer_length, + PCI_DMA_TODEVICE); + + itd = urb->hcpriv; + do { + for (i = 0; i < 8; i++) + itd->hw_transaction [i] + = itd->transaction [i]; + itd = list_entry (itd->itd_list.next, + struct ehci_itd, itd_list); + } while (itd != urb->hcpriv); + return flags; + } + + /* unlink done only on the last itd */ + } else if ((itd->index + 1) != urb->number_of_packets) + return flags; + + /* we're unlinking ... */ + + /* decouple urb from the hcd */ + spin_unlock_irqrestore (&ehci->lock, flags); + if (ehci->hcd.state == USB_STATE_HALT) + urb->status = -ESHUTDOWN; + itd = urb->hcpriv; + urb->hcpriv = 0; + ehci_urb_done (ehci, itd->buf_dma, urb); + spin_lock_irqsave (&ehci->lock, flags); + + /* take itds out of the hc's periodic schedule */ + list_entry (itd->itd_list.prev, struct ehci_itd, itd_list) + ->itd_list.next = 0; + do { + struct ehci_itd *next; + + if (itd->itd_list.next) + next = list_entry (itd->itd_list.next, + struct ehci_itd, itd_list); + else + next = 0; + + // FIXME: hc WILL (!) lap us here, if we get behind + // by 128 msec (or less, with smaller periodic_size). + // Reading/caching these itds will cause trouble... + + periodic_unlink (ehci, itd->uframe, itd); + itd_free (ehci, itd); + itd = next; + } while (itd); + return flags; +} + +/*-------------------------------------------------------------------------*/ + +static int itd_submit (struct ehci_hcd *ehci, struct urb *urb) +{ + struct ehci_itd *first_itd = 0, *itd; + unsigned frame_index; + dma_addr_t dma; + unsigned long flags; + + dbg ("itd_submit"); + + /* set up one dma mapping for this urb */ + dma = pci_map_single (ehci->hcd.pdev, + urb->transfer_buffer, urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); + if (dma == 0) + return -ENOMEM; + + /* + * Schedule as needed. This is VERY optimistic about free + * bandwidth! But the API assumes drivers can pick frames + * intelligently (how?), so there's no other good option. + * + * FIXME this doesn't handle urb->next rings, or try to + * use the iso periodicity. + */ + if (urb->transfer_flags & USB_ISO_ASAP) { + urb->start_frame = ehci_get_frame (&ehci->hcd); + urb->start_frame++; + } + urb->start_frame %= ehci->periodic_size; + + /* create and populate itds (doing uframe scheduling) */ + spin_lock_irqsave (&ehci->lock, flags); + for (frame_index = 0; + frame_index < urb->number_of_packets; + frame_index++) { + itd = itd_make (ehci, urb, frame_index, + urb->start_frame + frame_index, + dma, SLAB_ATOMIC); + if (itd) { + if (first_itd) + list_add_tail (&itd->itd_list, + &first_itd->itd_list); + else + first_itd = itd; + } else { + spin_unlock_irqrestore (&ehci->lock, flags); + if (first_itd) { + while (!list_empty (&first_itd->itd_list)) { + itd = list_entry ( + first_itd->itd_list.next, + struct ehci_itd, itd_list); + list_del (&itd->itd_list); + itd_free (ehci, itd); + } + itd_free (ehci, first_itd); + } + pci_unmap_single (ehci->hcd.pdev, + dma, urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); + return -ENOMEM; + } + } + + /* stuff into the schedule */ + itd = first_itd; + do { + unsigned i; + + for (i = 0; i < 8; i++) { + if (!itd->hw_transaction [i]) + continue; + itd_link (ehci, itd->uframe + i, itd); + } + itd = list_entry (itd->itd_list.next, + struct ehci_itd, itd_list); + } while (itd != first_itd); + urb->hcpriv = first_itd; + + spin_unlock_irqrestore (&ehci->lock, flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* + * "Split ISO TDs" ... used for USB 1.1 devices going through + * the TTs in USB 2.0 hubs. + */ + +static inline void +sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd) +{ + pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma); +} + +static struct ehci_sitd * +sitd_make ( + struct ehci_hcd *ehci, + struct urb *urb, + unsigned index, // urb->iso_frame_desc [index] + unsigned uframe, // scheduled start + dma_addr_t dma, // mapped transfer buffer + int mem_flags +) { + struct ehci_sitd *sitd; + unsigned length; + + sitd = pci_pool_alloc (ehci->sitd_pool, mem_flags, &dma); + if (!sitd) + return sitd; + sitd->urb = urb; + length = urb->iso_frame_desc [index].length; + dma += urb->iso_frame_desc [index].offset; + +#if 0 + // FIXME: do the rest! +#else + sitd_free (ehci, sitd); + return 0; +#endif + +} + +static inline void +sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd) +{ + u32 ptr; + + ptr = cpu_to_le32 (sitd->sitd_dma | 2); // type 2 == sitd + if (ehci->pshadow [frame].ptr) { + if (!sitd->sitd_next.ptr) { + sitd->sitd_next = ehci->pshadow [frame]; + sitd->hw_next = ehci->periodic [frame]; + } else if (sitd->sitd_next.ptr != ehci->pshadow [frame].ptr) { + dbg ("frame %d sitd link goof", frame); + BUG (); + } + } + ehci->pshadow [frame].sitd = sitd; + ehci->periodic [frame] = ptr; +} + +static unsigned long +sitd_complete ( + struct ehci_hcd *ehci, + struct ehci_sitd *sitd, + unsigned long flags +) { + // FIXME -- implement! + + dbg ("NYI -- sitd_complete"); + return flags; +} + +/*-------------------------------------------------------------------------*/ + +static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb) +{ + // struct ehci_sitd *first_sitd = 0; + unsigned frame_index; + dma_addr_t dma; + int mem_flags; + + dbg ("NYI -- sitd_submit"); + + // FIXME -- implement! + + // FIXME: setup one big dma mapping + dma = 0; + + mem_flags = SLAB_ATOMIC; + + for (frame_index = 0; + frame_index < urb->number_of_packets; + frame_index++) { + struct ehci_sitd *sitd; + unsigned uframe; + + // FIXME: use real arguments, schedule this! + uframe = -1; + + sitd = sitd_make (ehci, urb, frame_index, + uframe, dma, mem_flags); + + if (sitd) { + /* + if (first_sitd) + list_add_tail (&sitd->sitd_list, + &first_sitd->sitd_list); + else + first_sitd = sitd; + */ + } else { + // FIXME: clean everything up + } + } + + // if we have a first sitd, then + // store them all into the periodic schedule! + // urb->hcpriv = first sitd in sitd_list + + return -ENOSYS; +} + +#endif /* have_iso */ + +/*-------------------------------------------------------------------------*/ + +static void scan_periodic (struct ehci_hcd *ehci) +{ + unsigned frame; + unsigned clock; + unsigned long flags; + + spin_lock_irqsave (&ehci->lock, flags); + + /* + * When running, scan from last scan point up to "now" + * Touches as few pages as possible: cache-friendly. + * It's safe to scan entries more than once, though. + */ + if (HCD_IS_RUNNING (ehci->hcd.state)) { + frame = ehci->next_frame; + clock = ehci_get_frame (&ehci->hcd); + + /* when shutting down, scan everything for thoroughness */ + } else { + frame = 0; + clock = ehci->periodic_size - 1; + } + for (;;) { + union ehci_shadow q; + u32 type; + +restart: + q.ptr = ehci->pshadow [frame].ptr; + type = Q_NEXT_TYPE (ehci->periodic [frame]); + + /* scan each element in frame's queue for completions */ + while (q.ptr != 0) { + int last; + union ehci_shadow temp; + + switch (type) { + case Q_TYPE_QH: + last = (q.qh->hw_next == EHCI_LIST_END); + flags = intr_complete (ehci, frame, + qh_put (q.qh), flags); + type = Q_NEXT_TYPE (q.qh->hw_next); + temp = q.qh->qh_next; + qh_unput (ehci, q.qh); + q = temp; + break; + case Q_TYPE_FSTN: + last = (q.fstn->hw_next == EHCI_LIST_END); + /* for "save place" FSTNs, look at QH entries + * in the previous frame for completions. + */ + if (q.fstn->hw_prev != EHCI_LIST_END) { + dbg ("ignoring completions from FSTNs"); + } + type = Q_NEXT_TYPE (q.fstn->hw_next); + temp = q.fstn->fstn_next; + break; +#ifdef have_iso + case Q_TYPE_ITD: + last = (q.itd->hw_next == EHCI_LIST_END); + flags = itd_complete (ehci, q.itd, flags); + type = Q_NEXT_TYPE (q.itd->hw_next); + q = q.itd->itd_next; + break; + case Q_TYPE_SITD: + last = (q.sitd->hw_next == EHCI_LIST_END); + flags = sitd_complete (ehci, q.sitd, flags); + type = Q_NEXT_TYPE (q.sitd->hw_next); + q = q.sitd->sitd_next; + break; +#endif /* have_iso */ + default: + dbg ("corrupt type %d frame %d shadow %p", + type, frame, q.ptr); + // BUG (); + last = 1; + q.ptr = 0; + } + + /* did completion remove an interior q entry? */ + if (unlikely (q.ptr == 0 && !last)) + goto restart; + } + + /* stop when we catch up to the HC */ + + // FIXME: this assumes we won't get lapped when + // latencies climb; that should be rare, but... + // detect it, and just go all the way around. + // FLR might help detect this case, so long as latencies + // don't exceed periodic_size msec (default 1.024 sec). + + // FIXME: likewise assumes HC doesn't halt mid-scan + + if (frame == clock) { + unsigned now; + + if (!HCD_IS_RUNNING (ehci->hcd.state)) + break; + ehci->next_frame = clock; + now = ehci_get_frame (&ehci->hcd); + if (clock == now) + break; + clock = now; + } else if (++frame >= ehci->periodic_size) + frame = 0; + } + spin_unlock_irqrestore (&ehci->lock, flags); + } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd/ehci.h linux-2.5/drivers/usb/hcd/ehci.h --- linux-2.5.1/drivers/usb/hcd/ehci.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd/ehci.h Tue Jan 1 23:42:42 2002 @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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 __LINUX_EHCI_HCD_H +#define __LINUX_EHCI_HCD_H + +/* definitions used for the EHCI driver */ + +/* ehci_hcd->lock guards shared data against other CPUs: + * ehci_hcd: async, reclaim, periodic (and shadow), ... + * hcd_dev: ep[] + * ehci_qh: qh_next, qtd_list + * ehci_qtd: qtd_list + * + * Also, hold this lock when talking to HC registers or + * when updating hw_* fields in shared qh/qtd/... structures. + */ + +#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */ + +struct ehci_hcd { /* one per controller */ + spinlock_t lock; + + /* async schedule support */ + struct ehci_qh *async; + struct ehci_qh *reclaim; + int reclaim_ready; + + /* periodic schedule support */ +#define DEFAULT_I_TDPS 1024 /* some HCs can do less */ + unsigned periodic_size; + u32 *periodic; /* hw periodic table */ + dma_addr_t periodic_dma; + unsigned i_thresh; /* uframes HC might cache */ + + union ehci_shadow *pshadow; /* mirror hw periodic table */ + int next_frame; /* scan periodic, start here */ + unsigned periodic_urbs; /* how many urbs scheduled? */ + + /* deferred work from IRQ, etc */ + struct tasklet_struct tasklet; + + /* per root hub port */ + unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; + + /* glue to PCI and HCD framework */ + struct usb_hcd hcd; + struct ehci_caps *caps; + struct ehci_regs *regs; + + /* per-HC memory pools (could be per-PCI-bus, but ...) */ + struct pci_pool *qh_pool; /* qh per active urb */ + struct pci_pool *qtd_pool; /* one or more per qh */ + struct pci_pool *itd_pool; /* itd per iso urb */ + struct pci_pool *sitd_pool; /* sitd per split iso urb */ +}; + +/* unwrap an HCD pointer to get an EHCI_HCD pointer */ +#define hcd_to_ehci(hcd_ptr) list_entry(hcd_ptr, struct ehci_hcd, hcd) + +/* NOTE: urb->transfer_flags expected to not use this bit !!! */ +#define EHCI_STATE_UNLINK 0x8000 /* urb being unlinked */ + +/*-------------------------------------------------------------------------*/ + +/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ + +/* Section 2.2 Host Controller Capability Registers */ +struct ehci_caps { + u8 length; /* CAPLENGTH - size of this struct */ + u8 reserved; /* offset 0x1 */ + u16 hci_version; /* HCIVERSION - offset 0x2 */ + u32 hcs_params; /* HCSPARAMS - offset 0x4 */ +#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */ +#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ +#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */ +#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */ +#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */ +#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ +#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ + + u32 hcc_params; /* HCCPARAMS - offset 0x8 */ +#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */ +#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */ +#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */ +#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */ +#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ +#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */ + u8 portroute [8]; /* nibbles for routing - offset 0xC */ +} __attribute__ ((packed)); + + +/* Section 2.3 Host Controller Operational Registers */ +struct ehci_regs { + + /* USBCMD: offset 0x00 */ + u32 command; +/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ +#define CMD_PARK (1<<11) /* enable "park" on async qh */ +#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */ +#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ +#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ +#define CMD_ASE (1<<5) /* async schedule enable */ +#define CMD_PSE (1<<4) /* periodic schedule enable */ +/* 3:2 is periodic frame list size */ +#define CMD_RESET (1<<1) /* reset HC not bus */ +#define CMD_RUN (1<<0) /* start/stop HC */ + + /* USBSTS: offset 0x04 */ + u32 status; +#define STS_ASS (1<<15) /* Async Schedule Status */ +#define STS_PSS (1<<14) /* Periodic Schedule Status */ +#define STS_RECL (1<<13) /* Reclamation */ +#define STS_HALT (1<<12) /* Not running (any reason) */ +/* some bits reserved */ + /* these STS_* flags are also intr_enable bits (USBINTR) */ +#define STS_IAA (1<<5) /* Interrupted on async advance */ +#define STS_FATAL (1<<4) /* such as some PCI access errors */ +#define STS_FLR (1<<3) /* frame list rolled over */ +#define STS_PCD (1<<2) /* port change detect */ +#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */ +#define STS_INT (1<<0) /* "normal" completion (short, ...) */ + + /* USBINTR: offset 0x08 */ + u32 intr_enable; + + /* FRINDEX: offset 0x0C */ + u32 frame_index; /* current microframe number */ + /* CTRLDSSEGMENT: offset 0x10 */ + u32 segment; /* address bits 63:32 if needed */ + /* PERIODICLISTBASE: offset 0x14 */ + u32 frame_list; /* points to periodic list */ + /* ASYNCICLISTADDR: offset 0x18 */ + u32 async_next; /* address of next async queue head */ + + u32 reserved [9]; + + /* CONFIGFLAG: offset 0x40 */ + u32 configured_flag; +#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ + + /* PORTSC: offset 0x44 */ + u32 port_status [0]; /* up to N_PORTS */ +/* 31:23 reserved */ +#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */ +#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */ +#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */ +/* 19:16 for port testing */ +/* 15:14 for using port indicator leds (if HCS_INDICATOR allows) */ +#define PORT_OWNER (1<<13) /* true: companion hc owns this port */ +#define PORT_POWER (1<<12) /* true: has power (see PPC) */ +#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */ +/* 11:10 for detecting lowspeed devices (reset vs release ownership) */ +/* 9 reserved */ +#define PORT_RESET (1<<8) /* reset port */ +#define PORT_SUSPEND (1<<7) /* suspend port */ +#define PORT_RESUME (1<<6) /* resume it */ +#define PORT_OCC (1<<5) /* over current change */ +#define PORT_OC (1<<4) /* over current active */ +#define PORT_PEC (1<<3) /* port enable change */ +#define PORT_PE (1<<2) /* port enable */ +#define PORT_CSC (1<<1) /* connect status change */ +#define PORT_CONNECT (1<<0) /* device connected */ +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +#define QTD_NEXT(dma) cpu_to_le32((u32)dma) + +/* + * EHCI Specification 0.95 Section 3.5 + * QTD: describe data transfer components (buffer, direction, ...) + * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram". + * + * These are associated only with "QH" (Queue Head) structures, + * used with control, bulk, and interrupt transfers. + */ +struct ehci_qtd { + /* first part defined by EHCI spec */ + u32 hw_next; /* see EHCI 3.5.1 */ + u32 hw_alt_next; /* see EHCI 3.5.2 */ + u32 hw_token; /* see EHCI 3.5.3 */ +#define QTD_TOGGLE (1 << 31) /* data toggle */ +#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) +#define QTD_IOC (1 << 15) /* interrupt on complete */ +#define QTD_CERR(tok) (((tok)>>10) & 0x3) +#define QTD_PID(tok) (((tok)>>8) & 0x3) +#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */ +#define QTD_STS_HALT (1 << 6) /* halted on error */ +#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */ +#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */ +#define QTD_STS_XACT (1 << 3) /* device gave illegal response */ +#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ +#define QTD_STS_STS (1 << 1) /* split transaction state */ +#define QTD_STS_PING (1 << 0) /* issue PING? */ + u32 hw_buf [5]; /* see EHCI 3.5.4 */ + u32 hw_buf_hi [5]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t qtd_dma; /* qtd address */ + struct list_head qtd_list; /* sw qtd list */ + + /* dma same in urb's qtds, except 1st control qtd (setup buffer) */ + struct urb *urb; /* qtd's urb */ + dma_addr_t buf_dma; /* buffer address */ + size_t length; /* length of buffer */ +} __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +/* type tag from {qh,itd,sitd,fstn}->hw_next */ +#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1)) + +/* values for that type tag */ +#define Q_TYPE_ITD __constant_cpu_to_le32 (0 << 1) +#define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1) +#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1) +#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1) + +/* next async queue entry, or pointer to interrupt/periodic QH */ +#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH) + +/* for periodic/async schedules and qtd lists, mark end of list */ +#define EHCI_LIST_END __constant_cpu_to_le32(1) /* "null pointer" to hw */ + +/* + * Entries in periodic shadow table are pointers to one of four kinds + * of data structure. That's dictated by the hardware; a type tag is + * encoded in the low bits of the hardware's periodic schedule. Use + * Q_NEXT_TYPE to get the tag. + * + * For entries in the async schedule, the type tag always says "qh". + */ +union ehci_shadow { + struct ehci_qh *qh; /* Q_TYPE_QH */ + struct ehci_itd *itd; /* Q_TYPE_ITD */ + struct ehci_sitd *sitd; /* Q_TYPE_SITD */ + struct ehci_fstn *fstn; /* Q_TYPE_FSTN */ + void *ptr; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.6 + * QH: describes control/bulk/interrupt endpoints + * See Fig 3-7 "Queue Head Structure Layout". + * + * These appear in both the async and (for interrupt) periodic schedules. + */ + +struct ehci_qh { + /* first part defined by EHCI spec */ + u32 hw_next; /* see EHCI 3.6.1 */ + u32 hw_info1; /* see EHCI 3.6.2 */ +#define QH_HEAD 0x00008000 + u32 hw_info2; /* see EHCI 3.6.2 */ + u32 hw_current; /* qtd list - see EHCI 3.6.4 */ + + /* qtd overlay (hardware parts of a struct ehci_qtd) */ + u32 hw_qtd_next; + u32 hw_alt_next; + u32 hw_token; + u32 hw_buf [5]; + u32 hw_buf_hi [5]; + + /* the rest is HCD-private */ + dma_addr_t qh_dma; /* address of qh */ + union ehci_shadow qh_next; /* ptr to qh; or periodic */ + struct list_head qtd_list; /* sw qtd list */ + + atomic_t refcount; + unsigned short usecs; /* intr bandwidth */ + short qh_state; +#define QH_STATE_LINKED 1 /* HC sees this */ +#define QH_STATE_UNLINK 2 /* HC may still see this */ +#define QH_STATE_IDLE 3 /* HC doesn't see this */ + +#ifdef EHCI_SOFT_RETRIES + int retries; +#endif +} __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.3 + * Fig 3-4 "Isochronous Transaction Descriptor (iTD)" + * + * Schedule records for high speed iso xfers + */ +struct ehci_itd { + /* first part defined by EHCI spec */ + u32 hw_next; /* see EHCI 3.3.1 */ + u32 hw_transaction [8]; /* see EHCI 3.3.2 */ +#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */ +#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */ +#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */ +#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */ +#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x7fff) +#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */ + + u32 hw_bufp [7]; /* see EHCI 3.3.3 */ + u32 hw_bufp_hi [7]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t itd_dma; /* for this itd */ + union ehci_shadow itd_next; /* ptr to periodic q entry */ + + struct urb *urb; + unsigned index; /* in urb->iso_frame_desc */ + struct list_head itd_list; /* list of urb frames' itds */ + dma_addr_t buf_dma; /* frame's buffer address */ + + unsigned uframe; /* in periodic schedule */ + u32 transaction [8]; /* copy of hw_transaction */ + +} __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.4 + * siTD, aka split-transaction isochronous Transfer Descriptor + * ... describe low/full speed iso xfers through TT in hubs + * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD) + */ +struct ehci_sitd { + /* first part defined by EHCI spec */ + u32 hw_next; +/* uses bit field macros above - see EHCI 0.95 Table 3-8 */ + u32 hw_fullspeed_ep; /* see EHCI table 3-9 */ + u32 hw_uframe; /* see EHCI table 3-10 */ + u32 hw_tx_results1; /* see EHCI table 3-11 */ + u32 hw_tx_results2; /* see EHCI table 3-12 */ + u32 hw_tx_results3; /* see EHCI table 3-12 */ + u32 hw_backpointer; /* see EHCI table 3-13 */ + u32 hw_buf_hi [2]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t sitd_dma; + union ehci_shadow sitd_next; /* ptr to periodic q entry */ + struct urb *urb; + dma_addr_t buf_dma; /* buffer address */ +} __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.96 Section 3.7 + * Periodic Frame Span Traversal Node (FSTN) + * + * Manages split interrupt transactions (using TT) that span frame boundaries + * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN + * makes the HC jump (back) to a QH to scan for fs/ls QH completions until + * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work. + */ +struct ehci_fstn { + u32 hw_next; /* any periodic q entry */ + u32 hw_prev; /* qh or EHCI_LIST_END */ + + /* the rest is HCD-private */ + dma_addr_t fstn_dma; + union ehci_shadow fstn_next; /* ptr to periodic q entry */ +} __attribute__ ((aligned (32))); + +#endif /* __LINUX_EHCI_HCD_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd.c linux-2.5/drivers/usb/hcd.c --- linux-2.5.1/drivers/usb/hcd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd.c Tue Jan 8 00:44:24 2002 @@ -0,0 +1,1305 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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/module.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/kmod.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/uts.h> /* for UTS_SYSNAME */ + +#ifndef CONFIG_USB_DEBUG + #define CONFIG_USB_DEBUG /* this is experimental! */ +#endif + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include <linux/usb.h> +#include "hcd.h" + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/unaligned.h> + + +/*-------------------------------------------------------------------------*/ + +/* + * USB Host Controller Driver framework + * + * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing + * HCD-specific behaviors/bugs. + * + * This does error checks, tracks devices and urbs, and delegates to a + * "hc_driver" only for code (and data) that really needs to know about + * hardware differences. That includes root hub registers, i/o queues, + * and so on ... but as little else as possible. + * + * Shared code includes most of the "root hub" code (these are emulated, + * though each HC's hardware works differently) and PCI glue, plus request + * tracking overhead. The HCD code should only block on spinlocks or on + * hardware handshaking; blocking on software events (such as other kernel + * threads releasing resources, or completing actions) is all generic. + * + * Happens the USB 2.0 spec says this would be invisible inside the "USBD", + * and includes mostly a "HCDI" (HCD Interface) along with some APIs used + * only by the hub driver ... and that neither should be seen or used by + * usb client device drivers. + * + * Contributors of ideas or unattributed patches include: David Brownell, + * Roman Weissgaerber, Rory Bolt, ... + * + * HISTORY: + * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. + */ + +/*-------------------------------------------------------------------------*/ + +/* host controllers we manage */ +static LIST_HEAD (hcd_list); + +/* used when updating list of hcds */ +static DECLARE_MUTEX (hcd_list_lock); + +/* used when updating hcd data */ +static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; + +static struct usb_operations hcd_operations; + +/*-------------------------------------------------------------------------*/ + +/* + * Sharable chunks of root hub code. + */ + +/*-------------------------------------------------------------------------*/ + +/* usb 2.0 root hub device descriptor */ +static const u8 usb2_rh_dev_descriptor [18] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, 0x02, /* __u16 bcdUSB; v2.0 */ + + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + + 0x00, 0x00, /* __u16 idVendor; */ + 0x00, 0x00, /* __u16 idProduct; */ + 0x40, 0x02, /* __u16 bcdDevice; (v2.4) */ + + 0x03, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */ + +/* usb 1.1 root hub device descriptor */ +static const u8 usb11_rh_dev_descriptor [18] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x10, 0x01, /* __u16 bcdUSB; v1.1 */ + + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + + 0x00, 0x00, /* __u16 idVendor; */ + 0x00, 0x00, /* __u16 idProduct; */ + 0x40, 0x02, /* __u16 bcdDevice; (v2.4) */ + + 0x03, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + + +/*-------------------------------------------------------------------------*/ + +/* Configuration descriptor for all our root hubs */ + +static const u8 rh_config_descriptor [] = { + + /* one configuration */ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, 0x00, /* __u16 wTotalLength; */ + 0x01, /* __u8 bNumInterfaces; (1) */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, + 6: Self-powered, + 5 Remote-wakwup, + 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one 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; [usb1.1 or single tt] */ + 0x00, /* __u8 if_iInterface; */ + + /* one endpoint (status change endpoint) */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0x0c /* __u8 ep_bInterval; (12ms -- usb 2.0 spec) */ +}; + +/*-------------------------------------------------------------------------*/ + +/* + * helper routine for returning string descriptors in UTF-16LE + * input can actually be ISO-8859-1; ASCII is its 7-bit subset + */ +static int ascii2utf (char *ascii, u8 *utf, int utfmax) +{ + int retval; + + for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) { + *utf++ = *ascii++ & 0x7f; + *utf++ = 0; + } + return retval; +} + +/* + * rh_string - provides manufacturer, product and serial strings for root hub + * @id: the string ID number (1: serial number, 2: product, 3: vendor) + * @pci_desc: PCI device descriptor for the relevant HC + * @type: string describing our driver + * @data: return packet in UTF-16 LE + * @len: length of the return packet + * + * Produces either a manufacturer, product or serial number string for the + * virtual root hub device. + */ +static int rh_string ( + int id, + struct pci_dev *pci_desc, + char *type, + u8 *data, + int len +) { + char buf [100]; + + // language ids + if (id == 0) { + *data++ = 4; *data++ = 3; /* 4 bytes string data */ + *data++ = 0; *data++ = 0; /* some language id */ + return 4; + + // serial number + } else if (id == 1) { + strcpy (buf, pci_desc->slot_name); + + // product description + } else if (id == 2) { + strcpy (buf, pci_desc->name); + + // id 3 == vendor description + } else if (id == 3) { + sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, type); + + // unsupported IDs --> "protocol stall" + } else + return 0; + + data [0] = 2 + ascii2utf (buf, data + 2, len - 2); + data [1] = 3; /* type == string */ + return data [0]; +} + + +/* Root hub control transfers execute synchronously */ +static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) +{ + struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; + u16 typeReq, wValue, wIndex, wLength; + const u8 *bufp = 0; + u8 *ubuf = urb->transfer_buffer; + int len = 0; + + typeReq = (cmd->bRequestType << 8) | cmd->bRequest; + wValue = le16_to_cpu (cmd->wValue); + wIndex = le16_to_cpu (cmd->wIndex); + wLength = le16_to_cpu (cmd->wLength); + + if (wLength > urb->transfer_buffer_length) + goto error; + + /* set up for success */ + urb->status = 0; + urb->actual_length = wLength; + switch (typeReq) { + + /* DEVICE REQUESTS */ + + case DeviceRequest | USB_REQ_GET_STATUS: + // DEVICE_REMOTE_WAKEUP + ubuf [0] = 1; // selfpowered + ubuf [1] = 0; + /* FALLTHROUGH */ + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + case DeviceOutRequest | USB_REQ_SET_FEATURE: + dbg ("no device features yet yet"); + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + ubuf [0] = 1; + /* FALLTHROUGH */ + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch (wValue & 0xff00) { + case USB_DT_DEVICE << 8: + if (hcd->driver->flags & HCD_USB2) + bufp = usb2_rh_dev_descriptor; + else if (hcd->driver->flags & HCD_USB11) + bufp = usb11_rh_dev_descriptor; + else + goto error; + len = 18; + break; + case USB_DT_CONFIG << 8: + bufp = rh_config_descriptor; + len = sizeof rh_config_descriptor; + break; + case USB_DT_STRING << 8: + urb->actual_length = rh_string ( + wValue & 0xff, + hcd->pdev, + (char *) hcd->description, + ubuf, wLength); + break; + default: + goto error; + } + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + ubuf [0] = 0; + /* FALLTHROUGH */ + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + // wValue == urb->dev->devaddr + dbg ("%s root hub device address %d", + hcd->bus_name, wValue); + break; + + /* INTERFACE REQUESTS (no defined feature/status flags) */ + + /* ENDPOINT REQUESTS */ + + case EndpointRequest | USB_REQ_GET_STATUS: + // ENDPOINT_HALT flag + ubuf [0] = 0; + ubuf [1] = 0; + /* FALLTHROUGH */ + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + case EndpointOutRequest | USB_REQ_SET_FEATURE: + dbg ("no endpoint features yet"); + break; + + /* CLASS REQUESTS (and errors) */ + + default: + /* non-generic request */ + urb->status = hcd->driver->hub_control (hcd, + typeReq, wValue, wIndex, + ubuf, wLength); + break; +error: + /* "protocol stall" on error */ + urb->status = -EPIPE; + dbg ("unsupported hub control message (maxchild %d)", + urb->dev->maxchild); + } + if (urb->status) { + urb->actual_length = 0; + dbg ("CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d", + typeReq, wValue, wIndex, wLength, urb->status); + } + if (bufp) { + if (urb->transfer_buffer_length < len) + len = urb->transfer_buffer_length; + urb->actual_length = len; + // always USB_DIR_IN, toward host + memcpy (ubuf, bufp, len); + } + + /* any errors get returned through the urb completion */ + usb_hcd_giveback_urb (hcd, urb); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* + * Root Hub interrupt transfers are synthesized with a timer. + * Completions are called in_interrupt() but not in_irq(). + */ + +static void rh_report_status (unsigned long ptr); + +static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) +{ + int len = 1 + (urb->dev->maxchild / 8); + + /* rh_timer protected by hcd_data_lock */ + if (timer_pending (&hcd->rh_timer) + || urb->status != -EINPROGRESS + || !HCD_IS_RUNNING (hcd->state) + || urb->transfer_buffer_length < len) { + dbg ("not queuing status urb, stat %d", urb->status); + return -EINVAL; + } + + urb->hcpriv = hcd; /* nonzero to indicate it's queued */ + init_timer (&hcd->rh_timer); + hcd->rh_timer.function = rh_report_status; + hcd->rh_timer.data = (unsigned long) urb; + hcd->rh_timer.expires = jiffies + + (HZ * (urb->interval < 30 + ? 30 + : urb->interval)) / 1000; + add_timer (&hcd->rh_timer); + return 0; +} + +/* timer callback */ + +static void rh_report_status (unsigned long ptr) +{ + struct urb *urb; + struct usb_hcd *hcd; + int length; + unsigned long flags; + + urb = (struct urb *) ptr; + spin_lock_irqsave (&urb->lock, flags); + if (!urb->dev) { + spin_unlock_irqrestore (&urb->lock, flags); + return; + } + + hcd = urb->dev->bus->hcpriv; + if (urb->status == -EINPROGRESS) { + if (HCD_IS_RUNNING (hcd->state)) { + length = hcd->driver->hub_status_data (hcd, + urb->transfer_buffer); + spin_unlock_irqrestore (&urb->lock, flags); + if (length > 0) { + urb->actual_length = length; + urb->status = 0; + urb->complete (urb); + } + spin_lock_irqsave (&hcd_data_lock, flags); + urb->status = -EINPROGRESS; + if (HCD_IS_RUNNING (hcd->state) + && rh_status_urb (hcd, urb) != 0) { + /* another driver snuck in? */ + dbg ("%s, can't resubmit roothub status urb?", + hcd->bus_name); + spin_unlock_irqrestore (&hcd_data_lock, flags); + BUG (); + } + spin_unlock_irqrestore (&hcd_data_lock, flags); + } else + spin_unlock_irqrestore (&urb->lock, flags); + } else { + /* this urb's been unlinked */ + urb->hcpriv = 0; + spin_unlock_irqrestore (&urb->lock, flags); + + usb_hcd_giveback_urb (hcd, urb); + } +} + +/*-------------------------------------------------------------------------*/ + +static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) +{ + if (usb_pipeint (urb->pipe)) { + int retval; + unsigned long flags; + + spin_lock_irqsave (&hcd_data_lock, flags); + retval = rh_status_urb (hcd, urb); + spin_unlock_irqrestore (&hcd_data_lock, flags); + return retval; + } + if (usb_pipecontrol (urb->pipe)) + return rh_call_control (hcd, urb); + else + return -EINVAL; +} + +/*-------------------------------------------------------------------------*/ + +static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb) +{ + unsigned long flags; + + spin_lock_irqsave (&hcd_data_lock, flags); + del_timer_sync (&hcd->rh_timer); + hcd->rh_timer.data = 0; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + /* we rely on RH callback code not unlinking its URB! */ + usb_hcd_giveback_urb (hcd, urb); +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_PCI + +/* PCI-based HCs are normal, but custom bus glue should be ok */ + +static void hcd_irq (int irq, void *__hcd, struct pt_regs *r); +static void hc_died (struct usb_hcd *hcd); + +/*-------------------------------------------------------------------------*/ + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + +/** + * usb_hcd_pci_probe - initialize PCI-based HCDs + * @dev: USB Host Controller being probed + * @id: pci hotplug id connecting controller to HCD framework + * + * Allocates basic PCI resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + * Store this function in the HCD's struct pci_driver as probe(). + */ +int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + struct hc_driver *driver; + unsigned long resource, len; + void *base; + u8 latency, limit; + struct usb_bus *bus; + struct usb_hcd *hcd; + int retval, region; + char buf [8], *bufp = buf; + + if (!id || !(driver = (struct hc_driver *) id->driver_data)) + return -EINVAL; + + if (pci_enable_device (dev) < 0) + return -ENODEV; + + if (!dev->irq) { + err ("Found HC with no IRQ. Check BIOS/PCI %s setup!", + dev->slot_name); + return -ENODEV; + } + + if (driver->flags & HCD_MEMORY) { // EHCI, OHCI + region = 0; + resource = pci_resource_start (dev, 0); + len = pci_resource_len (dev, 0); + if (!request_mem_region (resource, len, driver->description)) { + dbg ("controller already in use"); + return -EBUSY; + } + base = ioremap_nocache (resource, len); + if (base == NULL) { + dbg ("error mapping memory"); + retval = -EFAULT; +clean_1: + release_mem_region (resource, len); + err ("init %s fail, %d", dev->slot_name, retval); + return retval; + } + + } else { // UHCI + resource = len = 0; + for (region = 0; region < PCI_ROM_RESOURCE; region++) { + if (!(pci_resource_flags (dev, region) & IORESOURCE_IO)) + continue; + + resource = pci_resource_start (dev, region); + len = pci_resource_len (dev, region); + if (request_region (resource, len, + driver->description)) + break; + } + if (region == PCI_ROM_RESOURCE) { + dbg ("no i/o regions available"); + return -EBUSY; + } + base = (void *) resource; + } + + // driver->start(), later on, will transfer device from + // control by SMM/BIOS to control by Linux (if needed) + + pci_set_master (dev); + hcd = driver->hcd_alloc (); + if (hcd == NULL){ + dbg ("hcd alloc fail"); + retval = -ENOMEM; +clean_2: + if (driver->flags & HCD_MEMORY) { + iounmap (base); + goto clean_1; + } else { + release_region (resource, len); + err ("init %s fail, %d", dev->slot_name, retval); + return retval; + } + } + dev->driver_data = hcd; + hcd->driver = driver; + hcd->description = driver->description; + hcd->pdev = dev; + info ("%s @ %s, %s", hcd->description, dev->slot_name, dev->name); + + pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); + if (latency) { + pci_read_config_byte (dev, PCI_MAX_LAT, &limit); + if (limit && limit < latency) { + dbg ("PCI latency reduced to max %d", limit); + pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit); + } + } + +#ifndef __sparc__ + sprintf (buf, "%d", dev->irq); +#else + bufp = __irq_itoa(irq); +#endif + if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd) + != 0) { + err ("request interrupt %s failed", bufp); + retval = -EBUSY; +clean_3: + driver->hcd_free (hcd); + goto clean_2; + } + hcd->irq = dev->irq; + + hcd->regs = base; + hcd->region = region; + info ("irq %s, %s %p", bufp, + (driver->flags & HCD_MEMORY) ? "pci mem" : "io base", + base); + +// FIXME simpler: make "bus" be that data, not pointer to it. + bus = usb_alloc_bus (&hcd_operations); + if (bus == NULL) { + dbg ("usb_alloc_bus fail"); + retval = -ENOMEM; + free_irq (dev->irq, hcd); + goto clean_3; + } + hcd->bus = bus; + hcd->bus_name = dev->slot_name; + bus->hcpriv = (void *) hcd; + + INIT_LIST_HEAD (&hcd->dev_list); + INIT_LIST_HEAD (&hcd->hcd_list); + + down (&hcd_list_lock); + list_add (&hcd->hcd_list, &hcd_list); + up (&hcd_list_lock); + + usb_register_bus (bus); + + if ((retval = driver->start (hcd)) < 0) + usb_hcd_pci_remove (dev); + + return retval; +} +EXPORT_SYMBOL (usb_hcd_pci_probe); + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs + * @dev: USB Host Controller being removed + * + * Reverses the effect of usb_hcd_pci_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + * Store this function in the HCD's struct pci_driver as remove(). + */ +void usb_hcd_pci_remove (struct pci_dev *dev) +{ + struct usb_hcd *hcd; + struct usb_device *hub; + + hcd = (struct usb_hcd *) dev->driver_data; + if (!hcd) + return; + info ("remove: %s, state %x", hcd->bus_name, hcd->state); + + if (in_interrupt ()) BUG (); + + hub = hcd->bus->root_hub; + hcd->state = USB_STATE_QUIESCING; + + dbg ("%s: roothub graceful disconnect", hcd->bus_name); + usb_disconnect (&hub); + // usb_disconnect (&hcd->bus->root_hub); + + hcd->driver->stop (hcd); + hcd->state = USB_STATE_HALT; + + free_irq (hcd->irq, hcd); + if (hcd->driver->flags & HCD_MEMORY) { + iounmap (hcd->regs); + release_mem_region (pci_resource_start (dev, 0), + pci_resource_len (dev, 0)); + } else { + release_region (pci_resource_start (dev, hcd->region), + pci_resource_len (dev, hcd->region)); + } + + down (&hcd_list_lock); + list_del (&hcd->hcd_list); + up (&hcd_list_lock); + + usb_deregister_bus (hcd->bus); + usb_free_bus (hcd->bus); + hcd->bus = NULL; + + hcd->driver->hcd_free (hcd); +} +EXPORT_SYMBOL (usb_hcd_pci_remove); + + +#ifdef CONFIG_PM + +/* + * Some "sleep" power levels imply updating struct usb_driver + * to include a callback asking hcds to do their bit by checking + * if all the drivers can suspend. Gets involved with remote wakeup. + * + * If there are pending urbs, then HCs will need to access memory, + * causing extra power drain. New sleep()/wakeup() PM calls might + * be needed, beyond PCI suspend()/resume(). The root hub timer + * still be accessing memory though ... + * + * FIXME: USB should have some power budgeting support working with + * all kinds of hubs. + * + * FIXME: This assumes only D0->D3 suspend and D3->D0 resume. + * D1 and D2 states should do something, yes? + * + * FIXME: Should provide generic enable_wake(), calling pci_enable_wake() + * for all supported states, so that USB remote wakeup can work for any + * devices that support it (and are connected via powered hubs). + * + * FIXME: resume doesn't seem to work right any more... + */ + + +// 2.4 kernels have issued concurrent resumes (w/APM) +// we defend against that error; PCI doesn't yet. + +/** + * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD + * @dev: USB Host Controller being suspended + * + * Store this function in the HCD's struct pci_driver as suspend(). + */ +int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) +{ + struct usb_hcd *hcd; + int retval; + + hcd = (struct usb_hcd *) dev->driver_data; + info ("suspend %s to state %d", hcd->bus_name, state); + + pci_save_state (dev, hcd->pci_state); + + // FIXME for all connected devices, leaf-to-root: + // driver->suspend() + // proposed "new 2.5 driver model" will automate that + + /* driver may want to disable DMA etc */ + retval = hcd->driver->suspend (hcd, state); + hcd->state = USB_STATE_SUSPENDED; + + pci_set_power_state (dev, state); + return retval; +} +EXPORT_SYMBOL (usb_hcd_pci_suspend); + +/** + * usb_hcd_pci_resume - power management resume of a PCI-based HCD + * @dev: USB Host Controller being resumed + * + * Store this function in the HCD's struct pci_driver as resume(). + */ +int usb_hcd_pci_resume (struct pci_dev *dev) +{ + struct usb_hcd *hcd; + int retval; + + hcd = (struct usb_hcd *) dev->driver_data; + info ("resume %s", hcd->bus_name); + + /* guard against multiple resumes (APM bug?) */ + atomic_inc (&hcd->resume_count); + if (atomic_read (&hcd->resume_count) != 1) { + err ("concurrent PCI resumes for %s", hcd->bus_name); + retval = 0; + goto done; + } + + retval = -EBUSY; + if (hcd->state != USB_STATE_SUSPENDED) { + dbg ("can't resume, not suspended!"); + goto done; + } + hcd->state = USB_STATE_RESUMING; + + pci_set_power_state (dev, 0); + pci_restore_state (dev, hcd->pci_state); + + retval = hcd->driver->resume (hcd); + if (!HCD_IS_RUNNING (hcd->state)) { + dbg ("resume %s failure, retval %d", hcd->bus_name, retval); + hc_died (hcd); +// FIXME: recover, reset etc. + } else { + // FIXME for all connected devices, root-to-leaf: + // driver->resume (); + // proposed "new 2.5 driver model" will automate that + } + +done: + atomic_dec (&hcd->resume_count); + return retval; +} +EXPORT_SYMBOL (usb_hcd_pci_resume); + +#endif /* CONFIG_PM */ + +#endif + +/*-------------------------------------------------------------------------*/ + +/* + * Generic HC operations. + */ + +/*-------------------------------------------------------------------------*/ + +/* called from khubd, or root hub init threads for hcd-private init */ +static int hcd_alloc_dev (struct usb_device *udev) +{ + struct hcd_dev *dev; + struct usb_hcd *hcd; + unsigned long flags; + + if (!udev || udev->hcpriv) + return -EINVAL; + if (!udev->bus || !udev->bus->hcpriv) + return -ENODEV; + hcd = udev->bus->hcpriv; + if (hcd->state == USB_STATE_QUIESCING) + return -ENOLINK; + + dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL); + if (dev == NULL) + return -ENOMEM; + memset (dev, 0, sizeof *dev); + + INIT_LIST_HEAD (&dev->dev_list); + INIT_LIST_HEAD (&dev->urb_list); + + spin_lock_irqsave (&hcd_data_lock, flags); + list_add (&dev->dev_list, &hcd->dev_list); + // refcount is implicit + udev->hcpriv = dev; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static void hc_died (struct usb_hcd *hcd) +{ + struct list_head *devlist, *urblist; + struct hcd_dev *dev; + struct urb *urb; + unsigned long flags; + + /* flag every pending urb as done */ + spin_lock_irqsave (&hcd_data_lock, flags); + list_for_each (devlist, &hcd->dev_list) { + dev = list_entry (devlist, struct hcd_dev, dev_list); + list_for_each (urblist, &dev->urb_list) { + urb = list_entry (urblist, struct urb, urb_list); + dbg ("shutdown %s urb %p pipe %x, current status %d", + hcd->bus_name, urb, urb->pipe, urb->status); + if (urb->status == -EINPROGRESS) + urb->status = -ESHUTDOWN; + } + } + urb = (struct urb *) hcd->rh_timer.data; + if (urb) + urb->status = -ESHUTDOWN; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + if (urb) + rh_status_dequeue (hcd, urb); + hcd->driver->stop (hcd); +} + +/*-------------------------------------------------------------------------*/ + +/* may be called in any context with a valid urb->dev usecount */ +/* caller surrenders "ownership" of urb (and chain at urb->next). */ + +static int hcd_submit_urb (struct urb *urb) +{ + int status; + struct usb_hcd *hcd; + struct hcd_dev *dev; + unsigned long flags; + int pipe; + int mem_flags; + + if (!urb || urb->hcpriv || !urb->complete) + return -EINVAL; + + urb->status = -EINPROGRESS; + urb->actual_length = 0; + INIT_LIST_HEAD (&urb->urb_list); + + if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0) + return -ENODEV; + hcd = urb->dev->bus->hcpriv; + dev = urb->dev->hcpriv; + if (!hcd || !dev) + return -ENODEV; + + /* can't submit new urbs when quiescing, halted, ... */ + if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state)) + return -ESHUTDOWN; + pipe = urb->pipe; + if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), + usb_pipeout (pipe))) + return -EPIPE; + + // FIXME paging/swapping requests over USB should not use GFP_KERNEL + // and might even need to use GFP_NOIO ... that flag actually needs + // to be passed from the higher level. + mem_flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL; + +#ifdef DEBUG + { + unsigned int orig_flags = urb->transfer_flags; + unsigned int allowed; + + /* enforce simple/standard policy */ + allowed = USB_ASYNC_UNLINK; // affects later unlinks + allowed |= USB_NO_FSBR; // only affects UHCI + switch (usb_pipetype (pipe)) { + case PIPE_CONTROL: + allowed |= USB_DISABLE_SPD; + break; + case PIPE_BULK: + allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK + | USB_ZERO_PACKET | URB_NO_INTERRUPT; + break; + case PIPE_INTERRUPT: + allowed |= USB_DISABLE_SPD; + break; + case PIPE_ISOCHRONOUS: + allowed |= USB_ISO_ASAP; + break; + } + urb->transfer_flags &= allowed; + + /* warn if submitter gave bogus flags */ + if (urb->transfer_flags != orig_flags) + warn ("BOGUS urb flags, %x --> %x", + orig_flags, urb->transfer_flags); + } +#endif + /* + * FIXME: alloc periodic bandwidth here, for interrupt and iso? + * Need to look at the ring submit mechanism for iso tds ... they + * aren't actually "periodic" in 2.4 kernels. + * + * FIXME: make urb timeouts be generic, keeping the HCD cores + * as simple as possible. + */ + + // NOTE: a generic device/urb monitoring hook would go here. + // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb) + // It would catch submission paths for all urbs. + + /* + * Atomically queue the urb, first to our records, then to the HCD. + * Access to urb->status is controlled by urb->lock ... changes on + * i/o completion (normal or fault) or unlinking. + */ + + // FIXME: verify that quiescing hc works right (RH cleans up) + + spin_lock_irqsave (&hcd_data_lock, flags); + if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) { + usb_inc_dev_use (urb->dev); + list_add (&urb->urb_list, &dev->urb_list); + status = 0; + } else { + INIT_LIST_HEAD (&urb->urb_list); + status = -ESHUTDOWN; + } + spin_unlock_irqrestore (&hcd_data_lock, flags); + + if (!status) { + if (urb->dev == hcd->bus->root_hub) + status = rh_urb_enqueue (hcd, urb); + else + status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); + } + if (status) { + if (urb->dev) { + urb->status = status; + usb_hcd_giveback_urb (hcd, urb); + } + } + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* called in any context */ +static int hcd_get_frame_number (struct usb_device *udev) +{ + struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; + return hcd->driver->get_frame_number (hcd); +} + +/*-------------------------------------------------------------------------*/ + +struct completion_splice { // modified urb context: + /* did we complete? */ + int done; + + /* original urb data */ + void (*complete)(struct urb *); + void *context; +}; + +static void unlink_complete (struct urb *urb) +{ + struct completion_splice *splice; + + splice = (struct completion_splice *) urb->context; + + /* issue original completion call */ + urb->complete = splice->complete; + urb->context = splice->context; + urb->complete (urb); + + splice->done = 1; +} + +/* + * called in any context; note ASYNC_UNLINK restrictions + * + * caller guarantees urb won't be recycled till both unlink() + * and the urb's completion function return + */ +static int hcd_unlink_urb (struct urb *urb) +{ + struct hcd_dev *dev; + struct usb_hcd *hcd = 0; + unsigned long flags; + struct completion_splice splice; + int retval; + + if (!urb) + return -EINVAL; + + // FIXME: add some explicit records to flag the + // state where the URB is "in periodic completion". + // Workaround is for driver to set the urb status + // to "-EINPROGRESS", so it can get through here + // and unlink from the completion handler. + + /* + * we contend for urb->status with the hcd core, + * which changes it while returning the urb. + */ + spin_lock_irqsave (&urb->lock, flags); + if (!urb->hcpriv + || urb->status != -EINPROGRESS + || urb->transfer_flags & USB_TIMEOUT_KILLED) { + retval = -EINVAL; + goto done; + } + + if (!urb->dev || !urb->dev->bus) { + retval = -ENODEV; + goto done; + } + dev = urb->dev->hcpriv; + hcd = urb->dev->bus->hcpriv; + if (!dev || !hcd) { + retval = -ENODEV; + goto done; + } + + /* maybe set up to block on completion notification */ + if ((urb->transfer_flags & USB_TIMEOUT_KILLED)) + urb->status = -ETIMEDOUT; + else if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) { + if (in_interrupt ()) { + dbg ("non-async unlink in_interrupt"); + retval = -EWOULDBLOCK; + goto done; + } + /* synchronous unlink: block till we see the completion */ + splice.done = 0; + splice.complete = urb->complete; + splice.context = urb->context; + urb->complete = unlink_complete; + urb->context = &splice; + urb->status = -ENOENT; + } else { + /* asynchronous unlink */ + urb->status = -ECONNRESET; + } + spin_unlock_irqrestore (&urb->lock, flags); + + if (urb == (struct urb *) hcd->rh_timer.data) { + rh_status_dequeue (hcd, urb); + retval = 0; + } else { + retval = hcd->driver->urb_dequeue (hcd, urb); +// FIXME: if retval and we tried to splice, whoa!! +if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval); + } + + /* block till giveback, if needed */ + if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED)) + && HCD_IS_RUNNING (hcd->state) + && !retval) { + while (!splice.done) { + set_current_state (TASK_UNINTERRUPTIBLE); + schedule_timeout ((2/*msec*/ * HZ) / 1000); + dbg ("%s: wait for giveback urb %p", + hcd->bus_name, urb); + } + } + goto bye; +done: + spin_unlock_irqrestore (&urb->lock, flags); +bye: + if (retval) + dbg ("%s: hcd_unlink_urb fail %d", + hcd ? hcd->bus_name : "(no bus?)", + retval); + return retval; +} + +/*-------------------------------------------------------------------------*/ + +/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup */ + +// FIXME: likely best to have explicit per-setting (config+alt) +// setup primitives in the usbcore-to-hcd driver API, so nothing +// is implicit. kernel 2.5 needs a bunch of config cleanup... + +static int hcd_free_dev (struct usb_device *udev) +{ + struct hcd_dev *dev; + struct usb_hcd *hcd; + unsigned long flags; + + if (!udev || !udev->hcpriv) + return -EINVAL; + + if (!udev->bus || !udev->bus->hcpriv) + return -ENODEV; + + // should udev->devnum == -1 ?? + + dev = udev->hcpriv; + hcd = udev->bus->hcpriv; + + /* device driver problem with refcounts? */ + if (!list_empty (&dev->urb_list)) { + dbg ("free busy dev, %s devnum %d (bug!)", + hcd->bus_name, udev->devnum); + return -EINVAL; + } + + hcd->driver->free_config (hcd, udev); + + spin_lock_irqsave (&hcd_data_lock, flags); + list_del (&dev->dev_list); + udev->hcpriv = NULL; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + kfree (dev); + return 0; +} + +static struct usb_operations hcd_operations = { + allocate: hcd_alloc_dev, + get_frame_number: hcd_get_frame_number, + submit_urb: hcd_submit_urb, + unlink_urb: hcd_unlink_urb, + deallocate: hcd_free_dev, +}; + +/*-------------------------------------------------------------------------*/ + +static void hcd_irq (int irq, void *__hcd, struct pt_regs * r) +{ + struct usb_hcd *hcd = __hcd; + int start = hcd->state; + + hcd->driver->irq (hcd); + if (hcd->state != start && hcd->state == USB_STATE_HALT) + hc_died (hcd); +} + +/*-------------------------------------------------------------------------*/ + +/** + * usb_hcd_giveback_urb - return URB from HCD to device driver + * @hcd: host controller returning the URB + * @urb: urb being returned to the USB device driver. + * + * This hands the URB from HCD to its USB device driver, using its + * completion function. The HCD has freed all per-urb resources + * (and is done using urb->hcpriv). It also released all HCD locks; + * the device driver won't cause deadlocks if it resubmits this URB, + * and won't confuse things by modifying and resubmitting this one. + * Bandwidth and other resources will be deallocated. + * + * HCDs must not use this for periodic URBs that are still scheduled + * and will be reissued. They should just call their completion handlers + * until the urb is returned to the device driver by unlinking. + * + * In common cases, urb->next will be submitted before the completion + * function gets called. That's not done if the URB includes error + * status (including unlinking). + */ +void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) +{ + unsigned long flags; + struct usb_device *dev; + + /* Release periodic transfer bandwidth */ + if (urb->bandwidth) { + switch (usb_pipetype (urb->pipe)) { + case PIPE_INTERRUPT: + usb_release_bandwidth (urb->dev, urb, 0); + break; + case PIPE_ISOCHRONOUS: + usb_release_bandwidth (urb->dev, urb, 1); + break; + } + } + + /* clear all state linking urb to this dev (and hcd) */ + + spin_lock_irqsave (&hcd_data_lock, flags); + list_del_init (&urb->urb_list); + dev = urb->dev; + urb->dev = NULL; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + // NOTE: a generic device/urb monitoring hook would go here. + // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev) + // It would catch exit/unlink paths for all urbs, but non-exit + // completions for periodic urbs need hooks inside the HCD. + // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev) + + if (urb->status) + dbg ("giveback urb %p status %d", urb, urb->status); + + /* if no error, make sure urb->next progresses */ + else if (urb->next) { + int status; + + status = usb_submit_urb (urb->next); + if (status) { + dbg ("urb %p chain fail, %d", urb->next, status); + urb->next->status = -ENOTCONN; + } + + /* HCDs never modify the urb->next chain, and only use it here, + * so that if urb->complete sees an URB there with -ENOTCONN, + * it knows the driver chained it but it couldn't be submitted. + */ + } + + /* pass ownership to the completion handler */ + usb_dec_dev_use (dev); + urb->complete (urb); +} +EXPORT_SYMBOL (usb_hcd_giveback_urb); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hcd.h linux-2.5/drivers/usb/hcd.h --- linux-2.5.1/drivers/usb/hcd.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/hcd.h Mon Jan 14 14:39:55 2002 @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2001 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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. + */ + + +/*-------------------------------------------------------------------------*/ + +/* + * USB Host Controller Driver (usb_hcd) framework + * + * Since "struct usb_bus" is so thin, you can't share much code in it. + * This framework is a layer over that, and should be more sharable. + */ + +/*-------------------------------------------------------------------------*/ + +struct usb_hcd { /* usb_bus.hcpriv points to this */ + + /* + * housekeeping + */ + struct usb_bus *bus; /* hcd is-a bus */ + struct list_head hcd_list; + + const char *bus_name; + + const char *description; /* "ehci-hcd" etc */ + + struct timer_list rh_timer; /* drives root hub */ + struct list_head dev_list; /* devices on this bus */ + + /* + * hardware info/state + */ + struct hc_driver *driver; /* hw-specific hooks */ + int irq; /* irq allocated */ + void *regs; /* device memory/io */ + +#ifdef CONFIG_PCI + /* a few non-PCI controllers exist, mostly for OHCI */ + struct pci_dev *pdev; /* pci is typical */ + int region; /* pci region for regs */ + u32 pci_state [16]; /* for PM state save */ + atomic_t resume_count; /* multiple resumes issue */ +#endif + + int state; +# define __ACTIVE 0x01 +# define __SLEEPY 0x02 +# define __SUSPEND 0x04 +# define __TRANSIENT 0x80 + +# define USB_STATE_HALT 0 +# define USB_STATE_RUNNING (__ACTIVE) +# define USB_STATE_READY (__ACTIVE|__SLEEPY) +# define USB_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE) +# define USB_STATE_RESUMING (__SUSPEND|__TRANSIENT) +# define USB_STATE_SUSPENDED (__SUSPEND) + +#define HCD_IS_RUNNING(state) ((state) & __ACTIVE) +#define HCD_IS_SUSPENDED(state) ((state) & __SUSPEND) + + /* more shared queuing code would be good; it should support + * smarter scheduling, handle transaction translators, etc; + * input size of periodic table to an interrupt scheduler. + * (ohci 32, uhci 1024, ehci 256/512/1024). + */ +}; + +struct hcd_dev { /* usb_device.hcpriv points to this */ + struct list_head dev_list; /* on this hcd */ + struct list_head urb_list; /* pending on this dev */ + + /* per-configuration HC/HCD state, such as QH or ED */ + void *ep[32]; +}; + +// urb.hcpriv is really hardware-specific + +struct hcd_timeout { /* timeouts we allocate */ + struct list_head timeout_list; + struct timer_list timer; +}; + +/*-------------------------------------------------------------------------*/ + +/* each driver provides one of these, and hardware init support */ + +struct hc_driver { + const char *description; /* "ehci-hcd" etc */ + + /* irq handler */ + void (*irq) (struct usb_hcd *hcd); + + int flags; +#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ +#define HCD_USB11 0x0010 /* USB 1.1 */ +#define HCD_USB2 0x0020 /* USB 2.0 */ + + /* called to init HCD and root hub */ + int (*start) (struct usb_hcd *hcd); + + /* called after all devices were suspended */ + int (*suspend) (struct usb_hcd *hcd, u32 state); + + /* called before any devices get resumed */ + int (*resume) (struct usb_hcd *hcd); + + /* cleanly make HCD stop writing memory and doing I/O */ + void (*stop) (struct usb_hcd *hcd); + + /* return current frame number */ + int (*get_frame_number) (struct usb_hcd *hcd); + +// FIXME: rework generic-to-specific HCD linkage (specific contains generic) + + /* memory lifecycle */ + struct usb_hcd *(*hcd_alloc) (void); + void (*hcd_free) (struct usb_hcd *hcd); + + /* manage i/o requests, device state */ + int (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb, + int mem_flags); + int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); + + // frees configuration resources -- allocated as needed during + // urb_enqueue, and not freed by urb_dequeue + void (*free_config) (struct usb_hcd *hcd, + struct usb_device *dev); + + /* root hub support */ + int (*hub_status_data) (struct usb_hcd *hcd, char *buf); + int (*hub_control) (struct usb_hcd *hcd, + u16 typeReq, u16 wValue, u16 wIndex, + char *buf, u16 wLength); +}; + +extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); + +#ifdef CONFIG_PCI + +extern int usb_hcd_pci_probe (struct pci_dev *dev, + const struct pci_device_id *id); +extern void usb_hcd_pci_remove (struct pci_dev *dev); + +#ifdef CONFIG_PM +// FIXME: see Documentation/power/pci.txt (2.4.6 and later?) +// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state); +extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state); +extern int usb_hcd_pci_resume (struct pci_dev *dev); +// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg); +#endif /* CONFIG_PM */ + +#endif /* CONFIG_PCI */ + +/*-------------------------------------------------------------------------*/ + +/* + * HCD Root Hub support + */ + +#include "hub.h" + +/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */ +#define DeviceRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) +#define DeviceOutRequest \ + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) + +#define InterfaceRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) + +#define EndpointRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) +#define EndpointOutRequest \ + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) + +/* table 9.6 standard features */ +#define DEVICE_REMOTE_WAKEUP 1 +#define ENDPOINT_HALT 0 + +/* class requests from the USB 2.0 hub spec, table 11-15 */ +/* GetBusState and SetHubDescriptor are optional, omitted */ +#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) +#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) +#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) +#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) +#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) +#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) +#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) + + +/*-------------------------------------------------------------------------*/ + +/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */ +// bleech -- resurfaced in 2.4.11 or 2.4.12 +#define bitmap DeviceRemovable + + +/*-------------------------------------------------------------------------*/ + +/* random stuff */ + +#define RUN_CONTEXT (in_irq () ? "in_irq" \ + : (in_interrupt () ? "in_interrupt" : "can sleep")) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hid-core.c linux-2.5/drivers/usb/hid-core.c --- linux-2.5.1/drivers/usb/hid-core.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/hid-core.c Tue Jan 8 00:44:24 2002 @@ -987,7 +987,7 @@ static int hid_submit_out(struct hid_device *hid) { - hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length); + hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.wLength); hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); hid->urbout.dev = hid->dev; @@ -1017,8 +1017,8 @@ { hid_output_report(report, hid->out[hid->outhead].buffer); - hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | report->id); - hid->out[hid->outhead].dr.length = cpu_to_le16((report->size + 7) >> 3); + hid->out[hid->outhead].dr.wValue = cpu_to_le16(0x200 | report->id); + hid->out[hid->outhead].dr.wLength = cpu_to_le16((report->size + 7) >> 3); hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1); @@ -1179,9 +1179,9 @@ hid->ifnum = interface->bInterfaceNumber; 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 = HID_REQ_SET_REPORT; - hid->out[n].dr.index = cpu_to_le16(hid->ifnum); + hid->out[n].dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; + hid->out[n].dr.bRequest = HID_REQ_SET_REPORT; + hid->out[n].dr.wIndex = cpu_to_le16(hid->ifnum); } hid->name[0] = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hid.h linux-2.5/drivers/usb/hid.h --- linux-2.5.1/drivers/usb/hid.h Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/hid.h Tue Jan 8 00:44:24 2002 @@ -367,7 +367,7 @@ #define HID_CONTROL_FIFO_SIZE 8 struct hid_control_fifo { - devrequest dr; + struct usb_ctrlrequest dr; char buffer[HID_BUFFER_SIZE]; }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hiddev.c linux-2.5/drivers/usb/hiddev.c --- linux-2.5.1/drivers/usb/hiddev.c Fri Nov 30 16:26:04 2001 +++ linux-2.5/drivers/usb/hiddev.c Thu Jan 3 22:57:36 2002 @@ -218,7 +218,7 @@ static int hiddev_open(struct inode * inode, struct file * file) { struct hiddev_list *list; - int i = MINOR(inode->i_rdev) - HIDDEV_MINOR_BASE; + int i = minor(inode->i_rdev) - HIDDEV_MINOR_BASE; if (i >= HIDDEV_MINORS || !hiddev_table[i]) return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hpusbscsi.c linux-2.5/drivers/usb/hpusbscsi.c --- linux-2.5.1/drivers/usb/hpusbscsi.c Tue Oct 9 22:15:02 2001 +++ linux-2.5/drivers/usb/hpusbscsi.c Mon Dec 31 01:39:36 2001 @@ -117,7 +117,7 @@ (struct hpusbscsi *) new->ctempl.proc_dir = new; new->ctempl.module = THIS_MODULE; - if (scsi_register_module (MODULE_SCSI_HA, &(new->ctempl))) + if (scsi_register_host(&new->ctempl)) goto err_out; /* adding to list for module unload */ @@ -185,7 +185,7 @@ tmp = tmp->next; o = (struct hpusbscsi *)old; usb_unlink_urb(&o->controlurb); - scsi_unregister_module(MODULE_SCSI_HA,&o->ctempl); + scsi_unregister_host(&o->ctempl); kfree(old); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hub.c linux-2.5/drivers/usb/hub.c --- linux-2.5.1/drivers/usb/hub.c Mon Nov 12 17:34:16 2001 +++ linux-2.5/drivers/usb/hub.c Tue Jan 1 23:42:42 2002 @@ -35,7 +35,7 @@ static DECLARE_MUTEX(usb_address0_sem); static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ -static LIST_HEAD(hub_list); /* List containing all of the hubs (for cleanup) */ +static LIST_HEAD(hub_list); /* List of all hubs (for cleanup) */ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static int khubd_pid = 0; /* PID of khubd */ @@ -110,22 +110,30 @@ data, sizeof(struct usb_hub_status), HZ); } +/* completion function, fires on port status changes and various faults */ static void hub_irq(struct urb *urb) { struct usb_hub *hub = (struct usb_hub *)urb->context; unsigned long flags; - /* Cause a hub reset after 10 consecutive errors */ - if (urb->status) { - if (urb->status == -ENOENT) - return; - - dbg("nonzero status in irq %d", urb->status); + switch (urb->status) { + case -ENOENT: /* synchronous unlink */ + case -ECONNRESET: /* async unlink */ + case -ESHUTDOWN: /* hardware going away */ + return; + default: /* presumably an error */ + /* Cause a hub reset after 10 consecutive errors */ + dbg("hub '%s' status %d for interrupt transfer", + urb->dev->devpath, urb->status); if ((++hub->nerrors < 10) || hub->error) return; - hub->error = urb->status; + /* FALL THROUGH */ + + /* let khubd handle things */ + case 0: /* we got data: port status changed */ + break; } hub->nerrors = 0; @@ -152,7 +160,8 @@ wait_ms(hub->descriptor->bPwrOn2PwrGood * 2); } -static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint) +static int usb_hub_configure(struct usb_hub *hub, + struct usb_endpoint_descriptor *endpoint) { struct usb_device *dev = hub->dev; struct usb_hub_status hubstatus; @@ -162,22 +171,30 @@ hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); if (!hub->descriptor) { - err("Unable to kmalloc %Zd bytes for hub descriptor", sizeof(*hub->descriptor)); + err("Unable to kmalloc %Zd bytes for hub descriptor", + sizeof(*hub->descriptor)); return -1; } - /* Request the entire hub descriptor. */ - 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. */ + /* Request the entire hub descriptor. + * hub->descriptor can handle USB_MAXCHILDREN ports, + * but the hub can/will return fewer bytes here. + */ + ret = usb_get_hub_descriptor(dev, hub->descriptor, + sizeof(*hub->descriptor)); if (ret < 0) { err("Unable to get hub descriptor (err = %d)", ret); kfree(hub->descriptor); return -1; + } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) { + err("Hub is too big! %d children", hub->descriptor->bNbrPorts); + kfree(hub->descriptor); + return -1; } dev->maxchild = hub->descriptor->bNbrPorts; - info("%d port%s detected", hub->descriptor->bNbrPorts, (hub->descriptor->bNbrPorts == 1) ? "" : "s"); + info("%d port%s detected", dev->maxchild, + (dev->maxchild == 1) ? "" : "s"); le16_to_cpus(&hub->descriptor->wHubCharacteristics); @@ -217,9 +234,12 @@ break; case 1: dbg("Single TT"); + hub->tt.hub = dev; break; case 2: - dbg("Multiple TT"); + dbg("TT per port"); + hub->tt.hub = dev; + hub->tt.multi = 1; break; default: dbg("Unrecognized hub protocol %d", @@ -244,13 +264,18 @@ } dbg("Port indicators are %s supported", - (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) ? "" : "not"); + (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); + 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->DeviceRemovable[((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); @@ -265,7 +290,8 @@ le16_to_cpus(&hubstatus.wHubStatus); dbg("local power source is %s", - (hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); + (hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) + ? "lost (inactive)" : "good"); dbg("%sover-current condition exists", (hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); @@ -337,14 +363,15 @@ } /* If it's not an interrupt endpoint, we'd better punt! */ - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) { - err("Device #%d is hub class, but has endpoint other than interrupt?", + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + != USB_ENDPOINT_XFER_INT) { + err("Device #%d is hub class, but endpoint is not interrupt?", dev->devnum); return NULL; } /* We found a hub */ - info("USB hub found"); + info("USB hub found at %s", dev->devpath); hub = kmalloc(sizeof(*hub), GFP_KERNEL); if (!hub) { @@ -367,7 +394,7 @@ if (usb_hub_configure(hub, endpoint) >= 0) return hub; - err("hub configuration failed for device #%d", dev->devnum); + err("hub configuration failed for device at %s", dev->devpath); /* free hub, but first clean up its list. */ spin_lock_irqsave(&hub_event_lock, flags); @@ -436,7 +463,8 @@ if (hub->children[i] == NULL) info->port[i] = 0; else - info->port[i] = hub->children[i]->devnum; + info->port[i] = + hub->children[i]->devnum; } } spin_unlock_irqrestore(&hub_event_lock, flags); @@ -493,7 +521,7 @@ } } - err("cannot disconnect hub %d", dev->devnum); + err("cannot disconnect hub %s", dev->devpath); } #define HUB_RESET_TRIES 5 @@ -510,14 +538,17 @@ struct usb_port_status portsts; unsigned short portchange, portstatus; - for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) { + for (delay_time = 0; + delay_time < HUB_RESET_TIMEOUT; + delay_time += delay) { /* wait to give the device a chance to reset */ wait_ms(delay); /* read and decode port status */ ret = usb_get_port_status(hub, port + 1, &portsts); if (ret < 0) { - err("get_port_status(%d) failed (err = %d)", port + 1, ret); + err("get_port_status(%d) failed (err = %d)", + port + 1, ret); return -1; } @@ -546,8 +577,8 @@ if (delay_time >= 2 * HUB_SHORT_RESET_TIME) delay = HUB_LONG_RESET_TIME; - dbg("port %d of hub %d not reset yet, waiting %dms", port + 1, - hub->devnum, delay); + dbg("port %d of hub %s not reset yet, waiting %dms", port + 1, + hub->devpath, delay); } return -1; @@ -566,17 +597,18 @@ /* return on disconnect or reset */ status = usb_hub_port_wait_reset(hub, port, dev, delay); if (status != -1) { - usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET); + usb_clear_port_feature(hub, + port + 1, USB_PORT_FEAT_C_RESET); return status; } - dbg("port %d of hub %d not enabled, trying reset again...", - port + 1, hub->devnum); + dbg("port %d of hub %s not enabled, trying reset again...", + port + 1, hub->devpath); delay = HUB_LONG_RESET_TIME; } - err("Cannot enable port %i of hub %d, disabling port.", - port + 1, hub->devnum); + err("Cannot enable port %i of hub %s, disabling port.", + port + 1, hub->devpath); err("Maybe the USB cable is bad?"); return -1; @@ -588,23 +620,24 @@ ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); if (ret) - err("cannot disable port %d of hub %d (err = %d)", - port + 1, hub->devnum, ret); + err("cannot disable port %d of hub %s (err = %d)", + port + 1, hub->devpath, ret); } -static void usb_hub_port_connect_change(struct usb_device *hub, int port, +static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, struct usb_port_status *portsts) { + struct usb_device *hub = hubstate->dev; struct usb_device *dev; unsigned short portstatus, portchange; unsigned int delay = HUB_SHORT_RESET_TIME; int i; - char *portstr, *tempstr; portstatus = le16_to_cpu(portsts->wPortStatus); portchange = le16_to_cpu(portsts->wPortChange); - dbg("port %d, portstatus %x, change %x, %s", - port + 1, portstatus, portchange, portspeed (portstatus)); + dbg("hub %s port %d, portstatus %x, change %x, %s", + hub->devpath, port + 1, + portstatus, portchange, portspeed (portstatus)); /* Clear the connection change status */ usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); @@ -630,11 +663,9 @@ down(&usb_address0_sem); - tempstr = kmalloc(1024, GFP_KERNEL); - portstr = kmalloc(1024, GFP_KERNEL); - for (i = 0; i < HUB_PROBE_TRIES; i++) { - struct usb_device *pdev, *cdev; + struct usb_device *pdev; + int len; /* Allocate a new device struct */ dev = usb_alloc_dev(hub, hub->bus); @@ -645,41 +676,46 @@ hub->children[port] = dev; - /* Reset the device */ + /* Reset the device, and detect its speed */ if (usb_hub_port_reset(hub, port, dev, delay)) { usb_free_dev(dev); break; } - /* Find a new device ID for it */ + /* Find a new address for it */ usb_connect(dev); - /* Create a readable topology string */ - cdev = dev; - pdev = dev->parent; - if (portstr && tempstr) { - portstr[0] = 0; - while (pdev) { - int port; - - for (port = 0; port < pdev->maxchild; port++) - if (pdev->children[port] == cdev) - break; - - strcpy(tempstr, portstr); - if (!strlen(tempstr)) - sprintf(portstr, "%d", port + 1); - else - sprintf(portstr, "%d/%s", port + 1, tempstr); + /* Set up TT records, if needed */ + if (hub->tt) { + dev->tt = hub->tt; + dev->ttport = hub->ttport; + } else if (dev->speed != USB_SPEED_HIGH + && hub->speed == USB_SPEED_HIGH) { + dev->tt = &hubstate->tt; + dev->ttport = port + 1; + } - cdev = pdev; - pdev = pdev->parent; - } - info("USB new device connect on bus%d/%s, assigned device number %d", - dev->bus->busnum, portstr, dev->devnum); - } else - info("USB new device connect on bus%d, assigned device number %d", - dev->bus->busnum, dev->devnum); + /* Save readable and stable topology id, distinguishing + * devices by location for diagnostics, tools, etc. The + * string is a path along hub ports, from the root. Each + * device's id will be stable until USB is re-cabled, and + * hubs are often labled with these port numbers. + * + * Initial size: "/NN" times five hubs + NUL = 16 bytes max + * (quite rare, since most hubs have 4-6 ports). + */ + pdev = dev->parent; + if (pdev->devpath [1] != '\0') /* parent not root */ + len = snprintf (dev->devpath, sizeof dev->devpath, + "%s/%d", pdev->devpath, port + 1); + else /* root == "/", root port 2 == "/2" */ + len = snprintf (dev->devpath, sizeof dev->devpath, + "/%d", port + 1); + if (len == sizeof dev->devpath) + warn ("devpath size! usb/%03d/%03d path %s", + dev->bus->busnum, dev->devnum, dev->devpath); + info("new USB device on bus %d path %s, assigned address %d", + dev->bus->busnum, dev->devpath, dev->devnum); /* Run it through the hoops (find a driver, etc) */ if (!usb_new_device(dev)) @@ -696,10 +732,6 @@ usb_hub_port_disable(hub, port); done: up(&usb_address0_sem); - if (portstr) - kfree(portstr); - if (tempstr) - kfree(tempstr); } static void usb_hub_events(void) @@ -737,10 +769,12 @@ spin_unlock_irqrestore(&hub_event_lock, flags); if (hub->error) { - dbg("resetting hub %d for error %d", dev->devnum, hub->error); + dbg("resetting hub %s for error %d", + dev->devpath, hub->error); if (usb_hub_reset(hub)) { - err("error resetting hub %d - disconnecting", dev->devnum); + err("error resetting hub %s - disconnecting", + dev->devpath); up(&hub->khubd_sem); usb_hub_disconnect(dev); continue; @@ -756,7 +790,8 @@ ret = usb_get_port_status(dev, i + 1, &portsts); if (ret < 0) { - err("get_port_status failed (err = %d)", ret); + err("hub %s get_port_status failed (err = %d)", + dev->devpath, ret); continue; } @@ -764,55 +799,68 @@ portchange = le16_to_cpu(portsts.wPortChange); if (portchange & USB_PORT_STAT_C_CONNECTION) { - dbg("port %d connection change", i + 1); - - usb_hub_port_connect_change(dev, i, &portsts); + dbg("hub %s port %d connection change", + dev->devpath, i + 1); + usb_hub_port_connect_change(hub, i, &portsts); } else if (portchange & USB_PORT_STAT_C_ENABLE) { - dbg("port %d enable change, status %x", i + 1, portstatus); - usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); + dbg("hub %s port %d enable change, status %x", + dev->devpath, i + 1, portstatus); + usb_clear_port_feature(dev, + i + 1, USB_PORT_FEAT_C_ENABLE); /* - * EM interference sometimes causes bad shielded USB devices to - * be shutdown by the hub, this hack enables them again. + * EM interference sometimes causes badly + * shielded USB devices to be shutdown by + * the hub, this hack enables them again. * Works at least with mouse driver. */ - if (!(portstatus & USB_PORT_STAT_ENABLE) && - (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) { - err("already running port %i disabled by hub (EMI?), re-enabling...", - i + 1); - usb_hub_port_connect_change(dev, i, &portsts); + if (!(portstatus & USB_PORT_STAT_ENABLE) + && (portstatus & USB_PORT_STAT_CONNECTION) + && (dev->children[i])) { + err("already running hub %s port %i " + "disabled by hub (EMI?), " + "re-enabling...", + dev->devpath, i + 1); + usb_hub_port_connect_change(hub, + i, &portsts); } } if (portchange & USB_PORT_STAT_C_SUSPEND) { - dbg("port %d suspend change", i + 1); - usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_SUSPEND); + dbg("hub %s port %d suspend change", + dev->devpath, i + 1); + usb_clear_port_feature(dev, + i + 1, USB_PORT_FEAT_C_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { - err("port %d over-current change", i + 1); - usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT); + err("hub %s port %d over-current change", + dev->devpath, i + 1); + usb_clear_port_feature(dev, + i + 1, USB_PORT_FEAT_C_OVER_CURRENT); usb_hub_power_on(hub); } if (portchange & USB_PORT_STAT_C_RESET) { - dbg("port %d reset change", i + 1); - usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); + dbg("hub %s port %d reset change", + dev->devpath, i + 1); + usb_clear_port_feature(dev, + i + 1, USB_PORT_FEAT_C_RESET); } } /* end for i */ /* deal with hub status changes */ if (usb_get_hub_status(dev, &hubsts) < 0) - err("get_hub_status failed"); + err("get_hub_status %s failed", dev->devpath); else { hubstatus = le16_to_cpup(&hubsts.wHubStatus); hubchange = le16_to_cpup(&hubsts.wHubChange); if (hubchange & HUB_CHANGE_LOCAL_POWER) { - dbg("hub power change"); + dbg("hub %s power change", dev->devpath); usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER); } if (hubchange & HUB_CHANGE_OVERCURRENT) { - dbg("hub overcurrent change"); + dbg("hub %s overcurrent change", dev->devpath); wait_ms(500); /* Cool down */ usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT); usb_hub_power_on(hub); @@ -851,6 +899,8 @@ } static struct usb_device_id hub_id_table [] = { + { match_flags: USB_DEVICE_ID_MATCH_DEV_CLASS, + bDeviceClass: USB_CLASS_HUB}, { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, bInterfaceClass: USB_CLASS_HUB}, { } /* Terminating entry */ @@ -989,9 +1039,13 @@ ret = usb_get_device_descriptor(dev); if (ret < sizeof(dev->descriptor)) { if (ret < 0) - err("unable to get device descriptor (error=%d)", ret); + err("unable to get device %s descriptor " + "(error=%d)", dev->devpath, ret); else - err("USB device descriptor short read (expected %Zi, got %i)", sizeof(dev->descriptor), ret); + err("USB device %s descriptor short read " + "(expected %Zi, got %i)", + dev->devpath, + sizeof(dev->descriptor), ret); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; @@ -1015,17 +1069,22 @@ ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue); if (ret < 0) { - err("failed to set active configuration (error=%d)", ret); + err("failed to set dev %s active configuration (error=%d)", + dev->devpath, ret); return ret; } for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { struct usb_interface *intf = &dev->actconfig->interface[i]; - struct usb_interface_descriptor *as = &intf->altsetting[intf->act_altsetting]; + struct usb_interface_descriptor *as; - ret = usb_set_interface(dev, as->bInterfaceNumber, as->bAlternateSetting); + as = &intf->altsetting[intf->act_altsetting]; + ret = usb_set_interface(dev, as->bInterfaceNumber, + as->bAlternateSetting); if (ret < 0) { - err("failed to set active alternate setting for interface %d (error=%d)", i, ret); + err("failed to set active alternate setting " + "for dev %s interface %d (error=%d)", + dev->devpath, i, ret); return ret; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/hub.h linux-2.5/drivers/usb/hub.h --- linux-2.5.1/drivers/usb/hub.h Sun Dec 16 23:47:13 2001 +++ linux-2.5/drivers/usb/hub.h Mon Jan 14 14:39:23 2002 @@ -1,6 +1,13 @@ #ifndef __LINUX_HUB_H #define __LINUX_HUB_H +/* + * Hub protocol and driver data structures. + * + * Some of these are known to the "virtual root hub" code + * in host controller drivers. + */ + #include <linux/list.h> /* @@ -11,6 +18,15 @@ #define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) /* + * Hub class requests + * See USB 2.0 spec Table 11-16 + */ +#define HUB_CLEAR_TT_BUFFER 8 +#define HUB_RESET_TT 9 +#define HUB_GET_TT_STATE 10 +#define HUB_STOP_TT 11 + +/* * Hub Class feature numbers * See USB 2.0 spec Table 11-17 */ @@ -55,7 +71,7 @@ #define USB_PORT_STAT_SUSPEND 0x0004 #define USB_PORT_STAT_OVERCURRENT 0x0008 #define USB_PORT_STAT_RESET 0x0010 -/* bits 5 for 7 are reserved */ +/* bits 5 to 7 are reserved */ #define USB_PORT_STAT_POWER 0x0100 #define USB_PORT_STAT_LOW_SPEED 0x0200 #define USB_PORT_STAT_HIGH_SPEED 0x0400 @@ -120,22 +136,21 @@ struct usb_device; struct usb_hub { - struct usb_device *dev; - - struct urb *urb; /* Interrupt polling pipe */ - - char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 bit for hub status change */ - /* and add 7 bits to round up to byte boundary */ - int error; - int nerrors; + struct usb_device *dev; /* the "real" device */ + struct urb *urb; /* for interrupt polling pipe */ - struct list_head hub_list; + /* buffer for urb ... 1 bit each for hub and children, rounded up */ + char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; - struct list_head event_list; + int error; /* last reported error */ + int nerrors; /* track consecutive errors */ - struct usb_hub_descriptor *descriptor; + struct list_head hub_list; /* all hubs */ + struct list_head event_list; /* hubs w/data or errs ready */ - struct semaphore khubd_sem; + struct usb_hub_descriptor *descriptor; /* class descriptor */ + struct semaphore khubd_sem; + struct usb_tt tt; /* Transaction Translator */ }; #endif /* __LINUX_HUB_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/inode.c linux-2.5/drivers/usb/inode.c --- linux-2.5.1/drivers/usb/inode.c Sun Dec 9 04:28:44 2001 +++ linux-2.5/drivers/usb/inode.c Tue Jan 1 23:42:42 2002 @@ -3,8 +3,8 @@ /* * inode.c -- Inode/Dentry functions for the USB device file system. * - * Copyright (C) 2000 - * Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.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 @@ -20,10 +20,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: inode.c,v 1.3 2000/01/11 13:58:25 tom Exp $ - * * History: * 0.1 04.01.2000 Created + * 0.2 10.12.2001 converted to use the vfs layer better */ /*****************************************************************************/ @@ -32,146 +31,40 @@ #include <linux/config.h> #include <linux/module.h> #include <linux/fs.h> -#include <linux/sched.h> -#include <linux/smp_lock.h> -#include <linux/locks.h> +#include <linux/pagemap.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/usb.h> #include <linux/usbdevice_fs.h> -#include <asm/uaccess.h> - -/* --------------------------------------------------------------------- */ - -/* - * This list of superblocks is still used, - * but since usbdevfs became FS_SINGLE - * there is only one super_block. - */ -static LIST_HEAD(superlist); - -struct special { - const char *name; - struct file_operations *fops; - struct inode *inode; - struct list_head inodes; -}; - -static struct special special[] = { - { "devices", &usbdevfs_devices_fops, }, - { "drivers", &usbdevfs_drivers_fops, } -}; - -#define NRSPECIAL (sizeof(special)/sizeof(special[0])) - -/* --------------------------------------------------------------------- */ - -static int dnumber(struct dentry *dentry) -{ - const char *name; - unsigned int s; - - if (dentry->d_name.len != 3) - return -1; - name = dentry->d_name.name; - if (name[0] < '0' || name[0] > '9' || - name[1] < '0' || name[1] > '9' || - name[2] < '0' || name[2] > '9') - return -1; - s = name[0] - '0'; - s = s * 10 + name[1] - '0'; - s = s * 10 + name[2] - '0'; - return s; -} - -/* - * utility functions; should be called with the kernel lock held - * to protect against busses/devices appearing/disappearing - */ - -static void new_dev_inode(struct usb_device *dev, struct super_block *sb) -{ - struct inode *inode; - unsigned int devnum = dev->devnum; - unsigned int busnum = dev->bus->busnum; - - if (devnum < 1 || devnum > 127 || busnum > 255) - return; - inode = iget(sb, IDEVICE | (busnum << 8) | devnum); - if (!inode) { - printk(KERN_ERR "usbdevfs: cannot create inode for bus %u device %u\n", busnum, devnum); - return; - } - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_uid = sb->u.usbdevfs_sb.devuid; - inode->i_gid = sb->u.usbdevfs_sb.devgid; - inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG; - inode->i_fop = &usbdevfs_device_file_operations; - inode->i_size = sizeof(struct usb_device_descriptor); - inode->u.usbdev_i.p.dev = dev; - list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist); - list_add_tail(&inode->u.usbdev_i.dlist, &dev->inodes); -} -static void recurse_new_dev_inode(struct usb_device *dev, struct super_block *sb) -{ - unsigned int i; - if (!dev) - return; - new_dev_inode(dev, sb); - for (i = 0; i < dev->maxchild; i++) { - if (!dev->children[i]) - continue; - recurse_new_dev_inode(dev->children[i], sb); - } -} - -static void new_bus_inode(struct usb_bus *bus, struct super_block *sb) -{ - struct inode *inode; - unsigned int busnum = bus->busnum; - - if (busnum > 255) - return; - inode = iget(sb, IBUS | (busnum << 8)); - if (!inode) { - printk(KERN_ERR "usbdevfs: cannot create inode for bus %u\n", busnum); - return; - } - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_uid = sb->u.usbdevfs_sb.busuid; - inode->i_gid = sb->u.usbdevfs_sb.busgid; - inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR; - inode->i_op = &usbdevfs_bus_inode_operations; - inode->i_fop = &usbdevfs_bus_file_operations; - inode->u.usbdev_i.p.bus = bus; - list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist); - list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes); -} - -static void free_inode(struct inode *inode) -{ - inode->u.usbdev_i.p.bus = NULL; - inode->u.usbdev_i.p.dev = NULL; - inode->i_mode &= ~S_IRWXUGO; - inode->i_uid = inode->i_gid = 0; - inode->i_size = 0; - list_del(&inode->u.usbdev_i.slist); - INIT_LIST_HEAD(&inode->u.usbdev_i.slist); - list_del(&inode->u.usbdev_i.dlist); - INIT_LIST_HEAD(&inode->u.usbdev_i.dlist); - iput(inode); -} +static struct super_operations usbfs_ops; +static struct address_space_operations usbfs_aops; +static struct file_operations usbfs_dir_operations; +static struct file_operations default_file_operations; +static struct inode_operations usbfs_dir_inode_operations; +static struct vfsmount *usbfs_mount; +static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED; +static int mount_count; /* = 0 */ + +static struct dentry *devices_dentry; +static struct dentry *drivers_dentry; +static int num_buses; /* = 0 */ + +static uid_t devuid; /* = 0 */ +static uid_t busuid; /* = 0 */ +static uid_t listuid; /* = 0 */ +static gid_t devgid; /* = 0 */ +static gid_t busgid; /* = 0 */ +static gid_t listgid; /* = 0 */ +static umode_t devmode = S_IWUSR | S_IRUGO; +static umode_t busmode = S_IXUGO | S_IRUGO; +static umode_t listmode = S_IRUGO; static int parse_options(struct super_block *s, char *data) { - uid_t devuid = 0, busuid = 0, listuid = 0; - gid_t devgid = 0, busgid = 0, listgid = 0; - umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO; char *curopt = NULL, *value; - /* parse options */ if (data) curopt = strtok(data, ","); for (; curopt; curopt = strtok(NULL, ",")) { @@ -242,481 +135,572 @@ } } - s->u.usbdevfs_sb.devuid = devuid; - s->u.usbdevfs_sb.devgid = devgid; - s->u.usbdevfs_sb.devmode = devmode; - s->u.usbdevfs_sb.busuid = busuid; - s->u.usbdevfs_sb.busgid = busgid; - s->u.usbdevfs_sb.busmode = busmode; - s->u.usbdevfs_sb.listuid = listuid; - s->u.usbdevfs_sb.listgid = listgid; - s->u.usbdevfs_sb.listmode = listmode; + return 0; +} + + +/* --------------------------------------------------------------------- */ +static struct dentry *usbfs_lookup (struct inode *dir, struct dentry *dentry) +{ + d_add(dentry, NULL); + return NULL; +} + +static int usbfs_statfs(struct super_block *sb, struct statfs *buf) +{ + buf->f_type = USBDEVICE_SUPER_MAGIC; + buf->f_bsize = PAGE_CACHE_SIZE; + buf->f_namelen = NAME_MAX; return 0; } -static struct usb_bus *usbdevfs_findbus(int busnr) +static struct inode *usbfs_get_inode (struct super_block *sb, int mode, int dev) { - struct list_head *list; - struct usb_bus *bus; + struct inode *inode = new_inode(sb); - down (&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) { - up (&usb_bus_list_lock); - return bus; + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = NODEV; + inode->i_mapping->a_ops = &usbfs_aops; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_fop = &default_file_operations; + break; + case S_IFDIR: + inode->i_op = &usbfs_dir_inode_operations; + inode->i_fop = &usbfs_dir_operations; + break; } - } - up (&usb_bus_list_lock); - return NULL; + } + return inode; } -#if 0 -static struct usb_device *finddev(struct usb_device *dev, int devnr) +static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode, + int dev) { - unsigned int i; - struct usb_device *d2; + struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev); + int error = -ENOSPC; - if (!dev) - return NULL; - if (dev->devnum == devnr) - return dev; - for (i = 0; i < dev->maxchild; i++) { - if (!dev->children[i]) - continue; - if ((d2 = finddev(dev->children[i], devnr))) - return d2; - } - return NULL; + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); + error = 0; + } + return error; } -static struct usb_device *usbdevfs_finddevice(struct usb_bus *bus, int devnr) +static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) { - return finddev(bus->root_hub, devnr); + return usbfs_mknod (dir, dentry, mode | S_IFDIR, 0); } -#endif -/* --------------------------------------------------------------------- */ +static int usbfs_create (struct inode *dir, struct dentry *dentry, int mode) +{ + return usbfs_mknod (dir, dentry, mode | S_IFREG, 0); +} -static int usbdevfs_revalidate(struct dentry *dentry, int flags) +static int usbfs_link (struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = old_dentry->d_inode; - if (!inode) - return 0; - if (ITYPE(inode->i_ino) == IBUS && !inode->u.usbdev_i.p.bus) - return 0; - if (ITYPE(inode->i_ino) == IDEVICE && !inode->u.usbdev_i.p.dev) - return 0; - return 1; + if(S_ISDIR(inode->i_mode)) + return -EPERM; + + inode->i_nlink++; + atomic_inc(&inode->i_count); + dget(dentry); + d_instantiate(dentry, inode); + return 0; } -static struct dentry_operations usbdevfs_dentry_operations = { - d_revalidate: usbdevfs_revalidate, -}; +static inline int usbfs_positive (struct dentry *dentry) +{ + return dentry->d_inode && !d_unhashed(dentry); +} -static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry) +static int usbfs_empty (struct dentry *dentry) { - int busnr; - unsigned long ino = 0; - unsigned int i; - struct inode *inode; + struct list_head *list; - /* sanity check */ - if (dir->i_ino != IROOT) - return ERR_PTR(-EINVAL); - dentry->d_op = &usbdevfs_dentry_operations; - busnr = dnumber(dentry); - if (busnr >= 0 && busnr <= 255) - ino = IBUS | (busnr << 8); - if (!ino) { - for (i = 0; i < NRSPECIAL; i++) { - if (strlen(special[i].name) == dentry->d_name.len && - !strncmp(special[i].name, dentry->d_name.name, dentry->d_name.len)) { - ino = ISPECIAL | (i + IROOT + 1); - break; - } + spin_lock(&dcache_lock); + + list_for_each(list, &dentry->d_subdirs) { + struct dentry *de = list_entry(list, struct dentry, d_child); + if (usbfs_positive(de)) { + spin_unlock(&dcache_lock); + return 0; } } - if (!ino) - return ERR_PTR(-ENOENT); - inode = iget(dir->i_sb, ino); - if (!inode) - return ERR_PTR(-EINVAL); - if (inode && ITYPE(ino) == IBUS && inode->u.usbdev_i.p.bus == NULL) { - iput(inode); - inode = NULL; - } - d_add(dentry, inode); - return NULL; + + spin_unlock(&dcache_lock); + return 1; } -static struct dentry *usbdevfs_bus_lookup(struct inode *dir, struct dentry *dentry) +static int usbfs_unlink (struct inode *dir, struct dentry *dentry) { - struct inode *inode; - int devnr; + int error = -ENOTEMPTY; - /* sanity check */ - if (ITYPE(dir->i_ino) != IBUS) - return ERR_PTR(-EINVAL); - dentry->d_op = &usbdevfs_dentry_operations; - devnr = dnumber(dentry); - if (devnr < 1 || devnr > 127) - return ERR_PTR(-ENOENT); - inode = iget(dir->i_sb, IDEVICE | (dir->i_ino & (0xff << 8)) | devnr); - if (!inode) - return ERR_PTR(-EINVAL); - if (inode && inode->u.usbdev_i.p.dev == NULL) { - iput(inode); - inode = NULL; + if (usbfs_empty(dentry)) { + struct inode *inode = dentry->d_inode; + + inode->i_nlink--; + dput(dentry); + error = 0; } - d_add(dentry, inode); - return NULL; + return error; } -static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t filldir) +static int usbfs_rename (struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) { - struct inode *inode = filp->f_dentry->d_inode; - unsigned long ino = inode->i_ino; - struct special *spec; - struct list_head *list; - struct usb_bus *bus; - char numbuf[8]; - unsigned int i; - - /* sanity check */ - if (ino != IROOT) - return -EINVAL; - i = filp->f_pos; - switch (i) { - case 0: - if (filldir(dirent, ".", 1, i, IROOT, DT_DIR) < 0) - return 0; - filp->f_pos++; - i++; - /* fall through */ + int error = -ENOTEMPTY; - case 1: - if (filldir(dirent, "..", 2, i, IROOT, DT_DIR) < 0) - return 0; - filp->f_pos++; - i++; - /* fall through */ - - default: - - while (i >= 2 && i < 2+NRSPECIAL) { - spec = &special[filp->f_pos-2]; - if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT), DT_UNKNOWN) < 0) - return 0; - filp->f_pos++; - i++; - } - if (i < 2+NRSPECIAL) - return 0; - i -= 2+NRSPECIAL; - down (&usb_bus_list_lock); - for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) { - if (i > 0) { - i--; - continue; - } - bus = list_entry(list, struct usb_bus, bus_list); - sprintf(numbuf, "%03d", bus->busnum); - if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8), DT_UNKNOWN) < 0) - break; - filp->f_pos++; + if (usbfs_empty(new_dentry)) { + struct inode *inode = new_dentry->d_inode; + if (inode) { + inode->i_nlink--; + dput(new_dentry); } - up (&usb_bus_list_lock); - return 0; + error = 0; } + return error; } -static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struct file *filp, void *dirent, filldir_t filldir) +#define usbfs_rmdir usbfs_unlink + +/* default file operations */ +static ssize_t default_read_file (struct file *file, char *buf, + size_t count, loff_t *ppos) { - char numbuf[8]; - unsigned int i; + return 0; +} - if (!dev) - return pos; - sprintf(numbuf, "%03d", dev->devnum); - if (pos > 0) - pos--; - else { - if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff), DT_UNKNOWN) < 0) - return -1; - filp->f_pos++; - } - for (i = 0; i < dev->maxchild; i++) { - if (!dev->children[i]) - continue; - pos = bus_readdir(dev->children[i], ino, pos, filp, dirent, filldir); - if (pos < 0) - return -1; - } - return pos; +static ssize_t default_write_file (struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + return count; } -static int usbdevfs_bus_readdir(struct file *filp, void *dirent, filldir_t filldir) +static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) { - struct inode *inode = filp->f_dentry->d_inode; - unsigned long ino = inode->i_ino; - struct usb_bus *bus; + loff_t retval = -EINVAL; - /* sanity check */ - if (ITYPE(ino) != IBUS) - return -EINVAL; - switch ((unsigned int)filp->f_pos) { + switch(orig) { case 0: - if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0) - return 0; - filp->f_pos++; - /* fall through */ - + if (offset > 0) { + file->f_pos = offset; + retval = file->f_pos; + } + break; case 1: - if (filldir(dirent, "..", 2, filp->f_pos, IROOT, DT_DIR) < 0) - return 0; - filp->f_pos++; - /* fall through */ - + if ((offset + file->f_pos) > 0) { + file->f_pos += offset; + retval = file->f_pos; + } + break; default: - lock_kernel(); - bus = usbdevfs_findbus(IBUSNR(ino)); - bus_readdir(bus->root_hub, IDEVICE | ((bus->busnum & 0xff) << 8), filp->f_pos-2, filp, dirent, filldir); - unlock_kernel(); - return 0; + break; } + return retval; +} + +static int default_open (struct inode *inode, struct file *filp) +{ + if (inode->u.generic_ip) + filp->private_data = inode->u.generic_ip; + + return 0; } -static struct file_operations usbdevfs_root_file_operations = { - readdir: usbdevfs_root_readdir, +static int default_sync_file (struct file *file, struct dentry *dentry, + int datasync) +{ + return 0; +} + +static struct address_space_operations usbfs_aops = { }; -static struct inode_operations usbdevfs_root_inode_operations = { - lookup: usbdevfs_root_lookup, +static struct file_operations usbfs_dir_operations = { + read: generic_read_dir, + readdir: dcache_readdir, + fsync: default_sync_file, }; -static struct file_operations usbdevfs_bus_file_operations = { - readdir: usbdevfs_bus_readdir, +static struct file_operations default_file_operations = { + read: default_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, }; -static struct inode_operations usbdevfs_bus_inode_operations = { - lookup: usbdevfs_bus_lookup, +static struct inode_operations usbfs_dir_inode_operations = { + create: usbfs_create, + lookup: usbfs_lookup, + link: usbfs_link, + unlink: usbfs_unlink, + mkdir: usbfs_mkdir, + rmdir: usbfs_rmdir, + mknod: usbfs_mknod, + rename: usbfs_rename, }; -static void usbdevfs_read_inode(struct inode *inode) -{ - struct special *spec; +static struct super_operations usbfs_ops = { + statfs: usbfs_statfs, + put_inode: force_delete, +}; - inode->i_ctime = inode->i_mtime = inode->i_atime = CURRENT_TIME; - inode->i_mode = S_IFREG; - inode->i_gid = inode->i_uid = 0; - INIT_LIST_HEAD(&inode->u.usbdev_i.dlist); - INIT_LIST_HEAD(&inode->u.usbdev_i.slist); - inode->u.usbdev_i.p.dev = NULL; - inode->u.usbdev_i.p.bus = NULL; - switch (ITYPE(inode->i_ino)) { - case ISPECIAL: - if (inode->i_ino == IROOT) { - inode->i_op = &usbdevfs_root_inode_operations; - inode->i_fop = &usbdevfs_root_file_operations; - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; - return; - } - if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL) - return; - spec = &special[inode->i_ino-(IROOT+1)]; - inode->i_fop = spec->fops; - return; +static struct super_block *usbfs_read_super (struct super_block *sb, void *data, + int silent) +{ + struct inode *inode; + struct dentry *root; - case IDEVICE: - return; + if (parse_options(sb, data)) { + warn("usbfs: mount parameter error:"); + return NULL; + } - case IBUS: - return; + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = USBDEVICE_SUPER_MAGIC; + sb->s_op = &usbfs_ops; + inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); - default: - return; - } -} + if (!inode) { + dbg("%s: could not get inode!\n",__FUNCTION__); + return NULL; + } -static void usbdevfs_put_super(struct super_block *sb) -{ - list_del(&sb->u.usbdevfs_sb.slist); - INIT_LIST_HEAD(&sb->u.usbdevfs_sb.slist); - while (!list_empty(&sb->u.usbdevfs_sb.ilist)) - free_inode(list_entry(sb->u.usbdevfs_sb.ilist.next, struct inode, u.usbdev_i.slist)); + root = d_alloc_root(inode); + if (!root) { + dbg("%s: could not get root dentry!\n",__FUNCTION__); + iput(inode); + return NULL; + } + sb->s_root = root; + return sb; } -static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf) +/** + * fs_create_by_name - create a file, given a name + * @name: name of file + * @mode: type of file + * @parent: dentry of directory to create it in + * @dentry: resulting dentry of file + * + * There is a bit of overhead in creating a file - basically, we + * have to hash the name of the file, then look it up. This will + * prevent files of the same name. + * We then call the proper vfs_ function to take care of all the + * file creation details. + * This function handles both regular files and directories. + */ +static int fs_create_by_name (const char *name, mode_t mode, + struct dentry *parent, struct dentry **dentry) { - buf->f_type = USBDEVICE_SUPER_MAGIC; - buf->f_bsize = PAGE_SIZE/sizeof(long); /* ??? */ - buf->f_bfree = 0; - buf->f_bavail = 0; - buf->f_ffree = 0; - buf->f_namelen = NAME_MAX; - return 0; -} + struct dentry *d = NULL; + struct qstr qstr; + int error; -static int usbdevfs_remount(struct super_block *s, int *flags, char *data) -{ - struct list_head *ilist = s->u.usbdevfs_sb.ilist.next; - struct inode *inode; - int ret; + /* If the parent is not specified, we create it in the root. + * We need the root dentry to do this, which is in the super + * block. A pointer to that is in the struct vfsmount that we + * have around. + */ + if (!parent ) { + if (usbfs_mount && usbfs_mount->mnt_sb) { + parent = usbfs_mount->mnt_sb->s_root; + } + } - if ((ret = parse_options(s, data))) { - printk(KERN_WARNING "usbdevfs: remount parameter error\n"); - return ret; + if (!parent) { + dbg("Ah! can not find a parent!\n"); + return -EFAULT; } - for (; ilist != &s->u.usbdevfs_sb.ilist; ilist = ilist->next) { - inode = list_entry(ilist, struct inode, u.usbdev_i.slist); + *dentry = NULL; + qstr.name = name; + qstr.len = strlen(name); + qstr.hash = full_name_hash(name,qstr.len); - switch (ITYPE(inode->i_ino)) { - case ISPECIAL : - inode->i_uid = s->u.usbdevfs_sb.listuid; - inode->i_gid = s->u.usbdevfs_sb.listgid; - inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG; - break; - case IBUS : - inode->i_uid = s->u.usbdevfs_sb.busuid; - inode->i_gid = s->u.usbdevfs_sb.busgid; - inode->i_mode = s->u.usbdevfs_sb.busmode | S_IFDIR; + parent = dget(parent); + + down(&parent->d_inode->i_sem); + + d = lookup_hash(&qstr,parent); + + error = PTR_ERR(d); + if (!IS_ERR(d)) { + switch(mode & S_IFMT) { + case 0: + case S_IFREG: + error = vfs_create(parent->d_inode,d,mode); break; - case IDEVICE : - inode->i_uid = s->u.usbdevfs_sb.devuid; - inode->i_gid = s->u.usbdevfs_sb.devgid; - inode->i_mode = s->u.usbdevfs_sb.devmode | S_IFREG; + case S_IFDIR: + error = vfs_mkdir(parent->d_inode,d,mode); break; + default: + err("cannot create special files\n"); } + *dentry = d; } + up(&parent->d_inode->i_sem); - return 0; + dput(parent); + return error; } -static struct super_operations usbdevfs_sops = { - read_inode: usbdevfs_read_inode, - put_super: usbdevfs_put_super, - statfs: usbdevfs_statfs, - remount_fs: usbdevfs_remount, -}; - -struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent) +static struct dentry *fs_create_file (const char *name, mode_t mode, + struct dentry *parent, void *data, + struct file_operations *fops, + uid_t uid, gid_t gid) { - struct inode *root_inode, *inode; - struct list_head *blist; - struct usb_bus *bus; - unsigned int i; + struct dentry *dentry; + int error; - if (parse_options(s, data)) { - printk(KERN_WARNING "usbdevfs: mount parameter error\n"); - return NULL; + dbg("creating file '%s'\n",name); + + error = fs_create_by_name(name,mode,parent,&dentry); + if (error) { + dentry = NULL; + } else { + if (dentry->d_inode) { + if (data) + dentry->d_inode->u.generic_ip = data; + if (fops) + dentry->d_inode->i_fop = fops; + dentry->d_inode->i_uid = uid; + dentry->d_inode->i_gid = gid; + } } - /* fill superblock */ - s->s_blocksize = 1024; - s->s_blocksize_bits = 10; - s->s_magic = USBDEVICE_SUPER_MAGIC; - s->s_op = &usbdevfs_sops; - INIT_LIST_HEAD(&s->u.usbdevfs_sb.slist); - INIT_LIST_HEAD(&s->u.usbdevfs_sb.ilist); - root_inode = iget(s, IROOT); - if (!root_inode) - goto out_no_root; - s->s_root = d_alloc_root(root_inode); - if (!s->s_root) - goto out_no_root; - list_add_tail(&s->u.usbdevfs_sb.slist, &superlist); - for (i = 0; i < NRSPECIAL; i++) { - if (!(inode = iget(s, IROOT+1+i))) - continue; - inode->i_uid = s->u.usbdevfs_sb.listuid; - inode->i_gid = s->u.usbdevfs_sb.listgid; - inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG; - special[i].inode = inode; - list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist); - list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes); - } - down (&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); - } - up (&usb_bus_list_lock); - return s; - - out_no_root: - printk("usbdevfs_read_super: get root inode failed\n"); - iput(root_inode); - return NULL; + return dentry; } +static void fs_remove_file (struct dentry *dentry) +{ + struct dentry *parent = dentry->d_parent; + + if (!parent || !parent->d_inode) + return; + + down(&parent->d_inode->i_sem); + if (usbfs_positive(dentry)) { + if (dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode)) + vfs_rmdir(parent->d_inode,dentry); + else + vfs_unlink(parent->d_inode,dentry); + } + + dput(dentry); + } + up(&parent->d_inode->i_sem); +} + +/* --------------------------------------------------------------------- */ + + + /* - * The usbdevfs name is now depreciated (as of 2.5.1). + * The usbdevfs name is now deprecated (as of 2.5.1). * It will be removed when the 2.7.x development cycle is started. * You have been warned :) */ -static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, FS_SINGLE); -static DECLARE_FSTYPE(usb_fs_type, "usbfs", usbdevfs_read_super, FS_SINGLE); +static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbfs_read_super, FS_SINGLE); +static DECLARE_FSTYPE(usb_fs_type, "usbfs", usbfs_read_super, FS_SINGLE); /* --------------------------------------------------------------------- */ +static int get_mount (void) +{ + struct vfsmount *mnt; -static void update_special_inodes (void) + spin_lock (&mount_lock); + if (usbfs_mount) { + mntget(usbfs_mount); + ++mount_count; + spin_unlock (&mount_lock); + goto go_ahead; + } + + spin_unlock (&mount_lock); + mnt = kern_mount (&usbdevice_fs_type); + if (IS_ERR(mnt)) { + err ("could not mount the fs...erroring out!\n"); + return -ENODEV; + } + spin_lock (&mount_lock); + if (!usbfs_mount) { + usbfs_mount = mnt; + ++mount_count; + spin_unlock (&mount_lock); + goto go_ahead; + } + mntget(usbfs_mount); + ++mount_count; + spin_unlock (&mount_lock); + mntput(mnt); + +go_ahead: + dbg("mount_count = %d\n", mount_count); + return 0; +} + +static void remove_mount (void) +{ + struct vfsmount *mnt; + + spin_lock (&mount_lock); + mnt = usbfs_mount; + --mount_count; + if (!mount_count) + usbfs_mount = NULL; + + spin_unlock (&mount_lock); + mntput(mnt); + dbg("mount_count = %d\n", mount_count); +} + +static int create_special_files (void) +{ + int retval; + + /* create the devices and drivers special files */ + retval = get_mount (); + if (retval) + return retval; + devices_dentry = fs_create_file ("devices", + listmode | S_IFREG, + NULL, NULL, + &usbdevfs_devices_fops, + listuid, listgid); + if (devices_dentry == NULL) { + err ("Unable to create devices usbfs file"); + return -ENODEV; + } + + drivers_dentry = fs_create_file ("drivers", + listmode | S_IFREG, + NULL, NULL, + &usbdevfs_drivers_fops, + listuid, listgid); + if (drivers_dentry == NULL) { + err ("Unable to create drivers usbfs file"); + return -ENODEV; + } + + return 0; +} + +static void remove_special_files (void) +{ + if (devices_dentry) + fs_remove_file (devices_dentry); + if (drivers_dentry) + fs_remove_file (drivers_dentry); + devices_dentry = NULL; + drivers_dentry = NULL; + remove_mount(); +} + +void usbfs_update_special (void) { - int i; - for (i = 0; i < NRSPECIAL; i++) { - struct inode *inode = special[i].inode; + struct inode *inode; + + if (devices_dentry) { + inode = devices_dentry->d_inode; + if (inode) + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + } + if (drivers_dentry) { + inode = devices_dentry->d_inode; if (inode) inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; } } - -void usbdevfs_add_bus(struct usb_bus *bus) +void usbfs_add_bus(struct usb_bus *bus) { - struct list_head *slist; + char name[8]; + int retval; + + /* create the special files if this is the first bus added */ + if (num_buses == 0) { + retval = create_special_files(); + if (retval) + return; + } + ++num_buses; + + sprintf (name, "%03d", bus->busnum); + bus->dentry = fs_create_file (name, + busmode | S_IFDIR, + NULL, bus, NULL, + busuid, busgid); + if (bus->dentry == NULL) + return; - lock_kernel(); - for (slist = superlist.next; slist != &superlist; slist = slist->next) - new_bus_inode(bus, list_entry(slist, struct super_block, u.usbdevfs_sb.slist)); - update_special_inodes(); - unlock_kernel(); + usbfs_update_special(); usbdevfs_conn_disc_event(); } -void usbdevfs_remove_bus(struct usb_bus *bus) + +void usbfs_remove_bus(struct usb_bus *bus) { - lock_kernel(); - while (!list_empty(&bus->inodes)) - free_inode(list_entry(bus->inodes.next, struct inode, u.usbdev_i.dlist)); - update_special_inodes(); - unlock_kernel(); + if (bus->dentry) { + fs_remove_file (bus->dentry); + bus->dentry = NULL; + } + + --num_buses; + if (num_buses <= 0) { + remove_special_files(); + num_buses = 0; + } + + usbfs_update_special(); usbdevfs_conn_disc_event(); } -void usbdevfs_add_device(struct usb_device *dev) +void usbfs_add_device(struct usb_device *dev) { - struct list_head *slist; + char name[8]; - lock_kernel(); - for (slist = superlist.next; slist != &superlist; slist = slist->next) - new_dev_inode(dev, list_entry(slist, struct super_block, u.usbdevfs_sb.slist)); - update_special_inodes(); - unlock_kernel(); + sprintf (name, "%03d", dev->devnum); + dev->dentry = fs_create_file (name, + devmode | S_IFREG, + dev->bus->dentry, dev, + &usbdevfs_device_file_operations, + devuid, devgid); + if (dev->dentry == NULL) + return; + + usbfs_update_special(); usbdevfs_conn_disc_event(); } -void usbdevfs_remove_device(struct usb_device *dev) +void usbfs_remove_device(struct usb_device *dev) { struct dev_state *ds; struct siginfo sinfo; - lock_kernel(); - while (!list_empty(&dev->inodes)) - free_inode(list_entry(dev->inodes.next, struct inode, u.usbdev_i.dlist)); + if (dev->dentry) { + fs_remove_file (dev->dentry); + dev->dentry = NULL; + } while (!list_empty(&dev->filelist)) { ds = list_entry(dev->filelist.next, struct dev_state, list); list_del(&ds->list); @@ -732,9 +716,7 @@ send_sig_info(ds->discsignr, &sinfo, ds->disctask); } } - - update_special_inodes(); - unlock_kernel(); + usbfs_update_special(); usbdevfs_conn_disc_event(); } @@ -744,39 +726,42 @@ static struct proc_dir_entry *usbdir = NULL; #endif -int __init usbdevfs_init(void) +int __init usbfs_init(void) { - int ret; + int retval; - for (ret = 0; ret < NRSPECIAL; ret++) { - INIT_LIST_HEAD(&special[ret].inodes); - } - if ((ret = usb_register(&usbdevfs_driver))) - return ret; - if ((ret = register_filesystem(&usb_fs_type))) { + retval = usb_register(&usbdevfs_driver); + if (retval) + return retval; + + retval = register_filesystem(&usb_fs_type); + if (retval) { usb_deregister(&usbdevfs_driver); - return ret; + return retval; } - if ((ret = register_filesystem(&usbdevice_fs_type))) { + retval = register_filesystem(&usbdevice_fs_type); + if (retval) { unregister_filesystem(&usb_fs_type); usb_deregister(&usbdevfs_driver); - return ret; + return retval; } + #ifdef CONFIG_PROC_FS /* create mount point for usbdevfs */ usbdir = proc_mkdir("usb", proc_bus); #endif - return ret; + + return 0; } -void __exit usbdevfs_cleanup(void) +void __exit usbfs_cleanup(void) { usb_deregister(&usbdevfs_driver); unregister_filesystem(&usb_fs_type); unregister_filesystem(&usbdevice_fs_type); #ifdef CONFIG_PROC_FS - if (usbdir) - remove_proc_entry("usb", proc_bus); + if (usbdir) + remove_proc_entry("usb", proc_bus); #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/kaweth.c linux-2.5/drivers/usb/kaweth.c --- linux-2.5.1/drivers/usb/kaweth.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/kaweth.c Tue Jan 8 00:44:24 2002 @@ -110,8 +110,8 @@ ); 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); + struct usb_ctrlrequest *cmd, void *data, + int len, int timeout); /**************************************************************** * usb_device_id @@ -229,7 +229,7 @@ __u16 size, int timeout) { - devrequest *dr; + struct usb_ctrlrequest *dr; kaweth_dbg("kaweth_control()"); @@ -238,20 +238,19 @@ return -EBUSY; } - dr = kmalloc(sizeof(devrequest), + dr = kmalloc(sizeof(struct usb_ctrlrequest), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - if(!dr) - { + if (!dr) { kaweth_dbg("kmalloc() failed"); return -ENOMEM; } - dr->requesttype = requesttype; - dr->request = request; - dr->value = cpu_to_le16p(&value); - dr->index = cpu_to_le16p(&index); - dr->length = cpu_to_le16p(&size); + dr->bRequestType= requesttype; + dr->bRequest = request; + dr->wValue = cpu_to_le16p(&value); + dr->wIndex = cpu_to_le16p(&index); + dr->wLength = cpu_to_le16p(&size); return kaweth_internal_control_msg(kaweth->dev, pipe, @@ -1015,7 +1014,8 @@ /*-------------------------------------------------------------------*/ // 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) + struct usb_ctrlrequest *cmd, void *data, int len, + int timeout) { urb_t *urb; int retv; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/mdc800.c linux-2.5/drivers/usb/mdc800.c --- linux-2.5.1/drivers/usb/mdc800.c Sun Dec 9 04:28:44 2001 +++ linux-2.5/drivers/usb/mdc800.c Tue Jan 1 23:42:42 2002 @@ -140,7 +140,7 @@ unsigned int endpoint [4]; - purb_t irq_urb; + struct urb * irq_urb; wait_queue_head_t irq_wait; int irq_woken; char* irq_urb_buffer; @@ -149,13 +149,13 @@ int camera_request_ready; // Status to synchronize with irq char camera_response [8]; // last Bytes send after busy - purb_t write_urb; + struct urb * write_urb; char* write_urb_buffer; wait_queue_head_t write_wait; int written; - purb_t download_urb; + struct urb * download_urb; char* download_urb_buffer; wait_queue_head_t download_wait; int downloaded; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/microtek.c linux-2.5/drivers/usb/microtek.c --- linux-2.5.1/drivers/usb/microtek.c Wed Nov 28 18:22:27 2001 +++ linux-2.5/drivers/usb/microtek.c Mon Dec 31 01:39:36 2001 @@ -367,7 +367,7 @@ } MTS_DEBUG_GOT_HERE(); - scsi_unregister_module(MODULE_SCSI_HA, &(to_remove->ctempl)); + scsi_unregister_host(&to_remove->ctempl); unlock_kernel(); kfree( to_remove ); @@ -982,11 +982,11 @@ MTS_DEBUG("registering SCSI module\n"); new_desc->ctempl.module = THIS_MODULE; - result = scsi_register_module(MODULE_SCSI_HA, &(new_desc->ctempl)); + result = scsi_register_host(&new_desc->ctempl); /* Will get hit back in microtek_detect by this func */ if ( result ) { - MTS_ERROR( "error %d from scsi_register_module! Help!\n", + MTS_ERROR( "error %d from scsi_register_host! Help!\n", (int)result ); /* FIXME: need more cleanup? */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/ov511.c linux-2.5/drivers/usb/ov511.c --- linux-2.5.1/drivers/usb/ov511.c Fri Sep 14 21:04:07 2001 +++ linux-2.5/drivers/usb/ov511.c Sat Jan 5 16:38:08 2002 @@ -1,13 +1,16 @@ /* * OmniVision OV511 Camera-to-USB Bridge Driver * - * Copyright (c) 1999-2000 Mark W. McClelland + * Copyright (c) 1999-2001 Mark W. McClelland + * Original decompression code Copyright 1998-2000 OmniVision Technologies * Many improvements by Bret Wallach <bwallac1@san.rr.com> * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000) * Snapshot code by Kevin Moore * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org> * Changes by Claudio Matsuoka <claudio@conectiva.com> - * + * Original SAA7111A code by Dave Perks <dperks@ibm.net> + * Kernel I2C interface adapted from nt1003 driver + * * Based on the Linux CPiA driver written by Peter Pregler, * Scott J. Bertin and Johannes Erdfelt. * @@ -30,11 +33,9 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define __NO_VERSION__ - #include <linux/config.h> -#include <linux/module.h> #include <linux/version.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/vmalloc.h> @@ -42,32 +43,51 @@ #include <linux/proc_fs.h> #include <linux/ctype.h> #include <linux/pagemap.h> -#include <linux/usb.h> #include <asm/io.h> #include <asm/semaphore.h> +#include <asm/processor.h> #include <linux/wrapper.h> +#if defined (__i386__) + #include <asm/cpufeature.h> +#endif + #include "ov511.h" /* * Version Information */ -#define DRIVER_VERSION "v1.28" -#define DRIVER_AUTHOR "Mark McClelland <mwm@i.am> & Bret Wallach & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>" +#define DRIVER_VERSION "v1.48 for Linux 2.4" +#define EMAIL "mmcclell@bigfoot.com" +#define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \ + & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \ + <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>" #define DRIVER_DESC "OV511 USB Camera Driver" #define OV511_I2C_RETRIES 3 +#define ENABLE_Y_QUANTABLE 1 +#define ENABLE_UV_QUANTABLE 1 + +/* Pixel count * 3 bytes for RGB */ +#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3) +#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval)) -/* Video Size 640 x 480 x 3 bytes for RGB */ -#define MAX_FRAME_SIZE (640 * 480 * 3) -#define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval)) +/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */ +#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024) -#define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_GREY ? 256 : 384) +#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM) /* PARAMETER VARIABLES: */ -static int autoadjust = 1; /* CCD dynamically changes exposure, etc... */ +/* (See ov511.txt for detailed descriptions of these.) */ -static int video_nr = -1; +/* Sensor automatically changes brightness */ +static int autobright = 1; + +/* Sensor automatically changes gain */ +static int autogain = 1; + +/* Sensor automatically changes exposure */ +static int autoexp = 1; /* 0=no debug messages * 1=init/detection/unload and other significant messages, @@ -77,27 +97,17 @@ * 5=highly repetitive mesgs * NOTE: This should be changed to 0, 1, or 2 for production kernels */ -static int debug = 0; +static int debug; /* = 0 */ /* Fix vertical misalignment of red and blue at 640x480 */ -static int fix_rgb_offset = 0; +static int fix_rgb_offset; /* = 0 */ /* Snapshot mode enabled flag */ -static int snapshot = 0; - -/* Sensor detection override (global for all attached cameras) */ -static int sensor = 0; - -/* Increase this if you are getting "Failed to read sensor ID..." */ -static int i2c_detect_tries = 5; - -/* For legal values, see the OV7610/7620 specs under register Common F, - * upper nybble (set to 0-F) */ -static int aperture = -1; +static int snapshot; /* = 0 */ /* Force image to be read in RGB instead of BGR. This option allow * programs that expect RGB data (e.g. gqcam) to work with this driver. */ -static int force_rgb = 0; +static int force_rgb; /* = 0 */ /* Number of seconds before inactive buffers are deallocated */ static int buf_timeout = 5; @@ -105,76 +115,219 @@ /* Number of cameras to stream from simultaneously */ static int cams = 1; -/* Prevent apps from timing out if frame is not done in time */ -static int retry_sync = 0; - -/* Enable compression. This is for experimentation only; compressed images - * still cannot be decoded yet. */ -static int compress = 0; +/* Enable compression. Needs a fast (>300 MHz) CPU. */ +static int compress; /* = 0 */ /* Display test pattern - doesn't work yet either */ -static int testpat = 0; +static int testpat; /* = 0 */ -/* Setting this to 1 will make the sensor output GBR422 instead on YUV420. Only +/* Setting this to 1 will make the sensor output GBR422 instead of YUV420. Only * affects RGB24 mode. */ -static int sensor_gbr = 0; +static int sensor_gbr; /* = 0 */ -/* Dump raw pixel data, in one of 3 formats. See ov511_dumppix() for details. */ -static int dumppix = 0; +/* Dump raw pixel data. */ +static int dumppix; /* = 0 */ -MODULE_PARM(autoadjust, "i"); -MODULE_PARM_DESC(autoadjust, "CCD dynamically changes exposure"); +/* LED policy. Only works on some OV511+ cameras. 0=off, 1=on (default), 2=auto + * (on when open) */ +static int led = 1; + +/* Set this to 1 to dump the bridge register contents after initialization */ +static int dump_bridge; /* = 0 */ + +/* Set this to 1 to dump the sensor register contents after initialization */ +static int dump_sensor; /* = 0 */ + +/* Temporary option for debugging "works, but no image" problem. Prints the + * first 12 bytes of data (potentially a packet header) in each isochronous + * data frame. */ +static int printph; /* = 0 */ + +/* Compression parameters - I'm not exactly sure what these do yet */ +static int phy = 0x1f; +static int phuv = 0x05; +static int pvy = 0x06; +static int pvuv = 0x06; +static int qhy = 0x14; +static int qhuv = 0x03; +static int qvy = 0x04; +static int qvuv = 0x04; + +/* Light frequency. Set to 50 or 60 (Hz), or zero for default settings */ +static int lightfreq; /* = 0 */ + +/* Set this to 1 to enable banding filter by default. Compensates for + * alternating horizontal light/dark bands caused by (usually fluorescent) + * lights */ +static int bandingfilter; /* = 0 */ + +/* Pixel clock divisor */ +static int clockdiv = -1; + +/* Isoc packet size */ +static int packetsize = -1; + +/* Frame drop register (16h) */ +static int framedrop = -1; + +/* Allows picture settings (brightness, hue, etc...) to take effect immediately, + * even in the middle of a frame. This reduces the time to change settings, but + * can ruin frames during the change. Only affects OmniVision sensors. */ +static int fastset; /* = 0 */ + +/* Forces the palette to a specific value. If an application requests a + * different palette, it will be rejected. */ +static int force_palette; /* = 0 */ + +/* Set tuner type, if not autodetected */ +static int tuner = -1; + +/* Allows proper exposure of objects that are illuminated from behind. Only + * affects OmniVision sensors. */ +static int backlight; /* = 0 */ + +/* If you change this, you must also change the MODULE_PARM definition */ +#define OV511_MAX_UNIT_VIDEO 16 + +/* Allows specified minor numbers to be forced. They will be assigned in the + * order that devices are detected. Note that you cannot specify 0 as a minor + * number. If you do not specify any, the next available one will be used. This + * requires kernel 2.4.5 or later. */ +static int unit_video[OV511_MAX_UNIT_VIDEO]; + +/* Remove zero-padding from uncompressed incoming data. This will compensate for + * the blocks of corruption that appear when the camera cannot keep up with the + * speed of the USB bus (eg. at low frame resolutions) */ +static int remove_zeros; /* = 0 */ + +MODULE_PARM(autobright, "i"); +MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); +MODULE_PARM(autogain, "i"); +MODULE_PARM_DESC(autogain, "Sensor automatically changes gain"); +MODULE_PARM(autoexp, "i"); +MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure"); MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug level: 0=none, 1=init/detection, 2=warning, 3=config/control, 4=function call, 5=max"); +MODULE_PARM_DESC(debug, + "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max"); MODULE_PARM(fix_rgb_offset, "i"); -MODULE_PARM_DESC(fix_rgb_offset, "Fix vertical misalignment of red and blue at 640x480"); +MODULE_PARM_DESC(fix_rgb_offset, + "Fix vertical misalignment of red and blue at 640x480"); MODULE_PARM(snapshot, "i"); MODULE_PARM_DESC(snapshot, "Enable snapshot mode"); -MODULE_PARM(sensor, "i"); -MODULE_PARM_DESC(sensor, "Override sensor detection"); -MODULE_PARM(i2c_detect_tries, "i"); -MODULE_PARM_DESC(i2c_detect_tries, "Number of tries to detect sensor"); -MODULE_PARM(aperture, "i"); -MODULE_PARM_DESC(aperture, "Read the OV7610/7620 specs"); MODULE_PARM(force_rgb, "i"); MODULE_PARM_DESC(force_rgb, "Read RGB instead of BGR"); MODULE_PARM(buf_timeout, "i"); MODULE_PARM_DESC(buf_timeout, "Number of seconds before buffer deallocation"); MODULE_PARM(cams, "i"); MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); -MODULE_PARM(retry_sync, "i"); -MODULE_PARM_DESC(retry_sync, "Prevent apps from timing out"); MODULE_PARM(compress, "i"); -MODULE_PARM_DESC(compress, "Turn on compression (not functional yet)"); +MODULE_PARM_DESC(compress, "Turn on compression (not reliable yet)"); MODULE_PARM(testpat, "i"); -MODULE_PARM_DESC(testpat, "Replace image with vertical bar testpattern (only partially working)"); -MODULE_PARM(sensor_gbr, "i"); -MODULE_PARM_DESC(sensor_gbr, "Make sensor output GBR422 rather than YUV420"); +MODULE_PARM_DESC(testpat, + "Replace image with vertical bar testpattern (only partially working)"); + +// Temporarily removed (needs to be rewritten for new format conversion code) +// MODULE_PARM(sensor_gbr, "i"); +// MODULE_PARM_DESC(sensor_gbr, "Make sensor output GBR422 rather than YUV420"); + MODULE_PARM(dumppix, "i"); -MODULE_PARM_DESC(dumppix, "Dump raw pixel data, in one of 3 formats. See ov511_dumppix() for details"); -MODULE_PARM(video_nr,"i"); +MODULE_PARM_DESC(dumppix, "Dump raw pixel data"); +MODULE_PARM(led, "i"); +MODULE_PARM_DESC(led, + "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)"); +MODULE_PARM(dump_bridge, "i"); +MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers"); +MODULE_PARM(dump_sensor, "i"); +MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers"); +MODULE_PARM(printph, "i"); +MODULE_PARM_DESC(printph, "Print frame start/end headers"); +MODULE_PARM(phy, "i"); +MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)"); +MODULE_PARM(phuv, "i"); +MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)"); +MODULE_PARM(pvy, "i"); +MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)"); +MODULE_PARM(pvuv, "i"); +MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)"); +MODULE_PARM(qhy, "i"); +MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)"); +MODULE_PARM(qhuv, "i"); +MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)"); +MODULE_PARM(qvy, "i"); +MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)"); +MODULE_PARM(qvuv, "i"); +MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)"); +MODULE_PARM(lightfreq, "i"); +MODULE_PARM_DESC(lightfreq, + "Light frequency. Set to 50 or 60 Hz, or zero for default settings"); +MODULE_PARM(bandingfilter, "i"); +MODULE_PARM_DESC(bandingfilter, + "Enable banding filter (to reduce effects of fluorescent lighting)"); +MODULE_PARM(clockdiv, "i"); +MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value"); +MODULE_PARM(packetsize, "i"); +MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size"); +MODULE_PARM(framedrop, "i"); +MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting"); +MODULE_PARM(fastset, "i"); +MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately"); +MODULE_PARM(force_palette, "i"); +MODULE_PARM_DESC(force_palette, "Force the palette to a specific value"); +MODULE_PARM(tuner, "i"); +MODULE_PARM_DESC(tuner, "Set tuner type, if not autodetected"); +MODULE_PARM(backlight, "i"); +MODULE_PARM_DESC(backlight, "For objects that are lit from behind"); +MODULE_PARM(unit_video, "0-16i"); +MODULE_PARM_DESC(unit_video, + "Force use of specific minor number(s). 0 is not allowed."); +MODULE_PARM(remove_zeros, "i"); +MODULE_PARM_DESC(remove_zeros, + "Remove zero-padding from uncompressed incoming data"); -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static struct usb_driver ov511_driver; -/* I know, I know, global variables suck. This is only a temporary hack */ -int output_offset; +static struct ov51x_decomp_ops *ov511_decomp_ops; +static struct ov51x_decomp_ops *ov511_mmx_decomp_ops; +static struct ov51x_decomp_ops *ov518_decomp_ops; +static struct ov51x_decomp_ops *ov518_mmx_decomp_ops; + +/* Number of times to retry a failed I2C transaction. Increase this if you + * are getting "Failed to read sensor ID..." */ +static int i2c_detect_tries = 5; + +/* MMX support is present in kernel and CPU. Checked upon decomp module load. */ +static int ov51x_mmx_available; + +/* Function prototypes */ +static void ov51x_clear_snapshot(struct usb_ov511 *); +static int ov51x_check_snapshot(struct usb_ov511 *); +static inline int sensor_get_picture(struct usb_ov511 *, + struct video_picture *); +static int sensor_get_exposure(struct usb_ov511 *, unsigned char *); +static int ov511_control_ioctl(struct inode *, struct file *, unsigned int, + unsigned long); /********************************************************************** * List of known OV511-based cameras **********************************************************************/ static struct cam_list clist[] = { - { 0, "generic model (no ID)" }, + { 0, "Generic Camera (no ID)" }, + { 1, "Mustek WCam 3X" }, { 3, "D-Link DSB-C300" }, - { 4, "generic OV511/OV7610" }, + { 4, "Generic OV511/OV7610" }, { 5, "Puretek PT-6007" }, + { 6, "Lifeview USB Life TV (NTSC)" }, { 21, "Creative Labs WebCam 3" }, { 36, "Koala-Cam" }, - { 38, "Lifeview USB Life TV" }, /* No support yet! */ + { 38, "Lifeview USB Life TV" }, + { 41, "Samsung Anycam MPC-M10" }, + { 43, "Mtekvision Zeca MV402" }, + { 46, "Suma eON" }, { 100, "Lifeview RoboCam" }, { 102, "AverMedia InterCam Elite" }, { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ @@ -182,9 +335,11 @@ }; static __devinitdata struct usb_device_id device_table [] = { - { USB_DEVICE(0x05a9, 0x0511) }, /* OV511 */ - { USB_DEVICE(0x05a9, 0xA511) }, /* OV511+ */ - { USB_DEVICE(0x0813, 0x0002) }, /* Intel Play Me2Cam OV511+ */ + { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) }, + { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) }, + { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) }, + { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) }, + { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) }, { } /* Terminating entry */ }; @@ -212,6 +367,11 @@ }; #endif +static unsigned char yQuanTable511[] = OV511_YQUANTABLE; +static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE; +static unsigned char yQuanTable518[] = OV518_YQUANTABLE; +static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE; + /********************************************************************** * * Memory management @@ -231,7 +391,8 @@ /* 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) +static inline unsigned long +uvirt_to_kva(pgd_t *pgd, unsigned long adr) { unsigned long ret = 0UL; pmd_t *pmd; @@ -243,7 +404,8 @@ ptep = pte_offset(pmd, adr); pte = *ptep; if (pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); + ret = (unsigned long) + page_address(pte_page(pte)); ret |= (adr & (PAGE_SIZE - 1)); } } @@ -256,7 +418,8 @@ * 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) +static inline unsigned long +kvirt_to_pa(unsigned long adr) { unsigned long va, kva, ret; @@ -266,7 +429,8 @@ return ret; } -static void *rvmalloc(unsigned long size) +static void * +rvmalloc(unsigned long size) { void *mem; unsigned long adr, page; @@ -294,7 +458,8 @@ return mem; } -static void rvfree(void *mem, unsigned long size) +static void +rvfree(void *mem, unsigned long size) { unsigned long adr, page; @@ -329,70 +494,90 @@ #define YES_NO(x) ((x) ? "yes" : "no") -static int ov511_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +/* /proc/video/ov511/<minor#>/info */ +static int +ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof, + void *data) { char *out = page; int i, j, len; struct usb_ov511 *ov511 = data; + struct video_picture p; + unsigned char exp; + + if (!ov511 || !ov511->dev) + return -ENODEV; + + sensor_get_picture(ov511, &p); + sensor_get_exposure(ov511, &exp); /* IMPORTANT: This output MUST be kept under PAGE_SIZE * or we need to get more sophisticated. */ - out += sprintf (out, "driver_version : %s\n", DRIVER_VERSION); - out += sprintf (out, "custom_id : %d\n", ov511->customid); - out += sprintf (out, "model : %s\n", ov511->desc ? - clist[ov511->desc].description : "unknown"); - out += sprintf (out, "streaming : %s\n", YES_NO (ov511->streaming)); - out += sprintf (out, "grabbing : %s\n", YES_NO (ov511->grabbing)); - out += sprintf (out, "compress : %s\n", YES_NO (ov511->compress)); - out += sprintf (out, "subcapture : %s\n", YES_NO (ov511->sub_flag)); - out += sprintf (out, "sub_size : %d %d %d %d\n", - ov511->subx, ov511->suby, ov511->subw, ov511->subh); - out += sprintf (out, "data_format : %s\n", force_rgb ? "RGB" : "BGR"); - out += sprintf (out, "brightness : %d\n", ov511->brightness >> 8); - out += sprintf (out, "colour : %d\n", ov511->colour >> 8); - out += sprintf (out, "contrast : %d\n", ov511->contrast >> 8); - out += sprintf (out, "num_frames : %d\n", OV511_NUMFRAMES); + out += sprintf(out, "driver_version : %s\n", DRIVER_VERSION); + out += sprintf(out, "custom_id : %d\n", ov511->customid); + out += sprintf(out, "model : %s\n", ov511->desc ? + clist[ov511->desc].description : "unknown"); + out += sprintf(out, "streaming : %s\n", YES_NO(ov511->streaming)); + out += sprintf(out, "grabbing : %s\n", YES_NO(ov511->grabbing)); + out += sprintf(out, "compress : %s\n", YES_NO(ov511->compress)); + out += sprintf(out, "subcapture : %s\n", YES_NO(ov511->sub_flag)); + out += sprintf(out, "sub_size : %d %d %d %d\n", + ov511->subx, ov511->suby, ov511->subw, ov511->subh); + out += sprintf(out, "data_format : %s\n", + force_rgb ? "RGB" : "BGR"); + out += sprintf(out, "brightness : %d\n", p.brightness >> 8); + out += sprintf(out, "colour : %d\n", p.colour >> 8); + out += sprintf(out, "contrast : %d\n", p.contrast >> 8); + out += sprintf(out, "hue : %d\n", p.hue >> 8); + out += sprintf(out, "exposure : %d\n", exp); + out += sprintf(out, "num_frames : %d\n", OV511_NUMFRAMES); for (i = 0; i < OV511_NUMFRAMES; i++) { - out += sprintf (out, "frame : %d\n", i); - out += sprintf (out, " depth : %d\n", - ov511->frame[i].depth); - out += sprintf (out, " size : %d %d\n", - ov511->frame[i].width, ov511->frame[i].height); - out += sprintf (out, " format : "); + out += sprintf(out, "frame : %d\n", i); + out += sprintf(out, " depth : %d\n", + ov511->frame[i].depth); + out += sprintf(out, " size : %d %d\n", + ov511->frame[i].width, ov511->frame[i].height); + out += sprintf(out, " format : "); for (j = 0; plist[j].num >= 0; j++) { if (plist[j].num == ov511->frame[i].format) { - out += sprintf (out, "%s\n", plist[j].name); + out += sprintf(out, "%s\n", plist[j].name); break; } } if (plist[j].num < 0) - out += sprintf (out, "unknown\n"); - out += sprintf (out, " segsize : %d\n", - ov511->frame[i].segsize); - out += sprintf (out, " data_buffer : 0x%p\n", - ov511->frame[i].data); - } - out += sprintf (out, "snap_enabled : %s\n", YES_NO (ov511->snap_enabled)); - out += sprintf (out, "bridge : %s\n", - ov511->bridge == BRG_OV511 ? "OV511" : - ov511->bridge == BRG_OV511PLUS ? "OV511+" : - "unknown"); - out += sprintf (out, "sensor : %s\n", - ov511->sensor == SEN_OV6620 ? "OV6620" : - ov511->sensor == SEN_OV7610 ? "OV7610" : - ov511->sensor == SEN_OV7620 ? "OV7620" : - ov511->sensor == SEN_OV7620AE ? "OV7620AE" : - "unknown"); - out += sprintf (out, "packet_size : %d\n", ov511->packet_size); - out += sprintf (out, "framebuffer : 0x%p\n", ov511->fbuf); - + out += sprintf(out, "unknown\n"); + out += sprintf(out, " data_buffer : 0x%p\n", + ov511->frame[i].data); + } + out += sprintf(out, "snap_enabled : %s\n", + YES_NO(ov511->snap_enabled)); + out += sprintf(out, "bridge : %s\n", + ov511->bridge == BRG_OV511 ? "OV511" : + ov511->bridge == BRG_OV511PLUS ? "OV511+" : + ov511->bridge == BRG_OV518 ? "OV518" : + ov511->bridge == BRG_OV518PLUS ? "OV518+" : + "unknown"); + out += sprintf(out, "sensor : %s\n", + ov511->sensor == SEN_OV6620 ? "OV6620" : + ov511->sensor == SEN_OV6630 ? "OV6630" : + ov511->sensor == SEN_OV7610 ? "OV7610" : + ov511->sensor == SEN_OV7620 ? "OV7620" : + ov511->sensor == SEN_OV7620AE ? "OV7620AE" : + ov511->sensor == SEN_OV8600 ? "OV8600" : + ov511->sensor == SEN_KS0127 ? "KS0127" : + ov511->sensor == SEN_KS0127B ? "KS0127B" : + ov511->sensor == SEN_SAA7111A ? "SAA7111A" : + "unknown"); + out += sprintf(out, "packet_size : %d\n", ov511->packet_size); + out += sprintf(out, "framebuffer : 0x%p\n", ov511->fbuf); + len = out - page; len -= off; if (len < count) { *eof = 1; - if (len <= 0) return 0; + if (len <= 0) + return 0; } else len = count; @@ -401,69 +586,160 @@ return len; } -static int ov511_write_proc(struct file *file, const char *buffer, - unsigned long count, void *data) +/* /proc/video/ov511/<minor#>/button + * + * When the camera's button is pressed, the output of this will change from a + * 0 to a 1 (ASCII). It will retain this value until it is read, after which + * it will reset to zero. + * + * SECURITY NOTE: Since reading this file can change the state of the snapshot + * status, it is important for applications that open it to keep it locked + * against access by other processes, using flock() or a similar mechanism. No + * locking is provided by this driver. + */ +static int +ov511_read_proc_button(char *page, char **start, off_t off, int count, int *eof, + void *data) { - return -EINVAL; + char *out = page; + int len, status; + struct usb_ov511 *ov511 = data; + + if (!ov511 || !ov511->dev) + return -ENODEV; + + status = ov51x_check_snapshot(ov511); + out += sprintf(out, "%d", status); + + if (status) + ov51x_clear_snapshot(ov511); + + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else { + len = count; + } + + *start = page + off; + + return len; } -static void create_proc_ov511_cam (struct usb_ov511 *ov511) +static void +create_proc_ov511_cam(struct usb_ov511 *ov511) { - char name[7]; - struct proc_dir_entry *ent; - + char dirname[4]; + if (!ov511_proc_entry || !ov511) return; - sprintf(name, "video%d", ov511->vdev.minor); - PDEBUG (4, "creating /proc/video/ov511/%s", name); - - ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, ov511_proc_entry); + /* Create per-device directory */ + sprintf(dirname, "%d", ov511->vdev.minor); + PDEBUG(4, "creating /proc/video/ov511/%s/", dirname); + ov511->proc_devdir = create_proc_entry(dirname, S_IFDIR, + ov511_proc_entry); + if (!ov511->proc_devdir) + return; - if (!ent) + /* Create "info" entry (human readable device information) */ + PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname); + ov511->proc_info = create_proc_read_entry("info", + S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir, + ov511_read_proc_info, ov511); + if (!ov511->proc_info) return; - ent->data = ov511; - ent->read_proc = ov511_read_proc; - ent->write_proc = ov511_write_proc; - ov511->proc_entry = ent; + /* Don't create it if old snapshot mode on (would cause race cond.) */ + if (!snapshot) { + /* Create "button" entry (snapshot button status) */ + PDEBUG(4, "creating /proc/video/ov511/%s/button", dirname); + ov511->proc_button = create_proc_read_entry("button", + S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir, + ov511_read_proc_button, ov511); + if (!ov511->proc_button) + return; + } + + /* Create "control" entry (ioctl() interface) */ + PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname); + lock_kernel(); + ov511->proc_control = create_proc_entry("control", + S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir); + if (!ov511->proc_control) { + unlock_kernel(); + return; + } + ov511->proc_control->proc_fops->ioctl = ov511_control_ioctl; + ov511->proc_control->data = ov511; + unlock_kernel(); } -static void destroy_proc_ov511_cam (struct usb_ov511 *ov511) +static void +destroy_proc_ov511_cam(struct usb_ov511 *ov511) { - char name[7]; + char dirname[4]; - if (!ov511 || !ov511->proc_entry) + if (!ov511 || !ov511->proc_devdir) return; - - sprintf(name, "video%d", ov511->vdev.minor); - PDEBUG (4, "destroying %s", name); - remove_proc_entry(name, ov511_proc_entry); - ov511->proc_entry = NULL; + + sprintf(dirname, "%d", ov511->vdev.minor); + + /* Destroy "control" entry */ + if (ov511->proc_control) { + PDEBUG(4, "destroying /proc/video/ov511/%s/control", dirname); + remove_proc_entry("control", ov511->proc_devdir); + ov511->proc_control = NULL; + } + + /* Destroy "button" entry */ + if (ov511->proc_button) { + PDEBUG(4, "destroying /proc/video/ov511/%s/button", dirname); + remove_proc_entry("button", ov511->proc_devdir); + ov511->proc_button = NULL; + } + + /* Destroy "info" entry */ + if (ov511->proc_info) { + PDEBUG(4, "destroying /proc/video/ov511/%s/info", dirname); + remove_proc_entry("info", ov511->proc_devdir); + ov511->proc_info = NULL; + } + + /* Destroy per-device directory */ + PDEBUG(4, "destroying /proc/video/ov511/%s/", dirname); + remove_proc_entry(dirname, ov511_proc_entry); + ov511->proc_devdir = NULL; } -static void proc_ov511_create(void) +static void +proc_ov511_create(void) { /* No current standard here. Alan prefers /proc/video/ as it keeps * /proc "less cluttered than /proc/randomcardifoundintheshed/" * -claudio */ if (video_proc_entry == NULL) { - err("Unable to initialise /proc/video/ov511"); + err("Error: /proc/video/ does not exist"); return; } - ov511_proc_entry = create_proc_entry("ov511", S_IFDIR, video_proc_entry); + ov511_proc_entry = create_proc_entry("ov511", S_IFDIR, + video_proc_entry); if (ov511_proc_entry) ov511_proc_entry->owner = THIS_MODULE; else - err("Unable to initialise /proc/ov511"); + err("Unable to create /proc/video/ov511"); } -static void proc_ov511_destroy(void) +static void +proc_ov511_destroy(void) { - PDEBUG (3, "removing /proc/video/ov511"); + PDEBUG(3, "removing /proc/video/ov511"); if (ov511_proc_entry == NULL) return; @@ -474,23 +750,22 @@ /********************************************************************** * - * Camera interface + * Register I/O * **********************************************************************/ -static int ov511_reg_write(struct usb_device *dev, - unsigned char reg, - unsigned char value) +static int +ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) { int rc; - rc = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - 2 /* REG_IO */, - USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, &value, 1, HZ); + PDEBUG(5, "0x%02X:0x%02X", reg, value); - PDEBUG(5, "reg write: 0x%02X:0x%02X, 0x%x", reg, value, rc); + rc = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 2 /* REG_IO */, + USB_TYPE_CLASS | USB_RECIP_DEVICE, + 0, (__u16)reg, &value, 1, HZ); if (rc < 0) err("reg write: error %d", rc); @@ -499,18 +774,19 @@ } /* returns: negative is error, pos or zero is data */ -static int ov511_reg_read(struct usb_device *dev, unsigned char reg) +static int +ov511_reg_read(struct usb_device *dev, unsigned char reg) { int rc; unsigned char buffer[1]; rc = usb_control_msg(dev, - usb_rcvctrlpipe(dev, 0), - 2 /* REG_IO */, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, buffer, 1, HZ); + usb_rcvctrlpipe(dev, 0), + 2 /* REG_IO */, + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, + 0, (__u16)reg, buffer, 1, HZ); - PDEBUG(5, "reg read: 0x%02X:0x%02X", reg, buffer[0]); + PDEBUG(5, "0x%02X:0x%02X", reg, buffer[0]); if (rc < 0) { err("reg read: error %d", rc); @@ -520,18 +796,197 @@ } } -static int ov511_i2c_write(struct usb_device *dev, - unsigned char reg, - unsigned char value) +/* + * Writes bits at positions specified by mask to a reg. Bits that are in + * the same position as 1's in "mask" are cleared and set to "value". Bits + * that are in the same position as 0's in "mask" are preserved, regardless + * of their respective state in "value". + */ +static int +ov511_reg_write_mask(struct usb_device *dev, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int ret; + unsigned char oldval, newval; + + ret = ov511_reg_read(dev, reg); + if (ret < 0) + return ret; + + oldval = (unsigned char) ret; + oldval &= (~mask); /* Clear the masked bits */ + value &= mask; /* Enforce mask on value */ + newval = oldval | value; /* Set the desired bits */ + + return (ov511_reg_write(dev, reg, newval)); +} + +/* Writes multiple (n) values to a single register. Only valid with certain + * registers (0x30 and 0xc4 - 0xce). Used for writing 16 and 24-bit values. */ +static int +ov518_reg_write_multi(struct usb_device *dev, + unsigned char reg, + unsigned char *values, + int n) +{ + int rc; + + PDEBUG(5, "0x%02X:[multiple], n=%d", reg, n); // FIXME + + if (values == NULL) { + err("reg write multiple: NULL buffer"); + return -EINVAL; + } + + rc = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 2 /* REG_IO */, + USB_TYPE_CLASS | USB_RECIP_DEVICE, + 0, (__u16)reg, values, n, HZ); + + if (rc < 0) + err("reg write multiple: error %d", rc); + + return rc; +} + +static int +ov511_upload_quan_tables(struct usb_device *dev) +{ + unsigned char *pYTable = yQuanTable511; + unsigned char *pUVTable = uvQuanTable511; + unsigned char val0, val1; + int i, rc, reg = OV511_OMNICE_Y_LUT_BEGIN; + + PDEBUG(4, "Uploading quantization tables"); + + for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) + { + if (ENABLE_Y_QUANTABLE) + { + val0 = *pYTable++; + val1 = *pYTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = ov511_reg_write(dev, reg, val0); + if (rc < 0) + return rc; + } + + if (ENABLE_UV_QUANTABLE) + { + val0 = *pUVTable++; + val1 = *pUVTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = ov511_reg_write(dev, reg + OV511_QUANTABLESIZE / 2, + val0); + if (rc < 0) + return rc; + } + + reg++; + } + + return 0; +} + +/* OV518 quantization tables are 8x4 (instead of 8x8) */ +static int +ov518_upload_quan_tables(struct usb_device *dev) +{ + unsigned char *pYTable = yQuanTable518; + unsigned char *pUVTable = uvQuanTable518; + unsigned char val0, val1; + int i, rc, reg = OV511_OMNICE_Y_LUT_BEGIN; + + PDEBUG(4, "Uploading quantization tables"); + + for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) + { + if (ENABLE_Y_QUANTABLE) + { + val0 = *pYTable++; + val1 = *pYTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = ov511_reg_write(dev, reg, val0); + if (rc < 0) + return rc; + } + + if (ENABLE_UV_QUANTABLE) + { + val0 = *pUVTable++; + val1 = *pUVTable++; + val0 &= 0x0f; + val1 &= 0x0f; + val0 |= val1 << 4; + rc = ov511_reg_write(dev, reg + OV518_QUANTABLESIZE / 2, + val0); + if (rc < 0) + return rc; + } + + reg++; + } + + return 0; +} + +/* NOTE: Do not call this function directly! + * The OV518 I2C I/O procedure is different, hence, this function. + * This is normally only called from ov51x_i2c_write(). Note that this function + * always succeeds regardless of whether the sensor is present and working. + */ +static int +ov518_i2c_write_internal(struct usb_device *dev, + unsigned char reg, + unsigned char value) +{ + int rc; + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + /* Select camera register */ + rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); + if (rc < 0) goto error; + + /* Write "value" to I2C data port of OV511 */ + rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); + if (rc < 0) goto error; + + /* Initiate 3-byte write cycle */ + rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x01); + if (rc < 0) goto error; + + return 0; + +error: + err("ov518 i2c write: error %d", rc); + return rc; +} + +/* NOTE: Do not call this function directly! */ +static int +ov511_i2c_write_internal(struct usb_device *dev, + unsigned char reg, + unsigned char value) { int rc, retries; - PDEBUG(5, "i2c write: 0x%02X:0x%02X", reg, value); + PDEBUG(5, "0x%02X:0x%02X", reg, value); /* Three byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); + rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, + reg); if (rc < 0) goto error; /* Write "value" to I2C data port of OV511 */ @@ -566,15 +1021,51 @@ return rc; } -/* returns: negative is error, pos or zero is data */ -static int ov511_i2c_read(struct usb_device *dev, unsigned char reg) +/* NOTE: Do not call this function directly! + * The OV518 I2C I/O procedure is different, hence, this function. + * This is normally only called from ov51x_i2c_read(). Note that this function + * always succeeds regardless of whether the sensor is present and working. + */ +static int +ov518_i2c_read_internal(struct usb_device *dev, unsigned char reg) +{ + int rc, value; + + /* Select camera register */ + rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); + if (rc < 0) goto error; + + /* Initiate 2-byte write cycle */ + rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x03); + if (rc < 0) goto error; + + /* Initiate 2-byte read cycle */ + rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x05); + if (rc < 0) goto error; + + value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); + + PDEBUG(5, "0x%02X:0x%02X", reg, value); + + return value; + +error: + err("ov518 i2c read: error %d", rc); + return rc; +} + +/* NOTE: Do not call this function directly! + * returns: negative is error, pos or zero is data */ +static int +ov511_i2c_read_internal(struct usb_device *dev, unsigned char reg) { int rc, value, retries; /* Two byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); + rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, + reg); if (rc < 0) goto error; /* Initiate 2-byte write cycle */ @@ -624,9 +1115,9 @@ value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); - PDEBUG(5, "i2c read: 0x%02X:0x%02X", reg, value); + PDEBUG(5, "0x%02X:0x%02X", reg, value); - /* This is needed to make ov511_i2c_write() work */ + /* This is needed to make ov51x_i2c_write() work */ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); if (rc < 0) goto error; @@ -638,19 +1129,207 @@ return rc; } -static int ov511_write_regvals(struct usb_device *dev, - struct ov511_regvals * pRegvals) +/* returns: negative is error, pos or zero is data */ +static int +ov51x_i2c_read(struct usb_ov511 *ov511, unsigned char reg) +{ + int rc; + struct usb_device *dev = ov511->dev; + + down(&ov511->i2c_lock); + + if (dev->descriptor.idProduct == PROD_OV518 || + dev->descriptor.idProduct == PROD_OV518PLUS) + rc = ov518_i2c_read_internal(dev, reg); + else + rc = ov511_i2c_read_internal(dev, reg); + + up(&ov511->i2c_lock); + + return rc; +} + +static int +ov51x_i2c_write(struct usb_ov511 *ov511, + unsigned char reg, + unsigned char value) +{ + int rc; + struct usb_device *dev = ov511->dev; + + down(&ov511->i2c_lock); + + if (dev->descriptor.idProduct == PROD_OV518 || + dev->descriptor.idProduct == PROD_OV518PLUS) + rc = ov518_i2c_write_internal(dev, reg, value); + else + rc = ov511_i2c_write_internal(dev, reg, value); + + up(&ov511->i2c_lock); + + return rc; +} + +/* Do not call this function directly! */ +static int +ov51x_i2c_write_mask_internal(struct usb_device *dev, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int rc; + unsigned char oldval, newval; + + if (mask == 0xff) { + newval = value; + } else { + if (dev->descriptor.idProduct == PROD_OV518 || + dev->descriptor.idProduct == PROD_OV518PLUS) + rc = ov518_i2c_read_internal(dev, reg); + else + rc = ov511_i2c_read_internal(dev, reg); + if (rc < 0) + return rc; + + oldval = (unsigned char) rc; + oldval &= (~mask); /* Clear the masked bits */ + value &= mask; /* Enforce mask on value */ + newval = oldval | value; /* Set the desired bits */ + } + + if (dev->descriptor.idProduct == PROD_OV518 || + dev->descriptor.idProduct == PROD_OV518PLUS) + return (ov518_i2c_write_internal(dev, reg, newval)); + else + return (ov511_i2c_write_internal(dev, reg, newval)); +} + +/* Writes bits at positions specified by mask to an I2C reg. Bits that are in + * the same position as 1's in "mask" are cleared and set to "value". Bits + * that are in the same position as 0's in "mask" are preserved, regardless + * of their respective state in "value". + */ +static int +ov51x_i2c_write_mask(struct usb_ov511 *ov511, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int rc; + struct usb_device *dev = ov511->dev; + + down(&ov511->i2c_lock); + rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask); + up(&ov511->i2c_lock); + + return rc; +} + +/* Write to a specific I2C slave ID and register, using the specified mask */ +static int +ov51x_i2c_write_slave(struct usb_ov511 *ov511, + unsigned char slave, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int rc = 0; + struct usb_device *dev = ov511->dev; + + down(&ov511->i2c_lock); + + /* Set new slave IDs */ + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + rc = -EIO; + goto out; + } + + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + rc = -EIO; + goto out; + } + + rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask); + /* Don't bail out yet if error; IDs must be restored */ + + /* Restore primary IDs */ + slave = ov511->primary_i2c_slave; + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + rc = -EIO; + goto out; + } + + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + rc = -EIO; + goto out; + } + +out: + up(&ov511->i2c_lock); + return rc; +} + +/* Read from a specific I2C slave ID and register */ +static int +ov51x_i2c_read_slave(struct usb_ov511 *ov511, + unsigned char slave, + unsigned char reg) +{ + int rc; + struct usb_device *dev = ov511->dev; + + down(&ov511->i2c_lock); + + /* Set new slave IDs */ + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + rc = -EIO; + goto out; + } + + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + rc = -EIO; + goto out; + } + + if (dev->descriptor.idProduct == PROD_OV518 || + dev->descriptor.idProduct == PROD_OV518PLUS) + rc = ov518_i2c_read_internal(dev, reg); + else + rc = ov511_i2c_read_internal(dev, reg); + /* Don't bail out yet if error; IDs must be restored */ + + /* Restore primary IDs */ + slave = ov511->primary_i2c_slave; + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + rc = -EIO; + goto out; + } + + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + rc = -EIO; + goto out; + } + +out: + up(&ov511->i2c_lock); + return rc; +} + +static int +ov511_write_regvals(struct usb_ov511 *ov511, + struct ov511_regvals * pRegvals) { int rc; + struct usb_device *dev = ov511->dev; while (pRegvals->bus != OV511_DONE_BUS) { if (pRegvals->bus == OV511_REG_BUS) { if ((rc = ov511_reg_write(dev, pRegvals->reg, - pRegvals->val)) < 0) + pRegvals->val)) < 0) goto error; } else if (pRegvals->bus == OV511_I2C_BUS) { - if ((rc = ov511_i2c_write(dev, pRegvals->reg, - pRegvals->val)) < 0) + if ((rc = ov51x_i2c_write(ov511, pRegvals->reg, + pRegvals->val)) < 0) goto error; } else { err("Bad regval array"); @@ -667,65 +1346,92 @@ } #ifdef OV511_DEBUG -static void ov511_dump_i2c_range(struct usb_device *dev, int reg1, int regn) +static void +ov511_dump_i2c_range(struct usb_ov511 *ov511, int reg1, int regn) { int i; int rc; - for(i = reg1; i <= regn; i++) { - rc = ov511_i2c_read(dev, i); - PDEBUG(1, "OV7610[0x%X] = 0x%X", i, rc); + for (i = reg1; i <= regn; i++) { + rc = ov51x_i2c_read(ov511, i); + info("OV7610[0x%X] = 0x%X", i, rc); } } -static void ov511_dump_i2c_regs(struct usb_device *dev) +static void +ov51x_dump_i2c_regs(struct usb_ov511 *ov511) { - PDEBUG(3, "I2C REGS"); - ov511_dump_i2c_range(dev, 0x00, 0x7C); + info("I2C REGS"); + ov511_dump_i2c_range(ov511, 0x00, 0x7C); } -#if 0 -static void ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn) +static void +ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn) { int i; int rc; - for(i = reg1; i <= regn; i++) { + for (i = reg1; i <= regn; i++) { rc = ov511_reg_read(dev, i); - PDEBUG(1, "OV511[0x%X] = 0x%X", i, rc); + info("OV511[0x%X] = 0x%X", i, rc); } } -static void ov511_dump_regs(struct usb_device *dev) +static void +ov511_dump_regs(struct usb_device *dev) { - PDEBUG(1, "CAMERA INTERFACE REGS"); + info("CAMERA INTERFACE REGS"); ov511_dump_reg_range(dev, 0x10, 0x1f); - PDEBUG(1, "DRAM INTERFACE REGS"); + info("DRAM INTERFACE REGS"); ov511_dump_reg_range(dev, 0x20, 0x23); - PDEBUG(1, "ISO FIFO REGS"); + info("ISO FIFO REGS"); ov511_dump_reg_range(dev, 0x30, 0x31); - PDEBUG(1, "PIO REGS"); + info("PIO REGS"); ov511_dump_reg_range(dev, 0x38, 0x39); ov511_dump_reg_range(dev, 0x3e, 0x3e); - PDEBUG(1, "I2C REGS"); + info("I2C REGS"); ov511_dump_reg_range(dev, 0x40, 0x49); - PDEBUG(1, "SYSTEM CONTROL REGS"); + info("SYSTEM CONTROL REGS"); ov511_dump_reg_range(dev, 0x50, 0x55); ov511_dump_reg_range(dev, 0x5e, 0x5f); - PDEBUG(1, "OmniCE REGS"); + info("OmniCE REGS"); ov511_dump_reg_range(dev, 0x70, 0x79); + /* NOTE: Quantization tables are not readable. You will get the value + * in reg. 0x79 for every table register */ ov511_dump_reg_range(dev, 0x80, 0x9f); ov511_dump_reg_range(dev, 0xa0, 0xbf); } #endif -#endif -static int ov511_reset(struct usb_device *dev, unsigned char reset_type) +/********************************************************************** + * + * Kernel I2C Interface + * + **********************************************************************/ + +/* For as-yet unimplemented I2C interface */ +static void +call_i2c_clients(struct usb_ov511 *ov511, unsigned int cmd, + void *arg) +{ + /* Do nothing */ +} + +/*****************************************************************************/ + +static int +ov511_reset(struct usb_ov511 *ov511, unsigned char reset_type) { int rc; - + + /* Setting bit 0 not allowed on 518/518Plus */ + if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) + reset_type &= 0xfe; + PDEBUG(4, "Reset: type=0x%X", reset_type); - rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type); - rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0); + + rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, reset_type); + rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0); if (rc < 0) err("reset: command failed"); @@ -735,29 +1441,150 @@ /* Temporarily stops OV511 from functioning. Must do this before changing * registers while the camera is streaming */ -static inline int ov511_stop(struct usb_device *dev) +static inline int +ov511_stop(struct usb_ov511 *ov511) { PDEBUG(4, "stopping"); - return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d)); + ov511->stopped = 1; + if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) + return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, + 0x3a)); + else + return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, + 0x3d)); +} + +/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not + * actually stopped (for performance). */ +static inline int +ov511_restart(struct usb_ov511 *ov511) +{ + if (ov511->stopped) { + PDEBUG(4, "restarting"); + ov511->stopped = 0; + + /* Reinitialize the stream */ + if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) + ov511_reg_write(ov511->dev, 0x2f, 0x80); + + return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, + 0x00)); + } + + return 0; } -/* Restarts OV511 after ov511_stop() is called */ -static inline int ov511_restart(struct usb_device *dev) +/* Resets the hardware snapshot button */ +static void +ov51x_clear_snapshot(struct usb_ov511 *ov511) { - PDEBUG(4, "restarting"); - return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00)); + if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { + ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); + ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03); + ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); + } else if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) { + warn("snapshot reset not supported yet on OV518(+)"); + } else { + err("clear snap: invalid bridge type"); + } + +} + +/* Checks the status of the snapshot button. Returns 1 if it was pressed since + * it was last cleared, and zero in all other cases (including errors) */ +static int +ov51x_check_snapshot(struct usb_ov511 *ov511) +{ + int ret, status = 0; + + if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { + ret = ov511_reg_read(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT); + if (ret < 0) { + err("Error checking snspshot status (%d)", ret); + } else if (ret & 0x08) { + status = 1; + } + } else if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) { + warn("snapshot check not supported yet on OV518(+)"); + } else { + err("check snap: invalid bridge type"); + } + + return status; } -static int ov511_set_packet_size(struct usb_ov511 *ov511, int size) +/* Sets I2C read and write slave IDs. Returns <0 for error */ +static int +ov51x_set_slave_ids(struct usb_ov511 *ov511, + unsigned char write_id, + unsigned char read_id) { - int alt, mult; + struct usb_device *dev = ov511->dev; - if (ov511_stop(ov511->dev) < 0) + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, write_id) < 0) return -EIO; - mult = size >> 5; + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, read_id) < 0) + return -EIO; - if (ov511->bridge == BRG_OV511) { + if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) + return -EIO; + + return 0; +} + +/* This does an initial reset of an OmniVision sensor and ensures that I2C + * is synchronized. Returns <0 for failure. + */ +static int +ov51x_init_ov_sensor(struct usb_ov511 *ov511) +{ + int i, success; + + /* Reset the sensor */ + if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -EIO; + + /* Wait for it to initialize */ + schedule_timeout (1 + 150 * HZ / 1000); + + for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { + if ((ov51x_i2c_read(ov511, OV7610_REG_ID_HIGH) == 0x7F) && + (ov51x_i2c_read(ov511, OV7610_REG_ID_LOW) == 0xA2)) { + success = 1; + continue; + } + + /* Reset the sensor */ + if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -EIO; + /* Wait for it to initialize */ + schedule_timeout(1 + 150 * HZ / 1000); + /* Dummy read to sync I2C */ + if (ov51x_i2c_read(ov511, 0x00) < 0) return -EIO; + } + + if (!success) + return -EIO; + + PDEBUG(1, "I2C synced in %d attempt(s)", i); + + return 0; +} + +static int +ov511_set_packet_size(struct usb_ov511 *ov511, int size) +{ + int alt, mult; + + if (ov511_stop(ov511) < 0) + return -EIO; + + mult = size >> 5; + + if (ov511->bridge == BRG_OV511) { if (size == 0) alt = OV511_ALT_SIZE_0; else if (size == 257) alt = OV511_ALT_SIZE_257; else if (size == 513) alt = OV511_ALT_SIZE_513; @@ -780,6 +1607,20 @@ err("Set packet size: invalid size (%d)", size); return -EINVAL; } + } else if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) { + if (size == 0) alt = OV518_ALT_SIZE_0; + else if (size == 128) alt = OV518_ALT_SIZE_128; + else if (size == 256) alt = OV518_ALT_SIZE_256; + else if (size == 384) alt = OV518_ALT_SIZE_384; + else if (size == 512) alt = OV518_ALT_SIZE_512; + else if (size == 640) alt = OV518_ALT_SIZE_640; + else if (size == 768) alt = OV518_ALT_SIZE_768; + else if (size == 896) alt = OV518_ALT_SIZE_896; + else { + err("Set packet size: invalid size (%d)", size); + return -EINVAL; + } } else { err("Set packet size: Invalid bridge type"); return -EINVAL; @@ -787,351 +1628,1578 @@ PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt); - if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, mult) < 0) - return -ENOMEM; + // FIXME: Don't know how to do this on OV518 yet + if (ov511->bridge != BRG_OV518 && + ov511->bridge != BRG_OV518PLUS) { + if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, + mult) < 0) { + return -EIO; + } + } if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) { err("Set packet size: set interface error"); return -EBUSY; } + /* Initialize the stream */ + if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) + if (ov511_reg_write(ov511->dev, 0x2f, 0x80) < 0) + return -EIO; + // FIXME - Should we only reset the FIFO? - if (ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0) - return -ENOMEM; + if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) + return -EIO; ov511->packet_size = size; - if (ov511_restart(ov511->dev) < 0) + if (ov511_restart(ov511) < 0) return -EIO; return 0; } +/* Upload compression params and quantization tables. Returns 0 for success. */ +static int +ov511_init_compression(struct usb_ov511 *ov511) +{ + struct usb_device *dev = ov511->dev; + int rc = 0; + + if (!ov511->compress_inited) { -static inline int -ov7610_set_picture(struct usb_ov511 *ov511, struct video_picture *p) + ov511_reg_write(dev, 0x70, phy); + ov511_reg_write(dev, 0x71, phuv); + ov511_reg_write(dev, 0x72, pvy); + ov511_reg_write(dev, 0x73, pvuv); + ov511_reg_write(dev, 0x74, qhy); + ov511_reg_write(dev, 0x75, qhuv); + ov511_reg_write(dev, 0x76, qvy); + ov511_reg_write(dev, 0x77, qvuv); + + if (ov511_upload_quan_tables(dev) < 0) { + err("Error uploading quantization tables"); + rc = -EIO; + goto out; + } + } + + ov511->compress_inited = 1; +out: + return rc; +} + +/* Upload compression params and quantization tables. Returns 0 for success. */ +static int +ov518_init_compression(struct usb_ov511 *ov511) { - int ret; struct usb_device *dev = ov511->dev; + int rc = 0; - PDEBUG(4, "ov511_set_picture"); + if (!ov511->compress_inited) { - if (ov511_stop(dev) < 0) - return -EIO; + if (ov518_upload_quan_tables(dev) < 0) { + err("Error uploading quantization tables"); + rc = -EIO; + goto out; + } + } - ov511->contrast = p->contrast; - ov511->brightness = p->brightness; - ov511->colour = p->colour; - ov511->hue = p->hue; - ov511->whiteness = p->whiteness; + ov511->compress_inited = 1; +out: + return rc; +} - if ((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0) - return -EIO; -#if 0 - /* disable auto adjust mode */ - if (ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0) - return -EIO; -#endif - if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE - || ov511->sensor == SEN_OV6620) - if (ov511_i2c_write(dev, OV7610_REG_SAT, p->colour >> 8) < 0) - return -EIO; +/* -------------------------------------------------------------------------- */ - if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV6620) { - if (ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0) - return -EIO; +/* Sets sensor's contrast setting to "val" */ +static int +sensor_set_contrast(struct usb_ov511 *ov511, unsigned short val) +{ + int rc; - if (ov511_i2c_write(dev, OV7610_REG_RED, 0xFF - (p->hue >> 8)) < 0) - return -EIO; + PDEBUG(3, "%d", val); - if (ov511_i2c_write(dev, OV7610_REG_BLUE, p->hue >> 8) < 0) + if (ov511->stop_during_set) + if (ov511_stop(ov511) < 0) return -EIO; - if (ov511_i2c_write(dev, OV7610_REG_BRT, p->brightness >> 8) < 0) - return -EIO; - } else if ((ov511->sensor == SEN_OV7620) - || (ov511->sensor == SEN_OV7620AE)) { -#if 0 - int cur_sat, new_sat, tmp; + switch (ov511->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + { + rc = ov51x_i2c_write(ov511, OV7610_REG_CNT, val >> 8); + if (rc < 0) + goto out; + break; + } + case SEN_OV7620: + { + unsigned char ctab[] = { + 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, + 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff + }; + + /* Use Y gamma control instead. Bit 0 enables it. */ + rc = ov51x_i2c_write(ov511, 0x64, ctab[val>>12]); + if (rc < 0) + goto out; + break; + } + case SEN_SAA7111A: + { + rc = ov51x_i2c_write(ov511, 0x0b, val >> 9); + if (rc < 0) + goto out; + break; + } + default: + { + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } + } - cur_sat = ov511_i2c_read(dev, OV7610_REG_BLUE); + rc = 0; /* Success */ + ov511->contrast = val; +out: + if (ov511_restart(ov511) < 0) + return -EIO; - tmp = (p->hue >> 8) - cur_sat; - new_sat = (tmp < 0) ? (-tmp) | 0x80 : tmp; + return rc; +} - PDEBUG(1, "cur=%d target=%d diff=%d", cur_sat, p->hue >> 8, tmp); +/* Gets sensor's contrast setting */ +static int +sensor_get_contrast(struct usb_ov511 *ov511, unsigned short *val) +{ + int rc; - if (ov511_i2c_write(dev, OV7610_REG_BLUE, new_sat) < 0) - return -EIO; + switch (ov511->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + rc = ov51x_i2c_read(ov511, OV7610_REG_CNT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_OV7620: + /* Use Y gamma reg instead. Bit 0 is the enable bit. */ + rc = ov51x_i2c_read(ov511, 0x64); + if (rc < 0) + return rc; + else + *val = (rc & 0xfe) << 8; + break; + case SEN_SAA7111A: + *val = ov511->contrast; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } - // DEBUG_CODE - PDEBUG(1, "hue=%d", ov511_i2c_read(dev, OV7610_REG_BLUE)); + PDEBUG(3, "%d", *val); + ov511->contrast = *val; -#endif + return 0; +} + +/* -------------------------------------------------------------------------- */ + +/* Sets sensor's brightness setting to "val" */ +static int +sensor_set_brightness(struct usb_ov511 *ov511, unsigned short val) +{ + int rc; + + PDEBUG(4, "%d", val); + + if (ov511->stop_during_set) + if (ov511_stop(ov511) < 0) + return -EIO; + + switch (ov511->sensor) { + case SEN_OV7610: + case SEN_OV7620AE: + case SEN_OV6620: + case SEN_OV6630: + rc = ov51x_i2c_write(ov511, OV7610_REG_BRT, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_OV7620: + /* 7620 doesn't like manual changes when in auto mode */ + if (!ov511->auto_brt) { + rc = ov51x_i2c_write(ov511, OV7610_REG_BRT, val >> 8); + if (rc < 0) + goto out; + } + break; + case SEN_SAA7111A: + rc = ov51x_i2c_write(ov511, 0x0a, val >> 8); + if (rc < 0) + goto out; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; } - if (ov511_restart(dev) < 0) + rc = 0; /* Success */ + ov511->brightness = val; +out: + if (ov511_restart(ov511) < 0) return -EIO; + return rc; +} + +/* Gets sensor's brightness setting */ +static int +sensor_get_brightness(struct usb_ov511 *ov511, unsigned short *val) +{ + int rc; + + switch (ov511->sensor) { + case SEN_OV7610: + case SEN_OV7620AE: + case SEN_OV7620: + case SEN_OV6620: + case SEN_OV6630: + rc = ov51x_i2c_read(ov511, OV7610_REG_BRT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_SAA7111A: + *val = ov511->brightness; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov511->brightness = *val; + return 0; } -static inline int -ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p) +/* -------------------------------------------------------------------------- */ + +/* Sets sensor's saturation (color intensity) setting to "val" */ +static int +sensor_set_saturation(struct usb_ov511 *ov511, unsigned short val) { - int ret; - struct usb_device *dev = ov511->dev; + int rc; - PDEBUG(4, "ov511_get_picture"); + PDEBUG(3, "%d", val); + + if (ov511->stop_during_set) + if (ov511_stop(ov511) < 0) + return -EIO; + + switch (ov511->sensor) { + case SEN_OV7610: + case SEN_OV7620AE: + case SEN_OV6620: + case SEN_OV6630: + rc = ov51x_i2c_write(ov511, OV7610_REG_SAT, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_OV7620: +// /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ +// rc = ov511_i2c_write(ov511->dev, 0x62, (val >> 9) & 0x7e); +// if (rc < 0) +// goto out; + rc = ov51x_i2c_write(ov511, OV7610_REG_SAT, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_SAA7111A: + rc = ov51x_i2c_write(ov511, 0x0c, val >> 9); + if (rc < 0) + goto out; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } - if (ov511_stop(dev) < 0) + rc = 0; /* Success */ + ov511->colour = val; +out: + if (ov511_restart(ov511) < 0) return -EIO; - if ((ret = ov511_i2c_read(dev, OV7610_REG_SAT)) < 0) return -EIO; - p->colour = ret << 8; + return rc; +} + +/* Gets sensor's saturation (color intensity) setting */ +static int +sensor_get_saturation(struct usb_ov511 *ov511, unsigned short *val) +{ + int rc; + + switch (ov511->sensor) { + case SEN_OV7610: + case SEN_OV7620AE: + case SEN_OV6620: + case SEN_OV6630: + rc = ov51x_i2c_read(ov511, OV7610_REG_SAT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_OV7620: +// /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */ +// rc = ov51x_i2c_read(ov511, 0x62); +// if (rc < 0) +// return rc; +// else +// *val = (rc & 0x7e) << 9; + rc = ov51x_i2c_read(ov511, OV7610_REG_SAT); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_SAA7111A: + *val = ov511->colour; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov511->colour = *val; - if ((ret = ov511_i2c_read(dev, OV7610_REG_CNT)) < 0) return -EIO; - p->contrast = ret << 8; + return 0; +} - if ((ret = ov511_i2c_read(dev, OV7610_REG_BRT)) < 0) return -EIO; - p->brightness = ret << 8; +/* -------------------------------------------------------------------------- */ - /* This may not be the best way to do it */ - if ((ret = ov511_i2c_read(dev, OV7610_REG_BLUE)) < 0) return -EIO; - p->hue = ret << 8; +/* Sets sensor's hue (red/blue balance) setting to "val" */ +static int +sensor_set_hue(struct usb_ov511 *ov511, unsigned short val) +{ + int rc; - p->whiteness = 105 << 8; + PDEBUG(3, "%d", val); - /* Can we get these from frame[0]? -claudio? */ - p->depth = ov511->frame[0].depth; - p->palette = ov511->frame[0].format; + if (ov511->stop_during_set) + if (ov511_stop(ov511) < 0) + return -EIO; + + switch (ov511->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + rc = ov51x_i2c_write(ov511, OV7610_REG_RED, 0xFF - (val >> 8)); + if (rc < 0) + goto out; + + rc = ov51x_i2c_write(ov511, OV7610_REG_BLUE, val >> 8); + if (rc < 0) + goto out; + break; + case SEN_OV7620: +// Hue control is causing problems. I will enable it once it's fixed. +#if 0 + rc = ov51x_i2c_write(ov511, 0x7a, + (unsigned char)(val >> 8) + 0xb); + if (rc < 0) + goto out; + + rc = ov51x_i2c_write(ov511, 0x79, + (unsigned char)(val >> 8) + 0xb); + if (rc < 0) + goto out; +#endif + break; + case SEN_SAA7111A: + rc = ov51x_i2c_write(ov511, 0x0d, (val + 32768) >> 8); + if (rc < 0) + goto out; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + rc = -EPERM; + goto out; + } - if (ov511_restart(dev) < 0) + rc = 0; /* Success */ + ov511->hue = val; +out: + if (ov511_restart(ov511) < 0) return -EIO; + return rc; +} + +/* Gets sensor's hue (red/blue balance) setting */ +static int +sensor_get_hue(struct usb_ov511 *ov511, unsigned short *val) +{ + int rc; + + switch (ov511->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + rc = ov51x_i2c_read(ov511, OV7610_REG_BLUE); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_OV7620: + rc = ov51x_i2c_read(ov511, 0x7a); + if (rc < 0) + return rc; + else + *val = rc << 8; + break; + case SEN_SAA7111A: + *val = ov511->hue; + break; + default: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + } + + PDEBUG(3, "%d", *val); + ov511->hue = *val; + return 0; } -/* Returns number of bits per pixel (regardless of where they are located; planar or - * not), or zero for unsupported format. - */ -static int ov511_get_depth(int palette) +/* -------------------------------------------------------------------------- */ + +static inline int +sensor_set_picture(struct usb_ov511 *ov511, struct video_picture *p) { - switch (palette) { - case VIDEO_PALETTE_GREY: return 8; - case VIDEO_PALETTE_RGB565: return 16; - case VIDEO_PALETTE_RGB24: return 24; - case VIDEO_PALETTE_YUV422: return 16; - case VIDEO_PALETTE_YUYV: return 16; - case VIDEO_PALETTE_YUV420: return 24; - case VIDEO_PALETTE_YUV422P: return 24; /* Planar */ - default: return 0; /* Invalid format */ + int rc; + + PDEBUG(4, "sensor_set_picture"); + + ov511->whiteness = p->whiteness; + + /* Don't return error if a setting is unsupported, or rest of settings + * will not be performed */ + + rc = sensor_set_contrast(ov511, p->contrast); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_brightness(ov511, p->brightness); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_saturation(ov511, p->colour); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_set_hue(ov511, p->hue); + if (FATAL_ERROR(rc)) + return rc; + + return 0; +} + +static inline int +sensor_get_picture(struct usb_ov511 *ov511, struct video_picture *p) +{ + int rc; + + PDEBUG(4, "sensor_get_picture"); + + /* Don't return error if a setting is unsupported, or rest of settings + * will not be performed */ + + rc = sensor_get_contrast(ov511, &(p->contrast)); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_get_brightness(ov511, &(p->brightness)); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_get_saturation(ov511, &(p->colour)); + if (FATAL_ERROR(rc)) + return rc; + + rc = sensor_get_hue(ov511, &(p->hue)); + if (FATAL_ERROR(rc)) + return rc; + + p->whiteness = 105 << 8; + + /* Can we get these from frame[0]? -claudio? */ + p->depth = ov511->frame[0].depth; + p->palette = ov511->frame[0].format; + + return 0; +} + +// FIXME: Exposure range is only 0x00-0x7f in interlace mode +/* Sets current exposure for sensor. This only has an effect if auto-exposure + * is off */ +static inline int +sensor_set_exposure(struct usb_ov511 *ov511, unsigned char val) +{ + int rc; + + PDEBUG(3, "%d", val); + + if (ov511->stop_during_set) + if (ov511_stop(ov511) < 0) + return -EIO; + + switch (ov511->sensor) { + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7610: + case SEN_OV7620: + case SEN_OV7620AE: + case SEN_OV8600: + rc = ov51x_i2c_write(ov511, 0x10, val); + if (rc < 0) + goto out; + + break; + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_exposure"); + return -EINVAL; + } + + rc = 0; /* Success */ + ov511->exposure = val; +out: + if (ov511_restart(ov511) < 0) + return -EIO; + + return rc; +} + +/* Gets current exposure level from sensor, regardless of whether it is under + * manual control. */ +static int +sensor_get_exposure(struct usb_ov511 *ov511, unsigned char *val) +{ + int rc; + + switch (ov511->sensor) { + case SEN_OV7610: + case SEN_OV6620: + case SEN_OV6630: + case SEN_OV7620: + case SEN_OV7620AE: + case SEN_OV8600: + rc = ov51x_i2c_read(ov511, 0x10); + if (rc < 0) + return rc; + else + *val = rc; + break; + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + val = 0; + PDEBUG(3, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for get_exposure"); + return -EINVAL; + } + + PDEBUG(3, "%d", *val); + ov511->exposure = *val; + + return 0; +} + +/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ +static inline void +ov51x_led_control(struct usb_ov511 *ov511, int enable) +{ + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + if (ov511->bridge == BRG_OV511PLUS) + ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_LED_CTL, + enable ? 1 : 0); + else if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) + ov511_reg_write_mask(ov511->dev, OV518_REG_GPIO_OUT, + enable ? 0x02 : 0x00, 0x02); + return; +} + +/* Matches the sensor's internal frame rate to the lighting frequency. + * Valid frequencies are: + * 50 - 50Hz, for European and Asian lighting + * 60 - 60Hz, for American lighting + * + * Tested with: OV7610, OV7620, OV7620AE, OV6620 + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_light_freq(struct usb_ov511 *ov511, int freq) +{ + int sixty; + + PDEBUG(4, "%d Hz", freq); + + if (freq == 60) + sixty = 1; + else if (freq == 50) + sixty = 0; + else { + err("Invalid light freq (%d Hz)", freq); + return -EINVAL; + } + + switch (ov511->sensor) { + case SEN_OV7610: + ov51x_i2c_write_mask(ov511, 0x2a, sixty?0x00:0x80, 0x80); + ov51x_i2c_write(ov511, 0x2b, sixty?0x00:0xac); + ov51x_i2c_write_mask(ov511, 0x13, 0x10, 0x10); + ov51x_i2c_write_mask(ov511, 0x13, 0x00, 0x10); + break; + case SEN_OV7620: + case SEN_OV7620AE: + case SEN_OV8600: + ov51x_i2c_write_mask(ov511, 0x2a, sixty?0x00:0x80, 0x80); + ov51x_i2c_write(ov511, 0x2b, sixty?0x00:0xac); + ov51x_i2c_write_mask(ov511, 0x76, 0x01, 0x01); + break; + case SEN_OV6620: + case SEN_OV6630: + ov51x_i2c_write(ov511, 0x2b, sixty?0xa8:0x28); + ov51x_i2c_write(ov511, 0x2a, sixty?0x84:0xa4); + break; + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_light_freq"); + return -EINVAL; + } + + ov511->lightfreq = freq; + + return 0; +} + +/* If enable is true, turn on the sensor's banding filter, otherwise turn it + * off. This filter tries to reduce the pattern of horizontal light/dark bands + * caused by some (usually fluorescent) lighting. The light frequency must be + * set either before or after enabling it with ov51x_set_light_freq(). + * + * Tested with: OV7610, OV7620, OV7620AE, OV6620. + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static inline int +sensor_set_banding_filter(struct usb_ov511 *ov511, int enable) +{ + int rc; + + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + if (ov511->sensor == SEN_KS0127 || ov511->sensor == SEN_KS0127B + || ov511->sensor == SEN_SAA7111A) { + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + } + + rc = ov51x_i2c_write_mask(ov511, 0x2d, enable?0x04:0x00, 0x04); + if (rc < 0) + return rc; + + ov511->bandfilt = enable; + + return 0; +} + +/* If enable is true, turn on the sensor's auto brightness control, otherwise + * turn it off. + * + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static inline int +sensor_set_auto_brightness(struct usb_ov511 *ov511, int enable) +{ + int rc; + + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + if (ov511->sensor == SEN_KS0127 || ov511->sensor == SEN_KS0127B + || ov511->sensor == SEN_SAA7111A) { + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + } + + rc = ov51x_i2c_write_mask(ov511, 0x2d, enable?0x10:0x00, 0x10); + if (rc < 0) + return rc; + + ov511->auto_brt = enable; + + return 0; +} + +/* If enable is true, turn on the sensor's auto exposure control, otherwise + * turn it off. + * + * Unsupported: KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static inline int +sensor_set_auto_exposure(struct usb_ov511 *ov511, int enable) +{ + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + switch (ov511->sensor) { + case SEN_OV7610: + ov51x_i2c_write_mask(ov511, 0x29, enable?0x00:0x80, 0x80); + break; + case SEN_OV6620: + case SEN_OV7620: + case SEN_OV7620AE: + case SEN_OV8600: + ov51x_i2c_write_mask(ov511, 0x13, enable?0x01:0x00, 0x01); + break; + case SEN_OV6630: + ov51x_i2c_write_mask(ov511, 0x28, enable?0x00:0x10, 0x10); + break; + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_auto_exposure"); + return -EINVAL; + } + + ov511->auto_exp = enable; + + return 0; +} + +/* Modifies the sensor's exposure algorithm to allow proper exposure of objects + * that are illuminated from behind. + * + * Tested with: OV6620, OV7620 + * Unsupported: OV7610, OV7620AE, KS0127, KS0127B, SAA7111A + * Returns: 0 for success + */ +static int +sensor_set_backlight(struct usb_ov511 *ov511, int enable) +{ + + PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); + + switch (ov511->sensor) { + case SEN_OV7620: + case SEN_OV8600: + ov51x_i2c_write_mask(ov511, 0x68, enable?0xe0:0xc0, 0xe0); + ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); + ov51x_i2c_write_mask(ov511, 0x28, enable?0x02:0x00, 0x02); + break; + case SEN_OV6620: + ov51x_i2c_write_mask(ov511, 0x4e, enable?0xe0:0xc0, 0xe0); + ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); + ov51x_i2c_write_mask(ov511, 0x0e, enable?0x80:0x00, 0x80); + break; + case SEN_OV6630: + ov51x_i2c_write_mask(ov511, 0x4e, enable?0x80:0x60, 0xe0); + ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); + ov51x_i2c_write_mask(ov511, 0x28, enable?0x02:0x00, 0x02); + break; + case SEN_OV7610: + case SEN_OV7620AE: + case SEN_KS0127: + case SEN_KS0127B: + case SEN_SAA7111A: + PDEBUG(5, "Unsupported with this sensor"); + return -EPERM; + default: + err("Sensor not supported for set_backlight"); + return -EINVAL; + } + + ov511->backlight = enable; + + return 0; +} + +/* Returns number of bits per pixel (regardless of where they are located; + * planar or not), or zero for unsupported format. + */ +static inline int +ov511_get_depth(int palette) +{ + switch (palette) { + case VIDEO_PALETTE_GREY: return 8; + case VIDEO_PALETTE_RGB565: return 16; + case VIDEO_PALETTE_RGB24: return 24; + case VIDEO_PALETTE_YUV422: return 16; + case VIDEO_PALETTE_YUYV: return 16; + case VIDEO_PALETTE_YUV420: return 12; + case VIDEO_PALETTE_YUV422P: return 16; /* Planar */ + case VIDEO_PALETTE_YUV420P: return 12; /* Planar */ + default: return 0; /* Invalid format */ + } +} + +/* Bytes per frame. Used by read(). Return of 0 indicates error */ +static inline long int +get_frame_length(struct ov511_frame *frame) +{ + if (!frame) + return 0; + else + return ((frame->width * frame->height + * ov511_get_depth(frame->format)) >> 3); +} + +static int +mode_init_ov_sensor_regs(struct usb_ov511 *ov511, int width, int height, + int mode, int sub_flag, int qvga) +{ + int clock; + + /******** Mode (VGA/QVGA) and sensor specific regs ********/ + + switch (ov511->sensor) { + case SEN_OV7610: + ov51x_i2c_write(ov511, 0x14, qvga?0x24:0x04); +// FIXME: Does this improve the image quality or frame rate? +#if 0 + ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); + ov51x_i2c_write(ov511, 0x24, 0x10); + ov51x_i2c_write(ov511, 0x25, qvga?0x40:0x8a); + ov51x_i2c_write(ov511, 0x2f, qvga?0x30:0xb0); + ov51x_i2c_write(ov511, 0x35, qvga?0x1c:0x9c); +#endif + break; + case SEN_OV7620: +// ov51x_i2c_write(ov511, 0x2b, 0x00); + ov51x_i2c_write(ov511, 0x14, qvga?0xa4:0x84); + ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); + ov51x_i2c_write(ov511, 0x24, qvga?0x20:0x3a); + ov51x_i2c_write(ov511, 0x25, qvga?0x30:0x60); + ov51x_i2c_write_mask(ov511, 0x2d, qvga?0x40:0x00, 0x40); + ov51x_i2c_write_mask(ov511, 0x67, qvga?0xf0:0x90, 0xf0); + ov51x_i2c_write_mask(ov511, 0x74, qvga?0x20:0x00, 0x20); + break; + case SEN_OV7620AE: +// ov51x_i2c_write(ov511, 0x2b, 0x00); + ov51x_i2c_write(ov511, 0x14, qvga?0xa4:0x84); +// FIXME: Enable this once 7620AE uses 7620 initial settings +#if 0 + ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); + ov51x_i2c_write(ov511, 0x24, qvga?0x20:0x3a); + ov51x_i2c_write(ov511, 0x25, qvga?0x30:0x60); + ov51x_i2c_write_mask(ov511, 0x2d, qvga?0x40:0x00, 0x40); + ov51x_i2c_write_mask(ov511, 0x67, qvga?0xb0:0x90, 0xf0); + ov51x_i2c_write_mask(ov511, 0x74, qvga?0x20:0x00, 0x20); +#endif + break; + case SEN_OV6620: + case SEN_OV6630: + ov51x_i2c_write(ov511, 0x14, qvga?0x24:0x04); + /* No special settings yet */ + break; + default: + err("Invalid sensor"); + return -EINVAL; + } + + /******** Palette-specific regs ********/ + + if (mode == VIDEO_PALETTE_GREY) { + if (ov511->sensor == SEN_OV7610 + || ov511->sensor == SEN_OV7620AE) { + /* these aren't valid on the OV6620/OV7620/6630? */ + ov51x_i2c_write_mask(ov511, 0x0e, 0x40, 0x40); + } + ov51x_i2c_write_mask(ov511, 0x13, 0x20, 0x20); + } else { + if (ov511->sensor == SEN_OV7610 + || ov511->sensor == SEN_OV7620AE) { + /* not valid on the OV6620/OV7620/6630? */ + ov51x_i2c_write_mask(ov511, 0x0e, 0x00, 0x40); + } + ov51x_i2c_write_mask(ov511, 0x13, 0x00, 0x20); + } + + /******** Clock programming ********/ + + // FIXME: Test this with OV6630 + + /* The OV6620 needs special handling. This prevents the + * severe banding that normally occurs */ + if (ov511->sensor == SEN_OV6620 || ov511->sensor == SEN_OV6630) + { + /* Clock down */ + + ov51x_i2c_write(ov511, 0x2a, 0x04); + + if (ov511->compress) { +// clock = 0; /* This ensures the highest frame rate */ + clock = 3; + } else if (clockdiv == -1) { /* If user didn't override it */ + clock = 3; /* Gives better exposure time */ + } else { + clock = clockdiv; + } + + PDEBUG(4, "Setting clock divisor to %d", clock); + + ov51x_i2c_write(ov511, 0x11, clock); + + ov51x_i2c_write(ov511, 0x2a, 0x84); + /* This next setting is critical. It seems to improve + * the gain or the contrast. The "reserved" bits seem + * to have some effect in this case. */ + ov51x_i2c_write(ov511, 0x2d, 0x85); + } + else + { + if (ov511->compress) { + clock = 1; /* This ensures the highest frame rate */ + } else if (clockdiv == -1) { /* If user didn't override it */ + /* Calculate and set the clock divisor */ + clock = ((sub_flag ? ov511->subw * ov511->subh + : width * height) + * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2) + / 66000; + } else { + clock = clockdiv; + } + + PDEBUG(4, "Setting clock divisor to %d", clock); + + ov51x_i2c_write(ov511, 0x11, clock); + } + + /******** Special Features ********/ + + if (framedrop >= 0) + ov51x_i2c_write(ov511, 0x16, framedrop); + + /* We only have code to convert GBR -> RGB24 */ + if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr) + ov51x_i2c_write_mask(ov511, 0x12, 0x08, 0x08); + else + ov51x_i2c_write_mask(ov511, 0x12, 0x00, 0x08); + + /* Test Pattern */ + ov51x_i2c_write_mask(ov511, 0x12, (testpat?0x02:0x00), 0x02); + + /* Auto white balance */ +// if (awb) + ov51x_i2c_write_mask(ov511, 0x12, 0x04, 0x04); +// else +// ov51x_i2c_write_mask(ov511, 0x12, 0x00, 0x04); + + // This will go away as soon as ov511_mode_init_sensor_regs() + // is fully tested. + /* 7620/6620/6630? don't have register 0x35, so play it safe */ + if (ov511->sensor == SEN_OV7610 || + ov511->sensor == SEN_OV7620AE) { + if (width == 640 && height == 480) + ov51x_i2c_write(ov511, 0x35, 0x9e); + else + ov51x_i2c_write(ov511, 0x35, 0x1e); + } + + return 0; +} + +static int +set_ov_sensor_window(struct usb_ov511 *ov511, int width, int height, int mode, + int sub_flag) +{ + int ret; + int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; + int hoffset, voffset, hwscale = 0, vwscale = 0; + + /* The different sensor ICs handle setting up of window differently. + * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */ + switch (ov511->sensor) { + case SEN_OV7610: + case SEN_OV7620AE: + hwsbase = 0x38; + hwebase = 0x3a; + vwsbase = vwebase = 0x05; + break; + case SEN_OV6620: + case SEN_OV6630: // FIXME: Is this right? + hwsbase = 0x38; + hwebase = 0x3a; + vwsbase = 0x05; + vwebase = 0x06; + break; + case SEN_OV7620: + hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ + hwebase = 0x2f; + vwsbase = vwebase = 0x05; + break; + default: + err("Invalid sensor"); + return -EINVAL; + } + + if (ov511->sensor == SEN_OV6620 || ov511->sensor == SEN_OV6630) { + if (width > 176 && height > 144) { /* CIF */ + ret = mode_init_ov_sensor_regs(ov511, width, height, + mode, sub_flag, 0); + if (ret < 0) + return ret; + hwscale = 1; + vwscale = 1; /* The datasheet says 0; it's wrong */ + hwsize = 352; + vwsize = 288; + } else if (width > 176 || height > 144) { + err("Illegal dimensions"); + return -EINVAL; + } else { /* QCIF */ + ret = mode_init_ov_sensor_regs(ov511, width, height, + mode, sub_flag, 1); + if (ret < 0) + return ret; + hwsize = 176; + vwsize = 144; + } + } else { + if (width > 320 && height > 240) { /* VGA */ + ret = mode_init_ov_sensor_regs(ov511, width, height, + mode, sub_flag, 0); + if (ret < 0) + return ret; + hwscale = 2; + vwscale = 1; + hwsize = 640; + vwsize = 480; + } else if (width > 320 || height > 240) { + err("Illegal dimensions"); + return -EINVAL; + } else { /* QVGA */ + ret = mode_init_ov_sensor_regs(ov511, width, height, + mode, sub_flag, 1); + if (ret < 0) + return ret; + hwscale = 1; + hwsize = 320; + vwsize = 240; + } + } + + /* Center the window */ + hoffset = ((hwsize - width) / 2) >> hwscale; + voffset = ((vwsize - height) / 2) >> vwscale; + + /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ + if (sub_flag) { + ov51x_i2c_write(ov511, 0x17, hwsbase+(ov511->subx>>hwscale)); + ov51x_i2c_write(ov511, 0x18, + hwebase+((ov511->subx+ov511->subw)>>hwscale)); + ov51x_i2c_write(ov511, 0x19, vwsbase+(ov511->suby>>vwscale)); + ov51x_i2c_write(ov511, 0x1a, + vwebase+((ov511->suby+ov511->subh)>>vwscale)); + } else { + ov51x_i2c_write(ov511, 0x17, hwsbase + hoffset); + ov51x_i2c_write(ov511, 0x18, + hwebase + hoffset + (hwsize>>hwscale)); + ov51x_i2c_write(ov511, 0x19, vwsbase + voffset); + ov51x_i2c_write(ov511, 0x1a, + vwebase + voffset + (vwsize>>vwscale)); + } + +#ifdef OV511_DEBUG + if (dump_sensor) + ov51x_dump_i2c_regs(ov511); +#endif + + return 0; +} + +/* Set up the OV511/OV511+ with the given image parameters. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ +static int +ov511_mode_init_regs(struct usb_ov511 *ov511, + int width, int height, int mode, int sub_flag) +{ + int lncnt, pxcnt, rc = 0; + struct usb_device *dev = ov511->dev; + + if (!ov511 || !dev) + return -EFAULT; + + if (sub_flag) { + width = ov511->subw; + height = ov511->subh; + } + + PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", + width, height, mode, sub_flag); + + // FIXME: This should be moved to a 7111a-specific function once + // subcapture is dealt with properly + if (ov511->sensor == SEN_SAA7111A) { + if (width == 320 && height == 240) { + /* No need to do anything special */ + } else if (width == 640 && height == 480) { + /* Set the OV511 up as 320x480, but keep the V4L + * resolution as 640x480 */ + width = 320; + } else { + err("SAA7111A only supports 320x240 or 640x480"); + return -EINVAL; + } + } + + /* Make sure width and height are a multiple of 8 */ + if (width % 8 || height % 8) { + err("Invalid size (%d, %d) (mode = %d)", width, height, mode); + return -EINVAL; + } + + if (width < ov511->minwidth || height < ov511->minheight) { + err("Requested dimensions are too small"); + return -EINVAL; + } + + if (ov511_stop(ov511) < 0) + return -EIO; + + if (mode == VIDEO_PALETTE_GREY) { + ov511_reg_write(dev, 0x16, 0x00); + + /* For snapshot */ + ov511_reg_write(dev, 0x1e, 0x00); + ov511_reg_write(dev, 0x1f, 0x01); + } else { + ov511_reg_write(dev, 0x16, 0x01); + + /* For snapshot */ + ov511_reg_write(dev, 0x1e, 0x01); + ov511_reg_write(dev, 0x1f, 0x03); + } + + /* Here I'm assuming that snapshot size == image size. + * I hope that's always true. --claudio + */ + pxcnt = (width >> 3) - 1; + lncnt = (height >> 3) - 1; + + ov511_reg_write(dev, 0x12, pxcnt); + ov511_reg_write(dev, 0x13, lncnt); + ov511_reg_write(dev, 0x14, 0x00); + ov511_reg_write(dev, 0x15, 0x00); + ov511_reg_write(dev, 0x18, 0x03); /* YUV420, low pass filer on */ + + /* Snapshot additions */ + ov511_reg_write(dev, 0x1a, pxcnt); + ov511_reg_write(dev, 0x1b, lncnt); + ov511_reg_write(dev, 0x1c, 0x00); + ov511_reg_write(dev, 0x1d, 0x00); + + if (ov511->compress) { + ov511_reg_write(dev, 0x78, 0x07); // Turn on Y & UV compression + ov511_reg_write(dev, 0x79, 0x03); // Enable LUTs + ov511_reset(ov511, OV511_RESET_OMNICE); } +//out: + if (ov511_restart(ov511) < 0) + return -EIO; + + return rc; } -/* LNCNT values fixed by Lawrence Glaister <lg@jfm.bc.ca> */ -static struct mode_list mlist[] = { - /* W H C PXCNT LNCNT PXDIV LNDIV M420 COMA COML */ - { 640, 480, 0, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x9e }, - { 640, 480, 1, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x9e }, - { 320, 240, 0, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 320, 240, 1, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 352, 288, 0, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 352, 288, 1, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 384, 288, 0, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 384, 288, 1, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 448, 336, 0, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 448, 336, 1, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 176, 144, 0, 0x15, 0x12, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 176, 144, 1, 0x15, 0x12, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 160, 120, 0, 0x13, 0x0e, 0x00, 0x00, 0x03, 0x04, 0x1e }, - { 160, 120, 1, 0x13, 0x0e, 0x00, 0x00, 0x03, 0x04, 0x1e }, +static struct mode_list_518 mlist518[] = { + /* W H reg28 reg29 reg2a reg2c reg2e reg24 reg25 */ + { 352, 288, 0x00, 0x16, 0x48, 0x00, 0x00, 0x9f, 0x90 }, + { 320, 240, 0x00, 0x14, 0x3c, 0x10, 0x18, 0x9f, 0x90 }, + { 176, 144, 0x05, 0x0b, 0x24, 0x00, 0x00, 0xff, 0xf0 }, + { 160, 120, 0x05, 0x0a, 0x1e, 0x08, 0x0c, 0xff, 0xf0 }, { 0, 0 } }; +/* Sets up the OV518/OV518+ with the given image parameters + * + * OV518 needs a completely different approach, until we can figure out what + * the individual registers do. Many register ops are commented out until we + * can find out if they are still valid. Also, only 15 FPS is supported now. + * + * Do not put any sensor-specific code in here (including I2C I/O functions) + */ static int -ov511_mode_init_regs(struct usb_ov511 *ov511, +ov518_mode_init_regs(struct usb_ov511 *ov511, int width, int height, int mode, int sub_flag) { int i; struct usb_device *dev = ov511->dev; - int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; - int hwscale = 0, vwscale = 0; + unsigned char b[3]; /* Multiple-value reg buffer */ PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", width, height, mode, sub_flag); - if (ov511_stop(ov511->dev) < 0) + if (ov511_stop(ov511) < 0) + return -EIO; + + for (i = 0; mlist518[i].width; i++) { +// int lncnt, pxcnt; + + if (width != mlist518[i].width || height != mlist518[i].height) + continue; + +// FIXME: Subcapture won't be possible until we know what the registers do +// FIXME: We can't handle anything but YUV420 so far + +// /* Here I'm assuming that snapshot size == image size. +// * I hope that's always true. --claudio +// */ +// pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt; +// lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt; +// +// ov511_reg_write(dev, 0x12, pxcnt); +// ov511_reg_write(dev, 0x13, lncnt); + + /******** Set the mode ********/ + + /* Mode independent regs */ + ov511_reg_write(dev, 0x2b, 0x00); + ov511_reg_write(dev, 0x2d, 0x00); + ov511_reg_write(dev, 0x3b, 0x00); + ov511_reg_write(dev, 0x3d, 0x00); + + /* Mode dependent regs. Regs 38 - 3e are always the same as + * regs 28 - 2e */ + ov511_reg_write_mask(dev, 0x28, mlist518[i].reg28 + | (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f); + ov511_reg_write(dev, 0x29, mlist518[i].reg29); + ov511_reg_write(dev, 0x2a, mlist518[i].reg2a); + ov511_reg_write(dev, 0x2c, mlist518[i].reg2c); + ov511_reg_write(dev, 0x2e, mlist518[i].reg2e); + ov511_reg_write_mask(dev, 0x38, mlist518[i].reg28 + | (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f); + ov511_reg_write(dev, 0x39, mlist518[i].reg29); + ov511_reg_write(dev, 0x3a, mlist518[i].reg2a); + ov511_reg_write(dev, 0x3c, mlist518[i].reg2c); + ov511_reg_write(dev, 0x3e, mlist518[i].reg2e); + ov511_reg_write(dev, 0x24, mlist518[i].reg24); + ov511_reg_write(dev, 0x25, mlist518[i].reg25); + + /* Windows driver does this here; who knows why */ + ov511_reg_write(dev, 0x2f, 0x80); + + /******** Set the framerate (to 15 FPS) ********/ + + /* Mode independent, but framerate dependent, regs */ + /* These are for 15 FPS only */ + ov511_reg_write(dev, 0x51, 0x08); + ov511_reg_write(dev, 0x22, 0x18); + ov511_reg_write(dev, 0x23, 0xff); + ov511_reg_write(dev, 0x71, 0x19); /* Compression-related? */ + + // FIXME: Sensor-specific + /* Bit 5 is what matters here. Of course, it is "reserved" */ + ov51x_i2c_write(ov511, 0x54, 0x23); + + ov511_reg_write(dev, 0x2f, 0x80); + + /* Mode dependent regs */ + if ((width == 352 && height == 288) || + (width == 320 && height == 240)) { + b[0]=0x80; b[1]=0x02; + ov518_reg_write_multi(dev, 0x30, b, 2); + b[0]=0x90; b[1]=0x01; + ov518_reg_write_multi(dev, 0xc4, b, 2); + b[0]=0xf4; b[1]=0x01; + ov518_reg_write_multi(dev, 0xc6, b, 2); + b[0]=0xf4; b[1]=0x01; + ov518_reg_write_multi(dev, 0xc7, b, 2); + b[0]=0x8e; b[1]=0x00; + ov518_reg_write_multi(dev, 0xc8, b, 2); + b[0]=0x1a; b[1]=0x00; b[2]=0x02; + ov518_reg_write_multi(dev, 0xca, b, 3); + b[0]=0x14; b[1]=0x02; + ov518_reg_write_multi(dev, 0xcb, b, 2); + b[0]=0xd0; b[1]=0x07; + ov518_reg_write_multi(dev, 0xcc, b, 2); + b[0]=0x20; b[1]=0x00; + ov518_reg_write_multi(dev, 0xcd, b, 2); + b[0]=0x60; b[1]=0x02; + ov518_reg_write_multi(dev, 0xce, b, 2); + + } else if ((width == 176 && height == 144) || + (width == 160 && height == 120)) { + b[0]=0x80; b[1]=0x01; + ov518_reg_write_multi(dev, 0x30, b, 2); + b[0]=0xc8; b[1]=0x00; + ov518_reg_write_multi(dev, 0xc4, b, 2); + b[0]=0x40; b[1]=0x01; + ov518_reg_write_multi(dev, 0xc6, b, 2); + b[0]=0x40; b[1]=0x01; + ov518_reg_write_multi(dev, 0xc7, b, 2); + b[0]=0x60; b[1]=0x00; + ov518_reg_write_multi(dev, 0xc8, b, 2); + b[0]=0x0f; b[1]=0x33; b[2]=0x01; + ov518_reg_write_multi(dev, 0xca, b, 3); + b[0]=0x40; b[1]=0x01; + ov518_reg_write_multi(dev, 0xcb, b, 2); + b[0]=0xec; b[1]=0x04; + ov518_reg_write_multi(dev, 0xcc, b, 2); + b[0]=0x13; b[1]=0x00; + ov518_reg_write_multi(dev, 0xcd, b, 2); + b[0]=0x6d; b[1]=0x01; + ov518_reg_write_multi(dev, 0xce, b, 2); + } else { + /* Can't happen, since we already handled this case */ + err("ov518_mode_init_regs(): **** logic error ****"); + } + + ov511_reg_write(dev, 0x2f, 0x80); + + break; + } + + if (ov511_restart(ov511) < 0) + return -EIO; + + /* Reset it just for good measure */ + if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) return -EIO; - /* Dumppix only works with RGB24 */ - if (dumppix && (mode != VIDEO_PALETTE_RGB24)) { - err("dumppix only supported with RGB 24"); + if (mlist518[i].width == 0) { + err("Unknown mode (%d, %d): %d", width, height, mode); return -EINVAL; } - if (mode == VIDEO_PALETTE_GREY) { - ov511_reg_write(dev, 0x16, 0x00); - if (ov511->sensor == SEN_OV7610 - || ov511->sensor == SEN_OV7620AE) { - /* these aren't valid on the OV6620/OV7620 */ - ov511_i2c_write(dev, 0x0e, 0x44); - } - ov511_i2c_write(dev, 0x13, autoadjust ? 0x21 : 0x20); + return 0; +} - /* For snapshot */ - ov511_reg_write(dev, 0x1e, 0x00); - ov511_reg_write(dev, 0x1f, 0x01); - } else { - ov511_reg_write(dev, 0x16, 0x01); - if (ov511->sensor == SEN_OV7610 - || ov511->sensor == SEN_OV7620AE) { - /* not valid on the OV6620/OV7620 */ - ov511_i2c_write(dev, 0x0e, 0x04); - } - ov511_i2c_write(dev, 0x13, autoadjust ? 0x01 : 0x00); +/* This is a wrapper around the OV511, OV518, and sensor specific functions */ +static int +mode_init_regs(struct usb_ov511 *ov511, + int width, int height, int mode, int sub_flag) +{ + int rc = 0; - /* For snapshot */ - ov511_reg_write(dev, 0x1e, 0x01); - ov511_reg_write(dev, 0x1f, 0x03); + if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) { + rc = ov518_mode_init_regs(ov511, width, height, mode, sub_flag); + } else { + rc = ov511_mode_init_regs(ov511, width, height, mode, sub_flag); } - /* The different sensor ICs handle setting up of window differently */ + if (FATAL_ERROR(rc)) + return rc; + switch (ov511->sensor) { case SEN_OV7610: + case SEN_OV7620: case SEN_OV7620AE: - hwsbase = 0x38; - hwebase = 0x3a; - vwsbase = vwebase = 0x05; - break; + case SEN_OV8600: case SEN_OV6620: - hwsbase = 0x38; - hwebase = 0x3a; - vwsbase = 0x05; - vwebase = 0x06; + case SEN_OV6630: + rc = set_ov_sensor_window(ov511, width, height, mode, sub_flag); break; - case SEN_OV7620: - hwsbase = 0x2c; - hwebase = 0x2d; - vwsbase = vwebase = 0x05; + case SEN_KS0127: + case SEN_KS0127B: + err("KS0127-series decoders not supported yet"); + rc = -EINVAL; + break; + case SEN_SAA7111A: +// rc = mode_init_saa_sensor_regs(ov511, width, height, mode, +// sub_flag); + + PDEBUG(1, "SAA status = 0X%x", ov51x_i2c_read(ov511, 0x1f)); break; default: - err("Invalid sensor"); - return -EINVAL; + err("Unknown sensor"); + rc = -EINVAL; } - /* Bit 5 of COM C register varies with sensor */ - if (ov511->sensor == SEN_OV6620) { - if (width > 176 && height > 144) { /* CIF */ - ov511_i2c_write(dev, 0x14, 0x04); - hwscale = 1; - vwscale = 1; /* The datasheet says 0; it's wrong */ - hwsize = 352; - vwsize = 288; - } else { /* QCIF */ - ov511_i2c_write(dev, 0x14, 0x24); - hwsize = 176; - vwsize = 144; - } - } - else { - if (width > 320 && height > 240) { /* VGA */ - ov511_i2c_write(dev, 0x14, 0x04); - hwscale = 2; - vwscale = 1; - hwsize = 640; - vwsize = 480; - } else { /* QVGA */ - ov511_i2c_write(dev, 0x14, 0x24); - hwscale = 1; - hwsize = 320; - vwsize = 240; - } - } + if (FATAL_ERROR(rc)) + return rc; - /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ - if (sub_flag) { - ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>hwscale)); - ov511_i2c_write(dev, 0x18, hwebase+((ov511->subx+ov511->subw)>>hwscale)); - ov511_i2c_write(dev, 0x19, vwsbase+(ov511->suby>>vwscale)); - ov511_i2c_write(dev, 0x1a, vwebase+((ov511->suby+ov511->subh)>>vwscale)); - } else { - ov511_i2c_write(dev, 0x17, hwsbase); - ov511_i2c_write(dev, 0x18, hwebase + (hwsize>>hwscale)); - ov511_i2c_write(dev, 0x19, vwsbase); - ov511_i2c_write(dev, 0x1a, vwebase + (vwsize>>vwscale)); - } + /* Sensor-independent settings */ + rc = sensor_set_auto_brightness(ov511, ov511->auto_brt); + if (FATAL_ERROR(rc)) + return rc; - for (i = 0; mlist[i].width; i++) { - int lncnt, pxcnt, clock; + rc = sensor_set_auto_exposure(ov511, ov511->auto_exp); + if (FATAL_ERROR(rc)) + return rc; - if (width != mlist[i].width || height != mlist[i].height) - continue; + rc = sensor_set_banding_filter(ov511, bandingfilter); + if (FATAL_ERROR(rc)) + return rc; - if (!mlist[i].color && mode != VIDEO_PALETTE_GREY) - continue; + if (ov511->lightfreq) { + rc = sensor_set_light_freq(ov511, lightfreq); + if (FATAL_ERROR(rc)) + return rc; + } - /* Here I'm assuming that snapshot size == image size. - * I hope that's always true. --claudio - */ - pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt; - lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt; + rc = sensor_set_backlight(ov511, ov511->backlight); + if (FATAL_ERROR(rc)) + return rc; - ov511_reg_write(dev, 0x12, pxcnt); - ov511_reg_write(dev, 0x13, lncnt); - ov511_reg_write(dev, 0x14, mlist[i].pxdv); - ov511_reg_write(dev, 0x15, mlist[i].lndv); - ov511_reg_write(dev, 0x18, mlist[i].m420); - - /* Snapshot additions */ - ov511_reg_write(dev, 0x1a, pxcnt); - ov511_reg_write(dev, 0x1b, lncnt); - ov511_reg_write(dev, 0x1c, mlist[i].pxdv); - ov511_reg_write(dev, 0x1d, mlist[i].lndv); - - /* Calculate and set the clock divisor */ - clock = ((sub_flag ? ov511->subw * ov511->subh : width * height) - * (mlist[i].color ? 3 : 2) / 2) / 66000; -#if 0 - clock *= cams; -#endif - ov511_i2c_write(dev, 0x11, clock); + return 0; +} + +/* This sets the default image parameters (Size = max, RGB24). This is + * useful for apps that use read() and do not set these. + */ +static int +ov51x_set_default_params(struct usb_ov511 *ov511) +{ + int i; + + PDEBUG(3, "%dx%d, RGB24", ov511->maxwidth, ov511->maxheight); - /* We only have code to convert GBR -> RGB24 */ - if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr) - ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x0a:0x08)); + /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used + * (using read() instead). */ + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov511->frame[i].width = ov511->maxwidth; + ov511->frame[i].height = ov511->maxheight; + ov511->frame[i].bytes_read = 0; + if (force_palette) + ov511->frame[i].format = force_palette; else - ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x02:0x00)); + ov511->frame[i].format = VIDEO_PALETTE_RGB24; + ov511->frame[i].depth = ov511_get_depth(ov511->frame[i].format); + } + + /* Initialize to max width/height, RGB24 */ + if (mode_init_regs(ov511, ov511->maxwidth, ov511->maxheight, + ov511->frame[0].format, 0) < 0) + return -EINVAL; + + return 0; +} + +/********************************************************************** + * + * Video decoder stuff + * + **********************************************************************/ - /* 7620/6620 don't have register 0x35, so play it safe */ - if (ov511->sensor == SEN_OV7610 || - ov511->sensor == SEN_OV7620AE) - ov511_i2c_write(dev, 0x35, mlist[i].common_L); +/* Set analog input port of decoder */ +static int +decoder_set_input(struct usb_ov511 *ov511, int input) +{ + PDEBUG(4, "port %d", input); + switch (ov511->sensor) { + case SEN_SAA7111A: + { + /* Select mode */ + ov51x_i2c_write_mask(ov511, 0x02, input, 0x07); + /* Bypass chrominance trap for modes 4..7 */ + ov51x_i2c_write_mask(ov511, 0x09, + (input > 3) ? 0x80:0x00, 0x80); break; } + default: + return -EINVAL; + } + + return 0; +} + +/* Get ASCII name of video input */ +static int +decoder_get_input_name(struct usb_ov511 *ov511, int input, char *name) +{ + switch (ov511->sensor) { + case SEN_SAA7111A: + { + if (input < 0 || input > 7) + return -EINVAL; + else if (input < 4) + sprintf(name, "CVBS-%d", input); + else // if (input < 8) + sprintf(name, "S-Video-%d", input - 4); - if (compress) { - ov511_reg_write(dev, 0x78, 0x03); // Turn on Y compression - ov511_reg_write(dev, 0x79, 0x00); // Disable LUTs + break; + } + default: + sprintf(name, "%s", "Camera"); } - if (ov511_restart(ov511->dev) < 0) - return -EIO; + return 0; +} - if (mlist[i].width == 0) { - err("Unknown mode (%d, %d): %d", width, height, mode); +/* Set norm (NTSC, PAL, SECAM, AUTO) */ +static int +decoder_set_norm(struct usb_ov511 *ov511, int norm) +{ + PDEBUG(4, "%d", norm); + + switch (ov511->sensor) { + case SEN_SAA7111A: + { + int reg_8, reg_e; + + if (norm == VIDEO_MODE_NTSC) { + reg_8 = 0x40; /* 60 Hz */ + reg_e = 0x00; /* NTSC M / PAL BGHI */ + } else if (norm == VIDEO_MODE_PAL) { + reg_8 = 0x00; /* 50 Hz */ + reg_e = 0x00; /* NTSC M / PAL BGHI */ + } else if (norm == VIDEO_MODE_AUTO) { + reg_8 = 0x80; /* Auto field detect */ + reg_e = 0x00; /* NTSC M / PAL BGHI */ + } else if (norm == VIDEO_MODE_SECAM) { + reg_8 = 0x00; /* 50 Hz */ + reg_e = 0x50; /* SECAM / PAL 4.43 */ + } else { + return -EINVAL; + } + + ov51x_i2c_write_mask(ov511, 0x08, reg_8, 0xc0); + ov51x_i2c_write_mask(ov511, 0x0e, reg_e, 0x70); + break; + } + default: return -EINVAL; } -#ifdef OV511_DEBUG - if (debug >= 5) - ov511_dump_i2c_regs(dev); -#endif - return 0; } + /********************************************************************** * * Color correction functions @@ -1169,7 +3237,7 @@ static inline void ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, - int rowPixels, unsigned char * rgb, int bits) + int rowPixels, unsigned char * rgb, int bits) { const int rvScale = 91881; const int guScale = -22553; @@ -1192,34 +3260,104 @@ if (bits == 24) { /* Write out top two pixels */ - rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL); - rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR); + rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); + rgb[2] = LIMIT(r+yTL); + + rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); + rgb[5] = LIMIT(r+yTR); /* Skip down to next line to write out bottom two pixels */ rgb += 3 * rowPixels; - rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL); - rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR); + rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); + rgb[2] = LIMIT(r+yBL); + + rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); + rgb[5] = LIMIT(r+yBR); } else if (bits == 16) { /* Write out top two pixels */ - rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) | ((LIMIT(g+yTL) << 3) & 0xE0); - rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07) | (LIMIT(r+yTL) & 0xF8); - - rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) | ((LIMIT(g+yTR) << 3) & 0xE0); - rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) | (LIMIT(r+yTR) & 0xF8); + rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) + | ((LIMIT(g+yTL) << 3) & 0xE0); + rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07) + | (LIMIT(r+yTL) & 0xF8); + + rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) + | ((LIMIT(g+yTR) << 3) & 0xE0); + rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) + | (LIMIT(r+yTR) & 0xF8); /* Skip down to next line to write out bottom two pixels */ rgb += 2 * rowPixels; - rgb[0] = ((LIMIT(b+yBL) >> 3) & 0x1F) | ((LIMIT(g+yBL) << 3) & 0xE0); - rgb[1] = ((LIMIT(g+yBL) >> 5) & 0x07) | (LIMIT(r+yBL) & 0xF8); + rgb[0] = ((LIMIT(b+yBL) >> 3) & 0x1F) + | ((LIMIT(g+yBL) << 3) & 0xE0); + rgb[1] = ((LIMIT(g+yBL) >> 5) & 0x07) + | (LIMIT(r+yBL) & 0xF8); + + rgb[2] = ((LIMIT(b+yBR) >> 3) & 0x1F) + | ((LIMIT(g+yBR) << 3) & 0xE0); + rgb[3] = ((LIMIT(g+yBR) >> 5) & 0x07) + | (LIMIT(r+yBR) & 0xF8); + } +} + +/********************************************************************** + * + * Raw data parsing + * + **********************************************************************/ + +/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the + * array at pOut is specified by w. + */ +static inline void +ov511_make_8x8(unsigned char *pIn, unsigned char *pOut, int w) +{ + unsigned char *pOut1 = pOut; + int x, y; + + for (y = 0; y < 8; y++) { + pOut1 = pOut; + for (x = 0; x < 8; x++) { + *pOut1++ = *pIn++; + } + pOut += w; + } + +} + +/* + * For RAW BW (YUV400) images, data shows up in 256 byte segments. + * The segments represent 4 squares of 8x8 pixels as follows: + * + * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 + * 8 9 ... 15 72 73 ... 79 200 201 ... 207 + * ... ... ... + * 56 57 ... 63 120 121 ... 127 248 249 ... 255 + * + */ +static void +yuv400raw_to_yuv400p(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + int x, y; + unsigned char *pIn, *pOut, *pOutLine; - rgb[2] = ((LIMIT(b+yBR) >> 3) & 0x1F) | ((LIMIT(g+yBR) << 3) & 0xE0); - rgb[3] = ((LIMIT(g+yBR) >> 5) & 0x07) | (LIMIT(r+yBR) & 0xF8); + /* Copy Y */ + pIn = pIn0; + pOutLine = pOut0; + for (y = 0; y < frame->rawheight - 1; y += 8) { + pOut = pOutLine; + for (x = 0; x < frame->rawwidth - 1; x += 8) { + ov511_make_8x8(pIn, pOut, frame->rawwidth); + pIn += 64; + pOut += 8; + } + pOutLine += 8 * frame->rawwidth; } } /* - * For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments. + * For YUV4:2:0 images, the data shows up in 384 byte segments. * The first 64 bytes of each segment are U, the next 64 are V. The U and * V are arranged as follows: * @@ -1239,7 +3377,9 @@ * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 * * Note that the U and V data in one segment represents a 16 x 16 pixel - * area, but the Y data represents a 32 x 8 pixel area. + * area, but the Y data represents a 32 x 8 pixel area. If the width is not an + * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the + * next horizontal stripe. * * If dumppix module param is set, _parse_data just dumps the incoming segments, * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 @@ -1248,391 +3388,504 @@ * this data is scrambled. */ -#define HDIV 8 -#define WDIV (256/HDIV) - +/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0. + * + * FIXME: Currently only handles width and height that are multiples of 16 + */ static void -ov511_parse_gbr422_to_rgb24(unsigned char *pIn0, unsigned char *pOut0, - int iOutY, int iOutUV, int iHalf, int iWidth) +yuv420raw_to_yuv420p(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) { - int k, l, m; - unsigned char *pIn; - unsigned char *pOut, *pOut1; + int k, x, y; + unsigned char *pIn, *pOut, *pOutLine; + const unsigned int a = frame->rawwidth * frame->rawheight; + const unsigned int w = frame->rawwidth / 2; + /* Copy U and V */ pIn = pIn0; - pOut = pOut0 + iOutUV + (force_rgb ? 2 : 0); - - for (k = 0; k < 8; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - *pOut1 = *(pOut1 + 3) = *(pOut1 + iWidth*3) = - *(pOut1 + iWidth*3 + 3) = *pIn++; - pOut1 += 6; + pOutLine = pOut0 + a; + for (y = 0; y < frame->rawheight - 1; y += 16) { + pOut = pOutLine; + for (x = 0; x < frame->rawwidth - 1; x += 16) { + ov511_make_8x8(pIn, pOut, w); + ov511_make_8x8(pIn + 64, pOut + a/4, w); + pIn += 384; + pOut += 8; } - pOut += iWidth*3*2; + pOutLine += 8 * w; } - pIn = pIn0 + 64; - pOut = pOut0 + iOutUV + (force_rgb ? 0 : 2); - for (k = 0; k < 8; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - *pOut1 = *(pOut1 + 3) = *(pOut1 + iWidth*3) = - *(pOut1 + iWidth*3 + 3) = *pIn++; - pOut1 += 6; + /* Copy Y */ + pIn = pIn0 + 128; + pOutLine = pOut0; + k = 0; + for (y = 0; y < frame->rawheight - 1; y += 8) { + pOut = pOutLine; + for (x = 0; x < frame->rawwidth - 1; x += 8) { + ov511_make_8x8(pIn, pOut, frame->rawwidth); + pIn += 64; + pOut += 8; + if ((++k) > 3) { + k = 0; + pIn += 128; + } + } + pOutLine += 8 * frame->rawwidth; + } +} + +/* + * fixFrameRGBoffset-- + * My camera seems to return the red channel about 1 pixel + * low, and the blue channel about 1 pixel high. After YUV->RGB + * conversion, we can correct this easily. OSL 2/24/2000. + */ +static void +fixFrameRGBoffset(struct ov511_frame *frame) +{ + int x, y; + int rowBytes = frame->width*3, w = frame->width; + unsigned char *rgb = frame->data; + const int shift = 1; /* Distance to shift pixels by, vertically */ + + /* Don't bother with little images */ + if (frame->width < 400) + return; + + /* This only works with RGB24 */ + if (frame->format != VIDEO_PALETTE_RGB24) + return; + + /* Shift red channel up */ + for (y = shift; y < frame->height; y++) { + int lp = (y-shift)*rowBytes; /* Previous line offset */ + int lc = y*rowBytes; /* Current line offset */ + for (x = 0; x < w; x++) + rgb[lp+x*3+2] = rgb[lc+x*3+2]; /* Shift red up */ + } + + /* Shift blue channel down */ + for (y = frame->height-shift-1; y >= 0; y--) { + int ln = (y + shift) * rowBytes; /* Next line offset */ + int lc = y * rowBytes; /* Current line offset */ + for (x = 0; x < w; x++) + rgb[ln+x*3+0] = rgb[lc+x*3+0]; /* Shift blue down */ + } +} + +/********************************************************************** + * + * Decompression + * + **********************************************************************/ + +/* Chooses a decompression module, locks it, and sets ov511->decomp_ops + * accordingly. Returns -ENXIO if decompressor is not available, otherwise + * returns 0 if no other error. + */ +static int +ov51x_request_decompressor(struct usb_ov511 *ov511) +{ + if (!ov511) + return -ENODEV; + + if (ov511->decomp_ops) { + err("ERROR: Decompressor already requested!"); + return -EINVAL; + } + + lock_kernel(); + + /* Try to get MMX, and fall back on no-MMX if necessary */ + if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { + if (ov511_mmx_decomp_ops) { + PDEBUG(3, "Using OV511 MMX decompressor"); + ov511->decomp_ops = ov511_mmx_decomp_ops; + } else if (ov511_decomp_ops) { + PDEBUG(3, "Using OV511 decompressor"); + ov511->decomp_ops = ov511_decomp_ops; + } else { + err("No decompressor available"); + } + } else if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) { + if (ov518_mmx_decomp_ops) { + PDEBUG(3, "Using OV518 MMX decompressor"); + ov511->decomp_ops = ov518_mmx_decomp_ops; + } else if (ov518_decomp_ops) { + PDEBUG(3, "Using OV518 decompressor"); + ov511->decomp_ops = ov518_decomp_ops; + } else { + err("No decompressor available"); } - pOut += iWidth*3*2; + } else { + err("Unknown bridge"); } - pIn = pIn0 + 128; - pOut = pOut0 + iOutY + 1; - for (k = 0; k < 4; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - for (m = 0; m < 8; m++) { - *pOut1 = *pIn++; - pOut1 += 3; - } - pOut1 += (iWidth - 8) * 3; + if (ov511->decomp_ops) { + if (!ov511->decomp_ops->decomp_lock) { + ov511->decomp_ops = NULL; + unlock_kernel(); + return -ENOSYS; } - pOut += 8 * 3; + ov511->decomp_ops->decomp_lock(); + unlock_kernel(); + return 0; + } else { + unlock_kernel(); + return -ENXIO; } } -static void -ov511_parse_yuv420_to_rgb(unsigned char *pIn0, unsigned char *pOut0, - int iOutY, int iOutUV, int iHalf, int iWidth, int bits) +/* Unlocks decompression module and nulls ov511->decomp_ops. Safe to call even + * if ov511->decomp_ops is NULL. + */ +static void +ov51x_release_decompressor(struct usb_ov511 *ov511) { - int k, l, m; - int bytes = bits >> 3; - unsigned char *pIn; - unsigned char *pOut, *pOut1; - - /* Just copy the Y's if in the first stripe */ - if (!iHalf) { - pIn = pIn0 + 128; - pOut = pOut0 + iOutY; - for (k = 0; k < 4; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - for (m = 0; m < 8; m++) { - *pOut1 = *pIn++; - pOut1 += bytes; - } - pOut1 += (iWidth - 8) * bytes; - } - pOut += 8 * bytes; - } - } + int released = 0; /* Did we actually do anything? */ - /* Use the first half of VUs to calculate value */ - pIn = pIn0; - pOut = pOut0 + iOutUV; - for (l = 0; l < 4; l++) { - for (m=0; m<8; m++) { - int y00 = *(pOut); - int y01 = *(pOut+bytes); - int y10 = *(pOut+iWidth*bytes); - int y11 = *(pOut+iWidth*bytes+bytes); - int v = *(pIn+64) - 128; - int u = *pIn++ - 128; - ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, - pOut, bits); - pOut += 2 * bytes; - } - pOut += (iWidth*2 - 16) * bytes; + if (!ov511) + return; + + lock_kernel(); + + if (ov511->decomp_ops && ov511->decomp_ops->decomp_unlock) { + ov511->decomp_ops->decomp_unlock(); + released = 1; } - /* Just copy the other UV rows */ - for (l = 0; l < 4; l++) { - for (m = 0; m < 8; m++) { - *pOut++ = *(pIn + 64); - *pOut = *pIn++; - pOut += 2 * bytes - 1; - } - pOut += (iWidth*2 - 16) * bytes; - } - - /* Calculate values if it's the second half */ - if (iHalf) { - pIn = pIn0 + 128; - pOut = pOut0 + iOutY; - for (k = 0; k < 4; k++) { - pOut1 = pOut; - for (l=0; l<4; l++) { - for (m=0; m<4; m++) { - int y10 = *(pIn+8); - int y00 = *pIn++; - int y11 = *(pIn+8); - int y01 = *pIn++; - int v = *pOut1 - 128; - int u = *(pOut1+1) - 128; - ov511_move_420_block(y00, y01, y10, - y11, u, v, iWidth, pOut1, bits); - pOut1 += 2 * bytes; - } - pOut1 += (iWidth*2 - 8) * bytes; - pIn += 8; - } - pOut += 8 * bytes; - } + ov511->decomp_ops = NULL; + + unlock_kernel(); + + if (released) + PDEBUG(3, "Decompressor released"); +} + +static void +ov51x_decompress(struct usb_ov511 *ov511, struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + if (!ov511->decomp_ops) + if (ov51x_request_decompressor(ov511)) + return; + + PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd); + + if (frame->format == VIDEO_PALETTE_GREY + && ov511->decomp_ops->decomp_400) { + int ret = ov511->decomp_ops->decomp_400( + pIn0, + pOut0, + frame->rawwidth, + frame->rawheight, + frame->bytes_recvd); + PDEBUG(4, "DEBUG: decomp_400 returned %d", ret); + } else if (ov511->decomp_ops->decomp_420) { + int ret = ov511->decomp_ops->decomp_420( + pIn0, + pOut0, + frame->rawwidth, + frame->rawheight, + frame->bytes_recvd); + PDEBUG(4, "DEBUG: decomp_420 returned %d", ret); + } else { + err("Decompressor does not support this format"); } } -static void -ov511_dumppix(unsigned char *pIn0, unsigned char *pOut0, - int iOutY, int iOutUV, int iHalf, int iWidth) -{ - int i, j, k; - unsigned char *pIn, *pOut, *pOut1; +/********************************************************************** + * + * Format conversion + * + **********************************************************************/ - switch (dumppix) { - case 1: /* Just dump YUV data straight out for debug */ - pOut0 += iOutY; - for (i = 0; i < HDIV; i++) { - for (j = 0; j < WDIV; j++) { - *pOut0++ = *pIn0++; - *pOut0++ = *pIn0++; - *pOut0++ = *pIn0++; - } - pOut0 += (iWidth - WDIV) * 3; - } - break; - case 2: /* This converts the Y data to "black-and-white" RGB data */ - /* Useful for experimenting with compression */ - pIn = pIn0 + 128; - pOut = pOut0 + iOutY; - for (i = 0; i < 4; i++) { - pOut1 = pOut; - for (j = 0; j < 8; j++) { - for (k = 0; k < 8; k++) { - *pOut1++ = *pIn; - *pOut1++ = *pIn; - *pOut1++ = *pIn++; - } - pOut1 += (iWidth - 8) * 3; - } - pOut += 8 * 3; - } - break; - case 3: /* This will dump only the Y channel data stream as-is */ - pIn = pIn0 + 128; - pOut = pOut0 + output_offset; - for (i = 0; i < 256; i++) { - *pOut++ = *pIn; - *pOut++ = *pIn; - *pOut++ = *pIn++; - output_offset += 3; - } - break; - } /* End switch (dumppix) */ -} +/* Converts from planar YUV420 to RGB24. */ +static void +yuv420p_to_rgb(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0, int bits) +{ + const int numpix = frame->width * frame->height; + const int bytes = bits >> 3; + int i, j, y00, y01, y10, y11, u, v; + unsigned char *pY = pIn0; + unsigned char *pU = pY + numpix; + unsigned char *pV = pU + numpix / 4; + unsigned char *pOut = pOut0; + + for (j = 0; j <= frame->height - 2; j += 2) { + for (i = 0; i <= frame->width - 2; i += 2) { + y00 = *pY; + y01 = *(pY + 1); + y10 = *(pY + frame->width); + y11 = *(pY + frame->width + 1); + u = (*pU++) - 128; + v = (*pV++) - 128; -/* This converts YUV420 segments to YUYV */ -static void -ov511_parse_data_yuv422(unsigned char *pIn0, unsigned char *pOut0, - int iOutY, int iOutUV, int iWidth) -{ - int k, l, m; - unsigned char *pIn, *pOut, *pOut1; + ov511_move_420_block(y00, y01, y10, y11, u, v, + frame->width, pOut, bits); + + pY += 2; + pOut += 2 * bytes; - pIn = pIn0 + 128; - pOut = pOut0 + iOutY; - for (k = 0; k < 4; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - for (m = 0; m < 8; m++) { - *pOut1 = (*pIn++); - pOut1 += 2; - } - pOut1 += (iWidth - 8) * 2; } - pOut += 8 * 2; + pY += frame->width; + pOut += frame->width * bytes; } +} - pIn = pIn0; - pOut = pOut0 + iOutUV + 1; - for (l = 0; l < 8; l++) { - for (m=0; m<8; m++) { - int v = *(pIn+64); - int u = *pIn++; +/* Converts from planar YUV420 to YUV422 (YUYV). */ +static void +yuv420p_to_yuv422(struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) +{ + const int numpix = frame->width * frame->height; + int i, j; + unsigned char *pY = pIn0; + unsigned char *pU = pY + numpix; + unsigned char *pV = pU + numpix / 4; + unsigned char *pOut = pOut0; + + for (i = 0; i < numpix; i++) { + *pOut = *(pY + i); + pOut += 2; + } + + pOut = pOut0 + 1; + for (j = 0; j <= frame->height - 2 ; j += 2) { + for (i = 0; i <= frame->width - 2; i += 2) { + int u = *pU++; + int v = *pV++; *pOut = u; *(pOut+2) = v; - *(pOut+iWidth) = u; - *(pOut+iWidth+2) = v; + *(pOut+frame->width*2) = u; + *(pOut+frame->width*2+2) = v; pOut += 4; } - pOut += (iWidth*4 - 32); + pOut += (frame->width * 2); } } +/* Converts pData from planar YUV420 to planar YUV422 **in place**. */ static void -ov511_parse_data_yuv420(unsigned char *pIn0, unsigned char *pOut0, - int iOutY, int iOutUV, int iWidth, int iHeight) +yuv420p_to_yuv422p(struct ov511_frame *frame, unsigned char *pData) { - int k, l, m; - unsigned char *pIn; - unsigned char *pOut, *pOut1; - unsigned a = iWidth * iHeight; - unsigned w = iWidth / 2; - - pIn = pIn0; - pOut = pOut0 + iOutUV + a; - for (k = 0; k < 8; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) *pOut1++ = *pIn++; + const int numpix = frame->width * frame->height; + const int w = frame->width; + int j; + unsigned char *pIn, *pOut; + + /* Clear U and V */ + memset(pData + numpix + numpix / 2, 127, numpix / 2); + + /* Convert V starting from beginning and working forward */ + pIn = pData + numpix + numpix / 4; + pOut = pData + numpix +numpix / 2; + for (j = 0; j <= frame->height - 2; j += 2) { + memmove(pOut, pIn, w/2); + memmove(pOut + w/2, pIn, w/2); + pIn += w/2; pOut += w; } - pIn = pIn0 + 64; - pOut = pOut0 + iOutUV + a + a/4; - for (k = 0; k < 8; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) *pOut1++ = *pIn++; - pOut += w; - } - - pIn = pIn0 + 128; - pOut = pOut0 + iOutY; - for (k = 0; k < 4; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - for (m = 0; m < 8; m++) - *pOut1++ =*pIn++; - pOut1 += iWidth - 8; - } - pOut += 8; + /* Convert U, starting from end and working backward */ + pIn = pData + numpix + numpix / 4; + pOut = pData + numpix + numpix / 2; + for (j = 0; j <= frame->height - 2; j += 2) { + pIn -= w/2; + pOut -= w; + memmove(pOut, pIn, w/2); + memmove(pOut + w/2, pIn, w/2); } } +/* Fuses even and odd fields together, and doubles width. + * INPUT: an odd field followed by an even field at pIn0, in YUV planar format + * OUTPUT: a normal YUV planar image, with correct aspect ratio + */ static void -ov511_parse_data_yuv422p(unsigned char *pIn0, unsigned char *pOut0, - int iOutY, int iOutUV, int iWidth, int iHeight) +deinterlace(struct ov511_frame *frame, int rawformat, + unsigned char *pIn0, unsigned char *pOut0) { - int k, l, m; - unsigned char *pIn; - unsigned char *pOut, *pOut1; - unsigned a = iWidth * iHeight; - unsigned w = iWidth / 2; + const int fieldheight = frame->rawheight / 2; + const int fieldpix = fieldheight * frame->rawwidth; + const int w = frame->width; + int x, y; + unsigned char *pInEven, *pInOdd, *pOut; - pIn = pIn0; - pOut = pOut0 + iOutUV + a; - for (k = 0; k < 8; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - *pOut1 = *(pOut1 + w) = *pIn++; - pOut1++; - } - pOut += iWidth; + PDEBUG(5, "fieldheight=%d", fieldheight); + + if (frame->rawheight != frame->height) { + err("invalid height"); + return; } - pIn = pIn0 + 64; - pOut = pOut0 + iOutUV + a + a/2; - for (k = 0; k < 8; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - *pOut1 = *(pOut1 + w) = *pIn++; - pOut1++; - } - pOut += iWidth; + if ((frame->rawwidth * 2) != frame->width) { + err("invalid width"); + return; } - pIn = pIn0 + 128; - pOut = pOut0 + iOutY; - for (k = 0; k < 4; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - for (m = 0; m < 8; m++) - *pOut1++ =*pIn++; - pOut1 += iWidth - 8; + /* Y */ + pInOdd = pIn0; + pInEven = pInOdd + fieldpix; + pOut = pOut0; + for (y = 0; y < fieldheight; y++) { + for (x = 0; x < frame->rawwidth; x++) { + *pOut = *pInEven; + *(pOut+1) = *pInEven++; + *(pOut+w) = *pInOdd; + *(pOut+w+1) = *pInOdd++; + pOut += 2; } - pOut += 8; + pOut += w; } -} - -/* - * For 640x480 RAW BW images, data shows up in 1200 256 byte segments. - * The segments represent 4 squares of 8x8 pixels as follows: - * - * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 - * 8 9 ... 15 72 73 ... 79 200 201 ... 207 - * ... ... ... - * 56 57 ... 63 120 121 ... 127 248 249 ... 255 - * - */ -static void -ov511_parse_data_grey(unsigned char *pIn0, unsigned char *pOut0, - int iOutY, int iWidth) -{ - int k, l, m; - unsigned char *pIn; - unsigned char *pOut, *pOut1; - pIn = pIn0; - pOut = pOut0 + iOutY; - for (k = 0; k < 4; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - for (m = 0; m < 8; m++) { - *pOut1++ = *pIn++; + if (rawformat == RAWFMT_YUV420) { + /* U */ + pInOdd = pIn0 + fieldpix * 2; + pInEven = pInOdd + fieldpix / 4; + for (y = 0; y < fieldheight / 2; y++) { + for (x = 0; x < frame->rawwidth / 2; x++) { + *pOut = *pInEven; + *(pOut+1) = *pInEven++; + *(pOut+w/2) = *pInOdd; + *(pOut+w/2+1) = *pInOdd++; + pOut += 2; + } + pOut += w/2; + } + /* V */ + pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2; + pInEven = pInOdd + fieldpix / 4; + for (y = 0; y < fieldheight / 2; y++) { + for (x = 0; x < frame->rawwidth / 2; x++) { + *pOut = *pInEven; + *(pOut+1) = *pInEven++; + *(pOut+w/2) = *pInOdd; + *(pOut+w/2+1) = *pInOdd++; + pOut += 2; } - pOut1 += iWidth - 8; + pOut += w/2; } - pOut += 8; } } -/* - * fixFrameRGBoffset-- - * My camera seems to return the red channel about 1 pixel - * low, and the blue channel about 1 pixel high. After YUV->RGB - * conversion, we can correct this easily. OSL 2/24/2000. +/* Post-processes the specified frame. This consists of: + * 1. Decompress frame, if necessary + * 2. Deinterlace frame and scale to proper size, if necessary + * 3. Convert from YUV planar to destination format, if necessary + * 4. Fix the RGB offset, if necessary */ -static void fixFrameRGBoffset(struct ov511_frame *frame) +static void +ov511_postprocess(struct usb_ov511 *ov511, struct ov511_frame *frame) { - int x, y; - int rowBytes = frame->width*3, w = frame->width; - unsigned char *rgb = frame->data; - const int shift = 1; /* Distance to shift pixels by, vertically */ + if (dumppix) { + memset(frame->data, 0, + MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); + PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); + memmove(frame->data, frame->rawdata, frame->bytes_recvd); + return; + } + + /* YUV400 must be handled separately */ + if (frame->format == VIDEO_PALETTE_GREY) { + /* Deinterlace frame, if necessary */ + if (ov511->sensor == SEN_SAA7111A && frame->rawheight == 480) { + if (frame->compressed) + ov51x_decompress(ov511, frame, frame->rawdata, + frame->tempdata); + else + yuv400raw_to_yuv400p(frame, frame->rawdata, + frame->tempdata); + + deinterlace(frame, RAWFMT_YUV400, frame->tempdata, + frame->data); + } else { + if (frame->compressed) + ov51x_decompress(ov511, frame, frame->rawdata, + frame->data); + else + yuv400raw_to_yuv400p(frame, frame->rawdata, + frame->data); + } - /* Don't bother with little images */ - if (frame->width < 400) return; + } - /* Shift red channel up */ - for (y = shift; y < frame->height; y++) { - int lp = (y-shift)*rowBytes; /* Previous line offset */ - int lc = y*rowBytes; /* Current line offset */ - for (x = 0; x < w; x++) - rgb[lp+x*3+2] = rgb[lc+x*3+2]; /* Shift red up */ + /* Process frame->data to frame->rawdata */ + if (frame->compressed) + ov51x_decompress(ov511, frame, frame->rawdata, frame->tempdata); + else + yuv420raw_to_yuv420p(frame, frame->rawdata, frame->tempdata); + + /* Deinterlace frame, if necessary */ + if (ov511->sensor == SEN_SAA7111A && frame->rawheight == 480) { + memmove(frame->rawdata, frame->tempdata, + MAX_RAW_DATA_SIZE(frame->width, frame->height)); + deinterlace(frame, RAWFMT_YUV420, frame->rawdata, + frame->tempdata); } - /* Shift blue channel down */ - for (y = frame->height-shift-1; y >= 0; y--) { - int ln = (y + shift) * rowBytes; /* Next line offset */ - int lc = y * rowBytes; /* Current line offset */ - for (x = 0; x < w; x++) - rgb[ln+x*3+0] = rgb[lc+x*3+0]; /* Shift blue down */ + /* Frame should be (width x height) and not (rawwidth x rawheight) at + * this point. */ + +#if 0 + /* Clear output buffer for testing purposes */ + memset(frame->data, 0, MAX_DATA_SIZE(frame->width, frame->height)); +#endif + + /* Process frame->tempdata to frame->data */ + switch (frame->format) { + case VIDEO_PALETTE_RGB565: + yuv420p_to_rgb(frame, frame->tempdata, frame->data, 16); + break; + case VIDEO_PALETTE_RGB24: + yuv420p_to_rgb(frame, frame->tempdata, frame->data, 24); + break; + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + yuv420p_to_yuv422(frame, frame->tempdata, frame->data); + break; + case VIDEO_PALETTE_YUV420: + case VIDEO_PALETTE_YUV420P: + memmove(frame->data, frame->tempdata, + MAX_RAW_DATA_SIZE(frame->width, frame->height)); + break; + case VIDEO_PALETTE_YUV422P: + /* Data is converted in place, so copy it in advance */ + memmove(frame->data, frame->tempdata, + MAX_RAW_DATA_SIZE(frame->width, frame->height)); + + yuv420p_to_yuv422p(frame, frame->data); + break; + default: + err("Cannot convert data to this format"); } + + if (fix_rgb_offset) + fixFrameRGBoffset(frame); } /********************************************************************** * - * OV511 data transfer, IRQ handler + * OV51x data transfer, IRQ handler * **********************************************************************/ -static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb) +static int +ov511_move_data(struct usb_ov511 *ov511, urb_t *urb) { unsigned char *cdata; - int i, totlen = 0; - int aPackNum[10]; + int data_size, num, offset, i, totlen = 0; + int aPackNum[FRAMES_PER_DESC]; struct ov511_frame *frame; - unsigned char *pData; - int iPix; + struct timeval *ts; + + PDEBUG(5, "Moving %d packets", urb->number_of_packets); - PDEBUG (4, "Moving %d packets", urb->number_of_packets); + data_size = ov511->packet_size - 1; for (i = 0; i < urb->number_of_packets; i++) { int n = urb->iso_frame_desc[i].actual_length; @@ -1652,44 +3905,65 @@ PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); frame = &ov511->frame[ov511->curframe]; - + /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th * byte non-zero. The EOF packet has image width/height in the - * 10th and 11th packets. The 9th bit is given as follows: + * 10th and 11th bytes. The 9th byte is given as follows: * * bit 7: EOF * 6: compression enabled * 5: 422/420/400 modes * 4: 422/420/400 modes * 3: 1 - * 2: snapshot bottom on + * 2: snapshot button on * 1: snapshot frame * 0: even/odd field */ + if (printph) { + info("packet header (%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", + cdata[ov511->packet_size - 1], + cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5], + cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]); + } + /* Check for SOF/EOF packet */ - if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | + if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | cdata[4] | cdata[5] | cdata[6] | cdata[7]) || (~cdata[8] & 0x08)) goto check_middle; /* Frame end */ if (cdata[8] & 0x80) { - struct timeval *ts; - - ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE); - do_gettimeofday (ts); - - PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d", - ov511->curframe, (int)(cdata[ov511->packet_size - 1]), - (int)(cdata[9]), (int)(cdata[10])); + ts = (struct timeval *)(frame->data + + MAX_FRAME_SIZE(ov511->maxwidth, ov511->maxheight)); + do_gettimeofday(ts); + + /* Get the actual frame size from the EOF header */ + frame->rawwidth = ((int)(cdata[9]) + 1) * 8; + frame->rawheight = ((int)(cdata[10]) + 1) * 8; + + PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d, recvd=%d", + ov511->curframe, + (int)(cdata[ov511->packet_size - 1]), + frame->rawwidth, + frame->rawheight, + frame->bytes_recvd); + + /* Validate the header data */ + RESTRICT_TO_RANGE(frame->rawwidth, ov511->minwidth, ov511->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov511->minheight, ov511->maxheight); + + /* Don't allow byte count to exceed buffer size */ + RESTRICT_TO_RANGE(frame->bytes_recvd, + 8, + MAX_RAW_DATA_SIZE(ov511->maxwidth, + ov511->maxheight)); if (frame->scanstate == STATE_LINES) { int iFrameNext; - if (fix_rgb_offset) - fixFrameRGBoffset(frame); - frame->grabstate = FRAME_DONE; + frame->grabstate = FRAME_DONE; // FIXME: Is this right? if (waitqueue_active(&frame->wq)) { frame->grabstate = FRAME_DONE; @@ -1713,6 +3987,8 @@ ov511->curframe = -1; } + } else { + PDEBUG(5, "Frame done, but not scanning"); } /* Image corruption caused by misplaced frame->segment = 0 * fixed by carlosf@conectiva.com.br @@ -1721,13 +3997,6 @@ /* Frame start */ PDEBUG(4, "Frame start, framenum = %d", ov511->curframe); -#if 0 - /* Make sure no previous data carries over; necessary - * for compression experimentation */ - memset(frame->data, 0, MAX_DATA_SIZE); -#endif - output_offset = 0; - /* Check to see if it's a snapshot frame */ /* FIXME?? Should the snapshot reset go here? Performance? */ if (cdata[8] & 0x02) { @@ -1736,129 +4005,324 @@ } frame->scanstate = STATE_LINES; - frame->segment = 0; + frame->bytes_recvd = 0; + frame->compressed = cdata[8] & 0x40; } check_middle: /* Are we in a frame? */ - if (frame->scanstate != STATE_LINES) + if (frame->scanstate != STATE_LINES) { + PDEBUG(5, "Not in a frame; packet skipped"); + continue; + } + +#if 0 + /* Skip packet if first 9 bytes are zero. These are common, so + * we use a less expensive test here instead of later */ + if (frame->compressed) { + int b, skip = 1; + + for (b = 0; b < 9; b++) { + if (cdata[b]) + skip=0; + } + + if (skip) { + PDEBUG(5, "Skipping packet (all zero)"); + continue; + } + } +#endif + /* If frame start, skip header */ + if (frame->bytes_recvd == 0) + offset = 9; + else + offset = 0; + + num = n - offset - 1; + + /* Dump all data exactly as received */ + if (dumppix == 2) { + frame->bytes_recvd += n - 1; + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + memmove(frame->rawdata + frame->bytes_recvd - (n - 1), + &cdata[0], n - 1); + else + PDEBUG(3, "Raw data buffer overrun!! (%d)", + frame->bytes_recvd + - MAX_RAW_DATA_SIZE(ov511->maxwidth, + ov511->maxheight)); + } else if (!frame->compressed && !remove_zeros) { + frame->bytes_recvd += num; + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + memmove(frame->rawdata + frame->bytes_recvd - num, + &cdata[offset], num); + else + PDEBUG(3, "Raw data buffer overrun!! (%d)", + frame->bytes_recvd + - MAX_RAW_DATA_SIZE(ov511->maxwidth, + ov511->maxheight)); + } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */ + int b, in = 0, allzero, copied=0; + if (offset) { + frame->bytes_recvd += 32 - offset; // Bytes out + memmove(frame->rawdata, + &cdata[offset], 32 - offset); + in += 32; + } + + while (in < n - 1) { + allzero = 1; + for (b = 0; b < 32; b++) { + if (cdata[in + b]) { + allzero = 0; + break; + } + } + + if (allzero) { + /* Don't copy it */ + } else { + if (frame->bytes_recvd + copied + 32 + <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) { + memmove(frame->rawdata + frame->bytes_recvd + copied, + &cdata[in], 32); + copied += 32; + } else { + PDEBUG(3, "Raw data buffer overrun!!"); + } + } + in += 32; + } + + frame->bytes_recvd += copied; + } + + } + + PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d", + aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4], + aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]); + + return totlen; +} + +static int +ov518_move_data(struct usb_ov511 *ov511, urb_t *urb) +{ + unsigned char *cdata; + int i, data_size, totlen = 0; + struct ov511_frame *frame; + struct timeval *ts; + + PDEBUG(5, "Moving %d packets", urb->number_of_packets); + + /* OV518(+) has no packet numbering */ + data_size = ov511->packet_size; + + 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; + + urb->iso_frame_desc[i].actual_length = 0; + urb->iso_frame_desc[i].status = 0; + + cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if (!n) { + PDEBUG(4, "Zero-length packet"); continue; + } + + if (ov511->curframe == -1) { + PDEBUG(4, "No frame currently active"); + continue; + } + + if (st) + PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); + + frame = &ov511->frame[ov511->curframe]; + +#if 0 + { + int d; + /* Print all data */ + for (d = 0; d <= data_size - 16; d += 16) { + info("%4x: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", d, + cdata[d], cdata[d+1], cdata[d+2], cdata[d+3], + cdata[d+4], cdata[d+5], cdata[d+6], cdata[d+7], + cdata[d+8], cdata[d+9], cdata[d+10], cdata[d+11], + cdata[d+12], cdata[d+13], cdata[d+14], cdata[d+15]); + } + } +#endif + + if (printph) { + info("packet header: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", + cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5], + cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]); + } - /* Deal with leftover from last segment, if any */ - if (frame->segment) { - pData = ov511->scratch; - iPix = -ov511->scratchlen; - memmove(pData + ov511->scratchlen, cdata, - iPix+frame->segsize); + /* A false positive here is likely, until OVT gives me + * the definitive SOF/EOF format */ + if ((!(cdata[0] | cdata[1] | cdata[2] | cdata[3] | + cdata[5])) && cdata[6]) { + + if (frame->scanstate == STATE_LINES) { + PDEBUG(4, "Detected frame end/start"); + goto eof; + } else { //scanstate == STATE_SCANNING + /* Frame start */ + PDEBUG(4, "Frame start, framenum = %d", ov511->curframe); + goto sof; + } } else { - pData = &cdata[iPix = 9]; - } + goto check_middle; + } + +eof: + ts = (struct timeval *)(frame->data + + MAX_FRAME_SIZE(ov511->maxwidth, ov511->maxheight)); + do_gettimeofday(ts); + + PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", + ov511->curframe, + (int)(cdata[9]), (int)(cdata[10]), frame->bytes_recvd); + + // FIXME: Since we don't know the header formats yet, + // there is no way to know what the actual image size is + frame->rawwidth = frame->width; + frame->rawheight = frame->height; + + /* Validate the header data */ + RESTRICT_TO_RANGE(frame->rawwidth, ov511->minwidth, ov511->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov511->minheight, ov511->maxheight); + + /* Don't allow byte count to exceed buffer size */ + RESTRICT_TO_RANGE(frame->bytes_recvd, + 8, + MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); - /* Parse the segments */ - while (iPix <= (ov511->packet_size - 1) - frame->segsize && - frame->segment < frame->width * frame->height / 256) { - int iSegY, iSegUV; - int iY, jY, iUV, jUV; - int iOutY, iOutYP, iOutUV, iOutUVP; - unsigned char *pOut; - - iSegY = iSegUV = frame->segment; - pOut = frame->data; - frame->segment++; - iPix += frame->segsize; - - /* Handle subwindow */ - if (frame->sub_flag) { - int iSeg1; - - iSeg1 = iSegY / (ov511->subw / 32); - iSeg1 *= frame->width / 32; - iSegY = iSeg1 + (iSegY % (ov511->subw / 32)); - if (iSegY >= frame->width * ov511->subh / 256) - break; - - iSeg1 = iSegUV / (ov511->subw / 16); - iSeg1 *= frame->width / 16; - iSegUV = iSeg1 + (iSegUV % (ov511->subw / 16)); - - pOut += (ov511->subx + ov511->suby * frame->width) * - (frame->depth >> 3); - } - - /* - * i counts segment lines - * j counts segment columns - * iOut is the offset (in bytes) of the upper left corner - */ - iY = iSegY / (frame->width / WDIV); - jY = iSegY - iY * (frame->width / WDIV); - iOutYP = iY*HDIV*frame->width + jY*WDIV; - iOutY = iOutYP * (frame->depth >> 3); - iUV = iSegUV / (frame->width / WDIV * 2); - jUV = iSegUV - iUV * (frame->width / WDIV * 2); - iOutUVP = iUV*HDIV*2*frame->width + jUV*WDIV/2; - iOutUV = iOutUVP * (frame->depth >> 3); - - switch (frame->format) { - case VIDEO_PALETTE_GREY: - ov511_parse_data_grey (pData, pOut, iOutY, frame->width); - break; - case VIDEO_PALETTE_RGB24: - if (dumppix) - ov511_dumppix(pData, pOut, iOutY, iOutUV, - iY & 1, frame->width); - else if (sensor_gbr) - ov511_parse_gbr422_to_rgb24(pData, pOut, iOutY, iOutUV, - iY & 1, frame->width); - else - ov511_parse_yuv420_to_rgb(pData, pOut, iOutY, iOutUV, - iY & 1, frame->width, 24); - break; - case VIDEO_PALETTE_RGB565: - ov511_parse_yuv420_to_rgb(pData, pOut, iOutY, iOutUV, - iY & 1, frame->width, 16); - break; - case VIDEO_PALETTE_YUV422: - case VIDEO_PALETTE_YUYV: - ov511_parse_data_yuv422(pData, pOut, iOutY, iOutUV, frame->width); - break; - case VIDEO_PALETTE_YUV420: - ov511_parse_data_yuv420 (pData, pOut, iOutYP, iUV*HDIV*frame->width/2 + jUV*WDIV/4, - frame->width, frame->height); - break; - case VIDEO_PALETTE_YUV422P: - ov511_parse_data_yuv422p (pData, pOut, iOutYP, iOutUVP/2, - frame->width, frame->height); - break; - default: - err("Unsupported format: %d", frame->format); + if (frame->scanstate == STATE_LINES) { + int iFrameNext; + + frame->grabstate = FRAME_DONE; // FIXME: Is this right? + + if (waitqueue_active(&frame->wq)) { + frame->grabstate = FRAME_DONE; + wake_up_interruptible(&frame->wq); } - pData = &cdata[iPix]; - } + /* If next frame is ready or grabbing, + * point to it */ + iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES; + if (ov511->frame[iFrameNext].grabstate == FRAME_READY + || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) { + ov511->curframe = iFrameNext; + ov511->frame[iFrameNext].scanstate = STATE_SCANNING; + frame = &ov511->frame[iFrameNext]; + } else { + if (frame->grabstate == FRAME_DONE) { + PDEBUG(4, "Frame done! congratulations"); + } else { + PDEBUG(4, "Frame not ready? state = %d", + ov511->frame[iFrameNext].grabstate); + } + + ov511->curframe = -1; + PDEBUG(4, "SOF dropped (no active frame)"); + continue; /* Nowhere to store this frame */ + } + } + /* Image corruption caused by misplaced frame->segment = 0 + * fixed by carlosf@conectiva.com.br + */ +sof: + PDEBUG(4, "Starting capture on frame %d", frame->framenum); +// Snapshot not reverse-engineered yet. +#if 0 + /* Check to see if it's a snapshot frame */ + /* FIXME?? Should the snapshot reset go here? Performance? */ + if (cdata[8] & 0x02) { + frame->snapshot = 1; + PDEBUG(3, "snapshot detected"); + } +#endif + frame->scanstate = STATE_LINES; + frame->bytes_recvd = 0; +// frame->compressed = 1; + +check_middle: + /* Are we in a frame? */ + if (frame->scanstate != STATE_LINES) { + PDEBUG(4, "scanstate: no SOF yet"); + continue; + } + + /* Dump all data exactly as received */ + if (dumppix == 2) { + frame->bytes_recvd += n; + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + memmove(frame->rawdata + frame->bytes_recvd - n, + &cdata[0], n); + else + PDEBUG(3, "Raw data buffer overrun!! (%d)", + frame->bytes_recvd + - MAX_RAW_DATA_SIZE(ov511->maxwidth, + ov511->maxheight)); + } else { + /* All incoming data are divided into 8-byte segments. If the + * segment contains all zero bytes, it must be skipped. These + * zero-segments allow the OV518 to mainain a constant data rate + * regardless of the effectiveness of the compression. Segments + * are aligned relative to the beginning of each isochronous + * packet. The first segment is a header. + */ + + int b, in = 0, allzero, copied=0; + +// Decompressor expects the header +#if 0 + if (frame->bytes_recvd == 0) + in += 8; /* Skip header */ +#endif + + while (in < n) { + allzero = 1; + for (b = 0; b < 8; b++) { + if (cdata[in + b]) { + allzero = 0; + break; + } + } - /* Save extra data for next time */ - if (frame->segment < frame->width * frame->height / 256) { - ov511->scratchlen = (ov511->packet_size - 1) - iPix; - if (ov511->scratchlen < frame->segsize) - memmove(ov511->scratch, pData, ov511->scratchlen); - else - ov511->scratchlen = 0; + if (allzero) { + /* Don't copy it */ + } else { + if (frame->bytes_recvd + copied + 8 + <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) { + memmove(frame->rawdata + frame->bytes_recvd + copied, + &cdata[in], 8); + copied += 8; + } else { + PDEBUG(3, "Raw data buffer overrun!!"); + } + } + in += 8; + } + frame->bytes_recvd += copied; } } - PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d", - aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4], - aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]); - return totlen; } -static void ov511_isoc_irq(struct urb *urb) +static void +ov511_isoc_irq(struct urb *urb) { int len; struct usb_ov511 *ov511; - struct ov511_sbuf *sbuf; if (!urb->context) { PDEBUG(4, "no context"); @@ -1876,60 +4340,86 @@ PDEBUG(4, "hmmm... not streaming, but got interrupt"); return; } - - sbuf = &ov511->sbuf[ov511->cursbuf]; - /* Copy the data received into our scratch buffer */ + /* Copy the data received into our frame buffer */ if (ov511->curframe >= 0) { - len = ov511_move_data(ov511, urb); + if (ov511->bridge == BRG_OV511 || + ov511->bridge == BRG_OV511PLUS) + len = ov511_move_data(ov511, urb); + else if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) + len = ov518_move_data(ov511, urb); + else + err("Unknown bridge device (%d)", ov511->bridge); } else if (waitqueue_active(&ov511->wq)) { wake_up_interruptible(&ov511->wq); } - /* Move to the next sbuf */ - ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF; - urb->dev = ov511->dev; return; } -static int ov511_init_isoc(struct usb_ov511 *ov511) +/**************************************************************************** + * + * Stream initialization and termination + * + ***************************************************************************/ + +static int +ov511_init_isoc(struct usb_ov511 *ov511) { urb_t *urb; int fx, err, n, size; PDEBUG(3, "*** Initializing capture ***"); - ov511->compress = 0; ov511->curframe = -1; - ov511->cursbuf = 0; - ov511->scratchlen = 0; - if (ov511->bridge == BRG_OV511) - if (cams == 1) size = 993; - else if (cams == 2) size = 513; - else if (cams == 3 || cams == 4) size = 257; + if (ov511->bridge == BRG_OV511) { + if (cams == 1) size = 993; + else if (cams == 2) size = 513; + else if (cams == 3 || cams == 4) size = 257; else { err("\"cams\" parameter too high!"); return -1; } - else if (ov511->bridge == BRG_OV511PLUS) - if (cams == 1) size = 961; - else if (cams == 2) size = 513; - else if (cams == 3 || cams == 4) size = 257; - else if (cams >= 5 && cams <= 8) size = 129; - else if (cams >= 9 && cams <= 31) size = 33; + } else if (ov511->bridge == BRG_OV511PLUS) { + if (cams == 1) size = 961; + else if (cams == 2) size = 513; + else if (cams == 3 || cams == 4) size = 257; + else if (cams >= 5 && cams <= 8) size = 129; + else if (cams >= 9 && cams <= 31) size = 33; else { err("\"cams\" parameter too high!"); return -1; } - else { + } else if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) { + if (cams == 1) size = 896; + else if (cams == 2) size = 512; + else if (cams == 3 || cams == 4) size = 256; + else if (cams >= 5 && cams <= 8) size = 128; + else { + err("\"cams\" parameter too high!"); + return -1; + } + } else { err("invalid bridge type"); return -1; } - ov511_set_packet_size(ov511, size); + if (packetsize == -1) { + // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now + if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) + ov511_set_packet_size(ov511, 640); + else + ov511_set_packet_size(ov511, size); + } else { + info("Forcing packet size to %d", packetsize); + ov511_set_packet_size(ov511, packetsize); + } for (n = 0; n < OV511_NUMSBUF; n++) { urb = usb_alloc_urb(FRAMES_PER_DESC); @@ -1946,13 +4436,17 @@ urb->transfer_buffer = ov511->sbuf[n].data; urb->complete = ov511_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC; + urb->transfer_buffer_length = + ov511->packet_size * FRAMES_PER_DESC; for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = ov511->packet_size * fx; + urb->iso_frame_desc[fx].offset = + ov511->packet_size * fx; urb->iso_frame_desc[fx].length = ov511->packet_size; } } + ov511->streaming = 1; + ov511->sbuf[OV511_NUMSBUF - 1].urb->next = ov511->sbuf[0].urb; for (n = 0; n < OV511_NUMSBUF - 1; n++) ov511->sbuf[n].urb->next = ov511->sbuf[n+1].urb; @@ -1964,19 +4458,18 @@ err("init isoc: usb_submit_urb(%d) ret %d", n, err); } - ov511->streaming = 1; - return 0; } -static void ov511_stop_isoc(struct usb_ov511 *ov511) +static void +ov511_stop_isoc(struct usb_ov511 *ov511) { int n; if (!ov511->streaming || !ov511->dev) return; - PDEBUG (3, "*** Stopping capture ***"); + PDEBUG(3, "*** Stopping capture ***"); ov511_set_packet_size(ov511, 0); @@ -1993,9 +4486,11 @@ } } -static int ov511_new_frame(struct usb_ov511 *ov511, int framenum) +static int +ov511_new_frame(struct usb_ov511 *ov511, int framenum) { struct ov511_frame *frame; + int newnum; PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511->curframe, framenum); @@ -2005,19 +4500,19 @@ /* If we're not grabbing a frame right now and the other frame is */ /* ready to be grabbed into, then use it instead */ if (ov511->curframe == -1) { - if (ov511->frame[(framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES].grabstate == FRAME_READY) - framenum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; + newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; + if (ov511->frame[newnum].grabstate == FRAME_READY) + framenum = newnum; } else return 0; frame = &ov511->frame[framenum]; - PDEBUG (4, "framenum = %d, width = %d, height = %d", framenum, - frame->width, frame->height); + PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, + frame->width, frame->height); frame->grabstate = FRAME_GRABBING; frame->scanstate = STATE_SCANNING; - frame->scanlength = 0; /* accumulated in ov511_parse_data() */ frame->snapshot = 0; ov511->curframe = framenum; @@ -2041,9 +4536,12 @@ * Buffer management * ***************************************************************************/ -static int ov511_alloc(struct usb_ov511 *ov511) +static int +ov511_alloc(struct usb_ov511 *ov511) { int i; + int w = ov511->maxwidth; + int h = ov511->maxheight; PDEBUG(4, "entered"); down(&ov511->buf_lock); @@ -2056,15 +4554,29 @@ if (ov511->buf_state == BUF_ALLOCATED) goto out; - ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE); + ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); if (!ov511->fbuf) goto error; - for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].grabstate = FRAME_UNUSED; - ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE; - PDEBUG(4, "frame[%d] @ %p", i, ov511->frame[i].data); + ov511->rawfbuf = vmalloc(OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); + if (!ov511->rawfbuf) { + rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); + ov511->fbuf = NULL; + goto error; + } + memset(ov511->rawfbuf, 0, OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); + ov511->tempfbuf = vmalloc(OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); + if (!ov511->tempfbuf) { + vfree(ov511->rawfbuf); + ov511->rawfbuf = NULL; + rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); + ov511->fbuf = NULL; + goto error; + } + memset(ov511->tempfbuf, 0, OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); + + for (i = 0; i < OV511_NUMSBUF; i++) { ov511->sbuf[i].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); if (!ov511->sbuf[i].data) { @@ -2072,12 +4584,28 @@ kfree(ov511->sbuf[i].data); ov511->sbuf[i].data = NULL; } - rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE); + vfree(ov511->tempfbuf); + ov511->tempfbuf = NULL; + vfree(ov511->rawfbuf); + ov511->rawfbuf = NULL; + rvfree(ov511->fbuf, + OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); ov511->fbuf = NULL; + goto error; } PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data); } + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE(w, h); + ov511->frame[i].rawdata = ov511->rawfbuf + + i * MAX_RAW_DATA_SIZE(w, h); + ov511->frame[i].tempdata = ov511->tempfbuf + + i * MAX_RAW_DATA_SIZE(w, h); + PDEBUG(4, "frame[%d] @ %p", i, ov511->frame[i].data); + } + ov511->buf_state = BUF_ALLOCATED; out: up(&ov511->buf_lock); @@ -2095,29 +4623,48 @@ * - Because this code will free any non-null pointer, you must be sure to null * them if you explicitly free them somewhere else! */ -static void ov511_do_dealloc(struct usb_ov511 *ov511) +static void +ov511_do_dealloc(struct usb_ov511 *ov511) { int i; PDEBUG(4, "entered"); if (ov511->fbuf) { - rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE); + rvfree(ov511->fbuf, OV511_NUMFRAMES + * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); ov511->fbuf = NULL; } - for (i = 0; i < OV511_NUMFRAMES; i++) { + if (ov511->rawfbuf) { + vfree(ov511->rawfbuf); + ov511->rawfbuf = NULL; + } + + if (ov511->tempfbuf) { + vfree(ov511->tempfbuf); + ov511->tempfbuf = NULL; + } + + for (i = 0; i < OV511_NUMSBUF; i++) { if (ov511->sbuf[i].data) { kfree(ov511->sbuf[i].data); ov511->sbuf[i].data = NULL; } } + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov511->frame[i].data = NULL; + ov511->frame[i].rawdata = NULL; + ov511->frame[i].tempdata = NULL; + } + PDEBUG(4, "buffer memory deallocated"); ov511->buf_state = BUF_NOT_ALLOCATED; PDEBUG(4, "leaving"); } -static void ov511_buf_callback(unsigned long data) +static void +ov511_buf_callback(unsigned long data) { struct usb_ov511 *ov511 = (struct usb_ov511 *)data; PDEBUG(4, "entered"); @@ -2130,7 +4677,8 @@ PDEBUG(4, "leaving"); } -static void ov511_dealloc(struct usb_ov511 *ov511, int now) +static void +ov511_dealloc(struct usb_ov511 *ov511, int now) { struct timer_list *bt = &(ov511->buf_timer); PDEBUG(4, "entered"); @@ -2163,13 +4711,14 @@ * ***************************************************************************/ -static int ov511_open(struct video_device *dev, int flags) +static int +ov511_open(struct video_device *vdev, int flags) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; - int err; + struct usb_ov511 *ov511 = vdev->priv; + int err, i; - MOD_INC_USE_COUNT; PDEBUG(4, "opening"); + down(&ov511->lock); err = -EBUSY; @@ -2182,6 +4731,24 @@ ov511->sub_flag = 0; + /* In case app doesn't set them... */ + if (ov51x_set_default_params(ov511) < 0) + goto out; + + /* Make sure frames are reset */ + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov511->frame[i].grabstate = FRAME_UNUSED; + ov511->frame[i].bytes_read = 0; + } + + /* If compression is on, make sure now that a + * decompressor can be loaded */ + if (ov511->compress && !ov511->decomp_ops) { + err = ov51x_request_decompressor(ov511); + if (err) + goto out; + } + err = ov511_init_isoc(ov511); if (err) { ov511_dealloc(ov511, 0); @@ -2189,17 +4756,18 @@ } ov511->user++; + + if (ov511->led_policy == LED_AUTO) + ov51x_led_control(ov511, 1); out: up(&ov511->lock); - if (err) - MOD_DEC_USE_COUNT; - return err; } -static void ov511_close(struct video_device *dev) +static void +ov511_close(struct video_device *dev) { struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; @@ -2210,40 +4778,50 @@ ov511->user--; ov511_stop_isoc(ov511); + ov51x_release_decompressor(ov511); + + if (ov511->led_policy == LED_AUTO) + ov51x_led_control(ov511, 0); + if (ov511->dev) ov511_dealloc(ov511, 0); up(&ov511->lock); + /* Device unplugged while open. Only a minimum of unregistration is done + * here; the disconnect callback already did the rest. */ if (!ov511->dev) { ov511_dealloc(ov511, 1); video_unregister_device(&ov511->vdev); kfree(ov511); ov511 = NULL; } - - MOD_DEC_USE_COUNT; } -static int ov511_init_done(struct video_device *dev) +static int +ov511_init_done(struct video_device *vdev) { #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - create_proc_ov511_cam((struct usb_ov511 *)dev); + create_proc_ov511_cam((struct usb_ov511 *)vdev); #endif return 0; } -static long ov511_write(struct video_device *dev, const char *buf, unsigned long count, int noblock) +static long +ov511_write(struct video_device *vdev, const char *buf, + unsigned long count, int noblock) { return -EINVAL; } -static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +/* Do not call this function directly! */ +static int +ov511_ioctl_internal(struct video_device *vdev, unsigned int cmd, void *arg) { struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev; - PDEBUG(4, "IOCtl: 0x%X", cmd); + PDEBUG(5, "IOCtl: 0x%X", cmd); if (!ov511->dev) return -EIO; @@ -2253,17 +4831,24 @@ { struct video_capability b; - PDEBUG (4, "VIDIOCGCAP"); + PDEBUG(4, "VIDIOCGCAP"); memset(&b, 0, sizeof(b)); - strcpy(b.name, "OV511 USB Camera"); + sprintf(b.name, "%s USB Camera", + ov511->bridge == BRG_OV511 ? "OV511" : + ov511->bridge == BRG_OV511PLUS ? "OV511+" : + ov511->bridge == BRG_OV518 ? "OV518" : + ov511->bridge == BRG_OV518PLUS ? "OV518+" : + "unknown"); b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; - b.channels = 1; - b.audios = 0; + if (ov511->has_tuner) + b.type |= VID_TYPE_TUNER; + b.channels = ov511->num_inputs; + b.audios = ov511->has_audio_proc ? 1:0; b.maxwidth = ov511->maxwidth; b.maxheight = ov511->maxheight; - b.minwidth = 160; - b.minheight = 120; + b.minwidth = ov511->minwidth; + b.minheight = ov511->minheight; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; @@ -2274,15 +4859,23 @@ { struct video_channel v; + PDEBUG(4, "VIDIOCGCHAN"); + if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if (v.channel != 0) + + if ((unsigned)(v.channel) >= ov511->num_inputs) { + err("Invalid channel (%d)", v.channel); return -EINVAL; + } - v.flags = 0; - v.tuners = 0; - v.type = VIDEO_TYPE_CAMERA; - strcpy(v.name, "Camera"); + v.norm = ov511->norm; + v.type = (ov511->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA; + v.flags = (ov511->has_tuner) ? VIDEO_VC_TUNER : 0; + v.flags |= (ov511->has_audio_proc) ? VIDEO_VC_AUDIO : 0; +// v.flags |= (ov511->has_decoder) ? VIDEO_VC_NORM : 0; + v.tuners = (ov511->has_tuner) ? 1:0; + decoder_get_input_name(ov511, v.channel, v.name); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; @@ -2291,13 +4884,42 @@ } case VIDIOCSCHAN: { - int v; + struct video_channel v; + int err; + + PDEBUG(4, "VIDIOCSCHAN"); if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if (v != 0) + /* Make sure it's not a camera */ + if (!ov511->has_decoder) { + if (v.channel == 0) + return 0; + else + return -EINVAL; + } + + if (v.norm != VIDEO_MODE_PAL && + v.norm != VIDEO_MODE_NTSC && + v.norm != VIDEO_MODE_SECAM && + v.norm != VIDEO_MODE_AUTO) { + err("Invalid norm (%d)", v.norm); + return -EINVAL; + } + + if ((unsigned)(v.channel) >= ov511->num_inputs) { + err("Invalid channel (%d)", v.channel); return -EINVAL; + } + + err = decoder_set_input(ov511, v.channel); + if (err) + return err; + + err = decoder_set_norm(ov511, v.norm); + if (err) + return err; return 0; } @@ -2305,11 +4927,11 @@ { struct video_picture p; - PDEBUG (4, "VIDIOCGPICT"); + PDEBUG(4, "VIDIOCGPICT"); memset(&p, 0, sizeof(p)); - if (ov7610_get_picture(ov511, &p)) + if (sensor_get_picture(ov511, &p)) return -EIO; if (copy_to_user(arg, &p, sizeof(p))) @@ -2322,22 +4944,40 @@ struct video_picture p; int i; - PDEBUG (4, "VIDIOCSPICT"); + PDEBUG(4, "VIDIOCSPICT"); if (copy_from_user(&p, arg, sizeof(p))) return -EFAULT; if (!ov511_get_depth(p.palette)) return -EINVAL; - - if (ov7610_set_picture(ov511, &p)) + + if (sensor_set_picture(ov511, &p)) return -EIO; + if (force_palette && p.palette != force_palette) { + info("Palette rejected (%d)", p.palette); + return -EINVAL; + } + + // FIXME: Format should be independent of frames + if (p.palette != ov511->frame[0].format) { + PDEBUG(4, "Detected format change"); + + /* If we're collecting previous frame wait + before changing modes */ + interruptible_sleep_on(&ov511->wq); + if (signal_pending(current)) return -EINTR; + + mode_init_regs(ov511, ov511->frame[0].width, + ov511->frame[0].height, p.palette, + ov511->sub_flag); + } + PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette); for (i = 0; i < OV511_NUMFRAMES; i++) { ov511->frame[i].depth = p.depth; ov511->frame[i].format = p.palette; - ov511->frame[i].segsize = GET_SEGSIZE(p.palette); } return 0; @@ -2346,7 +4986,7 @@ { int vf; - PDEBUG (4, "VIDIOCGCAPTURE"); + PDEBUG(4, "VIDIOCGCAPTURE"); if (copy_from_user(&vf, arg, sizeof(vf))) return -EFAULT; @@ -2357,6 +4997,8 @@ { struct video_capture vc; + PDEBUG(4, "VIDIOCSCAPTURE"); + if (copy_from_user(&vc, arg, sizeof(vc))) return -EFAULT; if (vc.flags) @@ -2391,7 +5033,7 @@ if (copy_from_user(&vw, arg, sizeof(vw))) return -EFAULT; - PDEBUG (4, "VIDIOCSWIN: width=%d, height=%d", + PDEBUG(4, "VIDIOCSWIN: width=%d, height=%d", vw.width, vw.height); #if 0 @@ -2410,7 +5052,7 @@ interruptible_sleep_on(&ov511->wq); if (signal_pending(current)) return -EINTR; - result = ov511_mode_init_regs(ov511, vw.width, vw.height, + result = mode_init_regs(ov511, vw.width, vw.height, ov511->frame[0].format, ov511->sub_flag); if (result < 0) return result; @@ -2433,7 +5075,7 @@ vw.height = ov511->frame[0].height; vw.flags = 30; - PDEBUG (4, "VIDIOCGWIN: %dx%d", vw.width, vw.height); + PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height); if (copy_to_user(arg, &vw, sizeof(vw))) return -EFAULT; @@ -2444,14 +5086,18 @@ { struct video_mbuf vm; int i; - + + PDEBUG(4, "VIDIOCGMBUF"); + memset(&vm, 0, sizeof(vm)); - vm.size = OV511_NUMFRAMES * MAX_DATA_SIZE; + vm.size = OV511_NUMFRAMES + * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight); vm.frames = OV511_NUMFRAMES; + vm.offsets[0] = 0; for (i = 1; i < OV511_NUMFRAMES; i++) { - vm.offsets[i] = vm.offsets[i-1] + MAX_FRAME_SIZE - + sizeof (struct timeval); + vm.offsets[i] = vm.offsets[i-1] + + MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight); } if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) @@ -2482,63 +5128,74 @@ return -EINVAL; } - if (vm.width > ov511->maxwidth || vm.height > ov511->maxheight) { + if (vm.width > ov511->maxwidth + || vm.height > ov511->maxheight) { err("VIDIOCMCAPTURE: requested dimensions too big"); return -EINVAL; } - if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) + if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) { + PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); return -EBUSY; + } + + if (force_palette && vm.format != force_palette) { + info("palette rejected (%d)", vm.format); + return -EINVAL; + } - /* Don't compress if the size changed */ if ((ov511->frame[vm.frame].width != vm.width) || (ov511->frame[vm.frame].height != vm.height) || (ov511->frame[vm.frame].format != vm.format) || - (ov511->frame[vm.frame].sub_flag != - ov511->sub_flag)) { + (ov511->frame[vm.frame].sub_flag != ov511->sub_flag) || + (ov511->frame[vm.frame].depth != depth)) { + PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); + /* If we're collecting previous frame wait before changing modes */ interruptible_sleep_on(&ov511->wq); if (signal_pending(current)) return -EINTR; - ret = ov511_mode_init_regs(ov511, vm.width, vm.height, + ret = mode_init_regs(ov511, vm.width, vm.height, vm.format, ov511->sub_flag); #if 0 - if (ret < 0) + if (ret < 0) { + PDEBUG(1, "Got error while initializing regs "); return ret; + } #endif + ov511->frame[vm.frame].width = vm.width; + ov511->frame[vm.frame].height = vm.height; + ov511->frame[vm.frame].format = vm.format; + ov511->frame[vm.frame].sub_flag = ov511->sub_flag; + ov511->frame[vm.frame].depth = depth; } - ov511->frame[vm.frame].width = vm.width; - ov511->frame[vm.frame].height = vm.height; - ov511->frame[vm.frame].format = vm.format; - ov511->frame[vm.frame].sub_flag = ov511->sub_flag; - ov511->frame[vm.frame].segsize = GET_SEGSIZE(vm.format); - ov511->frame[vm.frame].depth = depth; - /* Mark it as ready */ ov511->frame[vm.frame].grabstate = FRAME_READY; + PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame); + return ov511_new_frame(ov511, vm.frame); } case VIDIOCSYNC: { - int frame; + int fnum, rc; + struct ov511_frame *frame; - if (copy_from_user((void *)&frame, arg, sizeof(int))) + if (copy_from_user((void *)&fnum, arg, sizeof(int))) return -EFAULT; - if ((unsigned)frame >= OV511_NUMFRAMES) { - err("VIDIOCSYNC: invalid frame (%d)", frame); + if ((unsigned)fnum >= OV511_NUMFRAMES) { + err("VIDIOCSYNC: invalid frame (%d)", fnum); return -EINVAL; } - PDEBUG(4, "syncing to frame %d, grabstate = %d", frame, - ov511->frame[frame].grabstate); + frame = &ov511->frame[fnum]; - if(frame < 0 || frame >= OV511_NUMFRAMES) - return -EINVAL; - - switch (ov511->frame[frame].grabstate) { + PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum, + frame->grabstate); + + switch (frame->grabstate) { case FRAME_UNUSED: return -EINVAL; case FRAME_READY: @@ -2548,56 +5205,41 @@ if (!ov511->dev) return -EIO; - do { -#if 0 - init_waitqueue_head(&ov511->frame[frame].wq); -#endif - interruptible_sleep_on(&ov511->frame[frame].wq); - if (signal_pending(current)) { - if (retry_sync) { - PDEBUG(3, "***retry sync***"); - - /* Polling apps will destroy frames with that! */ - ov511_new_frame(ov511, frame); - ov511->curframe = -1; - - /* This will request another frame. */ - if (waitqueue_active(&ov511->frame[frame].wq)) - wake_up_interruptible(&ov511->frame[frame].wq); - - return 0; - } else { - return -EINTR; - } - } - } while (ov511->frame[frame].grabstate == FRAME_GRABBING); + rc = wait_event_interruptible(frame->wq, + (frame->grabstate == FRAME_DONE) + || (frame->grabstate == FRAME_ERROR)); + + if (rc) + return rc; - if (ov511->frame[frame].grabstate == FRAME_ERROR) { + if (frame->grabstate == FRAME_ERROR) { int ret; - if ((ret = ov511_new_frame(ov511, frame)) < 0) + if ((ret = ov511_new_frame(ov511, fnum)) < 0) return ret; goto redo; - } + } + /* Fall through */ case FRAME_DONE: - if (ov511->snap_enabled && !ov511->frame[frame].snapshot) { + if (ov511->snap_enabled && !frame->snapshot) { int ret; - if ((ret = ov511_new_frame(ov511, frame)) < 0) + if ((ret = ov511_new_frame(ov511, fnum)) < 0) return ret; goto redo; } - ov511->frame[frame].grabstate = FRAME_UNUSED; + frame->grabstate = FRAME_UNUSED; /* Reset the hardware snapshot button */ /* FIXME - Is this the best place for this? */ - if ((ov511->snap_enabled) && - (ov511->frame[frame].snapshot)) { - ov511->frame[frame].snapshot = 0; - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03); - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); + if ((ov511->snap_enabled) && (frame->snapshot)) { + frame->snapshot = 0; + ov51x_clear_snapshot(ov511); } + + /* Decompression, format conversion, etc... */ + ov511_postprocess(ov511, frame); + break; } /* end switch */ @@ -2607,6 +5249,8 @@ { struct video_buffer vb; + PDEBUG(4, "VIDIOCSCHAN"); + memset(&vb, 0, sizeof(vb)); vb.base = NULL; /* frame buffer not supported, not used */ @@ -2615,43 +5259,170 @@ return 0; } - case VIDIOCKEY: + case VIDIOCGUNIT: + { + struct video_unit vu; + + PDEBUG(4, "VIDIOCGUNIT"); + + memset(&vu, 0, sizeof(vu)); + + vu.video = ov511->vdev.minor; /* Video minor */ + vu.vbi = VIDEO_NO_UNIT; /* VBI minor */ + vu.radio = VIDEO_NO_UNIT; /* Radio minor */ + vu.audio = VIDEO_NO_UNIT; /* Audio minor */ + vu.teletext = VIDEO_NO_UNIT; /* Teletext minor */ + + if (copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) + return -EFAULT; + return 0; - case VIDIOCCAPTURE: - return -EINVAL; - case VIDIOCSFBUF: - return -EINVAL; + } case VIDIOCGTUNER: + { + struct video_tuner v; + + PDEBUG(4, "VIDIOCGTUNER"); + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (!ov511->has_tuner || v.tuner) // Only tuner 0 + return -EINVAL; + + strcpy(v.name, "Television"); + + // FIXME: Need a way to get the real values + v.rangelow = 0; + v.rangehigh = ~0; + + v.flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC | + VIDEO_TUNER_SECAM; + v.mode = 0; /* FIXME: Not sure what this is yet */ + v.signal = 0xFFFF; /* unknown */ + + call_i2c_clients(ov511, cmd, &v); + + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + + return 0; + } case VIDIOCSTUNER: - return -EINVAL; + { + struct video_tuner v; + int err; + + PDEBUG(4, "VIDIOCSTUNER"); + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + /* Only no or one tuner for now */ + if (!ov511->has_tuner || v.tuner) + return -EINVAL; + + /* and it only has certain valid modes */ + if (v.mode != VIDEO_MODE_PAL && + v.mode != VIDEO_MODE_NTSC && + v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP; + + /* Is this right/necessary? */ + err = decoder_set_norm(ov511, v.mode); + if (err) + return err; + + call_i2c_clients(ov511, cmd, &v); + + return 0; + } case VIDIOCGFREQ: + { + unsigned long v = ov511->freq; + + PDEBUG(4, "VIDIOCGFREQ"); + + if (!ov511->has_tuner) + return -EINVAL; +#if 0 + /* FIXME: this is necessary for testing */ + v = 46*16; +#endif + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + + return 0; + } case VIDIOCSFREQ: - return -EINVAL; + { + unsigned long v; + + if (!ov511->has_tuner) + return -EINVAL; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + PDEBUG(4, "VIDIOCSFREQ: %lx", v); + + ov511->freq = v; + call_i2c_clients(ov511, cmd, &v); + + return 0; + } case VIDIOCGAUDIO: case VIDIOCSAUDIO: - return -EINVAL; + { + /* FIXME: Implement this... */ + return 0; + } default: + PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd); return -ENOIOCTLCMD; } /* end switch */ return 0; } -static long ov511_read(struct video_device *dev, char *buf, unsigned long count, int noblock) +static int +ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; - int i; - int frmx = -1; - volatile struct ov511_frame *frame; + int rc; + struct usb_ov511 *ov511 = vdev->priv; + + if (down_interruptible(&ov511->lock)) + return -EINTR; + + rc = ov511_ioctl_internal(vdev, cmd, arg); + + up(&ov511->lock); + return rc; +} + +static inline long +ov511_read(struct video_device *vdev, char *buf, unsigned long count, + int noblock) +{ + struct usb_ov511 *ov511 = vdev->priv; + int i, rc = 0, frmx = -1; + struct ov511_frame *frame; + + if (down_interruptible(&ov511->lock)) + return -EINTR; PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); - if (!dev || !buf) - return -EFAULT; + if (!vdev || !buf) { + rc = -EFAULT; + goto error; + } - if (!ov511->dev) - return -EIO; + if (!ov511->dev) { + rc = -EIO; + goto error; + } +// FIXME: Only supports two frames /* See if a frame is completed, then use it. */ if (ov511->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ frmx = 0; @@ -2659,8 +5430,10 @@ frmx = 1; /* If nonblocking we return immediately */ - if (noblock && (frmx == -1)) - return -EAGAIN; + if (noblock && (frmx == -1)) { + rc = -EAGAIN; + goto error; + } /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ /* See if a frame is in process (grabbing), then use it. */ @@ -2672,89 +5445,116 @@ } /* If no frame is active, start one. */ - if (frmx == -1) - ov511_new_frame(ov511, frmx = 0); + if (frmx == -1) { + if ((rc = ov511_new_frame(ov511, frmx = 0))) { + err("read: ov511_new_frame error"); + goto error; + } + } frame = &ov511->frame[frmx]; restart: - if (!ov511->dev) - return -EIO; + if (!ov511->dev) { + rc = -EIO; + goto error; + } /* Wait while we're grabbing the image */ PDEBUG(4, "Waiting image grabbing"); - while (frame->grabstate == FRAME_GRABBING) { - interruptible_sleep_on(&ov511->frame[frmx].wq); - if (signal_pending(current)) - return -EINTR; - } + rc = wait_event_interruptible(frame->wq, + (frame->grabstate == FRAME_DONE) + || (frame->grabstate == FRAME_ERROR)); + + if (rc) + goto error; + PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate); + PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd); if (frame->grabstate == FRAME_ERROR) { frame->bytes_read = 0; err("** ick! ** Errored frame %d", ov511->curframe); - if (ov511_new_frame(ov511, frmx)) + if (ov511_new_frame(ov511, frmx)) { err("read: ov511_new_frame error"); + goto error; + } goto restart; } /* Repeat until we get a snapshot frame */ if (ov511->snap_enabled) - PDEBUG (4, "Waiting snapshot frame"); + PDEBUG(4, "Waiting snapshot frame"); if (ov511->snap_enabled && !frame->snapshot) { frame->bytes_read = 0; - if (ov511_new_frame(ov511, frmx)) - err("ov511_new_frame error"); + if ((rc = ov511_new_frame(ov511, frmx))) { + err("read: ov511_new_frame error"); + goto error; + } goto restart; } /* Clear the snapshot */ if (ov511->snap_enabled && frame->snapshot) { frame->snapshot = 0; - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03); - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); + ov51x_clear_snapshot(ov511); } - PDEBUG(4, "frmx=%d, bytes_read=%ld, scanlength=%ld", frmx, - frame->bytes_read, frame->scanlength); + /* Decompression, format conversion, etc... */ + ov511_postprocess(ov511, frame); + + PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx, + frame->bytes_read, + get_frame_length(frame)); /* copy bytes to user space; we allow for partials reads */ -// if ((count + frame->bytes_read) > frame->scanlength) +// if ((count + frame->bytes_read) +// > get_frame_length((struct ov511_frame *)frame)) // count = frame->scanlength - frame->bytes_read; /* FIXME - count hardwired to be one frame... */ - count = frame->width * frame->height * (frame->depth >> 3); + count = get_frame_length(frame); PDEBUG(4, "Copy to user space: %ld bytes", count); if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) { PDEBUG(4, "Copy failed! %d bytes not copied", i); - return -EFAULT; + rc = -EFAULT; + goto error; } frame->bytes_read += count; PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld", count, frame->bytes_read); - if (frame->bytes_read >= frame->scanlength) { /* All data has been read */ + /* If all data has been read... */ + if (frame->bytes_read + >= get_frame_length(frame)) { frame->bytes_read = 0; +// FIXME: Only supports two frames /* Mark it as available to be used again. */ ov511->frame[frmx].grabstate = FRAME_UNUSED; - if (ov511_new_frame(ov511, !frmx)) + if ((rc = ov511_new_frame(ov511, !frmx))) { err("ov511_new_frame returned error"); + goto error; + } } PDEBUG(4, "read finished, returning %ld (sweet)", count); + up(&ov511->lock); return count; + +error: + up(&ov511->lock); + return rc; } -static int ov511_mmap(struct video_device *dev, const char *adr, - unsigned long size) +static int +ov511_mmap(struct video_device *vdev, const char *adr, unsigned long size) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + struct usb_ov511 *ov511 = vdev->priv; unsigned long start = (unsigned long)adr; unsigned long page, pos; @@ -2763,14 +5563,21 @@ PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); - if (size > (((OV511_NUMFRAMES * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) + if (size > (((OV511_NUMFRAMES + * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight) + + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) return -EINVAL; + if (down_interruptible(&ov511->lock)) + return -EINTR; + pos = (unsigned long)ov511->fbuf; while (size > 0) { page = kvirt_to_pa(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { + up(&ov511->lock); return -EAGAIN; + } start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) @@ -2779,10 +5586,12 @@ size = 0; } + up(&ov511->lock); return 0; } static struct video_device ov511_template = { + owner: THIS_MODULE, name: "OV511 USB Camera", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_OV511, @@ -2795,15 +5604,237 @@ initialize: ov511_init_done, }; +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +static int +ov511_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long ularg) +{ + struct proc_dir_entry *pde; + struct usb_ov511 *ov511; + void *arg = (void *) ularg; + int rc; + + pde = (struct proc_dir_entry *) inode->u.generic_ip; + if (!pde) + return -ENOENT; + + ov511 = (struct usb_ov511 *) pde->data; + if (!ov511) + return -ENODEV; + + if (!ov511->dev) + return -EIO; + + /* Should we pass through standard V4L IOCTLs? */ + + switch (cmd) { + case OV511IOC_GINTVER: + { + int ver = OV511_INTERFACE_VER; + + PDEBUG(4, "Get interface version: %d", ver); + if (copy_to_user(arg, &ver, sizeof(ver))) + return -EFAULT; + + return 0; + } + case OV511IOC_GUSHORT: + { + struct ov511_ushort_opt opt; + + if (copy_from_user(&opt, arg, sizeof(opt))) + return -EFAULT; + + switch (opt.optnum) { + case OV511_USOPT_BRIGHT: + rc = sensor_get_brightness(ov511, &(opt.val)); + if (rc) return rc; + break; + case OV511_USOPT_SAT: + rc = sensor_get_saturation(ov511, &(opt.val)); + if (rc) return rc; + break; + case OV511_USOPT_HUE: + rc = sensor_get_hue(ov511, &(opt.val)); + if (rc) return rc; + break; + case OV511_USOPT_CONTRAST: + rc = sensor_get_contrast(ov511, &(opt.val)); + if (rc) return rc; + break; + default: + err("Invalid get short option number"); + return -EINVAL; + } + + if (copy_to_user(arg, &opt, sizeof(opt))) + return -EFAULT; + + return 0; + } + case OV511IOC_SUSHORT: + { + struct ov511_ushort_opt opt; + + if (copy_from_user(&opt, arg, sizeof(opt))) + return -EFAULT; + + switch (opt.optnum) { + case OV511_USOPT_BRIGHT: + rc = sensor_set_brightness(ov511, opt.val); + if (rc) return rc; + break; + case OV511_USOPT_SAT: + rc = sensor_set_saturation(ov511, opt.val); + if (rc) return rc; + break; + case OV511_USOPT_HUE: + rc = sensor_set_hue(ov511, opt.val); + if (rc) return rc; + break; + case OV511_USOPT_CONTRAST: + rc = sensor_set_contrast(ov511, opt.val); + if (rc) return rc; + break; + default: + err("Invalid set short option number"); + return -EINVAL; + } + + return 0; + } + case OV511IOC_GUINT: + { + struct ov511_uint_opt opt; + + if (copy_from_user(&opt, arg, sizeof(opt))) + return -EFAULT; + + switch (opt.optnum) { + case OV511_UIOPT_POWER_FREQ: + opt.val = ov511->lightfreq; + break; + case OV511_UIOPT_BFILTER: + opt.val = ov511->bandfilt; + break; + case OV511_UIOPT_LED: + opt.val = ov511->led_policy; + break; + case OV511_UIOPT_DEBUG: + opt.val = debug; + break; + case OV511_UIOPT_COMPRESS: + opt.val = ov511->compress; + break; + default: + err("Invalid get int option number"); + return -EINVAL; + } + + if (copy_to_user(arg, &opt, sizeof(opt))) + return -EFAULT; + + return 0; + } + case OV511IOC_SUINT: + { + struct ov511_uint_opt opt; + + if (copy_from_user(&opt, arg, sizeof(opt))) + return -EFAULT; + + switch (opt.optnum) { + case OV511_UIOPT_POWER_FREQ: + rc = sensor_set_light_freq(ov511, opt.val); + if (rc) return rc; + break; + case OV511_UIOPT_BFILTER: + rc = sensor_set_banding_filter(ov511, opt.val); + if (rc) return rc; + break; + case OV511_UIOPT_LED: + if (opt.val <= 2) { + ov511->led_policy = opt.val; + if (ov511->led_policy == LED_OFF) + ov51x_led_control(ov511, 0); + else if (ov511->led_policy == LED_ON) + ov51x_led_control(ov511, 1); + } else { + return -EINVAL; + } + break; + case OV511_UIOPT_DEBUG: + if (opt.val <= 5) + debug = opt.val; + else + return -EINVAL; + break; + case OV511_UIOPT_COMPRESS: + ov511->compress = opt.val; + if (ov511->compress) { + if (ov511->bridge == BRG_OV511 || + ov511->bridge == BRG_OV511PLUS) + ov511_init_compression(ov511); + else if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) + ov518_init_compression(ov511); + } + break; + default: + err("Invalid get int option number"); + return -EINVAL; + } + + return 0; + } + case OV511IOC_WI2C: + { + struct ov511_i2c_struct w; + + if (copy_from_user(&w, arg, sizeof(w))) + return -EFAULT; + + return ov51x_i2c_write_slave(ov511, w.slave, w.reg, w.value, + w.mask); + } + case OV511IOC_RI2C: + { + struct ov511_i2c_struct r; + + if (copy_from_user(&r, arg, sizeof(r))) + return -EFAULT; + + rc = ov51x_i2c_read_slave(ov511, r.slave, r.reg); + if (rc < 0) + return rc; + + r.value = rc; + + if (copy_to_user(arg, &r, sizeof(r))) + return -EFAULT; + + return 0; + } + default: + return -EINVAL; + } /* end switch */ + + return 0; +} +#endif + /**************************************************************************** * - * OV511/OV7610 configuration + * OV511 and sensor configuration * ***************************************************************************/ -static int ov76xx_configure(struct usb_ov511 *ov511) +/* This initializes the OV7610, OV7620, or OV7620AE sensor. The OV7620AE uses + * the same register settings as the OV7610, since they are very similar. + */ +static int +ov7xx0_configure(struct usb_ov511 *ov511) { - struct usb_device *dev = ov511->dev; int i, success; int rc; @@ -2832,9 +5863,11 @@ { OV511_I2C_BUS, 0x23, 0x2a }, { OV511_I2C_BUS, 0x24, 0x10 }, { OV511_I2C_BUS, 0x25, 0x8a }, + { OV511_I2C_BUS, 0x26, 0xa2 }, { OV511_I2C_BUS, 0x27, 0xc2 }, { OV511_I2C_BUS, 0x2a, 0x04 }, { OV511_I2C_BUS, 0x2c, 0xfe }, + { OV511_I2C_BUS, 0x2d, 0x93 }, { OV511_I2C_BUS, 0x30, 0x71 }, { OV511_I2C_BUS, 0x31, 0x60 }, { OV511_I2C_BUS, 0x32, 0x26 }, @@ -2848,81 +5881,96 @@ }; static struct ov511_regvals aRegvalsNorm7620[] = { - { OV511_I2C_BUS, 0x10, 0xff }, - { OV511_I2C_BUS, 0x16, 0x06 }, - { OV511_I2C_BUS, 0x28, 0x24 }, - { OV511_I2C_BUS, 0x2b, 0xac }, - { OV511_I2C_BUS, 0x12, 0x00 }, - { OV511_I2C_BUS, 0x28, 0x24 }, - { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ - { OV511_I2C_BUS, 0x15, 0x01 }, - { OV511_I2C_BUS, 0x23, 0x00 }, - { OV511_I2C_BUS, 0x24, 0x10 }, - { OV511_I2C_BUS, 0x25, 0x8a }, - { OV511_I2C_BUS, 0x27, 0xe2 }, - { OV511_I2C_BUS, 0x2a, 0x00 }, - { OV511_I2C_BUS, 0x2c, 0xfe }, - { OV511_I2C_BUS, 0x30, 0x71 }, - { OV511_I2C_BUS, 0x31, 0x60 }, - { OV511_I2C_BUS, 0x32, 0x26 }, - { OV511_I2C_BUS, 0x33, 0x20 }, - { OV511_I2C_BUS, 0x34, 0x48 }, - { OV511_I2C_BUS, 0x12, 0x24 }, - { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x00, 0x00 }, + { OV511_I2C_BUS, 0x01, 0x80 }, + { OV511_I2C_BUS, 0x02, 0x80 }, + { OV511_I2C_BUS, 0x03, 0xc0 }, + { OV511_I2C_BUS, 0x06, 0x60 }, + { OV511_I2C_BUS, 0x07, 0x00 }, + { OV511_I2C_BUS, 0x0c, 0x24 }, { OV511_I2C_BUS, 0x0c, 0x24 }, { OV511_I2C_BUS, 0x0d, 0x24 }, + { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x12, 0x24 }, + { OV511_I2C_BUS, 0x13, 0x01 }, + { OV511_I2C_BUS, 0x14, 0x84 }, + { OV511_I2C_BUS, 0x15, 0x01 }, + { OV511_I2C_BUS, 0x16, 0x03 }, + { OV511_I2C_BUS, 0x17, 0x2f }, + { OV511_I2C_BUS, 0x18, 0xcf }, + { OV511_I2C_BUS, 0x19, 0x06 }, + { OV511_I2C_BUS, 0x1a, 0xf5 }, + { OV511_I2C_BUS, 0x1b, 0x00 }, + { OV511_I2C_BUS, 0x20, 0x18 }, + { OV511_I2C_BUS, 0x21, 0x80 }, + { OV511_I2C_BUS, 0x22, 0x80 }, + { OV511_I2C_BUS, 0x23, 0x00 }, + { OV511_I2C_BUS, 0x26, 0xa2 }, + { OV511_I2C_BUS, 0x27, 0xea }, + { OV511_I2C_BUS, 0x28, 0x20 }, + { OV511_I2C_BUS, 0x29, 0x00 }, + { OV511_I2C_BUS, 0x2a, 0x10 }, + { OV511_I2C_BUS, 0x2b, 0x00 }, + { OV511_I2C_BUS, 0x2c, 0x88 }, + { OV511_I2C_BUS, 0x2d, 0x91 }, + { OV511_I2C_BUS, 0x2e, 0x80 }, + { OV511_I2C_BUS, 0x2f, 0x44 }, + { OV511_I2C_BUS, 0x60, 0x27 }, + { OV511_I2C_BUS, 0x61, 0x02 }, + { OV511_I2C_BUS, 0x62, 0x5f }, + { OV511_I2C_BUS, 0x63, 0xd5 }, + { OV511_I2C_BUS, 0x64, 0x57 }, + { OV511_I2C_BUS, 0x65, 0x83 }, + { OV511_I2C_BUS, 0x66, 0x55 }, + { OV511_I2C_BUS, 0x67, 0x92 }, + { OV511_I2C_BUS, 0x68, 0xcf }, + { OV511_I2C_BUS, 0x69, 0x76 }, + { OV511_I2C_BUS, 0x6a, 0x22 }, + { OV511_I2C_BUS, 0x6b, 0x00 }, + { OV511_I2C_BUS, 0x6c, 0x02 }, + { OV511_I2C_BUS, 0x6d, 0x44 }, + { OV511_I2C_BUS, 0x6e, 0x80 }, + { OV511_I2C_BUS, 0x6f, 0x1d }, + { OV511_I2C_BUS, 0x70, 0x8b }, + { OV511_I2C_BUS, 0x71, 0x00 }, + { OV511_I2C_BUS, 0x72, 0x14 }, + { OV511_I2C_BUS, 0x73, 0x54 }, + { OV511_I2C_BUS, 0x74, 0x00 }, + { OV511_I2C_BUS, 0x75, 0x8e }, + { OV511_I2C_BUS, 0x76, 0x00 }, + { OV511_I2C_BUS, 0x77, 0xff }, + { OV511_I2C_BUS, 0x78, 0x80 }, + { OV511_I2C_BUS, 0x79, 0x80 }, + { OV511_I2C_BUS, 0x7a, 0x80 }, + { OV511_I2C_BUS, 0x7b, 0xe2 }, + { OV511_I2C_BUS, 0x7c, 0x00 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; - PDEBUG (4, "starting configuration"); + PDEBUG(4, "starting configuration"); /* This looks redundant, but is necessary for WebCam 3 */ - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, - OV7610_I2C_WRITE_ID) < 0) - return -1; - - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, - OV7610_I2C_READ_ID) < 0) - return -1; - - if (ov511_reset(dev, OV511_RESET_NOREGS) < 0) + ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; + if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, + OV7xx0_I2C_READ_ID) < 0) return -1; - /* Reset the 76xx */ - if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1; - - /* Wait for it to initialize */ - schedule_timeout (1 + 150 * HZ / 1000); - - for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { - if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) && - (ov511_i2c_read(dev, OV7610_REG_ID_LOW) == 0xA2)) { - success = 1; - continue; - } - - /* Reset the 76xx */ - if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1; - /* Wait for it to initialize */ - schedule_timeout (1 + 150 * HZ / 1000); - /* Dummy read to sync I2C */ - if (ov511_i2c_read(dev, 0x00) < 0) return -1; - } - - if (success) { - PDEBUG(1, "I2C synced in %d attempt(s) (method 1)", i); + if (ov51x_init_ov_sensor(ov511) >= 0) { + PDEBUG(1, "OV7xx0 sensor initalized (method 1)"); } else { /* Reset the 76xx */ - if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1; + if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -1; /* Wait for it to initialize */ - schedule_timeout (1 + 150 * HZ / 1000); + schedule_timeout(1 + 150 * HZ / 1000); i = 0; success = 0; while (i <= i2c_detect_tries) { - if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) && - (ov511_i2c_read(dev, OV7610_REG_ID_LOW) == 0xA2)) { + if ((ov51x_i2c_read(ov511, + OV7610_REG_ID_HIGH) == 0x7F) && + (ov51x_i2c_read(ov511, + OV7610_REG_ID_LOW) == 0xA2)) { success = 1; break; } else { @@ -2930,311 +5978,705 @@ } } - if ((i == i2c_detect_tries) && (success == 0)) { - err("Failed to read sensor ID. You might not have an OV7610/20,"); - err("or it may be not responding. Report this to"); - err("mwm@i.am"); - return -1; +// Was (i == i2c_detect_tries) previously. This obviously used to always report +// success. Whether anyone actually depended on that bug is unknown + if ((i >= i2c_detect_tries) && (success == 0)) { + err("Failed to read sensor ID. You might not have an"); + err("OV7610/20, or it may be not responding. Report"); + err("this to " EMAIL); + err("This is only a warning. You can attempt to use"); + err("your camera anyway"); +// Only issue a warning for now +// return -1; } else { - PDEBUG(1, "I2C synced in %d attempt(s) (method 2)", i+1); + PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1); } } - /* Detect sensor if user didn't use override param */ - if (sensor == 0) { - rc = ov511_i2c_read(dev, OV7610_REG_COM_I); + /* Detect sensor (sub)type */ + rc = ov51x_i2c_read(ov511, OV7610_REG_COM_I); - if (rc < 0) { - err("Error detecting sensor type"); - return -1; - } else if((rc & 3) == 3) { - info("Sensor is an OV7610"); - ov511->sensor = SEN_OV7610; - } else if((rc & 3) == 1) { + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } else if ((rc & 3) == 3) { + info("Sensor is an OV7610"); + ov511->sensor = SEN_OV7610; + } else if ((rc & 3) == 1) { + /* I don't know what's different about the 76BE yet */ + if (ov51x_i2c_read(ov511, 0x15) & 1) info("Sensor is an OV7620AE"); - ov511->sensor = SEN_OV7620AE; - } else if((rc & 3) == 0) { - info("Sensor is an OV7620"); + else + info("Sensor is an OV76BE"); + + /* OV511+ will return all zero isoc data unless we + * configure the sensor as a 7620. Someone needs to + * find the exact reg. setting that causes this. */ + if (ov511->bridge == BRG_OV511PLUS) { + info("Enabling 511+/7620AE workaround"); ov511->sensor = SEN_OV7620; } else { - err("Unknown image sensor version: %d", rc & 3); + ov511->sensor = SEN_OV7620AE; + } + } else if ((rc & 3) == 0) { + info("Sensor is an OV7620"); + ov511->sensor = SEN_OV7620; + } else { + err("Unknown image sensor version: %d", rc & 3); + return -1; + } + + if (ov511->sensor == SEN_OV7620) { + PDEBUG(4, "Writing 7620 registers"); + if (ov511_write_regvals(ov511, aRegvalsNorm7620)) + return -1; + } else { + PDEBUG(4, "Writing 7610 registers"); + if (ov511_write_regvals(ov511, aRegvalsNorm7610)) + return -1; + } + + /* Set sensor-specific vars */ + ov511->maxwidth = 640; + ov511->maxheight = 480; + ov511->minwidth = 64; + ov511->minheight = 48; + + // FIXME: These do not match the actual settings yet + ov511->brightness = 0x80 << 8; + ov511->contrast = 0x80 << 8; + ov511->colour = 0x80 << 8; + ov511->hue = 0x80 << 8; + + return 0; +} + +/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ +static int +ov6xx0_configure(struct usb_ov511 *ov511) +{ + int rc; + + static struct ov511_regvals aRegvalsNorm6x20[] = { + { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ + { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x03, 0x60 }, + { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ + { OV511_I2C_BUS, 0x07, 0xa8 }, + /* The ratio of 0x0c and 0x0d controls the white point */ + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0d, 0x24 }, + { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */ + { OV511_I2C_BUS, 0x14, 0x04 }, + /* 0x16: 0x06 helps frame stability with moving objects */ + { OV511_I2C_BUS, 0x16, 0x06 }, +// { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ + { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ + /* 0x28: 0x05 Selects RGB format if RGB on */ + { OV511_I2C_BUS, 0x28, 0x05 }, + { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ +// { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ + { OV511_I2C_BUS, 0x2d, 0x99 }, + { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */ + { OV511_I2C_BUS, 0x38, 0x8b }, + { OV511_I2C_BUS, 0x39, 0x40 }, + + { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ + { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ + { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ + + { OV511_I2C_BUS, 0x3d, 0x80 }, + /* These next two registers (0x4a, 0x4b) are undocumented. They + * control the color balance */ + { OV511_I2C_BUS, 0x4a, 0x80 }, + { OV511_I2C_BUS, 0x4b, 0x80 }, + { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */ + { OV511_I2C_BUS, 0x4e, 0xc1 }, + { OV511_I2C_BUS, 0x4f, 0x04 }, +// Do 50-53 have any effect? +// Toggle 0x12[2] off and on here? + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + /* This chip is undocumented so many of these are guesses. OK=verified, + * A=Added since 6620, U=unknown function (not a 6620 reg) */ + static struct ov511_regvals aRegvalsNorm6x30[] = { + /*OK*/ { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ + /*00?*/ { OV511_I2C_BUS, 0x11, 0x01 }, + /*OK*/ { OV511_I2C_BUS, 0x03, 0x60 }, + /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ + { OV511_I2C_BUS, 0x07, 0xa8 }, + /* The ratio of 0x0c and 0x0d controls the white point */ + /*OK*/ { OV511_I2C_BUS, 0x0c, 0x24 }, + /*OK*/ { OV511_I2C_BUS, 0x0d, 0x24 }, + /*A*/ { OV511_I2C_BUS, 0x0e, 0x20 }, + +// /*24?*/ { OV511_I2C_BUS, 0x12, 0x28 }, /* Enable AGC */ +// { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */ + +// /*A*/ { OV511_I2C_BUS, 0x13, 0x21 }, +// /*A*/ { OV511_I2C_BUS, 0x13, 0x25 }, /* Tristate Y and UV busses */ + +// /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 }, + /* 0x16: 0x06 helps frame stability with moving objects */ + /*03?*/ { OV511_I2C_BUS, 0x16, 0x06 }, +// /*OK*/ { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ + // 21 & 22? The suggested values look wrong. Go with default + /*A*/ { OV511_I2C_BUS, 0x23, 0xc0 }, + /*A*/ { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default +// /*OK*/ { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ + + /* 0x28: 0x05 Selects RGB format if RGB on */ +// /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 }, +// /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus + + /*OK*/ { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ +// /*OK*/ { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ +// /*U*/ { OV511_I2C_BUS, 0x2c, 0xa0 }, + { OV511_I2C_BUS, 0x2d, 0x99 }, +// /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620 +// /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */ +// /*U*/ { OV511_I2C_BUS, 0x36, 0x8f }, // May not be necessary +// /*U*/ { OV511_I2C_BUS, 0x37, 0x80 }, // May not be necessary +// /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 }, +// /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7 +// { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ +// { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ +// { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ + /*OK*/ { OV511_I2C_BUS, 0x3d, 0x80 }, +// /*A*/ { OV511_I2C_BUS, 0x3f, 0x0e }, +// /*U*/ { OV511_I2C_BUS, 0x40, 0x00 }, +// /*U*/ { OV511_I2C_BUS, 0x41, 0x00 }, +// /*U*/ { OV511_I2C_BUS, 0x42, 0x80 }, +// /*U*/ { OV511_I2C_BUS, 0x43, 0x3f }, +// /*U*/ { OV511_I2C_BUS, 0x44, 0x80 }, +// /*U*/ { OV511_I2C_BUS, 0x45, 0x20 }, +// /*U*/ { OV511_I2C_BUS, 0x46, 0x20 }, +// /*U*/ { OV511_I2C_BUS, 0x47, 0x80 }, +// /*U*/ { OV511_I2C_BUS, 0x48, 0x7f }, +// /*U*/ { OV511_I2C_BUS, 0x49, 0x00 }, + + /* These next two registers (0x4a, 0x4b) are undocumented. They + * control the color balance */ +// /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these +// /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 }, +// /*U*/ { OV511_I2C_BUS, 0x4c, 0xd0 }, + /*d2?*/ { OV511_I2C_BUS, 0x4d, 0x10 }, /* This reduces noise a bit */ + /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 }, + /*04?*/ { OV511_I2C_BUS, 0x4f, 0x07 }, +// /*U*/ { OV511_I2C_BUS, 0x50, 0xff }, + /*U*/ { OV511_I2C_BUS, 0x54, 0x23 }, +// /*U*/ { OV511_I2C_BUS, 0x55, 0xff }, +// /*U*/ { OV511_I2C_BUS, 0x56, 0x12 }, + /*U*/ { OV511_I2C_BUS, 0x57, 0x81 }, +// /*U*/ { OV511_I2C_BUS, 0x58, 0x75 }, + /*U*/ { OV511_I2C_BUS, 0x59, 0x01 }, + /*U*/ { OV511_I2C_BUS, 0x5a, 0x2c }, + /*U*/ { OV511_I2C_BUS, 0x5b, 0x0f }, +// /*U*/ { OV511_I2C_BUS, 0x5c, 0x10 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + PDEBUG(4, "starting sensor configuration"); + + if (ov51x_init_ov_sensor(ov511) < 0) { + err("Failed to read sensor ID. You might not have an OV6xx0,"); + err("or it may be not responding. Report this to " EMAIL); + return -1; + } else { + PDEBUG(1, "OV6xx0 sensor detected"); + } + + /* Detect sensor (sub)type */ + rc = ov51x_i2c_read(ov511, OV7610_REG_COM_I); + + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } else if ((rc & 3) == 0) { + info("Sensor is an OV6630"); + ov511->sensor = SEN_OV6630; + } else if ((rc & 3) == 1) { + info("Sensor is an OV6620"); + ov511->sensor = SEN_OV6620; + } else if ((rc & 3) == 2) { + info("Sensor is an OV6630AE"); + ov511->sensor = SEN_OV6630; + } else if ((rc & 3) == 3) { + info("Sensor is an OV6630AF"); + ov511->sensor = SEN_OV6630; + } + + /* Set sensor-specific vars */ + if (ov511->sensor == SEN_OV6620) { + ov511->maxwidth = 352; + ov511->maxheight = 288; + } else { + /* 352x288 not working with OV518 yet */ + ov511->maxwidth = 320; + ov511->maxheight = 240; + } + ov511->minwidth = 64; + ov511->minheight = 48; + + // FIXME: These do not match the actual settings yet + ov511->brightness = 0x80 << 8; + ov511->contrast = 0x80 << 8; + ov511->colour = 0x80 << 8; + ov511->hue = 0x80 << 8; + + if (ov511->sensor == SEN_OV6620) { + PDEBUG(4, "Writing 6x20 registers"); + if (ov511_write_regvals(ov511, aRegvalsNorm6x20)) + return -1; + } else { + PDEBUG(4, "Writing 6x30 registers"); + if (ov511_write_regvals(ov511, aRegvalsNorm6x30)) + return -1; + } + + return 0; +} + +/* This initializes the KS0127 and KS0127B video decoders. */ +static int +ks0127_configure(struct usb_ov511 *ov511) +{ + int rc; + +// FIXME: I don't know how to sync or reset it yet +#if 0 + if (ov51x_init_ks_sensor(ov511) < 0) { + err("Failed to initialize the KS0127"); + return -1; + } else { + PDEBUG(1, "KS012x(B) sensor detected"); + } +#endif + + /* Detect decoder subtype */ + rc = ov51x_i2c_read(ov511, 0x00); + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } else if (rc & 0x08) { + rc = ov51x_i2c_read(ov511, 0x3d); + if (rc < 0) { + err("Error detecting sensor type"); return -1; + } else if ((rc & 0x0f) == 0) { + info("Sensor is a KS0127"); + ov511->sensor = SEN_KS0127; + } else if ((rc & 0x0f) == 9) { + info("Sensor is a KS0127B Rev. A"); + ov511->sensor = SEN_KS0127B; } - } else { /* sensor != 0; user overrode detection */ - ov511->sensor = sensor; - info("Sensor set to type %d", ov511->sensor); + } else { + err("Error: Sensor is an unsupported KS0122"); + return -1; } - if (ov511->sensor == SEN_OV7620) { - PDEBUG(4, "Writing 7620 registers"); - if (ov511_write_regvals(dev, aRegvalsNorm7620)) - return -1; + /* Set sensor-specific vars */ + ov511->maxwidth = 640; + ov511->maxheight = 480; + ov511->minwidth = 64; + ov511->minheight = 48; + + // FIXME: These do not match the actual settings yet + ov511->brightness = 0x80 << 8; + ov511->contrast = 0x80 << 8; + ov511->colour = 0x80 << 8; + ov511->hue = 0x80 << 8; + + /* This device is not supported yet. Bail out now... */ + err("This sensor is not supported yet."); + return -1; + + return 0; +} + +/* This initializes the SAA7111A video decoder. */ +static int +saa7111a_configure(struct usb_ov511 *ov511) +{ + struct usb_device *dev = ov511->dev; + int rc; + + /* Since there is no register reset command, all registers must be + * written, otherwise gives erratic results */ + static struct ov511_regvals aRegvalsNormSAA7111A[] = { + { OV511_I2C_BUS, 0x06, 0xce }, + { OV511_I2C_BUS, 0x07, 0x00 }, + { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */ + { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */ + { OV511_I2C_BUS, 0x00, 0x00 }, + { OV511_I2C_BUS, 0x01, 0x00 }, + { OV511_I2C_BUS, 0x03, 0x23 }, + { OV511_I2C_BUS, 0x04, 0x00 }, + { OV511_I2C_BUS, 0x05, 0x00 }, + { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */ + { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */ + { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */ + { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */ + { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */ + { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */ + { OV511_I2C_BUS, 0x0f, 0x00 }, + { OV511_I2C_BUS, 0x11, 0x0c }, + { OV511_I2C_BUS, 0x12, 0x00 }, + { OV511_I2C_BUS, 0x13, 0x00 }, + { OV511_I2C_BUS, 0x14, 0x00 }, + { OV511_I2C_BUS, 0x15, 0x00 }, + { OV511_I2C_BUS, 0x16, 0x00 }, + { OV511_I2C_BUS, 0x17, 0x00 }, + { OV511_I2C_BUS, 0x02, 0xc0 }, /* Composite input 0 */ + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + +// FIXME: I don't know how to sync or reset it yet +#if 0 + if (ov51x_init_saa_sensor(ov511) < 0) { + err("Failed to initialize the SAA7111A"); + return -1; } else { - PDEBUG(4, "Writing 7610 registers"); - if (ov511_write_regvals(dev, aRegvalsNorm7610)) - return -1; + PDEBUG(1, "SAA7111A sensor detected"); } +#endif /* Set sensor-specific vars */ ov511->maxwidth = 640; - ov511->maxheight = 480; + ov511->maxheight = 480; /* Even/Odd fields */ + ov511->minwidth = 320; + ov511->minheight = 240; /* Even field only */ + + ov511->has_decoder = 1; + ov511->num_inputs = 8; + ov511->norm = VIDEO_MODE_AUTO; + ov511->stop_during_set = 0; /* Decoder guarantees stable image */ + + /* Decoder doesn't change these values, so we use these instead of + * acutally reading the registers (which doesn't work) */ + ov511->brightness = 0x80 << 8; + ov511->contrast = 0x40 << 9; + ov511->colour = 0x40 << 9; + ov511->hue = 32768; - if (aperture < 0) { /* go with the default */ - if (ov511_i2c_write(dev, 0x26, 0xa2) < 0) return -1; - } else if (aperture <= 0xf) { /* user overrode default */ - if (ov511_i2c_write(dev, 0x26, (aperture << 4) + 2) < 0) - return -1; - } else { - err("Invalid setting for aperture; legal value: 0 - 15"); + PDEBUG(4, "Writing SAA7111A registers"); + if (ov511_write_regvals(ov511, aRegvalsNormSAA7111A)) return -1; - } - if (autoadjust) { - if (ov511_i2c_write(dev, 0x13, 0x01) < 0) return -1; - if (ov511_i2c_write(dev, 0x2d, - ov511->sensor==SEN_OV7620?0x91:0x93) < 0) return -1; + /* Detect version of decoder. This must be done after writing the + * initial regs or the decoder will lock up. */ + rc = ov51x_i2c_read(ov511, 0x00); + + if (rc < 0) { + err("Error detecting sensor version"); + return -1; } else { - if (ov511_i2c_write(dev, 0x13, 0x00) < 0) return -1; - if (ov511_i2c_write(dev, 0x2d, - ov511->sensor==SEN_OV7620?0x81:0x83) < 0) return -1; - ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8); + info("Sensor is an SAA7111A (version 0x%x)", rc); + ov511->sensor = SEN_SAA7111A; } + // FIXME: Fix this for OV518(+) + /* Latch to negative edge of clock. Otherwise, we get incorrect + * colors and jitter in the digital signal. */ + if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) + ov511_reg_write(dev, 0x11, 0x00); + else + warn("SAA7111A not yet supported with OV518/OV518+"); + return 0; } -static int ov6xx0_configure(struct usb_ov511 *ov511) +/* This initializes the OV511/OV511+ and the sensor */ +static int +ov511_configure(struct usb_ov511 *ov511) { struct usb_device *dev = ov511->dev; - int i, success, rc; + int i; - static struct ov511_regvals aRegvalsNorm6x20[] = { - { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ - { OV511_I2C_BUS, 0x11, 0x01 }, - { OV511_I2C_BUS, 0x03, 0xd0 }, - { OV511_I2C_BUS, 0x05, 0x7f }, - { OV511_I2C_BUS, 0x07, 0xa8 }, - { OV511_I2C_BUS, 0x0c, 0x24 }, - { OV511_I2C_BUS, 0x0d, 0x24 }, - { OV511_I2C_BUS, 0x10, 0xff }, /* ? */ - { OV511_I2C_BUS, 0x14, 0x04 }, - { OV511_I2C_BUS, 0x16, 0x06 }, /* ? */ - { OV511_I2C_BUS, 0x19, 0x04 }, - { OV511_I2C_BUS, 0x1a, 0x93 }, - { OV511_I2C_BUS, 0x20, 0x28 }, - { OV511_I2C_BUS, 0x27, 0xa2 }, - { OV511_I2C_BUS, 0x28, 0x24 }, - { OV511_I2C_BUS, 0x2a, 0x04 }, /* 84? */ - { OV511_I2C_BUS, 0x2b, 0xac }, /* a8? */ - { OV511_I2C_BUS, 0x2d, 0x95 }, - { OV511_I2C_BUS, 0x33, 0x28 }, - { OV511_I2C_BUS, 0x34, 0xc7 }, - { OV511_I2C_BUS, 0x38, 0x8b }, - { OV511_I2C_BUS, 0x3c, 0x5c }, - { OV511_I2C_BUS, 0x3d, 0x80 }, - { OV511_I2C_BUS, 0x3f, 0x00 }, - { OV511_I2C_BUS, 0x4a, 0x80 }, /* undocumented */ - { OV511_I2C_BUS, 0x4b, 0x80 }, /* undocumented */ - { OV511_I2C_BUS, 0x4d, 0xd2 }, - { OV511_I2C_BUS, 0x4e, 0xc1 }, - { OV511_I2C_BUS, 0x4f, 0x04 }, - { OV511_DONE_BUS, 0x0, 0x00 }, + static struct ov511_regvals aRegvalsInit511[] = { + { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f }, + { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f }, + { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3f }, + { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d }, + { OV511_DONE_BUS, 0x0, 0x00}, }; - PDEBUG (4, "starting sensor configuration"); - - /* Reset the 6xx0 */ - if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1; + static struct ov511_regvals aRegvalsNorm511[] = { + { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x01 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x03 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, + { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f }, + { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 }, + { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; - /* Wait for it to initialize */ - schedule_timeout (1 + 150 * HZ / 1000); + static struct ov511_regvals aRegvalsNorm511Plus[] = { + { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0xff }, + { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x03 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, + { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0xff }, + { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 }, + { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; - for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { - if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) && - (ov511_i2c_read(dev, OV7610_REG_ID_LOW) == 0xA2)) { - success = 1; - continue; - } + PDEBUG(4, ""); - /* Reset the 6xx0 */ - if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1; - /* Wait for it to initialize */ - schedule_timeout (1 + 150 * HZ / 1000); - /* Dummy read to sync I2C */ - if (ov511_i2c_read(dev, 0x00) < 0) return -1; + ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); + if (ov511->customid < 0) { + err("Unable to read camera bridge registers"); + goto error; } - if (success) { - PDEBUG(1, "I2C synced in %d attempt(s)", i); - } else { - err("Failed to read sensor ID. You might not have an OV6xx0,"); - err("or it may be not responding. Report this to"); - err("mwm@i.am"); - return -1; + ov511->desc = -1; + PDEBUG (1, "CustomID = %d", ov511->customid); + for (i = 0; clist[i].id >= 0; i++) { + if (ov511->customid == clist[i].id) { + info("model: %s", clist[i].description); + ov511->desc = i; + break; + } } - /* Detect sensor if user didn't use override param */ - if (sensor == 0) { - rc = ov511_i2c_read(dev, OV7610_REG_COM_I); + if (clist[i].id == -1) { + err("Camera type (%d) not recognized", ov511->customid); + err("Please notify " EMAIL " of the name,"); + err("manufacturer, model, and this number of your camera."); + err("Also include the output of the detection process."); + } - if (rc < 0) { - err("Error detecting sensor type"); - return -1; - } else { - info("Sensor is an OV6xx0 (version %d)", rc & 3); - ov511->sensor = SEN_OV6620; - } - } else { /* sensor != 0; user overrode detection */ - ov511->sensor = sensor; - info("Sensor set to type %d", ov511->sensor); + if (clist[i].id == 6) { /* USB Life TV (NTSC) */ + ov511->tuner_type = 8; /* Temic 4036FY5 3X 1981 */ } - /* Set sensor-specific vars */ - ov511->maxwidth = 352; - ov511->maxheight = 288; + if (ov511_write_regvals(ov511, aRegvalsInit511)) goto error; - PDEBUG(4, "Writing 6x20 registers"); - if (ov511_write_regvals(dev, aRegvalsNorm6x20)) - return -1; + if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO) + ov51x_led_control(ov511, 0); - if (aperture < 0) { /* go with the default */ - if (ov511_i2c_write(dev, 0x26, 0xa2) < 0) return -1; - } else if (aperture <= 0xf) { /* user overrode default */ - if (ov511_i2c_write(dev, 0x26, (aperture << 4) + 2) < 0) - return -1; + /* The OV511+ has undocumented bits in the flow control register. + * Setting it to 0xff fixes the corruption with moving objects. */ + if (ov511->bridge == BRG_OV511) { + if (ov511_write_regvals(ov511, aRegvalsNorm511)) goto error; + } else if (ov511->bridge == BRG_OV511PLUS) { + if (ov511_write_regvals(ov511, aRegvalsNorm511Plus)) goto error; } else { - err("Invalid setting for aperture; legal value: 0 - 15"); - return -1; + err("Invalid bridge"); } - if (autoadjust) { - if (ov511_i2c_write(dev, 0x13, 0x01) < 0) return -1; - if (ov511_i2c_write(dev, 0x2d, - ov511->sensor==SEN_OV7620?0x91:0x93) < 0) return -1; + if (ov511_init_compression(ov511)) goto error; + + ov511_set_packet_size(ov511, 0); + + ov511->snap_enabled = snapshot; + + /* Test for 7xx0 */ + PDEBUG(3, "Testing for 0V7xx0"); + ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; + if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, + OV7xx0_I2C_READ_ID) < 0) + goto error; + + if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + /* Test for 6xx0 */ + PDEBUG(3, "Testing for 0V6xx0"); + ov511->primary_i2c_slave = OV6xx0_I2C_WRITE_ID; + if (ov51x_set_slave_ids(ov511, OV6xx0_I2C_WRITE_ID, + OV6xx0_I2C_READ_ID) < 0) + goto error; + + if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + /* Test for 8xx0 */ + PDEBUG(3, "Testing for 0V8xx0"); + ov511->primary_i2c_slave = OV8xx0_I2C_WRITE_ID; + if (ov51x_set_slave_ids(ov511, OV8xx0_I2C_WRITE_ID, + OV8xx0_I2C_READ_ID)) + goto error; + + if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + /* Test for SAA7111A */ + PDEBUG(3, "Testing for SAA7111A"); + ov511->primary_i2c_slave = SAA7111A_I2C_WRITE_ID; + if (ov51x_set_slave_ids(ov511, SAA7111A_I2C_WRITE_ID, + SAA7111A_I2C_READ_ID)) + goto error; + + if (ov51x_i2c_write(ov511, 0x0d, 0x00) < 0) { + /* Test for KS0127 */ + PDEBUG(3, "Testing for KS0127"); + ov511->primary_i2c_slave = KS0127_I2C_WRITE_ID; + if (ov51x_set_slave_ids(ov511, KS0127_I2C_WRITE_ID, + KS0127_I2C_READ_ID)) + goto error; + + if (ov51x_i2c_write(ov511, 0x10, 0x00) < 0) { + err("Can't determine sensor slave IDs"); + goto error; + } else { + if(ks0127_configure(ov511) < 0) { + err("Failed to configure KS0127"); + goto error; + } + } + } else { + if(saa7111a_configure(ov511) < 0) { + err("Failed to configure SAA7111A"); + goto error; + } + } + } else { + err("Detected unsupported OV8xx0 sensor"); + goto error; + } + } else { + if(ov6xx0_configure(ov511) < 0) { + err("Failed to configure OV6xx0"); + goto error; + } + } } else { - if (ov511_i2c_write(dev, 0x13, 0x00) < 0) return -1; - if (ov511_i2c_write(dev, 0x2d, - ov511->sensor==SEN_OV7620?0x81:0x83) < 0) return -1; - ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8); + if(ov7xx0_configure(ov511) < 0) { + err("Failed to configure OV7xx0"); + goto error; + } } return 0; -} +error: + err("OV511 Config failed"); + + return -EBUSY; +} -static int ov511_configure(struct usb_ov511 *ov511) +/* This initializes the OV518/OV518+ and the sensor */ +static int +ov518_configure(struct usb_ov511 *ov511) { struct usb_device *dev = ov511->dev; - int i; - static struct ov511_regvals aRegvalsInit[] = { - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3f }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d }, + static struct ov511_regvals aRegvalsInit518[] = { + { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x40 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3e }, + { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x00 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, + { OV511_REG_BUS, 0x46, 0x00 }, + { OV511_REG_BUS, 0x5d, 0x03 }, { OV511_DONE_BUS, 0x0, 0x00}, }; - static struct ov511_regvals aRegvalsNorm511[] = { - { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x02 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x00 }, - { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f }, - { OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_Y, 0x08 }, - { OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_UV, 0x01 }, - { OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_Y, 0x08 }, - { OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_UV, 0x01 }, - { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_Y, 0x01 }, - { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_UV, 0x01 }, - { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_VERT_Y, 0x01 }, - { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_VERT_UV, 0x01 }, - { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x06 }, - { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 }, + /* New values, based on Windows driver. Since what they do is not + * known yet, this may be incorrect. */ + static struct ov511_regvals aRegvalsNorm518[] = { + { OV511_REG_BUS, 0x52, 0x02 }, /* Reset snapshot */ + { OV511_REG_BUS, 0x52, 0x01 }, /* Enable snapshot */ + { OV511_REG_BUS, 0x31, 0x0f }, + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, 0x24, 0x9f }, + { OV511_REG_BUS, 0x25, 0x90 }, + { OV511_REG_BUS, 0x20, 0x00 }, /* Was 0x08 */ + { OV511_REG_BUS, 0x51, 0x04 }, + { OV511_REG_BUS, 0x71, 0x19 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; - memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template)); + PDEBUG(4, ""); - for (i = 0; i < OV511_NUMFRAMES; i++) - init_waitqueue_head(&ov511->frame[i].wq); + /* First 5 bits of custom ID reg are a revision ID on OV518 */ + info("Device revision %d", + 0x1F & ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID)); - init_waitqueue_head(&ov511->wq); + if (ov511_write_regvals(ov511, aRegvalsInit518)) goto error; + + /* Set LED GPIO pin to output mode */ + if (ov511_reg_write_mask(dev, 0x57,0x00, 0x02) < 0) goto error; + + /* LED is off by default with OV518; have to explicitly turn it on */ + if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO) + ov51x_led_control(ov511, 0); + else + ov51x_led_control(ov511, 1); + + /* Don't require compression if dumppix is enabled; otherwise it's + * required. OV518 has no uncompressed mode, to save RAM. */ + if (!dumppix && !ov511->compress) { + ov511->compress = 1; + warn("Compression required with OV518...enabling"); + } + + if (ov511_write_regvals(ov511, aRegvalsNorm518)) goto error; - if (ov511_write_regvals(dev, aRegvalsInit)) goto error; - if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error; + if (ov511_reg_write(dev, 0x2f,0x80) < 0) goto error; + + if (ov518_init_compression(ov511)) goto error; ov511_set_packet_size(ov511, 0); - ov511->snap_enabled = snapshot; + ov511->snap_enabled = snapshot; /* Test for 76xx */ - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, - OV7610_I2C_WRITE_ID) < 0) - goto error; - - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, - OV7610_I2C_READ_ID) < 0) + ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; + if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, + OV7xx0_I2C_READ_ID) < 0) goto error; - if (ov511_reset(dev, OV511_RESET_NOREGS) < 0) - goto error; + /* The OV518 must be more aggressive about sensor detection since + * I2C write will never fail if the sensor is not present. We have + * to try to initialize the sensor to detect its presence */ - if (ov511_i2c_write(dev, 0x12, 0x80) < 0) { + if (ov51x_init_ov_sensor(ov511) < 0) { /* Test for 6xx0 */ - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, - OV6xx0_I2C_WRITE_ID) < 0) - goto error; - - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, - OV6xx0_I2C_READ_ID) < 0) + ov511->primary_i2c_slave = OV6xx0_I2C_WRITE_ID; + if (ov51x_set_slave_ids(ov511, OV6xx0_I2C_WRITE_ID, + OV6xx0_I2C_READ_ID) < 0) goto error; - if (ov511_reset(dev, OV511_RESET_NOREGS) < 0) - goto error; + if (ov51x_init_ov_sensor(ov511) < 0) { + /* Test for 8xx0 */ + ov511->primary_i2c_slave = OV8xx0_I2C_WRITE_ID; + if (ov51x_set_slave_ids(ov511, OV8xx0_I2C_WRITE_ID, + OV8xx0_I2C_READ_ID) < 0) + goto error; - if (ov511_i2c_write(dev, 0x12, 0x80) < 0) { - err("Can't determine sensor slave IDs"); - goto error; - } - - if(ov6xx0_configure(ov511) < 0) { - err("failed to configure OV6xx0"); - goto error; + if (ov51x_init_ov_sensor(ov511) < 0) { + err("Can't determine sensor slave IDs"); + goto error; + } else { + err("Detected unsupported OV8xx0 sensor"); + goto error; + } + } else { + if (ov6xx0_configure(ov511) < 0) { + err("Failed to configure OV6xx0"); + goto error; + } } } else { - if(ov76xx_configure(ov511) < 0) { - err("failed to configure OV76xx"); + if (ov7xx0_configure(ov511) < 0) { + err("Failed to configure OV7xx0"); goto error; } } - - /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used - * (using read() instead). */ - for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].width = ov511->maxwidth; - ov511->frame[i].height = ov511->maxheight; - ov511->frame[i].depth = 24; - ov511->frame[i].bytes_read = 0; - ov511->frame[i].segment = 0; - ov511->frame[i].format = VIDEO_PALETTE_RGB24; - ov511->frame[i].segsize = GET_SEGSIZE(ov511->frame[i].format); - } - /* Initialize to max width/height, RGB24 */ - if (ov511_mode_init_regs(ov511, ov511->maxwidth, ov511->maxheight, - VIDEO_PALETTE_RGB24, 0) < 0) - goto error; + // The OV518 cannot go as low as the sensor can + ov511->minwidth = 160; + ov511->minheight = 120; return 0; - + error: - usb_driver_release_interface(&ov511_driver, - &dev->actconfig->interface[ov511->iface]); + err("OV518 Config failed"); - return -EBUSY; + return -EBUSY; } @@ -3245,12 +6687,13 @@ ***************************************************************************/ static void * -ov511_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *id) +ov51x_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) { struct usb_interface_descriptor *interface; struct usb_ov511 *ov511; int i; + int registered = 0; PDEBUG(1, "probing for device..."); @@ -3271,98 +6714,147 @@ if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) { err("couldn't kmalloc ov511 struct"); - goto error; + goto error_unlock; } memset(ov511, 0, sizeof(*ov511)); ov511->dev = dev; ov511->iface = interface->bInterfaceNumber; + ov511->led_policy = led; + ov511->compress = compress; + ov511->lightfreq = lightfreq; + ov511->num_inputs = 1; /* Video decoder init functs. change this */ + ov511->stop_during_set = !fastset; + ov511->tuner_type = tuner; + ov511->backlight = backlight; + + ov511->auto_brt = autobright; + ov511->auto_gain = autogain; + ov511->auto_exp = autoexp; switch (dev->descriptor.idProduct) { - case 0x0511: + case PROD_OV511: info("USB OV511 camera found"); ov511->bridge = BRG_OV511; + ov511->bclass = BCL_OV511; break; - case 0xA511: + case PROD_OV511PLUS: info("USB OV511+ camera found"); ov511->bridge = BRG_OV511PLUS; + ov511->bclass = BCL_OV511; break; - case 0x0002: - if (dev->descriptor.idVendor != 0x0813) + case PROD_OV518: + info("USB OV518 camera found"); + ov511->bridge = BRG_OV518; + ov511->bclass = BCL_OV518; + break; + case PROD_OV518PLUS: + info("USB OV518+ camera found"); + ov511->bridge = BRG_OV518PLUS; + ov511->bclass = BCL_OV518; + break; + case PROD_ME2CAM: + if (dev->descriptor.idVendor != VEND_MATTEL) goto error; info("Intel Play Me2Cam (OV511+) found"); ov511->bridge = BRG_OV511PLUS; + ov511->bclass = BCL_OV511; break; default: - err("Unknown product ID"); - goto error; + err("Unknown product ID 0x%x", dev->descriptor.idProduct); + goto error_dealloc; } - ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); - if (ov511->customid < 0) { - err("Unable to read camera bridge registers"); - goto error; + /* Workaround for some applications that want data in RGB + * instead of BGR. */ + if (force_rgb) + info("data format set to RGB"); + + init_waitqueue_head(&ov511->wq); + + init_MUTEX(&ov511->lock); /* to 1 == available */ + init_MUTEX(&ov511->buf_lock); + init_MUTEX(&ov511->param_lock); + init_MUTEX(&ov511->i2c_lock); + ov511->buf_state = BUF_NOT_ALLOCATED; + + if (ov511->bridge == BRG_OV518 || + ov511->bridge == BRG_OV518PLUS) { + if (ov518_configure(ov511) < 0) + goto error; + } else { + if (ov511_configure(ov511) < 0) + goto error; } - ov511->desc = -1; - PDEBUG (4, "CustomID = %d", ov511->customid); - for (i = 0; clist[i].id >= 0; i++) { - if (ov511->customid == clist[i].id) { - info("camera: %s", clist[i].description); - ov511->desc = i; - break; - } + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov511->frame[i].framenum = i; + init_waitqueue_head(&ov511->frame[i].wq); } - /* Lifeview USB Life TV not supported */ - if (clist[i].id == 38) { - err("This device is not supported yet."); + /* Unnecessary? (This is done on open(). Need to make sure variables + * are properly initialized without this before removing it, though). */ + if (ov51x_set_default_params(ov511) < 0) goto error; - } - if (clist[i].id == -1) { - err("Camera type (%d) not recognized", ov511->customid); - err("Please contact mwm@i.am to request"); - err("support for your camera."); - } +#ifdef OV511_DEBUG + if (dump_bridge) + ov511_dump_regs(dev); +#endif - /* Workaround for some applications that want data in RGB - * instead of BGR */ - if (force_rgb) - info("data format set to RGB"); + memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template)); + ov511->vdev.priv = ov511; - if (!ov511_configure(ov511)) { - ov511->user = 0; - init_MUTEX(&ov511->lock); /* to 1 == available */ - init_MUTEX(&ov511->buf_lock); - ov511->buf_state = BUF_NOT_ALLOCATED; - } else { - err("Failed to configure camera"); - goto error; + for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { + /* Minor 0 cannot be specified; assume user wants autodetect */ + if (unit_video[i] == 0) + break; + + if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, + unit_video[i]) >= 0) { + registered = 1; + break; + } } - if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { + /* Use the next available one */ + if (!registered && + video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, -1) < 0) { err("video_register_device failed"); goto error; } + info("Device registered on minor %d", ov511->vdev.minor); + MOD_DEC_USE_COUNT; return ov511; error: + err("Camera initialization failed"); + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + /* Safe to call even if entry doesn't exist */ + destroy_proc_ov511_cam(ov511); +#endif + + usb_driver_release_interface(&ov511_driver, + &dev->actconfig->interface[ov511->iface]); + +error_dealloc: if (ov511) { kfree(ov511); ov511 = NULL; } +error_unlock: MOD_DEC_USE_COUNT; return NULL; } static void -ov511_disconnect(struct usb_device *dev, void *ptr) +ov51x_disconnect(struct usb_device *dev, void *ptr) { struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr; int n; @@ -3422,8 +6914,8 @@ static struct usb_driver ov511_driver = { name: "ov511", id_table: device_table, - probe: ov511_probe, - disconnect: ov511_disconnect + probe: ov51x_probe, + disconnect: ov51x_disconnect }; @@ -3433,7 +6925,88 @@ * ***************************************************************************/ -static int __init usb_ov511_init(void) +/* Returns 0 for success */ +int +ov511_register_decomp_module(int ver, struct ov51x_decomp_ops *ops, int ov518, + int mmx) +{ + if (ver != DECOMP_INTERFACE_VER) { + err("Decompression module has incompatible"); + err("interface version %d", ver); + err("Interface version %d is required", DECOMP_INTERFACE_VER); + return -EINVAL; + } + + if (!ops) + return -EFAULT; + + if (mmx && !ov51x_mmx_available) { + err("MMX not available on this system or kernel"); + return -EINVAL; + } + + lock_kernel(); + + if (ov518) { + if (mmx) { + if (ov518_mmx_decomp_ops) + goto err_in_use; + else + ov518_mmx_decomp_ops = ops; + } else { + if (ov518_decomp_ops) + goto err_in_use; + else + ov518_decomp_ops = ops; + } + } else { + if (mmx) { + if (ov511_mmx_decomp_ops) + goto err_in_use; + else + ov511_mmx_decomp_ops = ops; + } else { + if (ov511_decomp_ops) + goto err_in_use; + else + ov511_decomp_ops = ops; + } + } + + MOD_INC_USE_COUNT; + + unlock_kernel(); + return 0; + +err_in_use: + unlock_kernel(); + return -EBUSY; +} + +void +ov511_deregister_decomp_module(int ov518, int mmx) +{ + lock_kernel(); + + if (ov518) { + if (mmx) + ov518_mmx_decomp_ops = NULL; + else + ov518_decomp_ops = NULL; + } else { + if (mmx) + ov511_mmx_decomp_ops = NULL; + else + ov511_decomp_ops = NULL; + } + + MOD_DEC_USE_COUNT; + + unlock_kernel(); +} + +static int __init +usb_ov511_init(void) { #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) proc_ov511_create(); @@ -3442,20 +7015,33 @@ if (usb_register(&ov511_driver) < 0) return -1; - info(DRIVER_VERSION ":" DRIVER_DESC); + // FIXME: Don't know how to determine this yet + ov51x_mmx_available = 0; + +#if defined (__i386__) + if (test_bit(X86_FEATURE_MMX, &boot_cpu_data.x86_capability)) + ov51x_mmx_available = 1; +#endif + + info(DRIVER_VERSION " : " DRIVER_DESC); return 0; } -static void __exit usb_ov511_exit(void) +static void __exit +usb_ov511_exit(void) { usb_deregister(&ov511_driver); info("driver deregistered"); #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) proc_ov511_destroy(); -#endif +#endif } module_init(usb_ov511_init); module_exit(usb_ov511_exit); + +/* No version, for compatibility with binary-only modules */ +EXPORT_SYMBOL_NOVERS(ov511_register_decomp_module); +EXPORT_SYMBOL_NOVERS(ov511_deregister_decomp_module); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/ov511.h linux-2.5/drivers/usb/ov511.h --- linux-2.5.1/drivers/usb/ov511.h Mon Dec 11 21:17:59 2000 +++ linux-2.5/drivers/usb/ov511.h Mon Jan 14 14:39:43 2002 @@ -1,20 +1,41 @@ - #ifndef __LINUX_OV511_H #define __LINUX_OV511_H #include <asm/uaccess.h> #include <linux/videodev.h> #include <linux/smp_lock.h> +#include <linux/usb.h> #define OV511_DEBUG /* Turn on debug messages */ #ifdef OV511_DEBUG # define PDEBUG(level, fmt, args...) \ -if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args) +if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , \ + ## args) #else # define PDEBUG(level, fmt, args...) do {} while(0) #endif +/* 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); \ +} + +/* --------------------------------- */ +/* DEFINES FOR OV511 AND OTHER CHIPS */ +/* --------------------------------- */ + +/* USB IDs */ +#define VEND_OMNIVISION 0x05A9 +#define PROD_OV511 0x0511 +#define PROD_OV511PLUS 0xA511 +#define PROD_OV518 0x0518 +#define PROD_OV518PLUS 0xA518 + +#define VEND_MATTEL 0x0813 +#define PROD_ME2CAM 0x0002 + /* Camera interface register numbers */ #define OV511_REG_CAMERA_DELAY_MODE 0x10 #define OV511_REG_CAMERA_EDGE_MODE 0x11 @@ -52,6 +73,7 @@ /* I2C register numbers */ #define OV511_REG_I2C_CONTROL 0x40 +#define OV518_REG_I2C_CONTROL 0x47 /* OV518(+) only */ #define OV511_REG_I2C_SLAVE_ID_WRITE 0x41 #define OV511_REG_I2C_SUB_ADDRESS_3_BYTE 0x42 #define OV511_REG_I2C_SUB_ADDRESS_2_BYTE 0x43 @@ -78,8 +100,16 @@ #define OV511_REG_SYSTEM_CLOCK_DIVISOR 0x51 #define OV511_REG_SYSTEM_SNAPSHOT 0x52 #define OV511_REG_SYSTEM_INIT 0x53 -#define OV511_REG_SYSTEM_PWR_CLK 0x54 /* OV511+ only */ +#define OV511_REG_SYSTEM_PWR_CLK 0x54 /* OV511+/OV518(+) only */ #define OV511_REG_SYSTEM_LED_CTL 0x55 /* OV511+ only */ +#define OV518_REG_GPIO_IN 0x55 /* OV518(+) only */ +#define OV518_REG_GPIO_OUT 0x56 /* OV518(+) only */ +#define OV518_REG_GPIO_CTL 0x57 /* OV518(+) only */ +#define OV518_REG_GPIO_PULSE_IN 0x58 /* OV518(+) only */ +#define OV518_REG_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ +#define OV518_REG_GPIO_PULSE_POLARITY 0x5a /* OV518(+) only */ +#define OV518_REG_GPIO_PULSE_EN 0x5b /* OV518(+) only */ +#define OV518_REG_GPIO_RESET 0x5c /* OV518(+) only */ #define OV511_REG_SYSTEM_USER_DEFINED 0x5E #define OV511_REG_SYSTEM_CUSTOM_ID 0x5F @@ -119,6 +149,16 @@ #define OV511PLUS_ALT_SIZE_769 6 #define OV511PLUS_ALT_SIZE_961 7 +/* Alternate numbers for various max packet sizes (OV518(+) only) */ +#define OV518_ALT_SIZE_0 0 +#define OV518_ALT_SIZE_128 1 +#define OV518_ALT_SIZE_256 2 +#define OV518_ALT_SIZE_384 3 +#define OV518_ALT_SIZE_512 4 +#define OV518_ALT_SIZE_640 5 +#define OV518_ALT_SIZE_768 6 +#define OV518_ALT_SIZE_896 7 + /* OV7610 registers */ #define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ #define OV7610_REG_BLUE 0x01 /* blue channel balance */ @@ -170,44 +210,74 @@ /* 36-37 reserved */ #define OV7610_REG_COM_K 0x38 /* misc registers */ - -#define SCRATCH_BUF_SIZE 512 - #define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ #define FRAME_SIZE_PER_DESC 993 /* FIXME - Deprecated */ #define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */ +#define PIXELS_PER_SEG 256 /* Pixels per segment */ #define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ -// CAMERA SPECIFIC -// FIXME - these can vary between specific models -#define OV7610_I2C_WRITE_ID 0x42 -#define OV7610_I2C_READ_ID 0x43 -#define OV6xx0_I2C_WRITE_ID 0xC0 -#define OV6xx0_I2C_READ_ID 0xC1 +/* I2C addresses */ +#define OV7xx0_I2C_WRITE_ID 0x42 +#define OV7xx0_I2C_READ_ID 0x43 +#define OV6xx0_I2C_WRITE_ID 0xC0 +#define OV6xx0_I2C_READ_ID 0xC1 +#define OV8xx0_I2C_WRITE_ID 0xA0 +#define OV8xx0_I2C_READ_ID 0xA1 +#define KS0127_I2C_WRITE_ID 0xD8 +#define KS0127_I2C_READ_ID 0xD9 +#define SAA7111A_I2C_WRITE_ID 0x48 +#define SAA7111A_I2C_READ_ID 0x49 #define OV511_I2C_CLOCK_PRESCALER 0x03 -/* Prototypes */ -int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg); -int usb_ov511_reg_write(struct usb_device *dev, - unsigned char reg, - unsigned char value); - /* Bridge types */ enum { + BRG_UNKNOWN, BRG_OV511, BRG_OV511PLUS, + BRG_OV518, + BRG_OV518PLUS, +}; + +/* Bridge classes */ +enum { + BCL_UNKNOWN, + BCL_OV511, + BCL_OV518, }; /* Sensor types */ enum { SEN_UNKNOWN, + SEN_OV76BE, SEN_OV7610, SEN_OV7620, SEN_OV7620AE, SEN_OV6620, + SEN_OV6630, + SEN_OV6630AE, + SEN_OV6630AF, + SEN_OV8600, + SEN_KS0127, + SEN_KS0127B, + SEN_SAA7111A, +}; + +// Not implemented yet +#if 0 +/* Sensor classes */ +enum { + SCL_UNKNOWN, + SCL_OV7610, /* 7610, 76BE, 7620AE (for now) */ + SCL_OV7620, + SCL_OV6620, + SCL_OV6630, /* 6630, 6630AE, 6630AF */ + SCL_OV8600, + SCL_KS0127, /* SEN_KS0127, SEN_KS0127B */ + SCL_SAA7111A, }; +#endif enum { STATE_SCANNING, /* Scanning for start */ @@ -222,7 +292,77 @@ BUF_PEND_DEALLOC, /* ov511->buf_timer is set */ }; -struct usb_device; +/* --------- Definition of ioctl interface --------- */ + +#define OV511_INTERFACE_VER 101 + +/* LED options */ +enum { + LED_OFF, + LED_ON, + LED_AUTO, +}; + +/* Raw frame formats */ +enum { + RAWFMT_INVALID, + RAWFMT_YUV400, + RAWFMT_YUV420, + RAWFMT_YUV422, + RAWFMT_GBR422, +}; + +/* Unsigned short option numbers */ +enum { + OV511_USOPT_INVALID, + OV511_USOPT_BRIGHT, + OV511_USOPT_SAT, + OV511_USOPT_HUE, + OV511_USOPT_CONTRAST, +}; + +/* Unsigned int option numbers */ +enum { + OV511_UIOPT_INVALID, + OV511_UIOPT_POWER_FREQ, + OV511_UIOPT_BFILTER, + OV511_UIOPT_LED, + OV511_UIOPT_DEBUG, + OV511_UIOPT_COMPRESS, +}; + +struct ov511_ushort_opt { + int optnum; /* Specific option number */ + unsigned short val; +}; + +struct ov511_uint_opt { + int optnum; /* Specific option number */ + unsigned int val; +}; + +struct ov511_i2c_struct { + unsigned char slave; /* Write slave ID (read ID - 1) */ + unsigned char reg; /* Index of register */ + unsigned char value; /* User sets this w/ write, driver does w/ read */ + unsigned char mask; /* Bits to be changed. Not used with read ops */ +}; + +/* ioctls */ +#define OV511IOC_GINTVER _IOR('v', BASE_VIDIOCPRIVATE + 0, int) +#define OV511IOC_GUSHORT _IOWR('v', BASE_VIDIOCPRIVATE + 1, \ + struct ov511_ushort_opt) +#define OV511IOC_SUSHORT _IOW('v', BASE_VIDIOCPRIVATE + 2, \ + struct ov511_ushort_opt) +#define OV511IOC_GUINT _IOWR('v', BASE_VIDIOCPRIVATE + 3, \ + struct ov511_uint_opt) +#define OV511IOC_SUINT _IOW('v', BASE_VIDIOCPRIVATE + 4, \ + struct ov511_uint_opt) +#define OV511IOC_WI2C _IOW('v', BASE_VIDIOCPRIVATE + 5, \ + struct ov511_i2c_struct) +#define OV511IOC_RI2C _IOWR('v', BASE_VIDIOCPRIVATE + 6, \ + struct ov511_i2c_struct) +/* ------------- End IOCTL interface -------------- */ struct ov511_sbuf { char *data; @@ -248,36 +388,51 @@ }; struct ov511_frame { + int framenum; /* Index of this frame */ char *data; /* Frame buffer */ + char *tempdata; /* Temp buffer for multi-stage conversions */ + char *rawdata; /* Raw camera data buffer */ int depth; /* Bytes per pixel */ int width; /* Width application is expecting */ - int height; /* Height */ + int height; /* Height application is expecting */ - int hdrwidth; /* Width the frame actually is */ - int hdrheight; /* Height */ + int rawwidth; /* Actual width of frame sent from camera */ + int rawheight; /* Actual height of frame sent from camera */ int sub_flag; /* Sub-capture mode for this frame? */ unsigned int format; /* Format for this frame */ - int segsize; /* How big is each segment from the camera? */ + int compressed; /* Is frame compressed? */ volatile int grabstate; /* State of grabbing */ int scanstate; /* State of scanning */ - int curline; /* Line of frame we're working on */ - int curpix; - int segment; /* Segment from the incoming data */ + int bytes_recvd; /* Number of image bytes received from camera */ - long scanlength; /* uncompressed, raw data length of frame */ - long bytes_read; /* amount of scanlength that has been read from *data */ + long bytes_read; /* Amount that has been read() */ wait_queue_head_t wq; /* Processes waiting */ int snapshot; /* True if frame was a snapshot */ }; +#define DECOMP_INTERFACE_VER 2 + +/* Compression module operations */ +struct ov51x_decomp_ops { + int (*decomp_400)(unsigned char *, unsigned char *, int, int, int); + int (*decomp_420)(unsigned char *, unsigned char *, int, int, int); + int (*decomp_422)(unsigned char *, unsigned char *, int, int, int); + void (*decomp_lock)(void); + void (*decomp_unlock)(void); +}; + #define OV511_NUMFRAMES 2 -#define OV511_NUMSBUF 2 +#if OV511_NUMFRAMES > VIDEO_MAX_FRAME +#error "OV511_NUMFRAMES is too high" +#endif + +#define OV511_NUMSBUF 2 struct usb_ov511 { struct video_device vdev; @@ -292,22 +447,37 @@ /* Determined by sensor type */ int maxwidth; int maxheight; + int minwidth; + int minheight; int brightness; int colour; int contrast; int hue; int whiteness; + int exposure; + int auto_brt; /* Auto brightness enabled flag */ + int auto_gain; /* Auto gain control enabled flag */ + int auto_exp; /* Auto exposure enabled flag */ + int backlight; /* Backlight exposure algorithm flag */ - struct semaphore lock; + int led_policy; /* LED: off|on|auto; OV511+ only */ + + struct semaphore lock; /* Serializes user-accessible operations */ int user; /* user count for exclusive use */ int streaming; /* Are we streaming Isochronous? */ int grabbing; /* Are we grabbing? */ int compress; /* Should the next frame be compressed? */ + int compress_inited; /* Are compression params uploaded? */ + + int lightfreq; /* Power (lighting) frequency */ + int bandfilt; /* Banding filter enabled flag */ char *fbuf; /* Videodev buffer area */ + char *tempfbuf; /* Temporary (intermediate) buffer area */ + char *rawfbuf; /* Raw camera data buffer area */ int sub_flag; /* Pix Array subcapture on flag */ int subx; /* Pix Array subcapture x offset */ @@ -318,30 +488,53 @@ int curframe; /* Current receiving sbuf */ struct ov511_frame frame[OV511_NUMFRAMES]; - int cursbuf; /* Current receiving sbuf */ struct ov511_sbuf sbuf[OV511_NUMSBUF]; - /* Scratch space from the Isochronous pipe */ - unsigned char scratch[SCRATCH_BUF_SIZE]; - int scratchlen; - wait_queue_head_t wq; /* Processes waiting */ int snap_enabled; /* Snapshot mode enabled */ - int bridge; /* Type of bridge (OV511 or OV511+) */ - int sensor; /* Type of image sensor chip */ + int bridge; /* Type of bridge (BRG_*) */ + int bclass; /* Class of bridge (BCL_*) */ + int sensor; /* Type of image sensor chip (SEN_*) */ + int sclass; /* Type of image sensor chip (SCL_*) */ + int tuner; /* Type of TV tuner */ int packet_size; /* Frame size per isoc desc */ - /* proc interface */ struct semaphore param_lock; /* params lock for this camera */ - struct proc_dir_entry *proc_entry; /* /proc/ov511/videoX */ - + + /* /proc entries, relative to /proc/video/ov511/ */ + struct proc_dir_entry *proc_devdir; /* Per-device proc directory */ + struct proc_dir_entry *proc_info; /* <minor#>/info entry */ + struct proc_dir_entry *proc_button; /* <minor#>/button entry */ + struct proc_dir_entry *proc_control; /* <minor#>/control entry */ + /* Framebuffer/sbuf management */ int buf_state; struct semaphore buf_lock; struct timer_list buf_timer; + + struct ov51x_decomp_ops *decomp_ops; + + /* Stop streaming while changing picture settings */ + int stop_during_set; + + int stopped; /* Streaming is temporarily paused */ + + /* Video decoder stuff */ + int input; /* Composite, S-VIDEO, etc... */ + int num_inputs; /* Number of inputs */ + int norm; /* NTSC / PAL / SECAM */ + int has_decoder; /* Device has a video decoder */ + int has_tuner; /* Device has a TV tuner */ + int has_audio_proc; /* Device has an audio processor */ + int freq; /* Current tuner frequency */ + int tuner_type; /* Specific tuner model */ + + /* I2C interface to kernel */ + struct semaphore i2c_lock; /* Protect I2C controller regs */ + unsigned char primary_i2c_slave; /* I2C write id of sensor */ }; struct cam_list { @@ -354,18 +547,57 @@ char *name; }; -struct mode_list { +struct mode_list_518 { int width; int height; - int color; /* 0=grayscale, 1=color */ - u8 pxcnt; /* pixel counter */ - u8 lncnt; /* line counter */ - u8 pxdv; /* pixel divisor */ - u8 lndv; /* line divisor */ - u8 m420; - u8 common_A; - u8 common_L; -}; + u8 reg28; + u8 reg29; + u8 reg2a; + u8 reg2c; + u8 reg2e; + u8 reg24; + u8 reg25; +}; + +/* Compression stuff */ + +#define OV511_QUANTABLESIZE 64 +#define OV518_QUANTABLESIZE 32 + +#define OV511_YQUANTABLE { \ + 0, 1, 1, 2, 2, 3, 3, 4, \ + 1, 1, 1, 2, 2, 3, 4, 4, \ + 1, 1, 2, 2, 3, 4, 4, 4, \ + 2, 2, 2, 3, 4, 4, 4, 4, \ + 2, 2, 3, 4, 4, 5, 5, 5, \ + 3, 3, 4, 4, 5, 5, 5, 5, \ + 3, 4, 4, 4, 5, 5, 5, 5, \ + 4, 4, 4, 4, 5, 5, 5, 5 \ +} + +#define OV511_UVQUANTABLE { \ + 0, 2, 2, 3, 4, 4, 4, 4, \ + 2, 2, 2, 4, 4, 4, 4, 4, \ + 2, 2, 3, 4, 4, 4, 4, 4, \ + 3, 4, 4, 4, 4, 4, 4, 4, \ + 4, 4, 4, 4, 4, 4, 4, 4, \ + 4, 4, 4, 4, 4, 4, 4, 4, \ + 4, 4, 4, 4, 4, 4, 4, 4, \ + 4, 4, 4, 4, 4, 4, 4, 4 \ +} + +#define OV518_YQUANTABLE { \ + 5, 4, 5, 6, 6, 7, 7, 7, \ + 5, 5, 5, 5, 6, 7, 7, 7, \ + 6, 6, 6, 6, 7, 7, 7, 8, \ + 7, 7, 6, 7, 7, 7, 8, 8 \ +} + +#define OV518_UVQUANTABLE { \ + 6, 6, 6, 7, 7, 7, 7, 7, \ + 6, 6, 6, 7, 7, 7, 7, 7, \ + 6, 6, 6, 7, 7, 7, 7, 8, \ + 7, 7, 7, 7, 7, 7, 8, 8 \ +} #endif - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/pegasus.c linux-2.5/drivers/usb/pegasus.c --- linux-2.5.1/drivers/usb/pegasus.c Sun Dec 9 04:25:02 2001 +++ linux-2.5/drivers/usb/pegasus.c Tue Jan 8 00:44:24 2002 @@ -142,11 +142,11 @@ remove_wait_queue(&pegasus->ctrl_wait, &wait); set_current_state(TASK_RUNNING); - pegasus->dr.requesttype = PEGASUS_REQT_READ; - pegasus->dr.request = PEGASUS_REQ_GET_REGS; - pegasus->dr.value = cpu_to_le16 (0); - pegasus->dr.index = cpu_to_le16p(&indx); - pegasus->dr.length = cpu_to_le16p(&size); + pegasus->dr.bRequestType = PEGASUS_REQT_READ; + pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS; + pegasus->dr.wValue = cpu_to_le16 (0); + pegasus->dr.wIndex = cpu_to_le16p(&indx); + pegasus->dr.wLength = cpu_to_le16p(&size); pegasus->ctrl_urb.transfer_buffer_length = size; FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, @@ -192,11 +192,11 @@ remove_wait_queue(&pegasus->ctrl_wait, &wait); set_current_state(TASK_RUNNING); - pegasus->dr.requesttype = PEGASUS_REQT_WRITE; - pegasus->dr.request = PEGASUS_REQ_SET_REGS; - pegasus->dr.value = cpu_to_le16 (0); - pegasus->dr.index = cpu_to_le16p( &indx ); - pegasus->dr.length = cpu_to_le16p( &size ); + pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; + pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; + pegasus->dr.wValue = cpu_to_le16 (0); + pegasus->dr.wIndex = cpu_to_le16p( &indx ); + pegasus->dr.wLength = cpu_to_le16p( &size ); pegasus->ctrl_urb.transfer_buffer_length = size; FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, @@ -242,11 +242,11 @@ remove_wait_queue(&pegasus->ctrl_wait, &wait); set_current_state(TASK_RUNNING); - pegasus->dr.requesttype = PEGASUS_REQT_WRITE; - pegasus->dr.request = PEGASUS_REQ_SET_REG; - pegasus->dr.value = cpu_to_le16p( &dat); - pegasus->dr.index = cpu_to_le16p( &indx ); - pegasus->dr.length = cpu_to_le16( 1 ); + pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; + pegasus->dr.bRequest = PEGASUS_REQ_SET_REG; + pegasus->dr.wValue = cpu_to_le16p( &dat); + pegasus->dr.wIndex = cpu_to_le16p( &indx ); + pegasus->dr.wLength = cpu_to_le16( 1 ); pegasus->ctrl_urb.transfer_buffer_length = 1; FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, @@ -275,11 +275,11 @@ { int ret; - pegasus->dr.requesttype = PEGASUS_REQT_WRITE; - pegasus->dr.request = PEGASUS_REQ_SET_REGS; - pegasus->dr.value = 0; - pegasus->dr.index = cpu_to_le16(EthCtrl0); - pegasus->dr.length = cpu_to_le16(3); + pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; + pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; + pegasus->dr.wValue = 0; + pegasus->dr.wIndex = cpu_to_le16(EthCtrl0); + pegasus->dr.wLength = cpu_to_le16(3); pegasus->ctrl_urb.transfer_buffer_length = 3; FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/pegasus.h linux-2.5/drivers/usb/pegasus.h --- linux-2.5.1/drivers/usb/pegasus.h Sun Dec 9 04:25:02 2001 +++ linux-2.5/drivers/usb/pegasus.h Tue Jan 8 00:44:24 2002 @@ -108,7 +108,7 @@ int dev_index; int intr_interval; struct urb ctrl_urb, rx_urb, tx_urb, intr_urb; - devrequest dr; + struct usb_ctrlrequest dr; wait_queue_head_t ctrl_wait; struct semaphore ctrl_sem; unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/printer.c linux-2.5/drivers/usb/printer.c --- linux-2.5.1/drivers/usb/printer.c Tue Oct 9 22:15:02 2001 +++ linux-2.5/drivers/usb/printer.c Thu Jan 3 22:57:52 2002 @@ -201,7 +201,7 @@ static int usblp_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev) - USBLP_MINOR_BASE; + int minor = minor(inode->i_rdev) - USBLP_MINOR_BASE; struct usblp *usblp; int retval; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/pwc-ctrl.c linux-2.5/drivers/usb/pwc-ctrl.c --- linux-2.5.1/drivers/usb/pwc-ctrl.c Tue Nov 27 01:09:10 2001 +++ linux-2.5/drivers/usb/pwc-ctrl.c Sat Jan 5 16:38:08 2002 @@ -1008,6 +1008,8 @@ if (pdev->type < 730) return 0; + on_value /= 100; + off_value /= 100; if (on_value < 0) on_value = 0; if (on_value > 0xff) @@ -1048,8 +1050,8 @@ if (ret < 0) return ret; - *on_value = buf[0]; - *off_value = buf[1]; + *on_value = buf[0] * 100; + *off_value = buf[1] * 100; return 0; } @@ -1175,6 +1177,8 @@ wb.read_red = pwc_read_red_gain(pdev); wb.read_blue = pwc_read_blue_gain(pdev); } + if (copy_to_user(arg, &wb, sizeof(wb))) + return -EFAULT; break; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/pwc-if.c linux-2.5/drivers/usb/pwc-if.c --- linux-2.5.1/drivers/usb/pwc-if.c Tue Nov 27 01:09:10 2001 +++ linux-2.5/drivers/usb/pwc-if.c Sat Jan 5 16:38:08 2002 @@ -39,7 +39,10 @@ /* Contributors: - Alvarado: adding whitebalance code - - Alistar Moire: QuickCam 3000 Pro testing + - Alistar Moire: QuickCam 3000 Pro device/product ID + - Tony Hoyle: Creative Labs Webcam 5 device/product ID + - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged + - Jk Fang: SOTEC device/product ID */ #include <linux/errno.h> @@ -76,6 +79,8 @@ { USB_DEVICE(0x046D, 0x08b0) }, { USB_DEVICE(0x055D, 0x9000) }, { USB_DEVICE(0x055D, 0x9001) }, + { USB_DEVICE(0x041E, 0x400C) }, + { USB_DEVICE(0x04CC, 0x8116) }, { } }; MODULE_DEVICE_TABLE(usb, pwc_device_table); @@ -624,7 +629,7 @@ /* This gets called for the Isochronous pipe (video). This is done in * interrupt time, so it has to be fast, not crash, and not stall. Neat. */ -static void pwc_isoc_handler(purb_t urb) +static void pwc_isoc_handler(struct urb *urb) { struct pwc_device *pdev; int i, fst, flen; @@ -786,7 +791,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) { struct usb_device *udev; - purb_t urb; + struct urb *urb; int i, j, ret; struct usb_interface_descriptor *idesc; @@ -887,6 +892,7 @@ /* Stop camera, but only if we are sure the camera is still there */ if (!pdev->unplugged) usb_set_interface(pdev->udev, 0, 0); + /* Unlinking ISOC buffers one by one */ for (i = MAX_ISO_BUFS - 1; i >= 0; i--) { pdev->sbuf[i].urb->next = NULL; usb_unlink_urb(pdev->sbuf[i].urb); @@ -1493,6 +1499,12 @@ */ add_wait_queue(&pdev->frameq, &wait); while (pdev->full_frames == NULL) { + if (pdev->unplugged) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -ENODEV; + } + if (signal_pending(current)) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); @@ -1710,7 +1722,29 @@ break; } } - else return NULL; /* Not Philips, Askey, Logitech or Samsung, for sure. */ + else if (vendor_id == 0x041e) { + switch(product_id) { + case 0x400c: + Info("Creative Labs Webcam 5 detected.\n"); + type_id = 730; + break; + default: + return NULL; + break; + } + } + else if (vendor_id == 0x04cc) { + switch(product_id) { + case 0x8116: + Info("SOTEC CMS-001 USB webcam detected.\n"); + type_id = 730; + break; + default: + return NULL; + break; + } + } + else return NULL; /* Not Philips, Askey, Logitech, Samsung, Creative or SOTEC, for sure. */ memset(serial_number, 0, 30); usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); @@ -1780,16 +1814,6 @@ if (hint < MAX_DEV_HINTS) device_hint[hint].pdev = pdev; -#if 0 - /* Shut down camera now (some people like the LED off) */ - if (power_save) { - Trace(TRACE_PROBE, "Powering down camera"); - i = pwc_camera_power(pdev, 0); - if (i < 0) - Info("Failed to power-down the camera (%d)\n", i); - } -#endif - Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); return pdev; } @@ -1799,6 +1823,7 @@ { struct pwc_device *pdev; int hint; + DECLARE_WAITQUEUE(wait, current); lock_kernel(); free_mem_leak(); @@ -1833,13 +1858,19 @@ */ wake_up(&pdev->frameq); - /* Wait until we get a 'go' from _close(). This - had a gigantic race condition, since we kfree() + /* Wait until we get a 'go' from _close(). This used + to have a gigantic race condition, since we kfree() stuff here, but we have to wait until close() - is finished. */ + is finished. + */ Trace(TRACE_PROBE, "Sleeping on remove_ok.\n"); - sleep_on(&pdev->remove_ok); + add_wait_queue(&pdev->remove_ok, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + /* ... wait ... */ + schedule(); + remove_wait_queue(&pdev->remove_ok, &wait); + set_current_state(TASK_RUNNING); Trace(TRACE_PROBE, "Done sleeping.\n"); set_mem_leak(pdev->vdev); pdev->vdev = NULL; @@ -1920,7 +1951,7 @@ char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n"); - Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro and the Samsung MPC-C10 and MPC-C30.\n"); + Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30, the Creative WebCam 5 and the SOTEC CMS-001.\n"); if (fps) { if (fps < 5 || fps > 30) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/pwc-ioctl.h linux-2.5/drivers/usb/pwc-ioctl.h --- linux-2.5.1/drivers/usb/pwc-ioctl.h Wed Oct 17 21:34:06 2001 +++ linux-2.5/drivers/usb/pwc-ioctl.h Sat Jan 5 16:38:08 2002 @@ -79,8 +79,8 @@ /* Used with VIDIOCPWC[SG]LED */ struct pwc_leds { - int led_on; /* Led on-time; range = 0..255 */ - int led_off; /* */ + int led_on; /* Led on-time; range = 0..25000 */ + int led_off; /* Led off-time; range = 0..25000 */ }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/pwc.h linux-2.5/drivers/usb/pwc.h --- linux-2.5.1/drivers/usb/pwc.h Tue Nov 27 01:09:10 2001 +++ linux-2.5/drivers/usb/pwc.h Sat Jan 5 16:38:08 2002 @@ -60,8 +60,8 @@ /* Version block */ #define PWC_MAJOR 8 -#define PWC_MINOR 4 -#define PWC_VERSION "8.4" +#define PWC_MINOR 5 +#define PWC_VERSION "8.5" #define PWC_NAME "pwc" /* Turn certain features on/off */ @@ -96,7 +96,7 @@ void *data; int length; int read; - purb_t urb; + struct urb *urb; }; /* intermediate buffers with raw data from the USB cam */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/scanner.c linux-2.5/drivers/usb/scanner.c --- linux-2.5.1/drivers/usb/scanner.c Sun Dec 9 04:28:44 2001 +++ linux-2.5/drivers/usb/scanner.c Tue Jan 8 00:44:24 2002 @@ -281,7 +281,7 @@ * 0.4.7 11/28/2001 * - Fixed typo in Documentation/scanner.txt. Thanks to * Karel <karel.vervaeke@pandora.be> for pointing it out. - * - Added ID's for a Memorex 6136u. Thanks to =C1lvaro Gaspar de + * - Added ID's for a Memorex 6136u. Thanks to Álvaro Gaspar de * Valenzuela" <agaspard@utsi.edu>. * - Added ID's for Agfa e25. Thanks to Heinrich * Rust <Heinrich.Rust@gmx.de>. Also reported to work with @@ -365,7 +365,7 @@ struct scn_usb_data *scn; struct usb_device *dev; - kdev_t scn_minor; + int scn_minor; int err=0; @@ -432,7 +432,7 @@ { struct scn_usb_data *scn; - kdev_t scn_minor; + int scn_minor; scn_minor = USB_SCN_MINOR (inode); @@ -469,7 +469,7 @@ ssize_t bytes_written = 0; /* Overall count of bytes written */ ssize_t ret = 0; - kdev_t scn_minor; + int scn_minor; int this_write; /* Number of bytes to write */ int partial; /* Number of bytes successfully written */ @@ -556,7 +556,7 @@ ssize_t bytes_read; /* Overall count of bytes_read */ ssize_t ret; - kdev_t scn_minor; + int scn_minor; int partial; /* Number of bytes successfully read */ int this_read; /* Max number of bytes to read */ @@ -671,7 +671,7 @@ { struct usb_device *dev; - kdev_t scn_minor; + int scn_minor; scn_minor = USB_SCN_MINOR(inode); @@ -747,8 +747,8 @@ case SCANNER_IOCTL_CTRLMSG: { struct ctrlmsg_ioctl { - devrequest req; - void *data; + struct usb_ctrlrequest req; + void *data; } cmsg; int pipe, nb, ret; unsigned char buf[64]; @@ -756,12 +756,12 @@ if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) return -EFAULT; - nb = le16_to_cpup(&cmsg.req.length); + nb = le16_to_cpup(&cmsg.req.wLength); if (nb > sizeof(buf)) return -EINVAL; - if ((cmsg.req.requesttype & 0x80) == 0) { + if ((cmsg.req.bRequestType & 0x80) == 0) { pipe = usb_sndctrlpipe(dev, 0); if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) return -EFAULT; @@ -769,10 +769,10 @@ pipe = usb_rcvctrlpipe(dev, 0); } - ret = usb_control_msg(dev, pipe, cmsg.req.request, - cmsg.req.requesttype, - le16_to_cpup(&cmsg.req.value), - le16_to_cpup(&cmsg.req.index), + ret = usb_control_msg(dev, pipe, cmsg.req.bRequest, + cmsg.req.bRequestType, + le16_to_cpup(&cmsg.req.wValue), + le16_to_cpup(&cmsg.req.wIndex), buf, nb, HZ); if (ret < 0) { @@ -780,7 +780,7 @@ return -EIO; } - if (nb > 0 && (cmsg.req.requesttype & 0x80) && copy_to_user(cmsg.data, buf, nb)) + if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb)) return -EFAULT; return 0; @@ -811,7 +811,7 @@ int ep_cnt; int ix; - kdev_t scn_minor; + int scn_minor; char valid_device = 0; char have_bulk_in, have_bulk_out, have_intr; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/scanner.h linux-2.5/drivers/usb/scanner.h --- linux-2.5.1/drivers/usb/scanner.h Sun Dec 9 04:28:44 2001 +++ linux-2.5/drivers/usb/scanner.h Tue Jan 8 00:44:24 2002 @@ -203,7 +203,7 @@ #define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) #define IS_EP_INTR(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0) -#define USB_SCN_MINOR(X) MINOR((X)->i_rdev) - SCN_BASE_MNR +#define USB_SCN_MINOR(X) minor((X)->i_rdev) - SCN_BASE_MNR #ifdef DEBUG #define SCN_DEBUG(X) X @@ -230,7 +230,7 @@ #define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int) #define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int) /* send/recv a control message to the scanner */ -#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, devrequest ) +#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest) #define SCN_MAX_MNR 16 /* We're allocated 16 minors */ @@ -243,7 +243,7 @@ devfs_handle_t devfs; /* devfs device */ struct urb scn_irq; unsigned int ifnum; /* Interface number of the USB device */ - kdev_t scn_minor; /* Scanner minor - used in disconnect() */ + unsigned int scn_minor; /* Scanner minor - used in disconnect() */ unsigned char button; /* Front panel buffer */ char isopen; /* Not zero if the device is open */ char present; /* Not zero if device is present */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/Config.in linux-2.5/drivers/usb/serial/Config.in --- linux-2.5.1/drivers/usb/serial/Config.in Wed Oct 17 21:35:17 2001 +++ linux-2.5/drivers/usb/serial/Config.in Thu Jan 3 23:04:40 2002 @@ -15,6 +15,7 @@ dep_tristate ' USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL +dep_tristate ' USB Compaq iPAQ Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL dep_tristate ' USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL @@ -28,6 +29,7 @@ dep_mbool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W $CONFIG_USB_SERIAL_KEYSPAN dep_mbool ' USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W $CONFIG_USB_SERIAL_KEYSPAN dep_tristate ' USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL +dep_tristate ' USB KL5KUSB105 (Palmconnect) Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KLSI $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/Makefile linux-2.5/drivers/usb/serial/Makefile --- linux-2.5.1/drivers/usb/serial/Makefile Tue Oct 9 22:15:02 2001 +++ linux-2.5/drivers/usb/serial/Makefile Thu Jan 3 23:04:40 2002 @@ -8,6 +8,7 @@ obj-$(CONFIG_USB_SERIAL) += usbserial.o obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o +obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o @@ -22,7 +23,8 @@ obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o - +obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o + # Objects that export symbols. export-objs := usbserial.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/belkin_sa.c linux-2.5/drivers/usb/serial/belkin_sa.c --- linux-2.5.1/drivers/usb/serial/belkin_sa.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/belkin_sa.c Tue Jan 8 00:44:24 2002 @@ -119,6 +119,7 @@ /* All of the device info needed for the serial converters */ static struct usb_serial_device_type belkin_device = { + owner: THIS_MODULE, name: "Belkin / Peracom / GoHubs USB Serial Adapter", id_table: id_table_combined, num_interrupt_in: 1, @@ -209,7 +210,6 @@ down (&port->sem); ++port->open_count; - MOD_INC_USE_COUNT; if (port->open_count == 1) { /*Start reading from the device*/ @@ -264,7 +264,6 @@ } up (&port->sem); - MOD_DEC_USE_COUNT; } /* belkin_sa_close */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/cyberjack.c linux-2.5/drivers/usb/serial/cyberjack.c --- linux-2.5.1/drivers/usb/serial/cyberjack.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/cyberjack.c Tue Jan 8 00:44:24 2002 @@ -77,6 +77,7 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_serial_device_type cyberjack_device = { + owner: THIS_MODULE, name: "Reiner SCT Cyberjack USB card reader", id_table: id_table, num_interrupt_in: 1, @@ -148,8 +149,6 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - MOD_INC_USE_COUNT; - dbg(__FUNCTION__ " - port %d", port->number); down (&port->sem); @@ -204,7 +203,6 @@ } up (&port->sem); - MOD_DEC_USE_COUNT; } static int cyberjack_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/digi_acceleport.c linux-2.5/drivers/usb/serial/digi_acceleport.c --- linux-2.5.1/drivers/usb/serial/digi_acceleport.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/digi_acceleport.c Tue Jan 8 00:44:24 2002 @@ -501,6 +501,7 @@ /* device info needed for the Digi serial converter */ static struct usb_serial_device_type digi_acceleport_2_device = { + owner: THIS_MODULE, name: "Digi USB", id_table: id_table_2, num_interrupt_in: 0, @@ -524,6 +525,7 @@ }; static struct usb_serial_device_type digi_acceleport_4_device = { + owner: THIS_MODULE, name: "Digi USB", id_table: id_table_4, num_interrupt_in: 0, @@ -603,7 +605,6 @@ spin_lock_irqsave( &priv->dp_port_lock, flags ); digi_wakeup_write( port ); spin_unlock_irqrestore( &priv->dp_port_lock, flags ); - MOD_DEC_USE_COUNT; } static void digi_wakeup_write( struct usb_serial_port *port ) @@ -1410,9 +1411,7 @@ /* also queue up a wakeup at scheduler time, in case we */ /* lost the race in write_chan(). */ - MOD_INC_USE_COUNT; - if (schedule_task(&priv->dp_wakeup_task) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&priv->dp_wakeup_task); spin_unlock( &priv->dp_port_lock ); @@ -1493,7 +1492,6 @@ /* inc module use count before sleeping to wait for closes */ ++port->open_count; - MOD_INC_USE_COUNT; /* wait for a close in progress to finish */ while( priv->dp_in_close ) { @@ -1502,7 +1500,6 @@ &priv->dp_port_lock, flags ); if( signal_pending(current) ) { --port->open_count; - MOD_DEC_USE_COUNT; return( -EINTR ); } spin_lock_irqsave( &priv->dp_port_lock, flags ); @@ -1562,7 +1559,6 @@ spin_lock_irqsave( &priv->dp_port_lock, flags ); if( port->open_count > 1 ) { --port->open_count; - MOD_DEC_USE_COUNT; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); return; } else if( port->open_count <= 0 ) { @@ -1642,7 +1638,6 @@ priv->dp_write_urb_in_use = 0; priv->dp_in_close = 0; --port->open_count; - MOD_DEC_USE_COUNT; wake_up_interruptible( &priv->dp_close_wait ); spin_unlock_irqrestore( &priv->dp_port_lock, flags ); @@ -1787,7 +1782,6 @@ priv = serial->port[i].private; spin_lock_irqsave( &priv->dp_port_lock, flags ); while( serial->port[i].open_count > 0 ) { - MOD_DEC_USE_COUNT; --serial->port[i].open_count; } spin_unlock_irqrestore( &priv->dp_port_lock, flags ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/empeg.c linux-2.5/drivers/usb/serial/empeg.c --- linux-2.5.1/drivers/usb/serial/empeg.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/empeg.c Tue Jan 8 00:44:24 2002 @@ -114,6 +114,7 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_serial_device_type empeg_device = { + owner: THIS_MODULE, name: "Empeg", id_table: id_table, num_interrupt_in: 0, @@ -159,7 +160,6 @@ down (&port->sem); ++port->open_count; - MOD_INC_USE_COUNT; if (port->open_count == 1) { @@ -224,8 +224,6 @@ /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ - - MOD_DEC_USE_COUNT; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/ftdi_sio.c linux-2.5/drivers/usb/serial/ftdi_sio.c --- linux-2.5.1/drivers/usb/serial/ftdi_sio.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/ftdi_sio.c Tue Jan 8 00:44:24 2002 @@ -174,6 +174,7 @@ which share common code */ static struct usb_serial_device_type ftdi_sio_device = { + owner: THIS_MODULE, name: "FTDI SIO", id_table: id_table_sio, num_interrupt_in: 0, @@ -318,7 +319,6 @@ down (&port->sem); - MOD_INC_USE_COUNT; ++port->open_count; if (port->open_count == 1){ @@ -411,7 +411,6 @@ } up (&port->sem); - MOD_DEC_USE_COUNT; } /* ftdi_sio_close */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/io_edgeport.c linux-2.5/drivers/usb/serial/io_edgeport.c --- linux-2.5.1/drivers/usb/serial/io_edgeport.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/io_edgeport.c Tue Jan 8 00:44:24 2002 @@ -985,7 +985,6 @@ return -ENODEV; ++port->open_count; - MOD_INC_USE_COUNT; if (port->open_count == 1) { /* force low_latency on so that our tty_push actually forces the data through, @@ -999,7 +998,6 @@ edge_serial = (struct edgeport_serial *)serial->private; if (edge_serial == NULL) { port->open_count = 0; - MOD_DEC_USE_COUNT; return -ENODEV; } if (edge_serial->interrupt_in_buffer == NULL) { @@ -1062,7 +1060,6 @@ err(__FUNCTION__" - error sending open port command"); edge_port->openPending = FALSE; port->open_count = 0; - MOD_DEC_USE_COUNT; return -ENODEV; } @@ -1077,7 +1074,6 @@ dbg(__FUNCTION__" - open timedout"); edge_port->openPending = FALSE; port->open_count = 0; - MOD_DEC_USE_COUNT; return -ENODEV; } @@ -1283,7 +1279,6 @@ port->open_count = 0; } - MOD_DEC_USE_COUNT; dbg(__FUNCTION__" exited"); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/io_tables.h linux-2.5/drivers/usb/serial/io_tables.h --- linux-2.5.1/drivers/usb/serial/io_tables.h Thu Nov 29 21:45:52 2001 +++ linux-2.5/drivers/usb/serial/io_tables.h Tue Jan 8 00:44:24 2002 @@ -72,6 +72,7 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_serial_device_type edgeport_1port_device = { + owner: THIS_MODULE, name: "Edgeport 1 port adapter", id_table: edgeport_1port_id_table, num_interrupt_in: 1, @@ -93,6 +94,7 @@ }; static struct usb_serial_device_type edgeport_2port_device = { + owner: THIS_MODULE, name: "Edgeport 2 port adapter", id_table: edgeport_2port_id_table, num_interrupt_in: 1, @@ -114,6 +116,7 @@ }; static struct usb_serial_device_type edgeport_4port_device = { + owner: THIS_MODULE, name: "Edgeport 4 port adapter", id_table: edgeport_4port_id_table, num_interrupt_in: 1, @@ -135,6 +138,7 @@ }; static struct usb_serial_device_type edgeport_8port_device = { + owner: THIS_MODULE, name: "Edgeport 8 port adapter", id_table: edgeport_8port_id_table, num_interrupt_in: 1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/ipaq.c linux-2.5/drivers/usb/serial/ipaq.c --- linux-2.5.1/drivers/usb/serial/ipaq.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/serial/ipaq.c Tue Jan 1 23:42:42 2002 @@ -0,0 +1,525 @@ +/* + * USB Compaq iPAQ driver + * + * Copyright (C) 2001 + * Ganesh Varadarajan <ganesh@veritas.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. + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/fcntl.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/usb.h> + +#ifdef CONFIG_USB_SERIAL_DEBUG + static int debug = 1; +#else + static int debug = 0; +#endif + +#include "usb-serial.h" +#include "ipaq.h" + +/* + * Version Information + */ +#define DRIVER_VERSION "v0.1" +#define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>" +#define DRIVER_DESC "USB Compaq iPAQ driver" + +/* Function prototypes for an ipaq */ +static int ipaq_open (struct usb_serial_port *port, struct file *filp); +static void ipaq_close (struct usb_serial_port *port, struct file *filp); +static int ipaq_startup (struct usb_serial *serial); +static void ipaq_shutdown (struct usb_serial *serial); +static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, + int count); +static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf, + int count); +static int ipaq_write_flush(struct usb_serial_port *port); +static void ipaq_read_bulk_callback (struct urb *urb); +static void ipaq_write_bulk_callback(struct urb *urb); +static int ipaq_write_room(struct usb_serial_port *port); +static int ipaq_chars_in_buffer(struct usb_serial_port *port); +static void ipaq_destroy_lists(struct usb_serial_port *port); + + +static __devinitdata struct usb_device_id ipaq_id_table [] = { + { USB_DEVICE(IPAQ_VENDOR_ID, IPAQ_PRODUCT_ID) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, ipaq_id_table); + +/* All of the device info needed for the Compaq iPAQ */ +struct usb_serial_device_type ipaq_device = { + owner: THIS_MODULE, + name: "Compaq iPAQ", + id_table: ipaq_id_table, + num_interrupt_in: 0, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: ipaq_open, + close: ipaq_close, + startup: ipaq_startup, + shutdown: ipaq_shutdown, + write: ipaq_write, + write_room: ipaq_write_room, + chars_in_buffer: ipaq_chars_in_buffer, + read_bulk_callback: ipaq_read_bulk_callback, + write_bulk_callback: ipaq_write_bulk_callback, +}; + +static spinlock_t write_list_lock; +static int bytes_in; +static int bytes_out; + +static int ipaq_open(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + struct ipaq_private *priv; + struct ipaq_packet *pkt; + int i, result = 0; + + if (port_paranoia_check(port, __FUNCTION__)) { + return -ENODEV; + } + + dbg(__FUNCTION__ " - port %d", port->number); + + down(&port->sem); + + ++port->open_count; + + if (port->open_count == 1) { + bytes_in = 0; + bytes_out = 0; + priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL); + if (priv == NULL) { + err(__FUNCTION__ " - Out of memory"); + return -ENOMEM; + } + port->private = (void *)priv; + priv->active = 0; + priv->queue_len = 0; + INIT_LIST_HEAD(&priv->queue); + INIT_LIST_HEAD(&priv->freelist); + + for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) { + pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL); + if (pkt == NULL) { + goto enomem; + } + pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL); + if (pkt->data == NULL) { + kfree(pkt); + goto enomem; + } + pkt->len = 0; + pkt->written = 0; + INIT_LIST_HEAD(&pkt->list); + list_add(&pkt->list, &priv->freelist); + priv->free_len += PACKET_SIZE; + } + + /* + * Force low latency on. This will immediately push data to the line + * discipline instead of queueing. + */ + + port->tty->low_latency = 1; + + /* + * Lose the small buffers usbserial provides. Make larger ones. + */ + + kfree(port->bulk_in_buffer); + kfree(port->bulk_out_buffer); + port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); + if (port->bulk_in_buffer == NULL) { + goto enomem; + } + port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); + if (port->bulk_out_buffer == NULL) { + kfree(port->bulk_in_buffer); + goto enomem; + } + port->read_urb->transfer_buffer = port->bulk_in_buffer; + port->write_urb->transfer_buffer = port->bulk_out_buffer; + port->read_urb->transfer_buffer_length = URBDATA_SIZE; + port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE; + + /* Start reading from the device */ + FILL_BULK_URB(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, + ipaq_read_bulk_callback, port); + result = usb_submit_urb(port->read_urb); + if (result) { + err(__FUNCTION__ " - failed submitting read urb, error %d", result); + } + + /* + * Send out two control messages observed in win98 sniffs. Not sure what + * they do. + */ + + result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21, + 0x1, 0, NULL, 0, 5 * HZ); + if (result < 0) { + err(__FUNCTION__ " - failed doing control urb, error %d", result); + } + result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21, + 0x1, 0, NULL, 0, 5 * HZ); + if (result < 0) { + err(__FUNCTION__ " - failed doing control urb, error %d", result); + } + } + + up(&port->sem); + + return result; + +enomem: + ipaq_destroy_lists(port); + kfree(priv); + err(__FUNCTION__ " - Out of memory"); + return -ENOMEM; +} + + +static void ipaq_close(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial; + struct ipaq_private *priv = port->private; + + if (port_paranoia_check(port, __FUNCTION__)) { + return; + } + + dbg(__FUNCTION__ " - port %d", port->number); + + serial = get_usb_serial(port, __FUNCTION__); + if (!serial) + return; + + down (&port->sem); + + --port->open_count; + + if (port->open_count <= 0) { + + /* + * shut down bulk read and write + */ + + usb_unlink_urb(port->write_urb); + usb_unlink_urb(port->read_urb); + ipaq_destroy_lists(port); + kfree(priv); + port->private = NULL; + port->open_count = 0; + + } + up (&port->sem); + + /* Uncomment the following line if you want to see some statistics in your syslog */ + /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ +} + +static void ipaq_read_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + int i, result; + + if (port_paranoia_check(port, __FUNCTION__)) + return; + + dbg(__FUNCTION__ " - port %d", port->number); + + if (!serial) { + dbg(__FUNCTION__ " - bad serial pointer, exiting"); + return; + } + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + return; + } + + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + + tty = port->tty; + if (urb->actual_length) { + for (i = 0; i < urb->actual_length ; ++i) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ + if(tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + /* this doesn't actually push the data through unless tty->low_latency is set */ + tty_insert_flip_char(tty, data[i], 0); + } + tty_flip_buffer_push(tty); + bytes_in += urb->actual_length; + } + + /* Continue trying to always read */ + FILL_BULK_URB(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, + ipaq_read_bulk_callback, port); + result = usb_submit_urb(port->read_urb); + if (result) + err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + return; +} + +static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, + int count) +{ + const unsigned char *current_position = buf; + int bytes_sent = 0; + int transfer_size; + + dbg(__FUNCTION__ " - port %d", port->number); + + usb_serial_debug_data(__FILE__, __FUNCTION__, count, buf); + + while (count > 0) { + transfer_size = min(count, PACKET_SIZE); + if (ipaq_write_bulk(port, from_user, current_position, transfer_size)) { + break; + } + current_position += transfer_size; + bytes_sent += transfer_size; + count -= transfer_size; + bytes_out += transfer_size; + } + + return bytes_sent; +} + +static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf, + int count) +{ + struct ipaq_private *priv = port->private; + struct ipaq_packet *pkt = NULL; + int result = 0; + unsigned long flags; + + if (priv->free_len <= 0) { + dbg(__FUNCTION__ " - we're stuffed"); + return -EAGAIN; + } + + spin_lock_irqsave(&write_list_lock, flags); + if (!list_empty(&priv->freelist)) { + pkt = list_entry(priv->freelist.next, struct ipaq_packet, list); + list_del(&pkt->list); + priv->free_len -= PACKET_SIZE; + } + spin_unlock_irqrestore(&write_list_lock, flags); + if (pkt == NULL) { + dbg(__FUNCTION__ " - we're stuffed"); + return -EAGAIN; + } + + if (from_user) { + copy_from_user(pkt->data, buf, count); + } else { + memcpy(pkt->data, buf, count); + } + usb_serial_debug_data(__FILE__, __FUNCTION__, count, pkt->data); + + pkt->len = count; + pkt->written = 0; + spin_lock_irqsave(&write_list_lock, flags); + list_add_tail(&pkt->list, &priv->queue); + priv->queue_len += count; + if (priv->active == 0) { + priv->active = 1; + result = ipaq_write_flush(port); + } + spin_unlock_irqrestore(&write_list_lock, flags); + return result; +} + +static int ipaq_write_flush(struct usb_serial_port *port) +{ + struct ipaq_private *priv = (struct ipaq_private *)port->private; + struct usb_serial *serial = port->serial; + int count, room, result; + struct ipaq_packet *pkt; + struct urb *urb = port->write_urb; + struct list_head *tmp; + + if (urb->status == -EINPROGRESS) { + /* Should never happen */ + err(__FUNCTION__ " - flushing while urb is active !"); + return -EAGAIN; + } + room = URBDATA_SIZE; + for (tmp = priv->queue.next; tmp != &priv->queue;) { + pkt = list_entry(tmp, struct ipaq_packet, list); + tmp = tmp->next; + count = min(room, (int)(pkt->len - pkt->written)); + memcpy(urb->transfer_buffer + (URBDATA_SIZE - room), + pkt->data + pkt->written, count); + room -= count; + pkt->written += count; + priv->queue_len -= count; + if (pkt->written == pkt->len) { + list_del(&pkt->list); + list_add(&pkt->list, &priv->freelist); + priv->free_len += PACKET_SIZE; + } + if (room == 0) { + break; + } + } + + count = URBDATA_SIZE - room; + FILL_BULK_URB(port->write_urb, serial->dev, + usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback, + port); + result = usb_submit_urb(urb); + if (result) { + err(__FUNCTION__ " - failed submitting write urb, error %d", result); + } + return result; +} + +static void ipaq_write_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct ipaq_private *priv = (struct ipaq_private *)port->private; + unsigned long flags; + + if (port_paranoia_check (port, __FUNCTION__)) { + return; + } + + dbg(__FUNCTION__ " - port %d", port->number); + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); + } + + spin_lock_irqsave(&write_list_lock, flags); + if (!list_empty(&priv->queue)) { + ipaq_write_flush(port); + } else { + priv->active = 0; + } + spin_unlock_irqrestore(&write_list_lock, flags); + queue_task(&port->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return; +} + +static int ipaq_write_room(struct usb_serial_port *port) +{ + struct ipaq_private *priv = (struct ipaq_private *)port->private; + + dbg(__FUNCTION__ " - freelen %d", priv->free_len); + return priv->free_len; +} + +static int ipaq_chars_in_buffer(struct usb_serial_port *port) +{ + struct ipaq_private *priv = (struct ipaq_private *)port->private; + + dbg(__FUNCTION__ " - queuelen %d", priv->queue_len); + return priv->queue_len; +} + +static void ipaq_destroy_lists(struct usb_serial_port *port) +{ + struct ipaq_private *priv = (struct ipaq_private *)port->private; + struct list_head *tmp; + struct ipaq_packet *pkt; + + for (tmp = priv->queue.next; tmp != &priv->queue;) { + pkt = list_entry(tmp, struct ipaq_packet, list); + tmp = tmp->next; + kfree(pkt->data); + kfree(pkt); + } + for (tmp = priv->freelist.next; tmp != &priv->freelist;) { + pkt = list_entry(tmp, struct ipaq_packet, list); + tmp = tmp->next; + kfree(pkt->data); + kfree(pkt); + } + return; +} + + +static int ipaq_startup(struct usb_serial *serial) +{ + dbg(__FUNCTION__); + usb_set_configuration(serial->dev, 1); + return 0; +} + +static void ipaq_shutdown(struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + while (serial->port[i].open_count > 0) { + ipaq_close(&serial->port[i], NULL); + } + } +} + +static int __init ipaq_init(void) +{ + usb_serial_register(&ipaq_device); + info(DRIVER_DESC " " DRIVER_VERSION); + + return 0; +} + + +static void __exit ipaq_exit(void) +{ + usb_serial_deregister(&ipaq_device); +} + + +module_init(ipaq_init); +module_exit(ipaq_exit); + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE("GPL"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/ipaq.h linux-2.5/drivers/usb/serial/ipaq.h --- linux-2.5.1/drivers/usb/serial/ipaq.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/serial/ipaq.h Tue Jan 1 23:42:42 2002 @@ -0,0 +1,60 @@ +/* + * USB Compaq iPAQ driver + * + * Copyright (C) 2001 + * Ganesh Varadarajan <ganesh@veritas.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. + * + * + */ + +#ifndef __LINUX_USB_SERIAL_IPAQ_H +#define __LINUX_USB_SERIAL_IPAQ_H + + +#define IPAQ_VENDOR_ID 0x049f +#define IPAQ_PRODUCT_ID 0x0003 + +/* + * Since we can't queue our bulk write urbs (don't know why - it just + * doesn't work), we can send down only one write urb at a time. The simplistic + * approach taken by the generic usbserial driver will work, but it's not good + * for performance. Therefore, we buffer upto URBDATA_QUEUE_MAX bytes of write + * requests coming from the line discipline. This is done by chaining them + * in lists of struct ipaq_packet, each packet holding a maximum of + * PACKET_SIZE bytes. + * + * ipaq_write() can be called from bottom half context; hence we can't + * allocate memory for packets there. So we initialize a pool of packets at + * the first open and maintain a freelist. + * + * The value of PACKET_SIZE was empirically determined by + * checking the maximum write sizes sent down by the ppp ldisc. + * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size + * supported by the iPAQ. + */ + +struct ipaq_packet { + char *data; + size_t len; + size_t written; + struct list_head list; +}; + +struct ipaq_private { + int active; + int queue_len; + int free_len; + struct list_head queue; + struct list_head freelist; +}; + +#define URBDATA_SIZE 4096 +#define URBDATA_QUEUE_MAX (64 * 1024) +#define PACKET_SIZE 256 + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/ir-usb.c linux-2.5/drivers/usb/serial/ir-usb.c --- linux-2.5.1/drivers/usb/serial/ir-usb.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/ir-usb.c Tue Jan 8 00:44:24 2002 @@ -91,6 +91,7 @@ struct usb_serial_device_type ir_device = { + owner: THIS_MODULE, name: "IR Dongle", id_table: id_table, num_interrupt_in: 1, @@ -204,7 +205,6 @@ down (&port->sem); ++port->open_count; - MOD_INC_USE_COUNT; if (port->open_count == 1) { if (buffer_size) { @@ -270,7 +270,6 @@ } up (&port->sem); - MOD_DEC_USE_COUNT; } static int ir_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/keyspan.c linux-2.5/drivers/usb/serial/keyspan.c --- linux-2.5.1/drivers/usb/serial/keyspan.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/keyspan.c Tue Jan 8 00:44:24 2002 @@ -877,8 +877,6 @@ dbg("keyspan_open called for port%d.\n", port->number); - MOD_INC_USE_COUNT; - down (&port->sem); already_active = port->open_count; ++port->open_count; @@ -960,8 +958,6 @@ port->tty = 0; } up (&port->sem); - - MOD_DEC_USE_COUNT; } @@ -1789,7 +1785,6 @@ port = &serial->port[i]; while (port->open_count > 0) { --port->open_count; - MOD_DEC_USE_COUNT; } kfree(port->private); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/keyspan.h linux-2.5/drivers/usb/serial/keyspan.h --- linux-2.5.1/drivers/usb/serial/keyspan.h Thu Nov 29 21:45:52 2001 +++ linux-2.5/drivers/usb/serial/keyspan.h Tue Jan 8 00:44:24 2002 @@ -449,6 +449,7 @@ /* Structs for the devices, pre and post renumeration. */ static struct usb_serial_device_type keyspan_usa18x_pre_device = { + owner: THIS_MODULE, name: "Keyspan USA18X - (without firmware)", id_table: keyspan_usa18x_pre_ids, num_interrupt_in: NUM_DONT_CARE, @@ -459,6 +460,7 @@ }; static struct usb_serial_device_type keyspan_usa19_pre_device = { + owner: THIS_MODULE, name: "Keyspan USA19 - (without firmware)", id_table: keyspan_usa19_pre_ids, num_interrupt_in: NUM_DONT_CARE, @@ -470,6 +472,7 @@ static struct usb_serial_device_type keyspan_usa19w_pre_device = { + owner: THIS_MODULE, name: "Keyspan USA19W - (without firmware)", id_table: keyspan_usa19w_pre_ids, num_interrupt_in: NUM_DONT_CARE, @@ -481,6 +484,7 @@ static struct usb_serial_device_type keyspan_usa28_pre_device = { + owner: THIS_MODULE, name: "Keyspan USA28 - (without firmware)", id_table: keyspan_usa28_pre_ids, num_interrupt_in: NUM_DONT_CARE, @@ -491,6 +495,7 @@ }; static struct usb_serial_device_type keyspan_usa28x_pre_device = { + owner: THIS_MODULE, name: "Keyspan USA28X - (without firmware)", id_table: keyspan_usa28x_pre_ids, num_interrupt_in: NUM_DONT_CARE, @@ -501,6 +506,7 @@ }; static struct usb_serial_device_type keyspan_usa28xa_pre_device = { + owner: THIS_MODULE, name: "Keyspan USA28XA - (without firmware)", id_table: keyspan_usa28xa_pre_ids, num_interrupt_in: NUM_DONT_CARE, @@ -511,6 +517,7 @@ }; static struct usb_serial_device_type keyspan_usa28xb_pre_device = { + owner: THIS_MODULE, name: "Keyspan USA28XB - (without firmware)", id_table: keyspan_usa28xb_pre_ids, num_interrupt_in: NUM_DONT_CARE, @@ -521,6 +528,7 @@ }; static struct usb_serial_device_type keyspan_usa49w_pre_device = { + owner: THIS_MODULE, name: "Keyspan USA49W - (without firmware)", id_table: keyspan_usa49w_pre_ids, num_interrupt_in: NUM_DONT_CARE, @@ -531,6 +539,7 @@ }; static struct usb_serial_device_type keyspan_usa18x_device = { + owner: THIS_MODULE, name: "Keyspan USA18X", id_table: keyspan_usa18x_ids, num_interrupt_in: NUM_DONT_CARE, @@ -554,6 +563,7 @@ }; static struct usb_serial_device_type keyspan_usa19_device = { + owner: THIS_MODULE, name: "Keyspan USA19", id_table: keyspan_usa19_ids, num_interrupt_in: NUM_DONT_CARE, @@ -578,6 +588,7 @@ static struct usb_serial_device_type keyspan_usa19w_device = { + owner: THIS_MODULE, name: "Keyspan USA19W", id_table: keyspan_usa19w_ids, num_interrupt_in: NUM_DONT_CARE, @@ -602,6 +613,7 @@ static struct usb_serial_device_type keyspan_usa28_device = { + owner: THIS_MODULE, name: "Keyspan USA28", id_table: keyspan_usa28_ids, num_interrupt_in: NUM_DONT_CARE, @@ -617,6 +629,7 @@ static struct usb_serial_device_type keyspan_usa28x_device = { + owner: THIS_MODULE, name: "Keyspan USA28X/XB", id_table: keyspan_usa28x_ids, num_interrupt_in: NUM_DONT_CARE, @@ -641,6 +654,7 @@ }; static struct usb_serial_device_type keyspan_usa28xa_device = { + owner: THIS_MODULE, name: "Keyspan USA28XA", id_table: keyspan_usa28xa_ids, num_interrupt_in: NUM_DONT_CARE, @@ -665,6 +679,7 @@ }; static struct usb_serial_device_type keyspan_usa49w_device = { + owner: THIS_MODULE, name: "Keyspan USA49W", id_table: keyspan_usa49w_ids, num_interrupt_in: NUM_DONT_CARE, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/keyspan_pda.c linux-2.5/drivers/usb/serial/keyspan_pda.c --- linux-2.5.1/drivers/usb/serial/keyspan_pda.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/keyspan_pda.c Tue Jan 8 00:44:24 2002 @@ -193,7 +193,6 @@ /* wake up other tty processes */ wake_up_interruptible( &tty->write_wait ); /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */ - MOD_DEC_USE_COUNT; } static void keyspan_pda_request_unthrottle( struct usb_serial *serial ) @@ -212,7 +211,6 @@ NULL, 0, 2*HZ); - MOD_DEC_USE_COUNT; } @@ -261,9 +259,7 @@ tty = serial->port[0].tty; priv->tx_throttled = 0; /* queue up a wakeup at scheduler time */ - MOD_INC_USE_COUNT; - if (schedule_task(&priv->wakeup_task) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&priv->wakeup_task); break; default: break; @@ -602,9 +598,7 @@ if (request_unthrottle) { priv->tx_throttled = 1; /* block writers */ - MOD_INC_USE_COUNT; - if (schedule_task(&priv->unthrottle_task) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&priv->unthrottle_task); } rc = count; @@ -631,9 +625,7 @@ } /* queue up a wakeup at scheduler time */ - MOD_INC_USE_COUNT; - if (schedule_task(&priv->wakeup_task) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&priv->wakeup_task); } @@ -672,7 +664,6 @@ down (&port->sem); - MOD_INC_USE_COUNT; ++port->open_count; if (port->open_count == 1) { @@ -721,7 +712,6 @@ return rc; error: --port->open_count; - MOD_DEC_USE_COUNT; up (&port->sem); return rc; } @@ -749,7 +739,6 @@ } up (&port->sem); - MOD_DEC_USE_COUNT; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/kl5kusb105.c linux-2.5/drivers/usb/serial/kl5kusb105.c --- linux-2.5.1/drivers/usb/serial/kl5kusb105.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/serial/kl5kusb105.c Tue Jan 1 23:42:42 2002 @@ -0,0 +1,1086 @@ +/* + * KLSI KL5KUSB105 chip RS232 converter driver + * + * Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.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. + * + * All information about the device was acquired using SniffUSB ans snoopUSB + * on Windows98. + * It was written out of frustration with the PalmConnect USB Serial adapter + * sold by Palm Inc. + * Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided + * information that was not already available. + * + * It seems that KLSI bought some silicon-design information from ScanLogic, + * whose SL11R processor is at the core of the KL5KUSB chipset from KLSI. + * KLSI has firmware available for their devices; it is probable that the + * firmware differs from that used by KLSI in their products. If you have an + * original KLSI device and can provide some information on it, I would be + * most interested in adding support for it here. If you have any information + * on the protocol used (or find errors in my reverse-engineered stuff), please + * let me know. + * + * The code was only tested with a PalmConnect USB adapter; if you + * are adventurous, try it with any KLSI-based device and let me know how it + * breaks so that I can fix it! + */ + +/* TODO: + * check modem line signals + * implement handshaking or decide that we do not support it + */ + +/* History: + * 0.3a - implemented pools of write URBs + * 0.3 - alpha version for public testing + * 0.2 - TIOCMGET works, so autopilot(1) can be used! + * 0.1 - can be used to to pilot-xfer -p /dev/ttyUSB0 -l + * + * The driver skeleton is mainly based on mct_u232.c and various other + * pieces of code shamelessly copied from the drivers/usb/serial/ directory. + */ + + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/module.h> +#include <linux/usb.h> + +#ifdef CONFIG_USB_SERIAL_DEBUG + static int debug = 1; +#else + static int debug; +#endif + +#include "usb-serial.h" +#include "kl5kusb105.h" + + +/* + * Version Information + */ +#define DRIVER_VERSION "v0.3a" +#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>" +#define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver" + + +/* + * Function prototypes + */ +static int klsi_105_startup (struct usb_serial *serial); +static void klsi_105_shutdown (struct usb_serial *serial); +static int klsi_105_open (struct usb_serial_port *port, + struct file *filp); +static void klsi_105_close (struct usb_serial_port *port, + struct file *filp); +static int klsi_105_write (struct usb_serial_port *port, + int from_user, + const unsigned char *buf, + int count); +static void klsi_105_write_bulk_callback (struct urb *urb); +static int klsi_105_chars_in_buffer (struct usb_serial_port *port); +static int klsi_105_write_room (struct usb_serial_port *port); + +static void klsi_105_read_bulk_callback (struct urb *urb); +static void klsi_105_set_termios (struct usb_serial_port *port, + struct termios * old); +static int klsi_105_ioctl (struct usb_serial_port *port, + struct file * file, + unsigned int cmd, + unsigned long arg); +static void klsi_105_throttle (struct usb_serial_port *port); +static void klsi_105_unthrottle (struct usb_serial_port *port); +/* +static void klsi_105_break_ctl (struct usb_serial_port *port, + int break_state ); + */ + +/* + * All of the device info needed for the KLSI converters. + */ +static __devinitdata struct usb_device_id id_table [] = { + { USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) }, + { USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, id_table); + + +static struct usb_serial_device_type kl5kusb105d_device = { + owner: THIS_MODULE, + name: "KL5KUSB105D / PalmConnect", + id_table: id_table, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: klsi_105_open, + close: klsi_105_close, + write: klsi_105_write, + write_bulk_callback: klsi_105_write_bulk_callback, + chars_in_buffer: klsi_105_chars_in_buffer, + write_room: klsi_105_write_room, + read_bulk_callback: klsi_105_read_bulk_callback, + ioctl: klsi_105_ioctl, + set_termios: klsi_105_set_termios, + /*break_ctl: klsi_105_break_ctl,*/ + startup: klsi_105_startup, + shutdown: klsi_105_shutdown, + throttle: klsi_105_throttle, + unthrottle: klsi_105_unthrottle, +}; + +struct klsi_105_port_settings { + __u8 pktlen; /* always 5, it seems */ + __u8 baudrate; + __u8 databits; + __u8 unknown1; + __u8 unknown2; +} __attribute__ ((packed)); + +/* we implement a pool of NUM_URBS urbs per usb_serial */ +#define NUM_URBS 1 +#define URB_TRANSFER_BUFFER_SIZE 64 +struct klsi_105_private { + struct klsi_105_port_settings cfg; + struct termios termios; + unsigned long line_state; /* modem line settings */ + /* write pool */ + struct urb * write_urb_pool[NUM_URBS]; + spinlock_t write_urb_pool_lock; + unsigned long bytes_in; + unsigned long bytes_out; +}; + + +/* + * Handle vendor specific USB requests + */ + + +#define KLSI_TIMEOUT (HZ * 5 ) /* default urb timeout */ + +static int klsi_105_chg_port_settings(struct usb_serial *serial, + struct klsi_105_port_settings *settings) +{ + int rc; + + rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + KL5KUSB105A_SIO_SET_DATA, + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE, + 0, /* value */ + 0, /* index */ + settings, + sizeof(struct klsi_105_port_settings), + KLSI_TIMEOUT); + if (rc < 0) + err("Change port settings failed (error = %d)", rc); + info(__FUNCTION__ " - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d", + settings->pktlen, + settings->baudrate, settings->databits, + settings->unknown1, settings->unknown2); + return rc; +} /* klsi_105_chg_port_settings */ + +/* translate a 16-bit status value from the device to linux's TIO bits */ +static unsigned long klsi_105_status2linestate(const __u16 status) +{ + unsigned long res = 0; + + res = ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0) + | ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0) + ; + + return res; +} +/* + * Read line control via vendor command and return result through + * *line_state_p + */ +/* It seems that the status buffer has always only 2 bytes length */ +#define KLSI_STATUSBUF_LEN 2 +static int klsi_105_get_line_state(struct usb_serial *serial, + unsigned long *line_state_p) +{ + int rc; + __u8 status_buf[KLSI_STATUSBUF_LEN] = { -1,-1}; + __u16 status; + + info(__FUNCTION__ " - sending SIO Poll request"); + rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + KL5KUSB105A_SIO_POLL, + USB_TYPE_VENDOR | USB_DIR_IN, + 0, /* value */ + 0, /* index */ + status_buf, KLSI_STATUSBUF_LEN, + 10*HZ + ); + if (rc < 0) + err("Reading line status failed (error = %d)", rc); + else { + status = status_buf[0] + (status_buf[1]<<8); + + info(__FUNCTION__ " - read status %x %x", + status_buf[0], status_buf[1]); + + *line_state_p = klsi_105_status2linestate(status); + } + + return rc; +} + + +/* + * Driver's tty interface functions + */ + +static int klsi_105_startup (struct usb_serial *serial) +{ + struct klsi_105_private *priv; + int i; + + /* check if we support the product id (see keyspan.c) + * FIXME + */ + + /* allocate the private data structure */ + for (i=0; i<serial->num_ports; i++) { + serial->port[i].private = kmalloc(sizeof(struct klsi_105_private), + GFP_KERNEL); + if (!serial->port[i].private) { + dbg(__FUNCTION__ "kmalloc for klsi_105_private failed."); + return (-1); /* error */ + } + priv = (struct klsi_105_private *)serial->port[i].private; + /* set initial values for control structures */ + priv->cfg.pktlen = 5; + priv->cfg.baudrate = kl5kusb105a_sio_b9600; + priv->cfg.databits = kl5kusb105a_dtb_8; + priv->cfg.unknown1 = 0; + priv->cfg.unknown2 = 1; + + priv->line_state = 0; + + priv->bytes_in = 0; + priv->bytes_out = 0; + + spin_lock_init (&priv->write_urb_pool_lock); + for (i=0; i<NUM_URBS; i++) { + struct urb* urb = usb_alloc_urb(0); + + priv->write_urb_pool[i] = urb; + if (urb == NULL) { + err("No more urbs???"); + continue; + } + + urb->transfer_buffer = NULL; + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, + GFP_KERNEL); + if (!urb->transfer_buffer) { + err (__FUNCTION__ + " - out of memory for urb buffers."); + continue; + } + } + + /* priv->termios is left uninitalized until port opening */ + init_waitqueue_head(&serial->port[i].write_wait); + } + + return (0); +} /* klsi_105_startup */ + + +static void klsi_105_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + struct klsi_105_private *priv = + (struct klsi_105_private*) serial->port[i].private; + unsigned long flags; + while (serial->port[i].open_count > 0) { + klsi_105_close (&serial->port[i], NULL); + } + + if (priv) { + /* kill our write urb pool */ + int j; + struct urb **write_urbs = priv->write_urb_pool; + spin_lock_irqsave(&priv->write_urb_pool_lock,flags); + + for (j = 0; j < NUM_URBS; j++) { + if (write_urbs[j]) { + /* FIXME - uncomment the following + * usb_unlink_urb call when the host + * controllers get fixed to set + * urb->dev = NULL after the urb is + * finished. Otherwise this call + * oopses. */ + /* usb_unlink_urb(write_urbs[j]); */ + if (write_urbs[j]->transfer_buffer) + kfree(write_urbs[j]->transfer_buffer); + usb_free_urb (write_urbs[j]); + } + } + + spin_unlock_irqrestore (&priv->write_urb_pool_lock, + flags); + + kfree(serial->port[i].private); + } + } +} /* klsi_105_shutdown */ + +static int klsi_105_open (struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + struct klsi_105_private *priv = (struct klsi_105_private *)port->private; + int retval = 0; + + dbg(__FUNCTION__" port %d", port->number); + + down (&port->sem); + + ++port->open_count; + + if (port->open_count == 1) { + int rc; + int i; + unsigned long line_state; + + /* force low_latency on so that our tty_push actually forces + * the data through + * port->tty->low_latency = 1; */ + + /* Do a defined restart: + * Set up sane default baud rate and send the 'READ_ON' + * vendor command. + * FIXME: set modem line control (how?) + * Then read the modem line control and store values in + * priv->line_state. + */ + priv->cfg.pktlen = 5; + priv->cfg.baudrate = kl5kusb105a_sio_b9600; + priv->cfg.databits = kl5kusb105a_dtb_8; + priv->cfg.unknown1 = 0; + priv->cfg.unknown2 = 1; + klsi_105_chg_port_settings(serial, &(priv->cfg)); + + /* set up termios structure */ + priv->termios.c_iflag = port->tty->termios->c_iflag; + priv->termios.c_oflag = port->tty->termios->c_oflag; + priv->termios.c_cflag = port->tty->termios->c_cflag; + priv->termios.c_lflag = port->tty->termios->c_lflag; + for (i=0; i<NCCS; i++) + priv->termios.c_cc[i] = port->tty->termios->c_cc[i]; + + + /* READ_ON and urb submission */ + FILL_BULK_URB(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + klsi_105_read_bulk_callback, + port); + port->read_urb->transfer_flags |= USB_QUEUE_BULK; + + rc = usb_submit_urb(port->read_urb); + if (rc) { + err(__FUNCTION__ + " - failed submitting read urb, error %d", rc); + retval = rc; + goto exit; + } + + rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), + KL5KUSB105A_SIO_CONFIGURE, + USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE, + KL5KUSB105A_SIO_CONFIGURE_READ_ON, + 0, /* index */ + NULL, + 0, + KLSI_TIMEOUT); + if (rc < 0) { + err("Enabling read failed (error = %d)", rc); + retval = rc; + } else + dbg(__FUNCTION__ " - enabled reading"); + + rc = klsi_105_get_line_state(serial, &line_state); + if (rc >= 0) { + priv->line_state = line_state; + dbg(__FUNCTION__ + " - read line state 0x%lx", line_state); + retval = 0; + } else + retval = rc; + } + +exit: + up (&port->sem); + + return retval; +} /* klsi_105_open */ + + +static void klsi_105_close (struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial; + struct klsi_105_private *priv + = (struct klsi_105_private *)port->private; + dbg(__FUNCTION__" port %d", port->number); + + serial = get_usb_serial (port, __FUNCTION__); + + if(!serial) + return; + + down (&port->sem); + + --port->open_count; + + if (port->open_count <= 0) { + /* send READ_OFF */ + int rc = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + KL5KUSB105A_SIO_CONFIGURE, + USB_TYPE_VENDOR | USB_DIR_OUT, + KL5KUSB105A_SIO_CONFIGURE_READ_OFF, + 0, /* index */ + NULL, 0, + KLSI_TIMEOUT); + if (rc < 0) + err("Disabling read failed (error = %d)", rc); + + /* shutdown our bulk reads and writes */ + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->read_urb); + /* unlink our write pool */ + /* FIXME */ + /* wgg - do I need this? I think so. */ + usb_unlink_urb (port->interrupt_in_urb); + port->open_count = 0; + info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out); + } + + up (&port->sem); +} /* klsi_105_close */ + + +/* We need to write a complete 64-byte data block and encode the + * number actually sent in the first double-byte, LSB-order. That + * leaves at most 62 bytes of payload. + */ +#define KLSI_105_DATA_OFFSET 2 /* in the bulk urb data block */ + + +static int klsi_105_write (struct usb_serial_port *port, int from_user, + const unsigned char *buf, int count) +{ + struct usb_serial *serial = port->serial; + struct klsi_105_private *priv = + (struct klsi_105_private*) port->private; + int result, size; + int bytes_sent=0; + + dbg(__FUNCTION__ " - port %d", port->number); + + down (&port->sem); /* to lock against someone else trying to + take an URB we just selected from the pool */ + + while (count > 0) { + /* try to find a free urb (write 0 bytes if none) */ + struct urb *urb = NULL; + unsigned long flags; + int i; + /* since the pool is per-port we might not need the spin lock !? */ + spin_lock_irqsave (&priv->write_urb_pool_lock, flags); + for (i=0; i<NUM_URBS; i++) { + if (priv->write_urb_pool[i]->status != -EINPROGRESS) { + urb = priv->write_urb_pool[i]; + dbg(__FUNCTION__ " - using pool URB %d", i); + break; + } + } + spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); + + if (urb==NULL) { + dbg (__FUNCTION__ " - no more free urbs"); + goto exit; + } + + if (urb->transfer_buffer == NULL) { + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + if (urb->transfer_buffer == NULL) { + err(__FUNCTION__ " - no more kernel memory..."); + goto exit; + } + } + + size = min (count, port->bulk_out_size - KLSI_105_DATA_OFFSET); + size = min (size, URB_TRANSFER_BUFFER_SIZE - KLSI_105_DATA_OFFSET); + + if (from_user) { + if (copy_from_user(urb->transfer_buffer + + KLSI_105_DATA_OFFSET, buf, size)) { + up (&port->sem); + return -EFAULT; + } + } else { + memcpy (urb->transfer_buffer + KLSI_105_DATA_OFFSET, + buf, size); + } + + /* write payload size into transfer buffer */ + ((__u8 *)urb->transfer_buffer)[0] = (__u8) (size & 0xFF); + ((__u8 *)urb->transfer_buffer)[1] = (__u8) ((size & 0xFF00)>>8); + + /* set up our urb */ + FILL_BULK_URB(urb, serial->dev, + usb_sndbulkpipe(serial->dev, + port->bulk_out_endpointAddress), + urb->transfer_buffer, + URB_TRANSFER_BUFFER_SIZE, + klsi_105_write_bulk_callback, + port); + urb->transfer_flags |= USB_QUEUE_BULK; + + + /* send the data out the bulk port */ + result = usb_submit_urb(urb); + if (result) { + err(__FUNCTION__ + " - failed submitting write urb, error %d", result); + goto exit; + } + buf += size; + bytes_sent += size; + count -= size; + } +exit: + up (&port->sem); + priv->bytes_out+=bytes_sent; + + return bytes_sent; /* that's how much we wrote */ +} /* klsi_105_write */ + +static void klsi_105_write_bulk_callback ( struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial = port->serial; + + dbg(__FUNCTION__ " - port %d", port->number); + + if (!serial) { + dbg(__FUNCTION__ " - bad serial pointer, exiting"); + return; + } + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero write bulk status received: %d", + urb->status); + return; + } + + /* from generic_write_bulk_callback */ + queue_task(&port->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return; +} /* klsi_105_write_bulk_completion_callback */ + + +/* return number of characters currently in the writing process */ +static int klsi_105_chars_in_buffer (struct usb_serial_port *port) +{ + int chars = 0; + int i; + unsigned long flags; + struct klsi_105_private *priv = + (struct klsi_105_private*) port->private; + + spin_lock_irqsave (&priv->write_urb_pool_lock, flags); + + for (i = 0; i < NUM_URBS; ++i) { + if (priv->write_urb_pool[i]->status == -EINPROGRESS) { + chars += URB_TRANSFER_BUFFER_SIZE; + } + } + + spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); + + dbg (__FUNCTION__ " - returns %d", chars); + return (chars); +} + +static int klsi_105_write_room (struct usb_serial_port *port) +{ + unsigned long flags; + int i; + int room = 0; + struct klsi_105_private *priv = + (struct klsi_105_private*) port->private; + + spin_lock_irqsave (&priv->write_urb_pool_lock, flags); + for (i = 0; i < NUM_URBS; ++i) { + if (priv->write_urb_pool[i]->status != -EINPROGRESS) { + room += URB_TRANSFER_BUFFER_SIZE; + } + } + + spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags); + + dbg(__FUNCTION__ " - returns %d", room); + return (room); +} + + + +static void klsi_105_read_bulk_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial = port->serial; + struct klsi_105_private *priv = + (struct klsi_105_private*) port->private; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + int rc; + + dbg(__FUNCTION__ " - port %d", port->number); + + /* The urb might have been killed. */ + if (urb->status) { + dbg(__FUNCTION__ " - nonzero read bulk status received: %d", + urb->status); + return; + } + if (!serial) { + dbg(__FUNCTION__ " - bad serial pointer, exiting"); + return; + } + + /* The data received is again preceded by a length double-byte in LSB- + * first order (see klsi_105_write() ) + */ + if (urb->actual_length == 0) { + /* empty urbs seem to happen, we ignore them */ + /* dbg(__FUNCTION__ " - emtpy URB"); */ + ; + } else if (urb->actual_length <= 2) { + dbg(__FUNCTION__ " - size %d URB not understood", + urb->actual_length); + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + } else { + int i; + int bytes_sent = ((__u8 *) data)[0] + + ((unsigned int) ((__u8 *) data)[1] << 8); + tty = port->tty; + /* we should immediately resubmit the URB, before attempting + * to pass the data on to the tty layer. But that needs locking + * against re-entry an then mixed-up data because of + * intermixed tty_flip_buffer_push()s + * FIXME + */ + usb_serial_debug_data (__FILE__, __FUNCTION__, + urb->actual_length, data); + + if (bytes_sent + 2 > urb->actual_length) { + dbg(__FUNCTION__ + " - trying to read more data than available" + " (%d vs. %d)", + bytes_sent+2, urb->actual_length); + /* cap at implied limit */ + bytes_sent = urb->actual_length - 2; + } + + for (i = 2; i < 2+bytes_sent; i++) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, + * we drop them. */ + if(tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + /* this doesn't actually push the data through unless + * tty->low_latency is set */ + tty_insert_flip_char(tty, ((__u8*) data)[i], 0); + } + tty_flip_buffer_push(tty); + priv->bytes_in += bytes_sent; + } + /* Continue trying to always read */ + FILL_BULK_URB(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + klsi_105_read_bulk_callback, + port); + rc = usb_submit_urb(port->read_urb); + if (rc) + err(__FUNCTION__ + " - failed resubmitting read urb, error %d", rc); +} /* klsi_105_read_bulk_callback */ + + +static void klsi_105_set_termios (struct usb_serial_port *port, + struct termios *old_termios) +{ + struct usb_serial *serial = port->serial; + struct klsi_105_private *priv = (struct klsi_105_private *)port->private; + unsigned int iflag = port->tty->termios->c_iflag; + unsigned int old_iflag = old_termios->c_iflag; + unsigned int cflag = port->tty->termios->c_cflag; + unsigned int old_cflag = old_termios->c_cflag; + + /* + * Update baud rate + */ + if( (cflag & CBAUD) != (old_cflag & CBAUD) ) { + /* reassert DTR and (maybe) RTS on transition from B0 */ + if( (old_cflag & CBAUD) == B0 ) { + dbg(__FUNCTION__ ": baud was B0"); +#if 0 + priv->control_state |= TIOCM_DTR; + /* don't set RTS if using hardware flow control */ + if (!(old_cflag & CRTSCTS)) { + priv->control_state |= TIOCM_RTS; + } + mct_u232_set_modem_ctrl(serial, priv->control_state); +#endif + } + + switch(cflag & CBAUD) { + case B0: /* handled below */ + break; + case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200; + break; + case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400; + break; + case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800; + break; + case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600; + break; + case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200; + break; + case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400; + break; + case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600; + break; + case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200; + break; + default: + err("KLSI USB->Serial converter:" + " unsupported baudrate request, using default" + " of 9600"); + priv->cfg.baudrate = kl5kusb105a_sio_b9600; + break; + } + if ((cflag & CBAUD) == B0 ) { + dbg(__FUNCTION__ ": baud is B0"); + /* Drop RTS and DTR */ + /* maybe this should be simulated by sending read + * disable and read enable messages? + */ + ; +#if 0 + priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); + mct_u232_set_modem_ctrl(serial, priv->control_state); +#endif + } + } + + if ((cflag & CSIZE) != (old_cflag & CSIZE)) { + /* set the number of data bits */ + switch (cflag & CSIZE) { + case CS5: + dbg(__FUNCTION__ " - 5 bits/byte not supported"); + return ; + case CS6: + dbg(__FUNCTION__ " - 6 bits/byte not supported"); + return ; + case CS7: + priv->cfg.databits = kl5kusb105a_dtb_7; + break; + case CS8: + priv->cfg.databits = kl5kusb105a_dtb_8; + break; + default: + err("CSIZE was not CS5-CS8, using default of 8"); + priv->cfg.databits = kl5kusb105a_dtb_8; + break; + } + } + + /* + * Update line control register (LCR) + */ + if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD)) + || (cflag & CSTOPB) != (old_cflag & CSTOPB) ) { + +#if 0 + priv->last_lcr = 0; + + /* set the parity */ + if (cflag & PARENB) + priv->last_lcr |= (cflag & PARODD) ? + MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN; + else + priv->last_lcr |= MCT_U232_PARITY_NONE; + + /* set the number of stop bits */ + priv->last_lcr |= (cflag & CSTOPB) ? + MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; + + mct_u232_set_line_ctrl(serial, priv->last_lcr); +#endif + ; + } + + /* + * Set flow control: well, I do not really now how to handle DTR/RTS. + * Just do what we have seen with SniffUSB on Win98. + */ + if( (iflag & IXOFF) != (old_iflag & IXOFF) + || (iflag & IXON) != (old_iflag & IXON) + || (cflag & CRTSCTS) != (old_cflag & CRTSCTS) ) { + + /* Drop DTR/RTS if no flow control otherwise assert */ +#if 0 + if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) ) + priv->control_state |= TIOCM_DTR | TIOCM_RTS; + else + priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); + mct_u232_set_modem_ctrl(serial, priv->control_state); +#endif + ; + } + + /* now commit changes to device */ + klsi_105_chg_port_settings(serial, &(priv->cfg)); +} /* klsi_105_set_termios */ + + +#if 0 +static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state ) +{ + struct usb_serial *serial = port->serial; + struct mct_u232_private *priv = (struct mct_u232_private *)port->private; + unsigned char lcr = priv->last_lcr; + + dbg (__FUNCTION__ "state=%d", break_state); + + if (break_state) + lcr |= MCT_U232_SET_BREAK; + + mct_u232_set_line_ctrl(serial, lcr); +} /* mct_u232_break_ctl */ +#endif + +static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct usb_serial *serial = port->serial; + struct klsi_105_private *priv = (struct klsi_105_private *)port->private; + int mask; + + dbg (__FUNCTION__ "cmd=0x%x", cmd); + + /* Based on code from acm.c and others */ + switch (cmd) { + case TIOCMGET: { + int rc; + unsigned long line_state; + dbg (__FUNCTION__ " - TIOCMGET request, just guessing"); + + rc = klsi_105_get_line_state(serial, &line_state); + if (rc < 0) { + err("Reading line control failed (error = %d)", rc); + /* better return value? EAGAIN? */ + return -ENOIOCTLCMD; + } else { + priv->line_state = line_state; + dbg(__FUNCTION__ " - read line state 0x%lx", line_state); + } + return put_user(priv->line_state, (unsigned long *) arg); + }; + + case TIOCMSET: /* Turns on and off the lines as specified by the mask */ + case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */ + case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */ + if (get_user(mask, (unsigned long *) arg)) + return -EFAULT; + + if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) { + /* RTS needs set */ + if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || + (cmd == TIOCMBIS) ) + dbg (__FUNCTION__ " - set RTS not handled"); + /* priv->control_state |= TIOCM_RTS; */ + else + dbg (__FUNCTION__ " - clear RTS not handled"); + /* priv->control_state &= ~TIOCM_RTS; */ + } + + if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) { + /* DTR needs set */ + if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || + (cmd == TIOCMBIS) ) + dbg (__FUNCTION__ " - set DTR not handled"); + /* priv->control_state |= TIOCM_DTR; */ + else + dbg (__FUNCTION__ " - clear DTR not handled"); + /* priv->control_state &= ~TIOCM_DTR; */ + } + /* + mct_u232_set_modem_ctrl(serial, priv->control_state); + */ + break; + + case TIOCMIWAIT: + /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ + /* TODO */ + dbg (__FUNCTION__ " - TIOCMIWAIT not handled"); + return -ENOIOCTLCMD; + + case TIOCGICOUNT: + /* return count of modemline transitions */ + /* TODO */ + dbg (__FUNCTION__ " - TIOCGICOUNT not handled"); + return -ENOIOCTLCMD; + case TCGETS: { + /* return current info to caller */ + int retval; + + dbg (__FUNCTION__ " - TCGETS data faked/incomplete"); + + retval = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct termios)); + + if (retval) + return(retval); + + kernel_termios_to_user_termios((struct termios *)arg, + &priv->termios); + return(0); + } + case TCSETS: { + /* set port termios to the one given by the user */ + int retval; + + dbg (__FUNCTION__ " - TCSETS not handled"); + + retval = verify_area(VERIFY_READ, (void *)arg, + sizeof(struct termios)); + + if (retval) + return(retval); + + user_termios_to_kernel_termios(&priv->termios, + (struct termios *)arg); + klsi_105_set_termios(port, &priv->termios); + return(0); + } + case TCSETSW: { + /* set port termios and try to wait for completion of last + * write operation */ + /* We guess here. If there are not too many write urbs + * outstanding, we lie. */ + /* what is the right way to wait here? schedule() ? */ + /* + while (klsi_105_chars_in_buffer(port) > (NUM_URBS / 4 ) * URB_TRANSFER_BUFFER_SIZE) + schedule(); + */ + return -ENOIOCTLCMD; + } + default: + dbg(__FUNCTION__ ": arg not supported - 0x%04x",cmd); + return(-ENOIOCTLCMD); + break; + } + return 0; +} /* klsi_105_ioctl */ + +static void klsi_105_throttle (struct usb_serial_port *port) +{ + + dbg(__FUNCTION__ " - port %d", port->number); + + down (&port->sem); + + usb_unlink_urb (port->read_urb); + + up (&port->sem); + + return; +} +static void klsi_105_unthrottle (struct usb_serial_port *port) +{ + int result; + + dbg(__FUNCTION__ " - port %d", port->number); + + down (&port->sem); + + port->read_urb->dev = port->serial->dev; + result = usb_submit_urb(port->read_urb); + if (result) + err(__FUNCTION__ " - failed submitting read urb, error %d", + result); + + up (&port->sem); + + return; +} + + + +static int __init klsi_105_init (void) +{ + usb_serial_register (&kl5kusb105d_device); + + info(DRIVER_DESC " " DRIVER_VERSION); + return 0; +} + + +static void __exit klsi_105_exit (void) +{ + usb_serial_deregister (&kl5kusb105d_device); +} + + +module_init (klsi_105_init); +module_exit (klsi_105_exit); + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE("GPL"); + + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "enable extensive debugging messages"); +/* FIXME: implement +MODULE_PARM(num_urbs, "i"); +MODULE_PARM_DESC(num_urbs, "number of URBs to use in write pool"); +*/ + +/* vim: set sts=8 ts=8 sw=8: */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/kl5kusb105.h linux-2.5/drivers/usb/serial/kl5kusb105.h --- linux-2.5.1/drivers/usb/serial/kl5kusb105.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/serial/kl5kusb105.h Tue Jan 1 23:42:42 2002 @@ -0,0 +1,69 @@ +/* + * Definitions for the KLSI KL5KUSB105 serial port adapter + */ + +/* vendor/product pairs that are known to contain this chipset */ +#define PALMCONNECT_VID 0x0830 +#define PALMCONNECT_PID 0x0080 + +#define KLSI_VID 0x05e9 +#define KLSI_KL5KUSB105D_PID 0x00c0 + +/* Vendor commands: */ + + +/* port table -- the chip supports up to 4 channels */ + +/* baud rates */ + +typedef enum { + kl5kusb105a_sio_b115200 = 0, + kl5kusb105a_sio_b57600 = 1, + kl5kusb105a_sio_b38400 = 2, + kl5kusb105a_sio_b19200 = 4, + kl5kusb105a_sio_b14400 = 5, + kl5kusb105a_sio_b9600 = 6, + kl5kusb105a_sio_b4800 = 8, /* unchecked */ + kl5kusb105a_sio_b2400 = 9, /* unchecked */ + kl5kusb105a_sio_b1200 = 0xa, /* unchecked */ + kl5kusb105a_sio_b600 = 0xb /* unchecked */ +} KL5KUSB105A_SIO_baudrate_t; + +/* data bits */ +#define kl5kusb105a_dtb_7 7 +#define kl5kusb105a_dtb_8 8 + + + +/* requests: */ +#define KL5KUSB105A_SIO_SET_DATA 1 +#define KL5KUSB105A_SIO_POLL 2 +#define KL5KUSB105A_SIO_CONFIGURE 3 +/* values used for request KL5KUSB105A_SIO_CONFIGURE */ +#define KL5KUSB105A_SIO_CONFIGURE_READ_ON 3 +#define KL5KUSB105A_SIO_CONFIGURE_READ_OFF 2 + +/* Interpretation of modem status lines */ +/* These need sorting out by individually connecting pins and checking + * results. FIXME! + * When data is being sent we see 0x30 in the lower byte; this must + * contain DSR and CTS ... + */ +#define KL5KUSB105A_DSR ((1<<4) | (1<<5)) +#define KL5KUSB105A_CTS ((1<<5) | (1<<4)) + +#define KL5KUSB105A_WANTS_TO_SEND 0x30 +//#define KL5KUSB105A_DTR /* Data Terminal Ready */ +//#define KL5KUSB105A_CTS /* Clear To Send */ +//#define KL5KUSB105A_CD /* Carrier Detect */ +//#define KL5KUSB105A_DSR /* Data Set Ready */ +//#define KL5KUSB105A_RxD /* Receive pin */ + +//#define KL5KUSB105A_LE +//#define KL5KUSB105A_RTS +//#define KL5KUSB105A_ST +//#define KL5KUSB105A_SR +//#define KL5KUSB105A_RI /* Ring Indicator */ + +/* vim: set ts=8 sts=8: */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/mct_u232.c linux-2.5/drivers/usb/serial/mct_u232.c --- linux-2.5.1/drivers/usb/serial/mct_u232.c Sun Dec 9 04:28:44 2001 +++ linux-2.5/drivers/usb/serial/mct_u232.c Tue Jan 8 00:44:24 2002 @@ -144,6 +144,7 @@ static struct usb_serial_device_type mct_u232_device = { + owner: THIS_MODULE, name: "Magic Control Technology USB-RS232", id_table: id_table_combined, num_interrupt_in: 2, @@ -343,7 +344,6 @@ down (&port->sem); ++port->open_count; - MOD_INC_USE_COUNT; if (port->open_count == 1) { /* Compensate for a hardware bug: although the Sitecom U232-P25 @@ -423,7 +423,6 @@ } up (&port->sem); - MOD_DEC_USE_COUNT; } /* mct_u232_close */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/omninet.c linux-2.5/drivers/usb/serial/omninet.c --- linux-2.5.1/drivers/usb/serial/omninet.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/omninet.c Tue Jan 8 00:44:24 2002 @@ -88,6 +88,7 @@ static struct usb_serial_device_type zyxel_omninet_device = { + owner: THIS_MODULE, name: "ZyXEL - omni.net lcd plus usb", id_table: id_table, num_interrupt_in: 1, @@ -158,7 +159,6 @@ down (&port->sem); - MOD_INC_USE_COUNT; ++port->open_count; if (port->open_count == 1) { @@ -167,7 +167,6 @@ err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data)); port->open_count = 0; up (&port->sem); - MOD_DEC_USE_COUNT; return -ENOMEM; } @@ -223,7 +222,6 @@ } up (&port->sem); - MOD_DEC_USE_COUNT; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/pl2303.c linux-2.5/drivers/usb/serial/pl2303.c --- linux-2.5.1/drivers/usb/serial/pl2303.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/pl2303.c Tue Jan 8 00:44:24 2002 @@ -116,6 +116,7 @@ /* All of the device info needed for the PL2303 SIO serial converter */ static struct usb_serial_device_type pl2303_device = { + owner: THIS_MODULE, name: "PL-2303", id_table: id_table, num_interrupt_in: NUM_DONT_CARE, @@ -369,7 +370,6 @@ down (&port->sem); ++port->open_count; - MOD_INC_USE_COUNT; if (port->open_count == 1) { #define FISH(a,b,c,d) \ @@ -480,7 +480,6 @@ } up (&port->sem); - MOD_DEC_USE_COUNT; } static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsigned int *value) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/usb-serial.h linux-2.5/drivers/usb/serial/usb-serial.h --- linux-2.5.1/drivers/usb/serial/usb-serial.h Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/usb-serial.h Sat Jan 5 16:38:08 2002 @@ -116,6 +116,7 @@ /** * usb_serial_device_type - a structure that defines a usb serial device + * @owner: pointer to the module that owns this device. * @name: pointer to a string that describes this device. This string used * in the syslog messages when a device is inserted or removed. * @id_table: pointer to a list of usb_device_id structures that define all @@ -138,6 +139,7 @@ * called, the generic serial function will be used instead. */ struct usb_serial_device_type { + struct module *owner; char *name; const struct usb_device_id *id_table; char num_interrupt_in; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/usbserial.c linux-2.5/drivers/usb/serial/usbserial.c --- linux-2.5.1/drivers/usb/serial/usbserial.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/usbserial.c Sat Jan 5 16:38:08 2002 @@ -397,16 +397,16 @@ static LIST_HEAD(usb_serial_driver_list); -static struct usb_serial *get_serial_by_minor (int minor) +static struct usb_serial *get_serial_by_minor (unsigned int minor) { return serial_table[minor]; } -static struct usb_serial *get_free_serial (int num_ports, int *minor) +static struct usb_serial *get_free_serial (int num_ports, unsigned int *minor) { struct usb_serial *serial = NULL; - int i, j; + unsigned int i, j; int good_spot; dbg(__FUNCTION__ " %d", num_ports); @@ -505,7 +505,8 @@ { struct usb_serial *serial; struct usb_serial_port *port; - int portNumber; + unsigned int portNumber; + int retval; dbg(__FUNCTION__); @@ -513,24 +514,30 @@ tty->driver_data = NULL; /* get the serial object associated with this tty pointer */ - serial = get_serial_by_minor (MINOR(tty->device)); + serial = get_serial_by_minor (minor(tty->device)); if (serial_paranoia_check (serial, __FUNCTION__)) { return -ENODEV; } /* set up our port structure making the tty driver remember our port object, and us it */ - portNumber = MINOR(tty->device) - serial->minor; + portNumber = minor(tty->device) - serial->minor; port = &serial->port[portNumber]; tty->driver_data = port; port->tty = tty; /* pass on to the driver specific version of this function if it is available */ if (serial->type->open) { - return (serial->type->open(port, filp)); + if (serial->type->owner) + __MOD_INC_USE_COUNT(serial->type->owner); + retval = serial->type->open(port, filp); + if (retval) + __MOD_DEC_USE_COUNT(serial->type->owner); } else { - return (generic_open(port, filp)); + retval = generic_open(port, filp); } + + return retval; } @@ -553,6 +560,8 @@ /* pass on to the driver specific version of this function if it is available */ if (serial->type->close) { serial->type->close(port, filp); + if (serial->type->owner) + __MOD_DEC_USE_COUNT(serial->type->owner); } else { generic_close(port, filp); } @@ -1059,6 +1068,7 @@ struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; struct usb_serial_device_type *type = NULL; struct list_head *tmp; + int retval; int found; int minor; int buffer_size; @@ -1180,9 +1190,13 @@ /* if this device type has a startup function, call it */ if (type->startup) { - if (type->startup (serial)) { + if (type->owner) + __MOD_INC_USE_COUNT(type->owner); + retval = type->startup (serial); + if (type->owner) + __MOD_DEC_USE_COUNT(type->owner); + if (retval) goto probe_error; - } } /* set up the endpoint information */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/visor.c linux-2.5/drivers/usb/serial/visor.c --- linux-2.5.1/drivers/usb/serial/visor.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/visor.c Sat Jan 5 16:38:08 2002 @@ -12,6 +12,10 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (12/18/2001) gkh + * Added better Clie support for 3.5 devices. Thanks to Geoffrey Levand + * for the patch. + * * (11/11/2001) gkh * Added support for the m125 devices, and added check to prevent oopses * for Clié devices that lie about the number of ports they have. @@ -127,7 +131,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.7" +#define DRIVER_VERSION "v1.8" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" #define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clié driver" @@ -145,6 +149,7 @@ static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios); static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); +static int clie_3_5_startup (struct usb_serial *serial); static __devinitdata struct usb_device_id combined_id_table [] = { @@ -177,6 +182,7 @@ /* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */ static struct usb_serial_device_type handspring_device = { + owner: THIS_MODULE, name: "Handspring Visor / Palm 4.0 / Clié 4.0", id_table: combined_id_table, num_interrupt_in: 0, @@ -200,6 +206,7 @@ /* device info for the Sony Clie OS version 3.5 */ static struct usb_serial_device_type clie_3_5_device = { + owner: THIS_MODULE, name: "Sony Clié 3.5", id_table: clie_id_3_5_table, num_interrupt_in: 0, @@ -210,6 +217,7 @@ close: visor_close, throttle: visor_throttle, unthrottle: visor_unthrottle, + startup: clie_3_5_startup, ioctl: visor_ioctl, set_termios: visor_set_termios, write: visor_write, @@ -249,7 +257,6 @@ down (&port->sem); ++port->open_count; - MOD_INC_USE_COUNT; if (port->open_count == 1) { bytes_in = 0; @@ -321,8 +328,6 @@ /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ - - MOD_DEC_USE_COUNT; } @@ -644,6 +649,46 @@ return 0; } +static int clie_3_5_startup (struct usb_serial *serial) +{ + int result; + u8 data; + + dbg(__FUNCTION__); + + /* + * Note that PEG-300 series devices expect the following two calls. + */ + + /* get the config number */ + result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), + USB_REQ_GET_CONFIGURATION, USB_DIR_IN, + 0, 0, &data, 1, HZ * 3); + if (result < 0) { + err(__FUNCTION__ ": get config number failed: %d", result); + return result; + } + if (result != 1) { + err(__FUNCTION__ ": get config number bad return length: %d", result); + return -EIO; + } + + /* get the interface number */ + result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), + USB_REQ_GET_INTERFACE, + USB_DIR_IN | USB_DT_DEVICE, + 0, 0, &data, 1, HZ * 3); + if (result < 0) { + err(__FUNCTION__ ": get interface number failed: %d", result); + return result; + } + if (result != 1) { + err(__FUNCTION__ ": get interface number bad return length: %d", result); + return -EIO; + } + + return 0; +} static void visor_shutdown (struct usb_serial *serial) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/serial/whiteheat.c linux-2.5/drivers/usb/serial/whiteheat.c --- linux-2.5.1/drivers/usb/serial/whiteheat.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/serial/whiteheat.c Tue Jan 8 00:44:24 2002 @@ -133,6 +133,7 @@ static void whiteheat_real_shutdown (struct usb_serial *serial); static struct usb_serial_device_type whiteheat_fake_device = { + owner: THIS_MODULE, name: "Connect Tech - WhiteHEAT - (prerenumeration)", id_table: id_table_prerenumeration, num_interrupt_in: NUM_DONT_CARE, @@ -143,6 +144,7 @@ }; static struct usb_serial_device_type whiteheat_device = { + owner: THIS_MODULE, name: "Connect Tech - WhiteHEAT", id_table: id_table_std, num_interrupt_in: NUM_DONT_CARE, @@ -307,7 +309,6 @@ down (&port->sem); ++port->open_count; - MOD_INC_USE_COUNT; if (port->open_count == 1) { /* set up some stuff for our command port */ @@ -359,7 +360,6 @@ error_exit: --port->open_count; - MOD_DEC_USE_COUNT; dbg(__FUNCTION__ " - error_exit"); up (&port->sem); @@ -391,7 +391,6 @@ usb_unlink_urb (port->read_urb); port->open_count = 0; } - MOD_DEC_USE_COUNT; up (&port->sem); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/storage/datafab.c linux-2.5/drivers/usb/storage/datafab.c --- linux-2.5.1/drivers/usb/storage/datafab.c Tue Oct 9 22:15:02 2001 +++ linux-2.5/drivers/usb/storage/datafab.c Sat Jan 5 16:38:08 2002 @@ -208,7 +208,7 @@ if (use_sg) { sg = (struct scatterlist *) dest; - buffer = kmalloc(len, GFP_KERNEL); + buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; ptr = buffer; @@ -333,7 +333,7 @@ if (use_sg) { sg = (struct scatterlist *) src; - buffer = kmalloc(len, GFP_KERNEL); + buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; ptr = buffer; @@ -665,7 +665,7 @@ }; if (!us->extra) { - us->extra = kmalloc(sizeof(struct datafab_info), GFP_KERNEL); + us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO); if (!us->extra) { US_DEBUGP("datafab_transport: Gah! Can't allocate storage for Datafab info struct!\n"); return USB_STOR_TRANSPORT_ERROR; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/storage/freecom.c linux-2.5/drivers/usb/storage/freecom.c --- linux-2.5.1/drivers/usb/storage/freecom.c Tue Nov 13 17:19:41 2001 +++ linux-2.5/drivers/usb/storage/freecom.c Sat Jan 5 16:38:08 2002 @@ -1,6 +1,6 @@ /* Driver for Freecom USB/IDE adaptor * - * $Id: freecom.c,v 1.19 2001/11/11 05:42:34 mdharm Exp $ + * $Id: freecom.c,v 1.21 2001/12/29 03:47:33 mdharm Exp $ * * Freecom v0.1: * @@ -206,9 +206,7 @@ return USB_STOR_TRANSPORT_GOOD; } -#endif -#if 0 /* Unused at this time */ /* Read a value from an ide register. */ static int freecom_ide_read (struct us_data *us, int reg, int *value) @@ -435,7 +433,7 @@ /* Get the status again */ fcb->Type = FCM_PACKET_STATUS; fcb->Timeout = 0; - memset (fcb->Atapi, 0, sizeof(fcb->Filler)); + memset (fcb->Atapi, 0, sizeof(fcb->Atapi)); memset (fcb->Filler, 0, sizeof (fcb->Filler)); /* Send it out. */ @@ -487,10 +485,19 @@ * and such will hang. */ US_DEBUGP("Device indicates that it has %d bytes available\n", le16_to_cpu (fst->Count)); + US_DEBUGP("SCSI requested %d\n", usb_stor_transfer_length(srb)); /* Find the length we desire to read. */ - length = usb_stor_transfer_length (srb); - US_DEBUGP("SCSI requested %d\n", length); + switch (srb->cmnd[0]) { + case INQUIRY: + case REQUEST_SENSE: /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */ + case MODE_SENSE: + case MODE_SENSE_10: + length = fst->Count; + break; + default: + length = usb_stor_transfer_length (srb); + } /* verify that this amount is legal */ if (length > srb->request_bufflen) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/storage/jumpshot.c linux-2.5/drivers/usb/storage/jumpshot.c --- linux-2.5.1/drivers/usb/storage/jumpshot.c Fri Sep 14 21:04:07 2001 +++ linux-2.5/drivers/usb/storage/jumpshot.c Sat Jan 5 16:38:08 2002 @@ -284,7 +284,7 @@ if (use_sg) { sg = (struct scatterlist *) dest; - buffer = kmalloc(len, GFP_KERNEL); + buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; ptr = buffer; @@ -399,7 +399,7 @@ if (use_sg) { sg = (struct scatterlist *) src; - buffer = kmalloc(len, GFP_KERNEL); + buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; ptr = buffer; @@ -665,7 +665,7 @@ if (!us->extra) { - us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_KERNEL); + us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO); if (!us->extra) { US_DEBUGP("jumpshot_transport: Gah! Can't allocate storage for jumpshot info struct!\n"); return USB_STOR_TRANSPORT_ERROR; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/storage/sddr09.c linux-2.5/drivers/usb/storage/sddr09.c --- linux-2.5.1/drivers/usb/storage/sddr09.c Fri Nov 9 22:37:14 2001 +++ linux-2.5/drivers/usb/storage/sddr09.c Sat Jan 5 16:38:08 2002 @@ -1,6 +1,6 @@ /* Driver for SanDisk SDDR-09 SmartMedia reader * - * $Id: sddr09.c,v 1.21 2001/11/06 03:18:36 mdharm Exp $ + * $Id: sddr09.c,v 1.22 2001/12/08 23:32:48 mdharm Exp $ * * SDDR09 driver v0.1: * @@ -79,7 +79,7 @@ // copy the data into the buffer. /* if (xfer_len > 0) { - buffer = kmalloc(xfer_len, GFP_KERNEL); + buffer = kmalloc(xfer_len, GFP_NOIO); if (!(command[0] & USB_DIR_IN)) memcpy(buffer, xfer_data, xfer_len); } @@ -303,7 +303,7 @@ if (use_sg) { sg = (struct scatterlist *)content; - buffer = kmalloc(len, GFP_KERNEL); + buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; ptr = buffer; @@ -630,17 +630,17 @@ alloc_blocks = (alloc_len + (1<<17) - 1) >> 17; sg = kmalloc(alloc_blocks*sizeof(struct scatterlist), - GFP_KERNEL); + GFP_NOIO); if (sg == NULL) return 0; for (i=0; i<alloc_blocks; i++) { if (i<alloc_blocks-1) { - sg[i].address = kmalloc( (1<<17), GFP_KERNEL ); + sg[i].address = kmalloc( (1<<17), GFP_NOIO ); sg[i].page = NULL; sg[i].length = (1<<17); } else { - sg[i].address = kmalloc(alloc_len, GFP_KERNEL); + sg[i].address = kmalloc(alloc_len, GFP_NOIO); sg[i].page = NULL; sg[i].length = alloc_len; } @@ -672,8 +672,8 @@ kfree(info->lba_to_pba); if (info->pba_to_lba) kfree(info->pba_to_lba); - info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_KERNEL); - info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_KERNEL); + info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO); + info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { if (info->lba_to_pba != NULL) @@ -842,7 +842,7 @@ if (!us->extra) { us->extra = kmalloc( - sizeof(struct sddr09_card_info), GFP_KERNEL); + sizeof(struct sddr09_card_info), GFP_NOIO); if (!us->extra) return USB_STOR_TRANSPORT_ERROR; memset(us->extra, 0, sizeof(struct sddr09_card_info)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/storage/shuttle_usbat.c linux-2.5/drivers/usb/storage/shuttle_usbat.c --- linux-2.5.1/drivers/usb/storage/shuttle_usbat.c Mon Jul 30 04:11:50 2001 +++ linux-2.5/drivers/usb/storage/shuttle_usbat.c Sat Jan 5 16:38:08 2002 @@ -1,6 +1,6 @@ /* Driver for SCM Microsystems USB-ATAPI cable * - * $Id: shuttle_usbat.c,v 1.14 2001/03/28 01:02:06 groovyjava Exp $ + * $Id: shuttle_usbat.c,v 1.15 2001/12/08 23:32:48 mdharm Exp $ * * Current development and maintenance by: * (c) 2000, 2001 Robert Baruch (autophile@starband.net) @@ -681,7 +681,7 @@ len = (65535/srb->transfersize) * srb->transfersize; US_DEBUGP("Max read is %d bytes\n", len); - buffer = kmalloc(len, GFP_KERNEL); + buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) // bloody hell! return USB_STOR_TRANSPORT_FAILED; sector = short_pack(data[7+3], data[7+2]); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/storage/transport.c linux-2.5/drivers/usb/storage/transport.c --- linux-2.5.1/drivers/usb/storage/transport.c Fri Nov 9 22:37:14 2001 +++ linux-2.5/drivers/usb/storage/transport.c Tue Jan 8 00:44:24 2002 @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.41 2001/10/15 07:02:32 mdharm Exp $ + * $Id: transport.c,v 1.42 2001/12/08 23:32:48 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -385,19 +385,19 @@ { struct completion urb_done; int status; - devrequest *dr; + struct usb_ctrlrequest *dr; /* allocate the device request structure */ - dr = kmalloc(sizeof(devrequest), GFP_KERNEL); + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); if (!dr) return -ENOMEM; /* fill in the structure */ - dr->requesttype = requesttype; - dr->request = request; - dr->value = cpu_to_le16(value); - dr->index = cpu_to_le16(index); - dr->length = cpu_to_le16(size); + dr->bRequestType = requesttype; + dr->bRequest = request; + dr->wValue = cpu_to_le16(value); + dr->wIndex = cpu_to_le16(index); + dr->wLength = cpu_to_le16(size); /* set up data structures for the wakeup system */ init_completion(&urb_done); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/storage/unusual_devs.h linux-2.5/drivers/usb/storage/unusual_devs.h --- linux-2.5.1/drivers/usb/storage/unusual_devs.h Sun Dec 16 23:46:59 2001 +++ linux-2.5/drivers/usb/storage/unusual_devs.h Sat Jan 5 16:38:08 2002 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Ununsual Devices File * - * $Id: unusual_devs.h,v 1.20 2001/09/02 05:12:57 mdharm Exp $ + * $Id: unusual_devs.h,v 1.24 2001/12/29 03:12:45 mdharm Exp $ * * Current development and maintenance by: * (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -58,6 +58,11 @@ "HP", "CD-Writer+ 8200e", US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), + +UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001, + "HP", + "CD-Writer+ CD-4e", + US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), #endif #ifdef CONFIG_USB_STORAGE_DPCM @@ -86,6 +91,25 @@ "FinePix 1400Zoom", US_SC_8070, US_PR_CBI, NULL, US_FL_FIX_INQUIRY), +/* Reported by Peter Wächtler <pwaechtler@loewe-komp.de> + * The device needs the flags only. + */ +UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074, + "ScanLogic", + "SL11R-IDE", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY), + +/* Reported by Kriston Fincher <kriston@airmail.net> + * Patch submitted by Sean Millichamp <sean@bruenor.org> + * This is to support the Panasonic PalmCam PV-SD4090 + * This entry is needed because the device reports Sub=ff + */ +UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200, + "Panasonic", + "LS-120 Camera", + US_SC_UFI, US_PR_CBI, NULL, 0), + /* Most of the following entries were developed with the help of * Shuttle/SCM directly. */ @@ -161,14 +185,24 @@ US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG ), +/* Iomega Clik! Drive + * Reported by David Chatenay <dchatenay@hotmail.com> + * The reason this is needed is not fully known. + */ +UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100, + "Iomega", + "USB Clik! 40", + US_SC_8070, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY | US_FL_START_STOP ), + /* This entry is needed because the device reports Sub=ff */ -UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0322, +UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0422, "Sony", "DSC-S30/S70/S75/505V/F505", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), -/* Reported by win@geeks.nl */ +/* Reported by wim@geeks.nl */ UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100, "Sony", "Memorystick NW-MS7", @@ -194,6 +228,13 @@ US_SC_UFI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP ), +/* Submitted by Nathan Babb <nathan@lexi.com> */ +UNUSUAL_DEV( 0x054c, 0x006d, 0x0000, 0x9999, + "Sony", + "PEG Mass Storage", + US_SC_8070, US_PR_CBI, NULL, + US_FL_FIX_INQUIRY ), + UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data", "Flashbuster-U", @@ -264,6 +305,14 @@ US_FL_SINGLE_LUN | US_FL_START_STOP ), #endif +/* Submitted by f.brugmans@hccnet.nl + * Needed for START_STOP flag */ +UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001, + "Minolta", + "Dimage S304", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_START_STOP ), + UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara", "FlashGate SmartMedia", @@ -307,7 +356,7 @@ US_SC_QIC, US_PR_FREECOM, freecom_init, 0), #endif -UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0100, +UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133, "Microtech", "USB-SCSI-DB25", US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, @@ -374,16 +423,23 @@ "Simple Tech/Datafab CF+SM Reader", US_SC_SCSI, US_PR_DATAFAB, NULL, US_FL_MODE_XLATE | US_FL_START_STOP ), + +/* Submitted by Olaf Hering <olh@suse.de> */ +UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff, + "Datafab Systems, Inc.", + "USB to CF + SM Combo (LC1)", + US_SC_SCSI, US_PR_DATAFAB, NULL, + US_FL_MODE_XLATE | US_FL_START_STOP ), #endif -/* Casio QV 2x00/3x00/8000 digital still cameras are not conformant +/* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant * to the USB storage specification in two ways: * - They tell us they are using transport protocol CBI. In reality they * are using transport protocol CB. * - They don't like the INQUIRY command. So we must handle this command * of the SCSI layer ourselves. */ -UNUSUAL_DEV( 0x07cf, 0x1001, 0x9009, 0x9009, +UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009, "Casio", "QV DigitalCamera", US_SC_8070, US_PR_CB, NULL, @@ -402,3 +458,12 @@ US_SC_ISD200, US_PR_BULK, isd200_Initialization, 0 ), #endif + +/* Reported by Dan Pilone <pilone@slac.com> + * The device needs the flags only. + */ +UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999, + "CCYU TECHNOLOGY", + "EasyDisk Portable Device", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_MODE_XLATE | US_FL_START_STOP), diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/storage/usb.c linux-2.5/drivers/usb/storage/usb.c --- linux-2.5.1/drivers/usb/storage/usb.c Sun Nov 11 18:01:32 2001 +++ linux-2.5/drivers/usb/storage/usb.c Mon Dec 31 01:39:36 2001 @@ -1002,7 +1002,7 @@ /* now register - our detect function will be called */ ss->htmplt.module = THIS_MODULE; - scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt)); + scsi_register_host(&ss->htmplt); /* lock access to the data structures */ down(&us_list_semaphore); @@ -1107,8 +1107,8 @@ * interface */ for (next = us_list; next; next = next->next) { - US_DEBUGP("-- calling scsi_unregister_module()\n"); - scsi_unregister_module(MODULE_SCSI_HA, &(next->htmplt)); + US_DEBUGP("-- calling scsi_unregister_host()\n"); + scsi_unregister_host(&next->htmplt); } /* While there are still structures, free them. Note that we are diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/stv680.c linux-2.5/drivers/usb/stv680.c --- linux-2.5.1/drivers/usb/stv680.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/stv680.c Thu Jan 3 23:04:40 2002 @@ -0,0 +1,1633 @@ +/* + * STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net) + * + * Thanks to STMicroelectronics for information on the usb commands, and + * to Steve Miller at STM for his help and encouragement while I was + * writing this driver. + * + * This driver is based heavily on the + * Endpoints (formerly known as AOX) se401 USB Camera Driver + * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) + * + * Still somewhat based on the Linux ov511 driver. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the 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. + * + * History: + * ver 0.1 October, 2001. Initial attempt. + * + * ver 0.2 November, 2001. Fixed asbility to resize, added brightness + * function, made more stable (?) + * + * ver 0.21 Nov, 2001. Added gamma correction and white balance, + * due to Alexander Schwartz. Still trying to + * improve stablility. Moved stuff into stv680.h + * + * ver 0.22 Nov, 2001. Added sharpen function (by Michael Sweet, + * mike@easysw.com) from GIMP, also used in pencam. + * Simple, fast, good integer math routine. + * + * ver 0.23 Dec, 2001 (gkh) + * Took out sharpen function, ran code through + * Lindent, and did other minor tweaks to get + * things to work properly with 2.5.1 + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include <linux/pagemap.h> +#include <linux/wrapper.h> +#include <linux/smp_lock.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/videodev.h> +#include <linux/usb.h> + +#include "stv680.h" + +static int video_nr = -1; +static int swapRGB = 0; + +static unsigned int debug = 0; + +#define PDEBUG(level, fmt, args...) \ + do { \ + if (debug >= level) \ + info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args); \ + } while (0) + + +/* + * Version Information + */ +#define DRIVER_VERSION "v0.23" +#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>" +#define DRIVER_DESC "STV0680 USB Camera Driver" + +MODULE_AUTHOR (DRIVER_AUTHOR); +MODULE_DESCRIPTION (DRIVER_DESC); +MODULE_LICENSE ("GPL"); +MODULE_PARM (debug, "i"); +MODULE_PARM_DESC (debug, "Debug enabled or not"); +MODULE_PARM (swapRGB, "i"); +MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv"); +MODULE_PARM (video_nr, "i"); +EXPORT_NO_SYMBOLS; + +/******************************************************************** + * + * Memory management + * + * This is a shameless copy from the USB-cpia driver (linux kernel + * version 2.3.29 or so, I have no idea what this code actually does ;). + * Actually it seems to be a copy of a shameless copy of the bttv-driver. + * Or that is a copy of a shameless copy of ... (To the powers: is there + * no generic kernel-function to do this sort of stuff?) + * + * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says + * there will be one, but apparentely not yet -jerdfelt + * + * So I copied it again for the ov511 driver -claudio + * + * Same for the se401 driver -Jeroen + * + * And the STV0680 driver - Kevin + ********************************************************************/ + +/* 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)); + } + } + } + return ret; +} + +/* Here we want the physical address of the memory. This is used when + * initializing the contents of the area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa (unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR (adr); + kva = uvirt_to_kva (pgd_offset_k (va), va); + ret = __pa (kva); + return ret; +} + +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); +} + + +/********************************************************************* + * pencam read/write functions + ********************************************************************/ + +static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size) +{ + int ret = -1; + + switch (set) { + case 0: /* 0xc1 */ + ret = usb_control_msg (stv680->udev, + usb_rcvctrlpipe (stv680->udev, 0), + req, + (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), + value, 0, buffer, size, PENCAM_TIMEOUT); + break; + + case 1: /* 0x41 */ + ret = usb_control_msg (stv680->udev, + usb_sndctrlpipe (stv680->udev, 0), + req, + (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), + value, 0, buffer, size, PENCAM_TIMEOUT); + break; + + case 2: /* 0x80 */ + ret = usb_control_msg (stv680->udev, + usb_rcvctrlpipe (stv680->udev, 0), + req, + (USB_DIR_IN | USB_RECIP_DEVICE), + value, 0, buffer, size, PENCAM_TIMEOUT); + break; + + case 3: /* 0x40 */ + ret = usb_control_msg (stv680->udev, + usb_sndctrlpipe (stv680->udev, 0), + req, + (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), + value, 0, buffer, size, PENCAM_TIMEOUT); + break; + + } + if ((ret < 0) && (req != 0x0a)) { + PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret); + } + return ret; +} + +static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate) +{ + + if (usb_set_configuration (dev->udev, configuration) < 0) { + PDEBUG (1, "STV(e): FAILED to set configuration %i", configuration); + return -1; + } + if (usb_set_interface (dev->udev, interface, alternate) < 0) { + PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate); + return -1; + } + return 0; +} + +static int stv_stop_video (struct usb_stv *dev) +{ + int i; + unsigned char *buf; + + buf = kmalloc (40, GFP_KERNEL); + if (buf == NULL) { + PDEBUG (0, "STV(e): Out of (small buf) memory"); + return -1; + } + + /* this is a high priority command; it stops all lower order commands */ + if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) { + i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02); /* Get Last Error; 2 = busy */ + PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buf[0], buf[1]); + } else { + PDEBUG (1, "STV(i): Camera reset to idle mode."); + } + + if ((i = stv_set_config (dev, 1, 0, 0)) < 0) + PDEBUG (1, "STV(e): Reset config during exit failed"); + + /* get current mode */ + buf[0] = 0xf0; + if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08) /* get mode */ + PDEBUG (0, "STV(e): Stop_video: problem setting original mode"); + if (dev->origMode != buf[0]) { + memset (buf, 0, 8); + buf[0] = (unsigned char) dev->origMode; + if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) { + PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed"); + i = -1; + } + buf[0] = 0xf0; + i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08); + if ((i != 0x08) || (buf[0] != dev->origMode)) { + PDEBUG (0, "STV(e): camera NOT set to original resolution."); + i = -1; + } else + PDEBUG (0, "STV(i): Camera set to original resolution"); + } + /* origMode */ + kfree (buf); + return i; +} + +static int stv_set_video_mode (struct usb_stv *dev) +{ + int i, stop_video = 1; + unsigned char *buf; + + buf = kmalloc (40, GFP_KERNEL); + if (buf == NULL) { + PDEBUG (0, "STV(e): Out of (small buf) memory"); + return -1; + } + + if ((i = stv_set_config (dev, 1, 0, 0)) < 0) { + kfree (buf); + return i; + } + + i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12); + if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) { + PDEBUG (1, "STV(e): Could not get descriptor 0100."); + goto error; + } + + /* set alternate interface 1 */ + if ((i = stv_set_config (dev, 1, 0, 1)) < 0) + goto error; + + if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10) + goto error; + PDEBUG (1, "STV(i): Setting video mode."); + /* Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240) */ + if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) { + stop_video = 0; + goto error; + } + goto exit; + +error: + kfree (buf); + if (stop_video == 1) + stv_stop_video (dev); + return -1; + +exit: + kfree (buf); + return 0; +} + +static int stv_init (struct usb_stv *stv680) +{ + int i = 0; + unsigned char *buffer; + unsigned long int bufsize; + + buffer = kmalloc (40, GFP_KERNEL); + if (buffer == NULL) { + PDEBUG (0, "STV(e): Out of (small buf) memory"); + return -1; + } + memset (buffer, 0, 40); + udelay (100); + + /* set config 1, interface 0, alternate 0 */ + if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) { + kfree (buffer); + PDEBUG (0, "STV(e): set config 1,0,0 failed"); + return -1; + } + /* ping camera to be sure STV0680 is present */ + if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02) + goto error; + if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) { + PDEBUG (1, "STV(e): camera ping failed!!"); + goto error; + } + + /* get camera descriptor */ + if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09) + goto error; + i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22); + if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) { + PDEBUG (1, "STV(e): Could not get descriptor 0200."); + goto error; + } + if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02) + goto error; + if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24) + goto error; + if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10) + goto error; + + stv680->SupportedModes = buffer[7]; + i = stv680->SupportedModes; + stv680->CIF = 0; + stv680->VGA = 0; + stv680->QVGA = 0; + if (i & 1) + stv680->CIF = 1; + if (i & 2) + stv680->VGA = 1; + if (i & 8) + stv680->QVGA = 1; + if (stv680->SupportedModes == 0) { + PDEBUG (0, "STV(e): There are NO supported STV680 modes!!"); + i = -1; + goto error; + } else { + if (stv680->CIF) + PDEBUG (0, "STV(i): CIF is supported"); + if (stv680->QVGA) + PDEBUG (0, "STV(i): QVGA is supported"); + } + /* FW rev, ASIC rev, sensor ID */ + PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]); + PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]); + PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4)); + + /* set alternate interface 1 */ + if ((i = stv_set_config (stv680, 1, 0, 1)) < 0) + goto error; + + if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10) + goto error; + if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08) + goto error; + i = buffer[3]; + PDEBUG (0, "STV(i): Camera has %i pictures.", i); + + /* get current mode */ + if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08) + goto error; + stv680->origMode = buffer[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */ + + /* This will attemp CIF mode, if supported. If not, set to QVGA */ + memset (buffer, 0, 8); + if (stv680->CIF) + buffer[0] = 0x00; + else if (stv680->QVGA) + buffer[0] = 0x03; + if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) { + PDEBUG (0, "STV(i): Set_Camera_Mode failed"); + i = -1; + goto error; + } + buffer[0] = 0xf0; + stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08); + if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) { + PDEBUG (0, "STV(e): Error setting camera video mode!"); + i = -1; + goto error; + } else { + if (buffer[0] == 0) { + stv680->VideoMode = 0x0000; + PDEBUG (0, "STV(i): Video Mode set to CIF"); + } + if (buffer[0] == 0x03) { + stv680->VideoMode = 0x0300; + PDEBUG (0, "STV(i): Video Mode set to QVGA"); + } + } + if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10) + goto error; + bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); + stv680->cwidth = (buffer[4] << 8) | (buffer[5]); /* ->camera = 322, 356, 644 */ + stv680->cheight = (buffer[6] << 8) | (buffer[7]); /* ->camera = 242, 292, 484 */ + stv680->origGain = buffer[12]; + + goto exit; + +error: + i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02); /* Get Last Error */ + PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buffer[0], buffer[1]); + kfree (buffer); + return -1; + +exit: + kfree (buffer); + + /* video = 320x240, 352x288 */ + if (stv680->CIF == 1) { + stv680->maxwidth = 352; + stv680->maxheight = 288; + stv680->vwidth = 352; + stv680->vheight = 288; + } + if (stv680->QVGA == 1) { + stv680->maxwidth = 320; + stv680->maxheight = 240; + stv680->vwidth = 320; + stv680->vheight = 240; + } + + stv680->rawbufsize = bufsize; /* must be ./. by 8 */ + stv680->maxframesize = bufsize * 3; /* RGB size */ + PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight); + PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize); + + /* some default values */ + stv680->bulk_in_endpointAddr = 0x82; + stv680->dropped = 0; + stv680->error = 0; + stv680->framecount = 0; + stv680->readcount = 0; + stv680->streaming = 0; + /* bright, white, colour, hue, contrast are set by software, not in stv0680 */ + stv680->brightness = 32767; + stv680->chgbright = 0; + stv680->whiteness = 0; /* only for greyscale */ + stv680->colour = 32767; + stv680->contrast = 32767; + stv680->hue = 32767; + stv680->palette = STV_VIDEO_PALETTE; + stv680->depth = 24; /* rgb24 bits */ + swapRGB = 0; + PDEBUG (1, "STV(i): swapRGB is OFF"); + + if (stv_set_video_mode (stv680) < 0) { + PDEBUG (0, "STV(e): Could not set video mode in stv_init"); + return -1; + } + + return 0; +} + +/***************** last of pencam routines *******************/ + +/******************************************************************** + * /proc interface + *******************************************************************/ + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + +static struct proc_dir_entry *stv680_proc_entry = NULL; +extern struct proc_dir_entry *video_proc_entry; + +#define YES_NO(x) ((x) ? "yes" : "no") + +static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + char *out = page; + int len; + struct usb_stv *stv680 = data; + + /* Stay under PAGE_SIZE or else bla bla bla.... */ + + out += sprintf (out, "driver_version : %s\n", DRIVER_VERSION); + out += sprintf (out, "model : %s\n", stv680->camera_name); + out += sprintf (out, "in use : %s\n", YES_NO (stv680->user)); + out += sprintf (out, "streaming : %s\n", YES_NO (stv680->streaming)); + out += sprintf (out, "num_frames : %d\n", STV680_NUMFRAMES); + + out += sprintf (out, "Current size : %ix%i\n", stv680->vwidth, stv680->vheight); + out += sprintf (out, "swapRGB : %s\n", YES_NO (swapRGB)); + out += sprintf (out, "Palette : %i", stv680->palette); + + out += sprintf (out, "\n"); + + out += sprintf (out, "Frames total : %d\n", stv680->readcount); + out += sprintf (out, "Frames read : %d\n", stv680->framecount); + out += sprintf (out, "Packets dropped : %d\n", stv680->dropped); + out += sprintf (out, "Decoding Errors : %d\n", stv680->error); + + 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 create_proc_stv680_cam (struct usb_stv *stv680) +{ + char name[9]; + struct proc_dir_entry *ent; + + if (!stv680_proc_entry || !stv680) + return -1; + + sprintf (name, "video%d", stv680->vdev.minor); + + ent = create_proc_entry (name, S_IFREG | S_IRUGO | S_IWUSR, stv680_proc_entry); + if (!ent) + return -1; + + ent->data = stv680; + ent->read_proc = stv680_read_proc; + stv680->proc_entry = ent; + return 0; +} + +static void destroy_proc_stv680_cam (struct usb_stv *stv680) +{ + /* One to much, just to be sure :) */ + char name[9]; + + if (!stv680 || !stv680->proc_entry) + return; + + sprintf (name, "video%d", stv680->vdev.minor); + remove_proc_entry (name, stv680_proc_entry); + stv680->proc_entry = NULL; +} + +static int proc_stv680_create (void) +{ + if (video_proc_entry == NULL) { + PDEBUG (0, "STV(e): /proc/video/ doesn't exist!"); + return -1; + } + stv680_proc_entry = create_proc_entry ("stv680", S_IFDIR, video_proc_entry); + + if (stv680_proc_entry) { + stv680_proc_entry->owner = THIS_MODULE; + } else { + PDEBUG (0, "STV(e): Unable to initialize /proc/video/stv680"); + return -1; + } + return 0; +} + +static void proc_stv680_destroy (void) +{ + if (stv680_proc_entry == NULL) + return; + + remove_proc_entry ("stv", video_proc_entry); +} +#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ + +/******************************************************************** + * Camera control + *******************************************************************/ + +static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p) +{ + /* This sets values for v4l interface. max/min = 65535/0 */ + + p->brightness = stv680->brightness; + p->whiteness = stv680->whiteness; /* greyscale */ + p->colour = stv680->colour; + p->contrast = stv680->contrast; + p->hue = stv680->hue; + p->palette = stv680->palette; + p->depth = stv680->depth; + return 0; +} + +static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p) +{ + /* See above stv680_get_pict */ + + if (p->palette != STV_VIDEO_PALETTE) { + PDEBUG (2, "STV(e): Palette set error in _set_pic"); + return 1; + } + + if (stv680->brightness != p->brightness) { + stv680->chgbright = 1; + stv680->brightness = p->brightness; + } else { + stv680->chgbright = 0; + } + + stv680->whiteness = p->whiteness; /* greyscale */ + stv680->colour = p->colour; + stv680->contrast = p->contrast; + stv680->hue = p->hue; + stv680->palette = p->palette; + stv680->depth = p->depth; + + return 0; +} + +static void stv680_video_irq (struct urb *urb) +{ + struct usb_stv *stv680 = urb->context; + int length = urb->actual_length; + + if (length < stv680->rawbufsize) + PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length); + + /* ohoh... */ + if (!stv680->streaming) + return; + + if (!stv680->udev) { + PDEBUG (0, "STV(e): device vapourished in video_irq"); + return; + } + + /* 0 sized packets happen if we are to fast, but sometimes the camera + keeps sending them forever... + */ + if (length && !urb->status) { + stv680->nullpackets = 0; + switch (stv680->scratch[stv680->scratch_next].state) { + case BUFFER_READY: + case BUFFER_BUSY: + stv680->dropped++; + break; + + case BUFFER_UNUSED: + memcpy (stv680->scratch[stv680->scratch_next].data, + (unsigned char *) urb->transfer_buffer, length); + stv680->scratch[stv680->scratch_next].state = BUFFER_READY; + stv680->scratch[stv680->scratch_next].length = length; + if (waitqueue_active (&stv680->wq)) { + wake_up_interruptible (&stv680->wq); + } + stv680->scratch_overflow = 0; + stv680->scratch_next++; + if (stv680->scratch_next >= STV680_NUMSCRATCH) + stv680->scratch_next = 0;; + break; + } /* switch */ + } else { + stv680->nullpackets++; + if (stv680->nullpackets > STV680_MAX_NULLPACKETS) { + if (waitqueue_active (&stv680->wq)) { + wake_up_interruptible (&stv680->wq); + } + } + } /* if - else */ + + /* Resubmit urb for new data */ + urb->status = 0; + urb->dev = stv680->udev; + if (usb_submit_urb (urb)) + PDEBUG (0, "STV(e): urb burned down in video irq"); + return; +} /* _video_irq */ + +static int stv680_start_stream (struct usb_stv *stv680) +{ + urb_t *urb; + int err = 0, i; + + stv680->streaming = 1; + + /* Do some memory allocation */ + for (i = 0; i < STV680_NUMFRAMES; i++) { + stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize; + stv680->frame[i].curpix = 0; + } + /* packet size = 4096 */ + for (i = 0; i < STV680_NUMSBUF; i++) { + stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); + if (stv680->sbuf[i].data == NULL) { + PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i); + return -1; + } + } + + stv680->scratch_next = 0; + stv680->scratch_use = 0; + stv680->scratch_overflow = 0; + for (i = 0; i < STV680_NUMSCRATCH; i++) { + stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); + if (stv680->scratch[i].data == NULL) { + PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i); + return -1; + } + stv680->scratch[i].state = BUFFER_UNUSED; + } + + for (i = 0; i < STV680_NUMSBUF; i++) { + urb = usb_alloc_urb (0); + if (!urb) + return ENOMEM; + + /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */ + usb_fill_bulk_urb (urb, stv680->udev, + usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr), + stv680->sbuf[i].data, stv680->rawbufsize, + stv680_video_irq, stv680); + urb->timeout = PENCAM_TIMEOUT * 2; + urb->transfer_flags |= USB_QUEUE_BULK; + stv680->urb[i] = urb; + err = usb_submit_urb (stv680->urb[i]); + if (err) + PDEBUG (0, "STV(e): urb burned down in start stream"); + } /* i STV680_NUMSBUF */ + + stv680->framecount = 0; + return 0; +} + +static int stv680_stop_stream (struct usb_stv *stv680) +{ + int i; + + if (!stv680->streaming || !stv680->udev) + return 1; + + stv680->streaming = 0; + + for (i = 0; i < STV680_NUMSBUF; i++) + if (stv680->urb[i]) { + stv680->urb[i]->next = NULL; + usb_unlink_urb (stv680->urb[i]); + usb_free_urb (stv680->urb[i]); + stv680->urb[i] = NULL; + kfree (stv680->sbuf[i].data); + } + for (i = 0; i < STV680_NUMSCRATCH; i++) { + kfree (stv680->scratch[i].data); + stv680->scratch[i].data = NULL; + } + + return 0; +} + +static int stv680_set_size (struct usb_stv *stv680, int width, int height) +{ + int wasstreaming = stv680->streaming; + + /* Check to see if we need to change */ + if ((stv680->vwidth == width) && (stv680->vheight == height)) + return 0; + + PDEBUG (1, "STV(i): size request for %i x %i", width, height); + /* Check for a valid mode */ + if ((!width || !height) || ((width & 1) || (height & 1))) { + PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight); + return 1; + } + + if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) { + width = stv680->maxwidth / 2; + height = stv680->maxheight / 2; + } else if ((width >= 158) && (width <= 166)) { + width = 160; + height = 120; + } else if ((width >= 172) && (width <= 180)) { + width = 176; + height = 144; + } else if ((width >= 318) && (width <= 350)) { + width = 320; + height = 240; + } else if ((width >= 350) && (width <= 358)) { + width = 352; + height = 288; + } + + /* Stop a current stream and start it again at the new size */ + if (wasstreaming) + stv680_stop_stream (stv680); + stv680->vwidth = width; + stv680->vheight = height; + PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight); + if (wasstreaming) + stv680_start_stream (stv680); + + return 0; +} + +/********************************************************************** + * Video Decoding + **********************************************************************/ + +/******* routines from the pencam program; hey, they work! ********/ + +/* + * STV0680 Vision Camera Chipset Driver + * Copyright (C) 2000 Adam Harrison <adam@antispin.org> +*/ + +#define RED 0 +#define GREEN 1 +#define BLUE 2 +#define AD(x, y, w) (((y)*(w)+(x))*3) + +static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer) +{ + int x, y, i; + int w = stv680->cwidth; + int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1; + unsigned int p = 0; + int colour = 0, bayer = 0; + unsigned char *raw = buffer->data; + struct stv680_frame *frame = &stv680->frame[stv680->curframe]; + unsigned char *output = frame->data; + unsigned char *temp = frame->data; + int offset = buffer->offset; + + if (frame->curpix == 0) { + if (frame->grabstate == FRAME_READY) { + frame->grabstate = FRAME_GRABBING; + } + } + if (offset != frame->curpix) { /* Regard frame as lost :( */ + frame->curpix = 0; + stv680->error++; + return; + } + + if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) { + vw = 320; + vh = 240; + vstep = 1; + } + if ((stv680->vwidth == 352)) { + vw = 352; + vh = 288; + vstep = 1; + } + if ((stv680->vwidth == 160)) { + vw = 160; + vh = 120; + vstep = 2; + } + if ((stv680->vwidth == 176)) { + vw = 176; + vh = 144; + vstep = 2; + } + memset (output, 0, 3 * vw * vh); /* clear output matrix. Maybe not necessary. */ + + for (y = 0; y < vh; y++) { + for (x = 0; x < vw; x++) { + + switch (vstep) { + case 1: + if (x & 1) + p = *(raw + y * w + (x >> 1)); + else + p = *(raw + y * w + (x >> 1) + (w >> 1)); + break; + + case 2: + if (x & 1) + p = *(raw + ((y * w) << 1) + x); + else + p = *(raw + ((y * w) << 1) + x + (w >> 1)); + break; + } + + if (y & 1) + bayer = 2; + else + bayer = 0; + if (x & 1) + bayer++; + + switch (bayer) { + case 0: + case 3: + colour = 1; + break; + case 1: + colour = 0; + break; + case 2: + colour = 2; + break; + } + i = (y * vw + x) * 3; /* output already zeroed out with memset */ + *(output + i + colour) = (unsigned char) p; + } /* for x */ + } /* for y */ + + /****** gamma correction plus hardcoded white balance */ + /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code. + Correction values red[], green[], blue[], are generated by + (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. + White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and + converted to unsigned char. Values are in stv680.h */ + for (y = 0; y < vh; y++) { + for (x = 0; x < vw; x++) { + i = (y * vw + x) * 3; + *(output + i) = red[*(output + i)]; + *(output + i + 1) = green[*(output + i + 1)]; + *(output + i + 2) = blue[*(output + i + 2)]; + } + } + + /****** bayer demosaic ******/ + for (y = 1; y < (vh - 1); y++) { + for (x = 1; x < (vw - 1); x++) { /* work out pixel type */ + if (y & 1) + bayer = 0; + else + bayer = 2; + if (!(x & 1)) + bayer++; + + switch (bayer) { + case 0: /* green. blue lr, red tb */ + *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1; + *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1; + break; + + case 1: /* blue. green lrtb, red diagonals */ + *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2; + *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2; + break; + + case 2: /* red. green lrtb, blue diagonals */ + *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2; + *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2; + break; + + case 3: /* green. red lr, blue tb */ + *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1; + *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1; + break; + } /* switch */ + } /* for x */ + } /* for y - end demosaic */ + + /* output is RGB; some programs want BGR */ + if (swapRGB == 1) { + for (y = 0; y < vh; y++) { + for (x = 0; x < vw; x++) { + i = (y * vw + x) * 3; + *(temp) = *(output + i); + *(output + i) = *(output + i + 2); + *(output + i + 2) = *(temp); + } + } + } + /* brightness */ + if (stv680->chgbright == 1) { + if (stv680->brightness >= 32767) { + p = (stv680->brightness - 32767) / 256; + for (x = 0; x < (vw * vh * 3); x++) { + if ((*(output + x) + (unsigned char) p) > 255) + *(output + x) = 255; + else + *(output + x) += (unsigned char) p; + } /* for */ + } else { + p = (32767 - stv680->brightness) / 256; + for (x = 0; x < (vw * vh * 3); x++) { + if ((unsigned char) p > *(output + x)) + *(output + x) = 0; + else + *(output + x) -= (unsigned char) p; + } /* for */ + } /* else */ + } + /* if */ + frame->curpix = 0; + frame->curlinepix = 0; + frame->grabstate = FRAME_DONE; + stv680->framecount++; + stv680->readcount++; + if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) { + stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1); + } + +} /* bayer_unshuffle */ + +/******* end routines from the pencam program *********/ + +static int stv680_newframe (struct usb_stv *stv680, int framenr) +{ + int errors = 0; + + while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) { + if (!stv680->frame[framenr].curpix) { + errors++; + } + wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY)); + + if (stv680->nullpackets > STV680_MAX_NULLPACKETS) { + stv680->nullpackets = 0; + PDEBUG (2, "STV(i): too many null length packets, restarting capture"); + stv680_stop_stream (stv680); + stv680_start_stream (stv680); + } else { + if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) { + stv680->frame[framenr].grabstate = FRAME_ERROR; + PDEBUG (2, "STV(e): FRAME_ERROR in _newframe"); + return -EIO; + } + stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY; + + bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]); + + stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED; + stv680->scratch_use++; + if (stv680->scratch_use >= STV680_NUMSCRATCH) + stv680->scratch_use = 0; + if (errors > STV680_MAX_ERRORS) { + errors = 0; + PDEBUG (2, "STV(i): too many errors, restarting capture"); + stv680_stop_stream (stv680); + stv680_start_stream (stv680); + } + } /* else */ + } /* while */ + return 0; +} + +/********************************************************************* + * Video4Linux + *********************************************************************/ + +static int stv_open (struct video_device *dev, int flags) +{ + struct usb_stv *stv680 = (struct usb_stv *) dev; + int err = 0; + + /* we are called with the BKL held */ + MOD_INC_USE_COUNT; + stv680->user = 1; + err = stv_init (stv680); /* main initialization routine for camera */ + + if (err >= 0) { + stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES); + if (!stv680->fbuf) { + PDEBUG (0, "STV(e): Could not rvmalloc frame bufer"); + err = -ENOMEM; + } + } + if (err) { + MOD_DEC_USE_COUNT; + stv680->user = 0; + } + + return err; +} + +static void stv_close (struct video_device *dev) +{ + /* called with BKL held */ + struct usb_stv *stv680 = (struct usb_stv *) dev; + int i; + + for (i = 0; i < STV680_NUMFRAMES; i++) + stv680->frame[i].grabstate = FRAME_UNUSED; + if (stv680->streaming) + stv680_stop_stream (stv680); + + if ((i = stv_stop_video (stv680)) < 0) + PDEBUG (1, "STV(e): stop_video failed in stv_close"); + + rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES); + stv680->user = 0; + + if (stv680->removed) { + video_unregister_device (&stv680->vdev); + kfree (stv680); + stv680 = NULL; + PDEBUG (0, "STV(i): device unregistered"); + } + MOD_DEC_USE_COUNT; +} + +static long stv680_write (struct video_device *dev, const char *buf, unsigned long count, int noblock) +{ + return -EINVAL; +} + +static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg) +{ + struct usb_stv *stv680 = (struct usb_stv *) vdev; + + if (!stv680->udev) + return -EIO; + + switch (cmd) { + case VIDIOCGCAP:{ + struct video_capability b; + + strcpy (b.name, stv680->camera_name); + b.type = VID_TYPE_CAPTURE; + b.channels = 1; + b.audios = 0; + b.maxwidth = stv680->maxwidth; + b.maxheight = stv680->maxheight; + b.minwidth = stv680->maxwidth / 2; + b.minheight = stv680->maxheight / 2; + + if (copy_to_user (arg, &b, sizeof (b))) { + PDEBUG (2, "STV(e): VIDIOCGGAP failed"); + return -EFAULT; + } + return 0; + } + case VIDIOCGCHAN:{ + struct video_channel v; + + if (copy_from_user (&v, arg, sizeof (v))) + return -EFAULT; + if (v.channel != 0) + return -EINVAL; + + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + strcpy (v.name, "STV Camera"); + + if (copy_to_user (arg, &v, sizeof (v))) { + PDEBUG (2, "STV(e): VIDIOCGCHAN failed"); + return -EFAULT; + } + return 0; + } + case VIDIOCSCHAN:{ + int v; + + if (copy_from_user (&v, arg, sizeof (v))) { + PDEBUG (2, "STV(e): VIDIOCSCHAN failed"); + return -EFAULT; + } + if (v != 0) + return -EINVAL; + + return 0; + } + case VIDIOCGPICT:{ + struct video_picture p; + + stv680_get_pict (stv680, &p); + if (copy_to_user (arg, &p, sizeof (p))) { + PDEBUG (2, "STV(e): VIDIOCGPICT failed"); + return -EFAULT; + } + return 0; + } + case VIDIOCSPICT:{ + struct video_picture p; + + if (copy_from_user (&p, arg, sizeof (p))) { + PDEBUG (2, "STV(e): VIDIOCSPICT failed"); + return -EFAULT; + } + copy_from_user (&p, arg, sizeof (p)); + PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT"); + + if (stv680_set_pict (stv680, &p)) + return -EINVAL; + 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 != stv680->vwidth) { + if (stv680_set_size (stv680, vw.width, vw.height)) { + PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN"); + return -EINVAL; + } + } + return 0; + } + case VIDIOCGWIN:{ + struct video_window vw; + + vw.x = 0; /* FIXME */ + vw.y = 0; + vw.chromakey = 0; + vw.flags = 0; + vw.clipcount = 0; + vw.width = stv680->vwidth; + vw.height = stv680->vheight; + + if (copy_to_user (arg, &vw, sizeof (vw))) { + PDEBUG (2, "STV(e): VIDIOCGWIN failed"); + return -EFAULT; + } + return 0; + } + case VIDIOCGMBUF:{ + struct video_mbuf vm; + int i; + + memset (&vm, 0, sizeof (vm)); + vm.size = STV680_NUMFRAMES * stv680->maxframesize; + vm.frames = STV680_NUMFRAMES; + for (i = 0; i < STV680_NUMFRAMES; i++) + vm.offsets[i] = stv680->maxframesize * i; + + if (copy_to_user ((void *) arg, (void *) &vm, sizeof (vm))) { + PDEBUG (2, "STV(e): VIDIOCGMBUF failed"); + return -EFAULT; + } + + return 0; + } + case VIDIOCMCAPTURE:{ + struct video_mmap vm; + + if (copy_from_user (&vm, arg, sizeof (vm))) { + PDEBUG (2, "STV(e): VIDIOCMCAPTURE failed"); + return -EFAULT; + } + if (vm.format != STV_VIDEO_PALETTE) { + PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)", + vm.format, STV_VIDEO_PALETTE); + if (vm.format == 3) { + PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON"); + /* this may fix those apps (e.g., xawtv) that want BGR */ + swapRGB = 1; + } + return -EINVAL; + } + if (vm.frame >= STV680_NUMFRAMES) { + PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES"); + return -EINVAL; + } + if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) { + PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED"); + return -EBUSY; + } + /* Is this according to the v4l spec??? */ + if (stv680->vwidth != vm.width) { + if (stv680_set_size (stv680, vm.width, vm.height)) { + PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed"); + return -EINVAL; + } + } + stv680->frame[vm.frame].grabstate = FRAME_READY; + + if (!stv680->streaming) + stv680_start_stream (stv680); + + return 0; + } + case VIDIOCSYNC:{ + int frame, ret = 0; + + if (copy_from_user ((void *) &frame, arg, sizeof (int))) { + PDEBUG (2, "STV(e): VIDIOCSYNC failed"); + return -EFAULT; + } + if (frame < 0 || frame >= STV680_NUMFRAMES) { + PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC"); + return -EINVAL; + } + ret = stv680_newframe (stv680, frame); + stv680->frame[frame].grabstate = FRAME_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))) { + PDEBUG (2, "STV(e): VIDIOCSYNC failed"); + return -EFAULT; + } + return 0; + } + case VIDIOCKEY: + return 0; + case VIDIOCCAPTURE: + { + PDEBUG (2, "STV(e): VIDIOCCAPTURE failed"); + return -EINVAL; + } + case VIDIOCSFBUF: + return -EINVAL; + case VIDIOCGTUNER: + case VIDIOCSTUNER: + return -EINVAL; + case VIDIOCGFREQ: + case VIDIOCSFREQ: + return -EINVAL; + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + default: + return -ENOIOCTLCMD; + } /* end switch */ + + return 0; +} + +static int stv680_mmap (struct video_device *dev, const char *adr, unsigned long size) +{ + struct usb_stv *stv680 = (struct usb_stv *) dev; + unsigned long start = (unsigned long) adr; + unsigned long page, pos; + + down (&stv680->lock); + + if (stv680->udev == NULL) { + up (&stv680->lock); + return -EIO; + } + if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1) + & ~(PAGE_SIZE - 1))) { + up (&stv680->lock); + return -EINVAL; + } + pos = (unsigned long) stv680->fbuf; + while (size > 0) { + page = kvirt_to_pa (pos); + if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)) { + up (&stv680->lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + up (&stv680->lock); + + return 0; +} + +static long stv680_read (struct video_device *dev, char *buf, unsigned long count, int noblock) +{ + unsigned long int realcount = count; + int ret = 0; + struct usb_stv *stv680 = (struct usb_stv *) dev; + unsigned long int i; + + if (STV680_NUMFRAMES != 2) { + PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!"); + return -1; + } + if (stv680->udev == NULL) + return -EIO; + if (realcount > (stv680->vwidth * stv680->vheight * 3)) + realcount = stv680->vwidth * stv680->vheight * 3; + + /* Shouldn't happen: */ + if (stv680->frame[0].grabstate == FRAME_GRABBING) { + PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read"); + return -EBUSY; + } + stv680->frame[0].grabstate = FRAME_READY; + stv680->frame[1].grabstate = FRAME_UNUSED; + stv680->curframe = 0; + + if (!stv680->streaming) + stv680_start_stream (stv680); + + if (!stv680->streaming) { + ret = stv680_newframe (stv680, 0); /* ret should = 0 */ + } + + ret = stv680_newframe (stv680, 0); + + if (!ret) { + if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) { + PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i); + return -EFAULT; + } + } else { + realcount = ret; + } + stv680->frame[0].grabstate = FRAME_UNUSED; + return realcount; +} /* stv680_read */ + +static int stv_init_done (struct video_device *dev) +{ + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + if (create_proc_stv680_cam ((struct usb_stv *) dev) < 0) + return -1; +#endif + return 0; +} + +static struct video_device stv680_template = { + owner: THIS_MODULE, + name: "STV0680 USB camera", + type: VID_TYPE_CAPTURE, + hardware: VID_HARDWARE_SE401, + open: stv_open, + close: stv_close, + read: stv680_read, + write: stv680_write, + ioctl: stv680_ioctl, + mmap: stv680_mmap, + initialize: stv_init_done, +}; + +static void *__devinit stv680_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) +{ + struct usb_interface_descriptor *interface; + struct usb_stv *stv680; + char *camera_name = NULL; + + /* We don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) { + PDEBUG (0, "STV(e): Number of Configurations != 1"); + return NULL; + } + + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + /* Is it a STV680? */ + if ((dev->descriptor.idVendor == USB_PENCAM_VENDOR_ID) && (dev->descriptor.idProduct == USB_PENCAM_PRODUCT_ID)) { + camera_name = "STV0680"; + PDEBUG (0, "STV(i): STV0680 camera found."); + } else { + PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values."); + PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer."); + return NULL; + } + /* We found one */ + if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) { + PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct."); + return NULL; + } + + memset (stv680, 0, sizeof (*stv680)); + + stv680->udev = dev; + stv680->camera_name = camera_name; + + memcpy (&stv680->vdev, &stv680_template, sizeof (stv680_template)); + memcpy (stv680->vdev.name, stv680->camera_name, strlen (stv680->camera_name)); + init_waitqueue_head (&stv680->wq); + init_MUTEX (&stv680->lock); + wmb (); + + if (video_register_device (&stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + kfree (stv680); + PDEBUG (0, "STV(e): video_register_device failed"); + return NULL; + } + PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev.minor); + + return stv680; +} + +static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680) +{ + int i; + + stv680->udev = NULL; + stv680->frame[0].grabstate = FRAME_ERROR; + stv680->frame[1].grabstate = FRAME_ERROR; + stv680->streaming = 0; + + wake_up_interruptible (&stv680->wq); + + for (i = 0; i < STV680_NUMSBUF; i++) + if (stv680->urb[i]) { + stv680->urb[i]->next = NULL; + usb_unlink_urb (stv680->urb[i]); + usb_free_urb (stv680->urb[i]); + stv680->urb[i] = NULL; + kfree (stv680->sbuf[i].data); + } + for (i = 0; i < STV680_NUMSCRATCH; i++) + if (stv680->scratch[i].data) { + kfree (stv680->scratch[i].data); + } + PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name); + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + destroy_proc_stv680_cam (stv680); +#endif + /* Free the memory */ + kfree (stv680); +} + +static void stv680_disconnect (struct usb_device *dev, void *ptr) +{ + struct usb_stv *stv680 = (struct usb_stv *) ptr; + + lock_kernel (); + /* We don't want people trying to open up the device */ + if (!stv680->user) { + video_unregister_device (&stv680->vdev); + usb_stv680_remove_disconnected (stv680); + } else { + stv680->removed = 1; + } + unlock_kernel (); +} + +static struct usb_driver stv680_driver = { + name: "stv680", + probe: stv680_probe, + disconnect: stv680_disconnect, + id_table: device_table +}; + +/******************************************************************** + * Module routines + ********************************************************************/ + +static int __init usb_stv680_init (void) +{ +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + if (proc_stv680_create () < 0) + return -1; +#endif + if (usb_register (&stv680_driver) < 0) { + PDEBUG (0, "STV(e): Could not setup STV0680 driver"); + return -1; + } + PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION); + + info(DRIVER_DESC " " DRIVER_VERSION); + return 0; +} + +static void __exit usb_stv680_exit (void) +{ + usb_deregister (&stv680_driver); + PDEBUG (0, "STV(i): driver deregistered"); + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + proc_stv680_destroy (); +#endif +} + +module_init (usb_stv680_init); +module_exit (usb_stv680_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/stv680.h linux-2.5/drivers/usb/stv680.h --- linux-2.5.1/drivers/usb/stv680.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/stv680.h Thu Jan 3 23:04:40 2002 @@ -0,0 +1,222 @@ +/**************************************************************************** + * + * Filename: stv680.h + * + * Description: + * This is a USB driver for STV0680 based usb video cameras. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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. + * + ****************************************************************************/ + +/* size of usb transfers */ +#define STV680_PACKETSIZE 4096 + +/* number of queued bulk transfers to use, may have problems if > 1 */ +#define STV680_NUMSBUF 1 + +/* number of frames supported by the v4l part */ +#define STV680_NUMFRAMES 2 + +/* scratch buffers for passing data to the decoders: 2 or 4 are good */ +#define STV680_NUMSCRATCH 2 + +/* number of nul sized packets to receive before kicking the camera */ +#define STV680_MAX_NULLPACKETS 200 + +/* number of decoding errors before kicking the camera */ +#define STV680_MAX_ERRORS 100 + +#define USB_PENCAM_VENDOR_ID 0x0553 +#define USB_PENCAM_PRODUCT_ID 0x0202 +#define PENCAM_TIMEOUT 1000 +/* fmt 4 */ +#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24 + +static __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)}, + {} +}; +MODULE_DEVICE_TABLE (usb, device_table); + +struct stv680_sbuf { + unsigned char *data; +}; + +enum { + FRAME_UNUSED, /* Unused (no MCAPTURE) */ + FRAME_READY, /* Ready to start grabbing */ + FRAME_GRABBING, /* In the process of being grabbed into */ + FRAME_DONE, /* Finished grabbing, but not been synced yet */ + FRAME_ERROR, /* Something bad happened while processing */ +}; + +enum { + BUFFER_UNUSED, + BUFFER_READY, + BUFFER_BUSY, + BUFFER_DONE, +}; + +/* raw camera data <- sbuf (urb transfer buf) */ +struct stv680_scratch { + unsigned char *data; + volatile int state; + int offset; + int length; +}; + +/* processed data for display ends up here, after bayer */ +struct stv680_frame { + unsigned char *data; /* Frame buffer */ + volatile int grabstate; /* State of grabbing */ + unsigned char *curline; + int curlinepix; + int curpix; +}; + +/* this is almost the video structure uvd_t, with extra parameters for stv */ +struct usb_stv { + struct video_device vdev; + + struct usb_device *udev; + + unsigned char bulk_in_endpointAddr; /* __u8 the address of the bulk in endpoint */ + char *camera_name; + + unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */ + int SupportedModes; + int CIF; + int VGA; + int QVGA; + int cwidth; /* camera width */ + int cheight; /* camera height */ + int maxwidth; /* max video width */ + int maxheight; /* max video height */ + int vwidth; /* current width for video window */ + int vheight; /* current height for video window */ + unsigned long int rawbufsize; + unsigned long int maxframesize; /* rawbufsize * 3 for RGB */ + + int origGain; + int origMode; /* original camera mode */ + + struct semaphore lock; /* to lock the structure */ + int user; /* user count for exclusive use */ + int removed; /* device disconnected */ + int streaming; /* Are we streaming video? */ + char *fbuf; /* Videodev buffer area */ + urb_t *urb[STV680_NUMSBUF]; /* # of queued bulk transfers */ + int curframe; /* Current receiving frame */ + struct stv680_frame frame[STV680_NUMFRAMES]; /* # frames supported by v4l part */ + int readcount; + int framecount; + int error; + int dropped; + int scratch_next; + int scratch_use; + int scratch_overflow; + struct stv680_scratch scratch[STV680_NUMSCRATCH]; /* for decoders */ + struct stv680_sbuf sbuf[STV680_NUMSBUF]; + + unsigned int brightness; + unsigned int chgbright; + unsigned int whiteness; + unsigned int colour; + unsigned int contrast; + unsigned int hue; + unsigned int palette; + unsigned int depth; /* rgb24 in bits */ + + wait_queue_head_t wq; /* Processes waiting */ + + struct proc_dir_entry *proc_entry; /* /proc/stv680/videoX */ + int nullpackets; +}; + +unsigned char red[256] = { + 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, + 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, + 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, + 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, + 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, + 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, + 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, + 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, + 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, + 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, + 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, + 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, + 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, + 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, + 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, + 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, + 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, + 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, + 245, 245, 246, 246 +}; + +unsigned char green[256] = { + 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54, + 58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90, + 92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113, + 114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132, + 133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147, + 148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161, + 162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174, + 175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186, + 187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196, + 197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207, + 207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216, + 217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225, + 225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233, + 235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242, + 243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250, + 250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255 +}; + +unsigned char blue[256] = { + 0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69, + 74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113, + 116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143, + 145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167, + 168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186, + 187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204, + 205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220, + 222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235, + 236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248, + 250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255 +}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/uhci.c linux-2.5/drivers/usb/uhci.c --- linux-2.5.1/drivers/usb/uhci.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/usb/uhci.c Tue Jan 8 00:44:24 2002 @@ -646,7 +646,7 @@ if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) { urbp->setup_packet_dma_handle = pci_map_single(uhci->dev, - urb->setup_packet, sizeof(devrequest), + urb->setup_packet, sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE); if (!urbp->setup_packet_dma_handle) return NULL; @@ -715,7 +715,7 @@ if (urbp->setup_packet_dma_handle) pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle, - sizeof(devrequest), PCI_DMA_TODEVICE); + sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE); if (urbp->transfer_buffer_dma_handle) pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle, @@ -2013,7 +2013,7 @@ { struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; unsigned int pipe = urb->pipe; - devrequest *cmd = (devrequest *)urb->setup_packet; + struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet; void *data = urb->transfer_buffer; int leni = urb->transfer_buffer_length; int len = 0; @@ -2036,10 +2036,10 @@ return -EINPROGRESS; } - 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); + bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8; + wValue = le16_to_cpu(cmd->wValue); + wIndex = le16_to_cpu(cmd->wIndex); + wLength = le16_to_cpu(cmd->wLength); for (i = 0; i < 8; i++) uhci->rh.c_p_r[i] = 0; @@ -2276,7 +2276,7 @@ if (urbp->setup_packet_dma_handle) pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle, - sizeof(devrequest), PCI_DMA_TODEVICE); + sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE); urb->dev = NULL; if (urb->complete) @@ -2990,7 +2990,7 @@ id_table: uhci_pci_ids, probe: uhci_pci_probe, - remove: uhci_pci_remove, + remove: __devexit_p(uhci_pci_remove), #ifdef CONFIG_PM suspend: uhci_pci_suspend, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/usb-debug.c linux-2.5/drivers/usb/usb-debug.c --- linux-2.5.1/drivers/usb/usb-debug.c Fri Feb 9 19:30:23 2001 +++ linux-2.5/drivers/usb/usb-debug.c Tue Jan 1 23:42:42 2002 @@ -181,23 +181,23 @@ kfree(buf); } -void usb_dump_urb (purb_t purb) +void usb_dump_urb (struct urb *urb) { - printk ("urb :%p\n", purb); - printk ("next :%p\n", purb->next); - printk ("dev :%p\n", purb->dev); - printk ("pipe :%08X\n", purb->pipe); - printk ("status :%d\n", purb->status); - printk ("transfer_flags :%08X\n", purb->transfer_flags); - printk ("transfer_buffer :%p\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 :%p\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 :%p\n", purb->context); - printk ("complete :%p\n", purb->complete); + printk ("urb :%p\n", urb); + printk ("next :%p\n", urb->next); + printk ("dev :%p\n", urb->dev); + printk ("pipe :%08X\n", urb->pipe); + printk ("status :%d\n", urb->status); + printk ("transfer_flags :%08X\n", urb->transfer_flags); + printk ("transfer_buffer :%p\n", urb->transfer_buffer); + printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length); + printk ("actual_length :%d\n", urb->actual_length); + printk ("setup_packet :%p\n", urb->setup_packet); + printk ("start_frame :%d\n", urb->start_frame); + printk ("number_of_packets :%d\n", urb->number_of_packets); + printk ("interval :%d\n", urb->interval); + printk ("error_count :%d\n", urb->error_count); + printk ("context :%p\n", urb->context); + printk ("complete :%p\n", urb->complete); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/usb-ohci.c linux-2.5/drivers/usb/usb-ohci.c --- linux-2.5.1/drivers/usb/usb-ohci.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/usb-ohci.c Thu Jan 10 22:41:07 2002 @@ -76,7 +76,8 @@ #ifdef CONFIG_PMAC_PBOOK -#include <asm/feature.h> +#include <asm/machdep.h> +#include <asm/pmac_feature.h> #include <asm/pci-bridge.h> #ifndef CONFIG_PM #define CONFIG_PM @@ -1905,7 +1906,7 @@ struct usb_device * usb_dev = urb->dev; ohci_t * ohci = usb_dev->bus->hcpriv; unsigned int pipe = urb->pipe; - devrequest * cmd = (devrequest *) urb->setup_packet; + struct usb_ctrlrequest * cmd = (struct usb_ctrlrequest *) urb->setup_packet; void * data = urb->transfer_buffer; int leni = urb->transfer_buffer_length; int len = 0; @@ -1929,10 +1930,10 @@ 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); + bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8); + wValue = le16_to_cpu (cmd->wValue); + wIndex = le16_to_cpu (cmd->wIndex); + wLength = le16_to_cpu (cmd->wLength); switch (bmRType_bReq) { /* Request Destination: @@ -2699,12 +2700,12 @@ pci_write_config_word (dev, PCI_COMMAND, cmd); #ifdef CONFIG_PMAC_PBOOK { - struct device_node *of_node; + struct device_node *of_node; - /* Disable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (ohci->ohci_dev); - if (of_node && _machine == _MACH_Pmac) - feature_set_usb_power (of_node, 0); + /* Disable USB PAD & cell clock */ + of_node = pci_device_to_OF_node (ohci->ohci_dev); + if (of_node) + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); } #endif return 0; @@ -2729,12 +2730,12 @@ #ifdef CONFIG_PMAC_PBOOK { - struct device_node *of_node; + struct device_node *of_node; - /* Re-enable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (ohci->ohci_dev); - if (of_node && _machine == _MACH_Pmac) - feature_set_usb_power (of_node, 1); + /* Re-enable USB PAD & cell clock */ + of_node = pci_device_to_OF_node (ohci->ohci_dev); + if (of_node) + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1); } #endif @@ -2860,7 +2861,7 @@ id_table: &ohci_pci_ids [0], probe: ohci_pci_probe, - remove: ohci_pci_remove, + remove: __devexit_p(ohci_pci_remove), #ifdef CONFIG_PM suspend: ohci_pci_suspend, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/usb-skeleton.c linux-2.5/drivers/usb/usb-skeleton.c --- linux-2.5.1/drivers/usb/usb-skeleton.c Mon Nov 12 17:53:56 2001 +++ linux-2.5/drivers/usb/usb-skeleton.c Tue Jan 8 00:44:24 2002 @@ -138,9 +138,37 @@ /* lock to protect the minor_table structure */ static DECLARE_MUTEX (minor_table_mutex); -/* file operations needed when we register this driver */ +/* + * File operations needed when we register this driver. + * This assumes that this driver NEEDS file operations, + * of course, which means that the driver is expected + * to have a node in the /dev directory. If the USB + * device were for a network interface then the driver + * would use "struct net_driver" instead, and a serial + * device would use "struct tty_driver". + */ static struct file_operations skel_fops = { + /* + * The owner field is part of the module-locking + * mechanism. The idea is that the kernel knows + * which module to increment the use-counter of + * BEFORE it calls the device's open() function. + * This also means that the kernel can decrement + * the use-counter again before calling release() + * or should the open() function fail. + * + * Not all device structures have an "owner" field + * yet. "struct file_operations" and "struct net_device" + * do, while "struct tty_driver" does not. If the struct + * has an "owner" field, then initialize it to the value + * THIS_MODULE and the kernel will handle all module + * locking for you automatically. Otherwise, you must + * increment the use-counter in the open() function + * and decrement it again in the release() function + * yourself. + */ owner: THIS_MODULE, + read: skel_read, write: skel_write, ioctl: skel_ioctl, @@ -215,7 +243,11 @@ return -ENODEV; } - /* increment our usage count for the module */ + /* Increment our usage count for the module. + * This is redundant here, because "struct file_operations" + * has an "owner" field. This line is included here soley as + * a reference for drivers using lesser structures... ;-) + */ MOD_INC_USE_COUNT; /* lock our minor table and get our local data for this minor */ @@ -278,8 +310,8 @@ /* the device was unplugged before the file was released */ up (&dev->sem); skel_delete (dev); - MOD_DEC_USE_COUNT; up (&minor_table_mutex); + MOD_DEC_USE_COUNT; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/usb-uhci.c linux-2.5/drivers/usb/usb-uhci.c --- linux-2.5.1/drivers/usb/usb-uhci.c Fri Nov 9 21:41:42 2001 +++ linux-2.5/drivers/usb/usb-uhci.c Tue Jan 8 00:44:24 2002 @@ -1085,7 +1085,7 @@ { if (urb_priv->setup_packet_dma) pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma, - sizeof(devrequest), PCI_DMA_TODEVICE); + sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE); if (urb_priv->transfer_buffer_dma) pci_dma_sync_single(s->uhci_pci, urb_priv->transfer_buffer_dma, @@ -1099,7 +1099,7 @@ { if (urb_priv->setup_packet_dma) { pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma, - sizeof(devrequest), PCI_DMA_TODEVICE); + sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE); urb_priv->setup_packet_dma = 0; } if (urb_priv->transfer_buffer_dma) { @@ -1678,7 +1678,7 @@ if (type == PIPE_CONTROL) urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet, - sizeof(devrequest), PCI_DMA_TODEVICE); + sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE); if (urb->transfer_buffer_length) urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci, @@ -1963,7 +1963,7 @@ struct usb_device *usb_dev = urb->dev; uhci_t *uhci = usb_dev->bus->hcpriv; unsigned int pipe = urb->pipe; - devrequest *cmd = (devrequest *) urb->setup_packet; + struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; void *data = urb->transfer_buffer; int leni = urb->transfer_buffer_length; int len = 0; @@ -1989,10 +1989,10 @@ } - 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); + bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8; + wValue = le16_to_cpu (cmd->wValue); + wIndex = le16_to_cpu (cmd->wIndex); + wLength = le16_to_cpu (cmd->wLength); for (i = 0; i < 8; i++) uhci->rh.c_p_r[i] = 0; @@ -2845,7 +2845,7 @@ s->running = 1; } -_static void __devexit +_static void uhci_pci_remove (struct pci_dev *dev) { uhci_t *s = pci_get_drvdata(dev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/usb.c linux-2.5/drivers/usb/usb.c --- linux-2.5.1/drivers/usb/usb.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/usb.c Tue Jan 8 00:44:24 2002 @@ -97,6 +97,8 @@ usb_scan_devices(); + usbfs_update_special(); + return 0; } @@ -148,9 +150,13 @@ struct usb_interface *interface = &dev->actconfig->interface[i]; if (interface->driver == driver) { + if (driver->owner) + __MOD_INC_USE_COUNT(driver->owner); down(&driver->serialize); driver->disconnect(dev, interface->private_data); up(&driver->serialize); + if (driver->owner) + __MOD_DEC_USE_COUNT(driver->owner); /* if driver->disconnect didn't release the interface */ if (interface->driver) usb_driver_release_interface(driver, interface); @@ -192,6 +198,8 @@ usb_drivers_purge(driver, bus->root_hub); } up (&usb_bus_list_lock); + + usbfs_update_special(); } /** @@ -421,7 +429,6 @@ bus->bandwidth_isoc_reqs = 0; INIT_LIST_HEAD(&bus->bus_list); - INIT_LIST_HEAD(&bus->inodes); atomic_set(&bus->refcnt, 1); @@ -468,7 +475,7 @@ list_add(&bus->bus_list, &usb_bus_list); up (&usb_bus_list_lock); - usbdevfs_add_bus(bus); + usbfs_add_bus(bus); info("new USB bus registered, assigned bus number %d", bus->busnum); } @@ -494,7 +501,7 @@ list_del(&bus->bus_list); up (&usb_bus_list_lock); - usbdevfs_remove_bus(bus); + usbfs_remove_bus(bus); clear_bit(bus->busnum, busmap.busmap); @@ -778,6 +785,8 @@ driver = list_entry(tmp, struct usb_driver, driver_list); tmp = tmp->next; + if (driver->owner) + __MOD_INC_USE_COUNT(driver->owner); id = driver->id_table; /* new style driver? */ if (id) { @@ -801,6 +810,8 @@ private = driver->probe(dev, ifnum, NULL); up(&driver->serialize); } + if (driver->owner) + __MOD_DEC_USE_COUNT(driver->owner); /* probe() may have changed the config on us */ interface = dev->actconfig->interface + ifnum; @@ -923,7 +934,7 @@ /* a simple/common case: one config, one interface, one driver * with current altsetting being a reasonable setting. - * everything needs a smart agent and usbdevfs; or can rely on + * everything needs a smart agent and usbfs; or can rely on * device-specific binding policies. */ envp [i++] = scratch; @@ -1013,10 +1024,11 @@ usb_bus_get(bus); + if (!parent) + dev->devpath [0] = '/'; dev->bus = bus; dev->parent = parent; atomic_set(&dev->refcnt, 1); - INIT_LIST_HEAD(&dev->inodes); INIT_LIST_HEAD(&dev->filelist); init_MUTEX(&dev->serialize); @@ -1275,7 +1287,7 @@ /*-------------------------------------------------------------------*/ // returns status (negative) or length (positive) int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, - devrequest *cmd, void *data, int len, int timeout) + struct usb_ctrlrequest *cmd, void *data, int len, int timeout) { urb_t *urb; int retv; @@ -1319,17 +1331,17 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout) { - devrequest *dr = kmalloc(sizeof(devrequest), GFP_KERNEL); + struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); int ret; if (!dr) return -ENOMEM; - dr->requesttype = requesttype; - dr->request = request; - dr->value = cpu_to_le16p(&value); - dr->index = cpu_to_le16p(&index); - dr->length = cpu_to_le16p(&size); + dr->bRequestType= requesttype; + dr->bRequest = request; + dr->wValue = cpu_to_le16p(&value); + dr->wIndex = cpu_to_le16p(&index); + dr->wLength = cpu_to_le16p(&size); //dbg("usb_control_msg"); @@ -1523,6 +1535,9 @@ } ifp = interface->altsetting + interface->num_altsetting; + ifp->endpoint = NULL; + ifp->extra = NULL; + ifp->extralen = 0; interface->num_altsetting++; memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE); @@ -1564,10 +1579,7 @@ /* Copy any unknown descriptors into a storage area for */ /* drivers to later parse */ len = (int)(buffer - begin); - if (!len) { - ifp->extra = NULL; - ifp->extralen = 0; - } else { + if (len) { ifp->extra = kmalloc(len, GFP_KERNEL); if (!ifp->extra) { @@ -1883,9 +1895,13 @@ struct usb_interface *interface = &dev->actconfig->interface[i]; struct usb_driver *driver = interface->driver; if (driver) { + if (driver->owner) + __MOD_INC_USE_COUNT(driver->owner); down(&driver->serialize); driver->disconnect(dev, interface->private_data); up(&driver->serialize); + if (driver->owner) + __MOD_DEC_USE_COUNT(driver->owner); /* if driver->disconnect didn't release the interface */ if (interface->driver) usb_driver_release_interface(driver, interface); @@ -1906,7 +1922,7 @@ /* Free the device number and remove the /proc/bus/usb entry */ if (dev->devnum > 0) { clear_bit(dev->devnum, &dev->bus->devmap.devicemap); - usbdevfs_remove_device(dev); + usbfs_remove_device(dev); } /* Free up the device itself */ @@ -2579,7 +2595,7 @@ #endif /* now that the basic setup is over, add a /proc/bus/usb entry */ - usbdevfs_add_device(dev); + usbfs_add_device(dev); /* find drivers willing to handle this device */ usb_find_drivers(dev); @@ -2592,7 +2608,7 @@ static int usb_open(struct inode * inode, struct file * file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); struct usb_driver *c = usb_minors[minor/16]; int err = -ENODEV; struct file_operations *old_fops, *new_fops = NULL; @@ -2660,7 +2676,7 @@ { init_MUTEX(&usb_bus_list_lock); usb_major_init(); - usbdevfs_init(); + usbfs_init(); usb_hub_init(); return 0; @@ -2672,7 +2688,7 @@ static void __exit usb_exit(void) { usb_major_cleanup(); - usbdevfs_cleanup(); + usbfs_cleanup(); usb_hub_cleanup(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/usbkbd.c linux-2.5/drivers/usb/usbkbd.c --- linux-2.5.1/drivers/usb/usbkbd.c Sun Dec 9 04:28:45 2001 +++ linux-2.5/drivers/usb/usbkbd.c Tue Jan 8 00:44:24 2002 @@ -74,7 +74,7 @@ unsigned char new[8]; unsigned char old[8]; struct urb irq, led; - devrequest dr; + struct usb_ctrlrequest dr; unsigned char leds, newleds; char name[128]; int open; @@ -218,11 +218,11 @@ FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, usb_kbd_irq, kbd, endpoint->bInterval); - kbd->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; - kbd->dr.request = HID_REQ_SET_REPORT; - kbd->dr.value = 0x200; - kbd->dr.index = interface->bInterfaceNumber; - kbd->dr.length = 1; + kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kbd->dr.bRequest = HID_REQ_SET_REPORT; + kbd->dr.wValue = 0x200; + kbd->dr.wIndex = interface->bInterfaceNumber; + kbd->dr.wLength = 1; kbd->dev.name = kbd->name; kbd->dev.idbus = BUS_USB; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/usbnet.c linux-2.5/drivers/usb/usbnet.c --- linux-2.5.1/drivers/usb/usbnet.c Sun Dec 9 04:25:02 2001 +++ linux-2.5/drivers/usb/usbnet.c Sat Jan 5 16:38:08 2002 @@ -1571,13 +1571,13 @@ struct urb *urb = 0; struct skb_data *entry; struct driver_info *info = dev->driver_info; - int flags; + unsigned long flags; #ifdef CONFIG_USB_NET1080 struct nc_header *header = 0; struct nc_trailer *trailer = 0; #endif /* CONFIG_USB_NET1080 */ - flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL; + flags = in_interrupt () ? GFP_ATOMIC : GFP_NOIO; /* might be used for nfs */ // some devices want funky USB-level framing, for // win32 driver (usually) and/or hardware quirks diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/vicam.c linux-2.5/drivers/usb/vicam.c --- linux-2.5.1/drivers/usb/vicam.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/vicam.c Thu Jan 3 23:04:40 2002 @@ -0,0 +1,986 @@ +/* -*- linux-c -*- + * USB ViCAM driver + * + * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx) + * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the 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 driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB + * + * Thanks to Greg Kroah-Hartman for the USB Skeleton driver + * + * TODO: + * - find out the ids for the Vista Imaging ViCAM + * + * History: + * + * 2001_07_07 - 0.1 - christopher: first version + * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try + while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done + yep, moving pictures. + * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun, + get gqcam-0.9, compile it and run. Better than dd ;-). + * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional) + kill update_params if it does not seem to work for you. + * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk + + * + * FIXME: It crashes on rmmod with camera plugged. + */ +#define DEBUG 1 + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/fcntl.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/smp_lock.h> +#include <linux/devfs_fs_kernel.h> +#include <linux/usb.h> + +#include <asm/io.h> +#include <linux/wrapper.h> +#include <linux/vmalloc.h> + +#include <linux/videodev.h> + +#include "vicam.h" +#include "vicamurbs.h" + +/* Version Information */ +#define DRIVER_VERSION "v0" +#define DRIVER_AUTHOR "Christopher L Cheney <ccheney@cheney.cx>, Pavel Machek <pavel@suse.cz>" +#define DRIVER_DESC "USB ViCAM Driver" + +/* Define these values to match your device */ +#define USB_VICAM_VENDOR_ID 0x04C1 +#define USB_VICAM_PRODUCT_ID 0x009D + +/* table of devices that work with this driver */ +static struct usb_device_id vicam_table [] = { + { USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, vicam_table); + +static int video_nr = -1; /* next avail video device */ +static struct usb_driver vicam_driver; + +static char *buf, *buf2; +static int change_pending = 0; + +static int vicam_parameters(struct usb_vicam *vicam); + +/****************************************************************************** + * + * Memory management functions + * + * Taken from bttv-drivers.c 2.4.7-pre3 + * + ******************************************************************************/ + +/* [DaveM] I've recoded most of this so that: + * 1) It's easier to tell what is happening + * 2) It's more portable, especially for translating things + * out of vmalloc mapped areas in the kernel. + * 3) Less unnecessary translations happen. + * + * The code used to assume that the kernel vmalloc mappings + * existed in the page tables of every process, this is simply + * not guarenteed. We now use pgd_offset_k which is the + * defined way to get at the kernel page tables. + */ + +/* 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)); + + } + } + } + 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); + 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); + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + return ret; +} + +static void * rvmalloc(signed long size) +{ + void * mem; + unsigned long adr, page; + + mem=vmalloc_32(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, signed 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); + } +} + +/****************************************************************************** + * + * Foo Bar + * + ******************************************************************************/ + +/** + * usb_vicam_debug_data + */ +static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data) +{ + int i; + + if (!debug) + return; + + printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", + function, size); + for (i = 0; i < size; ++i) { + printk ("%.2x ", data[i]); + } + printk ("\n"); +} + +/***************************************************************************** + * + * Send command to vicam + * + *****************************************************************************/ + +static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req, + unsigned short value, unsigned char *cp, int size) +{ + int ret; + unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL); + + /* Needs to return data I think, works for sending though */ + memcpy(transfer_buffer, cp, size); + + ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ); + + kfree(transfer_buffer); + if (ret) + printk("vicam: error: %d\n", ret); + mdelay(100); + return ret; +} + + +/***************************************************************************** + * + * Video4Linux Helpers + * + *****************************************************************************/ + +static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b) +{ + dbg("vicam_get_capability"); + + strcpy(b->name, vicam->camera_name); + b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME; + b->channels = 1; + b->audios = 0; + + b->maxwidth = vicam->width[vicam->sizes-1]; + b->maxheight = vicam->height[vicam->sizes-1]; + b->minwidth = vicam->width[0]; + b->minheight = vicam->height[0]; + + return 0; +} + +static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v) +{ + dbg("vicam_get_channel"); + + if (v->channel != 0) + return -EINVAL; + + v->flags = 0; + v->tuners = 0; + v->type = VIDEO_TYPE_CAMERA; + strcpy(v->name, "Camera"); + + return 0; +} + +static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v) +{ + dbg("vicam_set_channel"); + + if (v->channel != 0) + return -EINVAL; + + return 0; +} + +static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm) +{ + int i; + + dbg("vicam_get_mmapbuffer"); + + memset(vm, 0, sizeof(vm)); + vm->size = VICAM_NUMFRAMES * vicam->maxframesize; + vm->frames = VICAM_NUMFRAMES; + + for (i=0; i<VICAM_NUMFRAMES; i++) + vm->offsets[i] = vicam->maxframesize * i; + + return 0; +} + +static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p) +{ + dbg("vicam_get_picture"); + + /* This is probably where that weird 0x56 call goes */ + p->brightness = vicam->win.brightness; + p->hue = vicam->win.hue; + p->colour = vicam->win.colour; + p->contrast = vicam->win.contrast; + p->whiteness = vicam->win.whiteness; + p->depth = vicam->win.depth; + p->palette = vicam->win.palette; + + return 0; +} + +static void synchronize(struct usb_vicam *vicam) +{ + change_pending = 1; + interruptible_sleep_on(&vicam->wait); + vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); + mdelay(10); + vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); + mdelay(10); +} + +static void params_changed(struct usb_vicam *vicam) +{ +#if 1 + synchronize(vicam); + mdelay(10); + vicam_parameters(vicam); + printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb)); +#endif +} + +static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p) +{ + int changed = 0; + info("vicam_set_picture (%d)", p->brightness); + + +#define SET(x) \ + if (vicam->win.x != p->x) \ + vicam->win.x = p->x, changed = 1; + SET(brightness); + SET(hue); + SET(colour); + SET(contrast); + SET(whiteness); + SET(depth); + SET(palette); + if (changed) + params_changed(vicam); + + return 0; + /* Investigate what should be done maybe 0x56 type call */ + if (p->depth != 8) return 1; + if (p->palette != VIDEO_PALETTE_GREY) return 1; + + return 0; +} + +/* FIXME - vicam_sync_frame - important */ +static int vicam_sync_frame(struct usb_vicam *vicam, int frame) +{ + dbg("vicam_sync_frame"); + + if(frame <0 || frame >= VICAM_NUMFRAMES) + return -EINVAL; + + /* Probably need to handle various cases */ +/* ret=vicam_newframe(vicam, frame); + vicam->frame[frame].grabstate=FRAME_UNUSED; +*/ + return 0; +} + +static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw) +{ + dbg("vicam_get_window"); + + vw->x = 0; + vw->y = 0; + vw->chromakey = 0; + vw->flags = 0; + vw->clipcount = 0; + vw->width = vicam->win.width; + vw->height = vicam->win.height; + + return 0; +} + +static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw) +{ + info("vicam_set_window"); + + if (vw->flags) + return -EINVAL; + if (vw->clipcount) + return -EINVAL; + + if (vicam->win.width == vw->width && vicam->win.height == vw->height) + return 0; + + /* Pick largest mode that is smaller than specified res */ + /* If specified res is too small reject */ + + /* Add urb send to device... */ + + vicam->win.width = vw->width; + vicam->win.height = vw->height; + params_changed(vicam); + + return 0; +} + +/* FIXME - vicam_mmap_capture - important */ +static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm) +{ + dbg("vicam_mmap_capture"); + + /* usbvideo.c looks good for using here */ + + /* + if (vm->frame >= VICAM_NUMFRAMES) + return -EINVAL; + if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED) + return -EBUSY; + vicam->frame[vm->frame].grabstate=FRAME_READY; + */ + + /* No need to vicam_set_window here according to Alan */ + + /* + if (!vicam->streaming) + vicam_start_stream(vicam); + */ + + /* set frame as ready */ + + return 0; +} + +/***************************************************************************** + * + * Video4Linux + * + *****************************************************************************/ + +static int vicam_v4l_open(struct video_device *vdev, int flags) +{ + struct usb_vicam *vicam = (struct usb_vicam *)vdev; + int err = 0; + + dbg("vicam_v4l_open"); + + MOD_INC_USE_COUNT; + down(&vicam->sem); + + if (vicam->open_count) /* Maybe not needed? */ + err = -EBUSY; + else { + vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES); + if (!vicam->fbuf) + err=-ENOMEM; + else { + vicam->open_count = 1; + } +#ifdef BLINKING + vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); + info ("led on"); + vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); +#endif + } + + up(&vicam->sem); + if (err) + MOD_DEC_USE_COUNT; + return err; +} + +static void vicam_v4l_close(struct video_device *vdev) +{ + struct usb_vicam *vicam = (struct usb_vicam *)vdev; + + dbg("vicam_v4l_close"); + + down(&vicam->sem); + +#ifdef BLINKING + info ("led off"); + vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); +// vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on +#endif + + rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES); + vicam->fbuf = 0; + vicam->open_count=0; + + up(&vicam->sem); + /* Why does se401.c have a usbdevice check here? */ + /* If device is unplugged while open, I guess we only may unregister now */ + MOD_DEC_USE_COUNT; +} + +static long vicam_v4l_read(struct video_device *vdev, char *user_buf, unsigned long buflen, int noblock) +{ + //struct usb_vicam *vicam = (struct usb_vicam *)vdev; + + dbg("vicam_v4l_read(%ld)", buflen); + + if (!vdev || !buf) + return -EFAULT; + + if (copy_to_user(user_buf, buf2, buflen)) + return -EFAULT; + return buflen; +} + +static long vicam_v4l_write(struct video_device *dev, const char *buf, unsigned long count, int noblock) +{ + info("vicam_v4l_write"); + return -EINVAL; +} + +static int vicam_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +{ + struct usb_vicam *vicam = (struct usb_vicam *)vdev; + int ret = -EL3RST; + + if (!vicam->udev) + return -EIO; + + down(&vicam->sem); + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + ret = vicam_get_capability(vicam,&b); + dbg("name %s",b.name); + if (copy_to_user(arg, &b, sizeof(b))) + ret = -EFAULT; + } + case VIDIOCGFBUF: + { + struct video_buffer vb; + info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param"); + /* frame buffer not supported, not used */ + memset(&vb, 0, sizeof(vb)); + vb.base = NULL; + + /* FIXME - VIDIOCGFBUF - why the void */ + if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) + ret = -EFAULT; + ret = 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + ret = vicam_get_window(vicam, &vw); + if (copy_to_user(arg, &vw, sizeof(vw))) + ret = -EFAULT; + } + case VIDIOCSWIN: + { + struct video_window vw; + if (copy_from_user(&vw, arg, sizeof(vw))) + ret = -EFAULT; + else + ret = vicam_set_window(vicam, &vw); + return ret; + } + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) + ret = -EFAULT; + else { + ret = vicam_get_channel(vicam,&v); + if (copy_to_user(arg, &v, sizeof(v))) + ret = -EFAULT; + } + } + case VIDIOCSCHAN: + { + struct video_channel v; + if (copy_from_user(&v, arg, sizeof(v))) + ret = -EFAULT; + else + ret = vicam_set_channel(vicam,&v); + } + case VIDIOCGPICT: + { + struct video_picture p; + ret = vicam_get_picture(vicam, &p); + if (copy_to_user(arg, &p, sizeof(p))) + ret = -EFAULT; + } + case VIDIOCSPICT: + { + struct video_picture p; + if (copy_from_user(&p, arg, sizeof(p))) + ret = -EFAULT; + else + ret = vicam_set_picture(vicam, &p); + } + case VIDIOCGMBUF: + { + struct video_mbuf vm; + ret = vicam_get_mmapbuffer(vicam,&vm); + /* FIXME - VIDIOCGMBUF - why the void */ + if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + ret = -EFAULT; + } + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + ret = vicam_mmap_capture(vicam, &vm); + /* FIXME: This is probably not right */ + } + case VIDIOCSYNC: + { + int frame; + /* FIXME - VIDIOCSYNC - why the void */ + if (copy_from_user((void *)&frame, arg, sizeof(int))) + ret = -EFAULT; + else + ret = vicam_sync_frame(vicam,frame); + } + + case VIDIOCKEY: + ret = 0; + + case VIDIOCCAPTURE: + case VIDIOCSFBUF: + case VIDIOCGTUNER: + case VIDIOCSTUNER: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + case VIDIOCGUNIT: + ret = -EINVAL; + + default: + { + info("vicam_v4l_ioctl - %ui",cmd); + ret = -ENOIOCTLCMD; + } + } /* end switch */ + + up(&vicam->sem); + return ret; +} + +static int vicam_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct usb_vicam *vicam = (struct usb_vicam *)dev; + unsigned long start = (unsigned long)adr; + unsigned long page, pos; + + down(&vicam->sem); + + if (vicam->udev == NULL) { + up(&vicam->sem); + return -EIO; + } +#if 0 + if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { + up(&vicam->sem); + return -EINVAL; + } +#endif + pos = (unsigned long)vicam->fbuf; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { + up(&vicam->sem); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + up(&vicam->sem); + + return 0; +} + +/* FIXME - vicam_v4l_init */ +static int vicam_v4l_init(struct video_device *dev) +{ + /* stick proc fs stuff in here if wanted */ + dbg("vicam_v4l_init"); + return 0; +} + +/* FIXME - vicam_template - important */ +static struct video_device vicam_template = { + name: "vicam USB camera", + type: VID_TYPE_CAPTURE, + hardware: VID_HARDWARE_SE401, /* need to ask for own id */ + open: vicam_v4l_open, + close: vicam_v4l_close, + read: vicam_v4l_read, + write: vicam_v4l_write, + ioctl: vicam_v4l_ioctl, + mmap: vicam_v4l_mmap, + initialize: vicam_v4l_init, +}; + +/****************************************************************************** + * + * Some Routines + * + ******************************************************************************/ + +/* +Flash the led +vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); +info ("led on"); +vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); +info ("led off"); +vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); +vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); +*/ + +static void vicam_bulk(struct urb *urb) +{ + struct usb_vicam *vicam = urb->context; + + /* if (!vicam || !vicam->dev || !vicam->used) + return; + */ + + if (urb->status) + printk("vicam%d: nonzero read/write bulk status received: %d", + 0, urb->status); + + urb->actual_length = 0; + urb->dev = vicam->udev; + + memcpy(buf2, buf+64, 0x1e480); + if (vicam->fbuf) + memcpy(vicam->fbuf, buf+64, 0x1e480); + + if (!change_pending) { + if (usb_submit_urb(urb)) + dbg("failed resubmitting read urb"); + } else { + change_pending = 0; + wake_up_interruptible(&vicam->wait); + } +} + +static int vicam_parameters(struct usb_vicam *vicam) +{ + unsigned char req[0x10]; + unsigned int shutter; + shutter = 10; + + switch (vicam->win.width) { + case 512: + default: + memcpy(req, s512x242bw, 0x10); + break; + case 256: + memcpy(req, s256x242bw, 0x10); + break; + case 128: + memcpy(req, s128x122bw, 0x10); + break; + } + + + mdelay(10); + vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); + info ("led on"); + vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); + + mdelay(10); + + shutter = vicam->win.contrast / 256; + if (shutter == 0) + shutter = 1; + printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter ); + req[0] = vicam->win.brightness /256; + shutter = 15600/shutter - 1; + req[6] = shutter & 0xff; + req[7] = (shutter >> 8) & 0xff; + vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10); + mdelay(10); + vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10); + mdelay(10); + + return 0; +} + +static int vicam_init(struct usb_vicam *vicam) +{ + int width[] = {128, 256, 512}; + int height[] = {122, 242, 242}; + + dbg("vicam_init"); + buf = kmalloc(0x1e480, GFP_KERNEL); + buf2 = kmalloc(0x1e480, GFP_KERNEL); + if ((!buf) || (!buf2)) { + printk("Not enough memory for vicam!\n"); + goto error; + } + + /* do we do aspect correction in kernel or not? */ + vicam->sizes = 3; + vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL); + vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL); + memcpy(vicam->width, &width, sizeof(width)); + memcpy(vicam->height, &height, sizeof(height)); + vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1]; + + /* Download firmware to camera */ + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1)); + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1)); + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup)); + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2)); + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2)); + vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup)); + + vicam_parameters(vicam); + + FILL_BULK_URB(&vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81), + buf, 0x1e480, vicam_bulk, vicam); + printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb)); + + return 0; +error: + if (buf) + kfree(buf); + if (buf2) + kfree(buf2); + return 1; +} + +static void * __devinit vicam_probe(struct usb_device *udev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_vicam *vicam; + char *camera_name=NULL; + + dbg("vicam_probe"); + + /* See if the device offered us matches what we can accept */ + if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) || + (udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) { + return NULL; + } + + camera_name="3Com HomeConnect USB"; + info("ViCAM camera found: %s", camera_name); + + vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL); + if (vicam == NULL) { + err ("couldn't kmalloc vicam struct"); + return NULL; + } + memset(vicam, 0, sizeof(*vicam)); + + vicam->udev = udev; + vicam->camera_name = camera_name; + vicam->win.brightness = 128; + vicam->win.contrast = 10; + + /* FIXME */ + if (vicam_init(vicam)) + return NULL; + memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template)); + memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name)); + + if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + err("video_register_device"); + return NULL; + } + + info("registered new video device: video%d", vicam->vdev.minor); + + init_MUTEX (&vicam->sem); + init_waitqueue_head(&vicam->wait); + + return vicam; +} + + +/* FIXME - vicam_disconnect - important */ +static void vicam_disconnect(struct usb_device *udev, void *ptr) +{ + struct usb_vicam *vicam; + + vicam = (struct usb_vicam *) ptr; + + if (!vicam->open_count) + video_unregister_device(&vicam->vdev); + vicam->udev = NULL; +/* + vicam->frame[0].grabstate = FRAME_ERROR; + vicam->frame[1].grabstate = FRAME_ERROR; +*/ + + /* Free buffers and shit */ + + info("%s disconnected", vicam->camera_name); + synchronize(vicam); + + if (!vicam->open_count) { + /* Other random junk */ + kfree(vicam); + vicam = NULL; + } +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver vicam_driver = { + name: "vicam", + probe: vicam_probe, + disconnect: vicam_disconnect, + id_table: vicam_table, +}; + +/****************************************************************************** + * + * Module Routines + * + ******************************************************************************/ + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* Module paramaters */ +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +static int __init usb_vicam_init(void) +{ + int result; + + printk("VICAM: initializing\n"); + /* register this driver with the USB subsystem */ + result = usb_register(&vicam_driver); + if (result < 0) { + err("usb_register failed for the "__FILE__" driver. Error number %d", + result); + return -1; + } + + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; +} + +static void __exit usb_vicam_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&vicam_driver); +} + +module_init(usb_vicam_init); +module_exit(usb_vicam_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/vicam.h linux-2.5/drivers/usb/vicam.h --- linux-2.5.1/drivers/usb/vicam.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/vicam.h Thu Jan 3 23:04:40 2002 @@ -0,0 +1,81 @@ +/* + * + * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver + * Christopher L Cheney (C) 2001 + * + */ + +#ifndef __LINUX_VICAM_H +#define __LINUX_VICAM_H + + +#ifdef CONFIG_USB_DEBUG + static int debug = 1; +#else + static int debug; +#endif + +/* Use our own dbg macro */ +#undef dbg +#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) + +#define VICAM_NUMFRAMES 30 +#define VICAM_NUMSBUF 1 + +/* USB REQUEST NUMBERS */ +#define VICAM_REQ_VENDOR 0xff +#define VICAM_REQ_CAMERA_POWER 0x50 +#define VICAM_REQ_CAPTURE 0x51 +#define VICAM_REQ_LED_CONTROL 0x55 +#define VICAM_REQ_GET_SOMETHIN 0x56 + +/* not required but lets you know camera is on */ +/* camera must be on to turn on led */ +/* 0x01 always on 0x03 on when picture taken (flashes) */ + +struct picture_parm +{ + int width; + int height; + int brightness; + int hue; + int colour; + int contrast; + int whiteness; + int depth; + int palette; +}; + +struct vicam_scratch { + unsigned char *data; + volatile int state; + int offset; + int length; +}; + +/* Structure to hold all of our device specific stuff */ +struct usb_vicam +{ + struct video_device vdev; + struct usb_device *udev; + + int open_count; /* number of times this port has been opened */ + struct semaphore sem; /* locks this structure */ + wait_queue_head_t wait; /* Processes waiting */ + + int streaming; + + /* v4l stuff */ + char *camera_name; + char *fbuf; + urb_t *urb[VICAM_NUMSBUF]; + int sizes; + int *width; + int *height; + int maxframesize; + struct picture_parm win; + struct proc_dir_entry *proc_entry; /* /proc/se401/videoX */ + struct urb readurb; +}; + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/usb/vicamurbs.h linux-2.5/drivers/usb/vicamurbs.h --- linux-2.5.1/drivers/usb/vicamurbs.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/vicamurbs.h Thu Jan 3 23:04:40 2002 @@ -0,0 +1,330 @@ +/* + * + * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver + * Christopher L Cheney (C) 2001 + * + */ + + +#ifndef __LINUX_VICAMURBS_H +#define __LINUX_VICAMURBS_H + +/* -------------------------------------------------------------------------- */ + +/* FIXME - Figure out transfers so that this doesn't need to be here + * + * Notice: in pieces below, "0" means other code will fill it while "0x00" means this is zero */ + +/* Request 0x51 Image Setup */ + +/* 128x98 ? 0x3180 size */ +static unsigned char s128x98bw[] = { + 0, 0x34, 0xC4, 0x00, 0x00, 0x00, 0, 0, + 0x18, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 +}; + +/* 128x122 3D80 size */ +static unsigned char s128x122bw[] = { + 0, 0x34, 0xF4, 0x00, 0x00, 0x00, 0, 0, + 0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 +}; + +/* 256x242 ? 0xF280 size */ +static unsigned char s256x242bw[] = { + 0, 0x03, 0xC8, 0x03, 0x00, 0x00, 0, 0, + 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 +}; + +/* 512x242 0x1E480 size */ +static unsigned char s512x242bw[] = { + 0, 0x05, 0x90, 0x07, 0x00, 0x00, 0, 0, + 0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 +}; + +/* In s512x242: + byte 0: gain -- higher number means brighter image + byte 6, 7: shutter speed, little-endian; set this to 15600 * (shutter speed) - 1. (Where shutter speed is something like 1/1000). +*/ + +/* -------------------------------------------------------------------------- */ + +static unsigned char fsetup[] = { + 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, + + 0x00, 0x00 +}; + +static unsigned char firmware1[] = { + 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, + + 0xE7, 0x67, 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, + 0xDE, 0x00, 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, + 0xC0, 0x17, 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, + 0x00, 0x00, 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 +}; + +static unsigned char findex1[] = { + 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, + + 0x18, 0x00, 0x00, 0x00 +}; + +static unsigned char firmware2[] = { + 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, + + 0xE7, 0x07, 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, + 0x00, 0x00, 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, + 0xAA, 0x00, 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, + 0xE7, 0x07, 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, + 0x7C, 0x00, 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, + 0x18, 0x00, 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, + 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, + 0xFF, 0xFF, 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, + 0x24, 0xC0, 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, + 0xE7, 0x07, 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, + 0x01, 0x00, 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, + 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, + 0x09, 0xC1, 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, + 0xE7, 0x09, 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, + 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, + 0xC0, 0xDF, 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, + 0x17, 0x02, 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, + 0x01, 0x00, 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, + 0xFF, 0xFF, 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, + 0x00, 0x00, 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, + 0xC6, 0x00, 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, + 0xC1, 0x05, 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, + 0x27, 0xDA, 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, + 0x0B, 0x06, 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, + 0x9F, 0xAF, 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, + 0xFC, 0x05, 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, + 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, + 0xE7, 0x09, 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, + 0x02, 0x06, 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, + 0xFC, 0x05, 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, + 0x27, 0xDA, 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, + 0xFA, 0x05, 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, + 0x9F, 0xAF, 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, + 0x40, 0x00, 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, + 0x9F, 0xAF, 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, + 0x02, 0x00, 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, + 0x9F, 0xA0, 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, + 0x09, 0x06, 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, + 0x01, 0x00, 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, + 0xE7, 0x07, 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, + 0x47, 0xAF, 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, + 0x2E, 0x00, 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, + 0x09, 0x06, 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, + 0xC0, 0x57, 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, + 0xC0, 0x57, 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, + 0x55, 0x00, 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, + 0x9F, 0xC0, 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, + 0xC1, 0x0B, 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, + 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, + 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, + 0x2F, 0x0E, 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, + 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, + 0x28, 0x05, 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, + 0x02, 0x00, 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, + 0x09, 0x06, 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, + 0x7F, 0xFF, 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, + 0x22, 0xC0, 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, + 0xE7, 0x87, 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, + 0xB8, 0x05, 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, + 0x9F, 0xAF, 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, + 0x24, 0xC0, 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, + 0xC8, 0x07, 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, + 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0x9F, 0xAF, 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, + 0x9F, 0xAF, 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, + 0x24, 0xC0, 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, + 0x00, 0x01, 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, + 0x0F, 0xC1, 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, + 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, + 0x08, 0x00, 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, + 0xEF, 0x07, 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, + 0xEF, 0x07, 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, + 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, + 0x00, 0x00, 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, + 0x09, 0x06, 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, + 0xE7, 0x67, 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, + 0x17, 0xD8, 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, + 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, + 0x97, 0xCF, 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, + 0xDA, 0x02, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, + 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, + 0x0E, 0x06, 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, + 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, + 0x00, 0x80, 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, + 0x02, 0x00, 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, + 0x06, 0x06, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, + 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, + 0xE2, 0x05, 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, + 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, + 0x00, 0x80, 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, + 0x66, 0x04, 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, + 0x97, 0xCF, 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, + 0x0C, 0x06, 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, + 0x68, 0x00, 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, + 0x44, 0x05, 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, + 0xE0, 0x07, 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, + 0xE8, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, + 0xE0, 0x07, 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, + 0x97, 0xCF, 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, + 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, + 0x0E, 0x06, 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, + 0xFE, 0x05, 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, + 0xE7, 0x07, 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, + 0x07, 0x00, 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, + 0x02, 0x00, 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, + 0xEF, 0x77, 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, + 0x14, 0x04, 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, + 0x37, 0xC0, 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, + 0x0F, 0xC1, 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, + 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, + 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0xC8, 0x07, 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, + 0xC0, 0x07, 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, + 0xC1, 0x77, 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, + 0x75, 0xC1, 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, + 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, + 0x06, 0x06, 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, + 0xC1, 0x07, 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0xEF, 0x07, 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, + 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, + 0x01, 0x00, 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, + 0x01, 0x00, 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, + 0x30, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, + 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, + 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, + 0x03, 0x00, 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, + 0x08, 0xDA, 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, + 0xC1, 0x07, 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, + 0x06, 0x06, 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, + 0xC1, 0x0B, 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, + 0xE7, 0x09, 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, + 0xFA, 0x05, 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, + 0xE7, 0x07, 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, + 0x40, 0x00, 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, + 0x9F, 0xAF, 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, + 0xE2, 0x05, 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, + 0x23, 0x00, 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, + 0x04, 0x00, 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, + 0xE6, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x07, 0x00, 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, + 0xC1, 0x09, 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, + 0xC1, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x0D, 0x00, 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, + 0x32, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x0F, 0x00, 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, + 0x24, 0xC0, 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, + 0xC0, 0x67, 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, + 0xE7, 0x87, 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, + 0xFF, 0xF9, 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, + 0x72, 0xC1, 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, + 0x97, 0xCF, 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, + 0xFF, 0x00, 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, + 0x24, 0xC0, 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, + 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, + 0x9F, 0xAF, 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, + 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, + 0x40, 0x00, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, + 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, + 0xE7, 0x67, 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, + 0xFF, 0xFE, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, + 0x24, 0xC0, 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, + 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, + 0x40, 0x00, 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, + 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, + 0x24, 0xC0, 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, + 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, + 0xE8, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, + 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, + 0x00, 0xDA, 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, + 0xE7, 0x87, 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, + 0xE7, 0x07, 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, + 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, + 0xE7, 0x07, 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, + 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, + 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, + 0x96, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned char findex2[] = { + 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, + + 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, + 0x26, 0x00, 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, + 0x92, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, + 0xB8, 0x00, 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, + 0xCE, 0x00, 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, + 0xE0, 0x00, 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, + 0xEC, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, + 0x0A, 0x01, 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, + 0x22, 0x01, 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, + 0x36, 0x01, 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, + 0x72, 0x01, 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, + 0x88, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, + 0xA0, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, + 0xB4, 0x01, 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, + 0xF6, 0x01, 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, + 0x3C, 0x02, 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, + 0x56, 0x02, 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, + 0x84, 0x02, 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, + 0x8E, 0x02, 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, + 0xAE, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, + 0xC0, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, + 0xD4, 0x02, 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, + 0xF8, 0x02, 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, + 0x24, 0x03, 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, + 0x3C, 0x03, 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, + 0x58, 0x03, 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, + 0x7A, 0x03, 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, + 0xB2, 0x03, 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, + 0xD4, 0x03, 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, + 0xFC, 0x03, 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, + 0x32, 0x04, 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, + 0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, + 0x54, 0x04, 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, + 0x62, 0x04, 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, + 0x80, 0x04, 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, + 0x9A, 0x04, 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, + 0xB4, 0x04, 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, + 0x2A, 0x05, 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 +}; + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/S3triofb.c linux-2.5/drivers/video/S3triofb.c --- linux-2.5.1/drivers/video/S3triofb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/S3triofb.c Mon Jan 14 23:58:39 2002 @@ -86,9 +86,11 @@ struct fb_info *info); static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); static int s3trio_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info); - +static int s3triofb_blank(int blank, struct fb_info *info); /* * Interface to the low level console driver @@ -97,10 +99,6 @@ int s3triofb_init(void); static int s3triofbcon_switch(int con, struct fb_info *info); static int s3triofbcon_updatevar(int con, struct fb_info *info); -static void s3triofbcon_blank(int blank, struct fb_info *info); -#if 0 -static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con); -#endif /* * Text console acceleration @@ -130,8 +128,6 @@ static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); @@ -142,7 +138,9 @@ fb_set_var: s3trio_set_var, fb_get_cmap: s3trio_get_cmap, fb_set_cmap: s3trio_set_cmap, + fb_setcolreg: s3trio_setcolreg, fb_pan_display: s3trio_pan_display, + fb_blank: s3triofb_blank, }; /* @@ -253,7 +251,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, s3trio_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -554,7 +552,7 @@ strcpy(fb_info.modename, "Trio64 "); strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename)); - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &s3trio_ops; #if 0 fb_info.fbvar_num = 1; @@ -565,7 +563,6 @@ fb_info.changevar = NULL; fb_info.switch_con = &s3triofbcon_switch; fb_info.updatevar = &s3triofbcon_updatevar; - fb_info.blank = &s3triofbcon_blank; #if 0 fb_info.setcmap = &s3triofbcon_setcmap; #endif @@ -621,13 +618,14 @@ * Blank the display. */ -static void s3triofbcon_blank(int blank, struct fb_info *info) +static int s3triofb_blank(int blank, struct fb_info *info) { unsigned char x; mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4); x = mem_in8(s3trio_base+0x1008000 + 0x03c5); mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5); + return 0; } /* @@ -691,10 +689,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, s3trio_setcolreg, &fb_info); + fb_set_cmap(&fb_display[con].cmap, 1, &fb_info); else fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), 1, - s3trio_setcolreg, &fb_info); + &fb_info); } static void Trio_WaitQueue(u_short fifo) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/acornfb.c linux-2.5/drivers/video/acornfb.c --- linux-2.5.1/drivers/video/acornfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/acornfb.c Mon Jan 14 23:58:39 2002 @@ -801,8 +801,7 @@ current_par.palette_size, 0); if (!err) { if (con == current_par.currcon) - err = fb_set_cmap(cmap, kspc, acornfb_setcolreg, - info); + err = fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); @@ -1087,7 +1086,7 @@ else cmap = fb_default_cmap(current_par.palette_size); - fb_set_cmap(cmap, 1, acornfb_setcolreg, info); + fb_set_cmap(cmap, 1, info); } return 0; } @@ -1166,7 +1165,9 @@ fb_set_var: acornfb_set_var, fb_get_cmap: acornfb_get_cmap, fb_set_cmap: acornfb_set_cmap, + fb_setcolreg: acornfb_setcolreg, fb_pan_display: acornfb_pan_display, + fb_blank: acornfb_blank, fb_mmap: acornfb_mmap, }; @@ -1200,7 +1201,7 @@ return 0; } -static void +static int acornfb_blank(int blank, struct fb_info *info) { union palette p; @@ -1232,6 +1233,7 @@ acornfb_palette_write(i, p); } } + return 0; } /* @@ -1318,13 +1320,12 @@ strcpy(fb_info.modename, "Acorn"); strcpy(fb_info.fontname, "Acorn8x8"); - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &acornfb_ops; fb_info.disp = &global_disp; fb_info.changevar = NULL; fb_info.switch_con = acornfb_switch; fb_info.updatevar = acornfb_updatevar; - fb_info.blank = acornfb_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; global_disp.dispsw = &fbcon_dummy; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/amifb.c linux-2.5/drivers/video/amifb.c --- linux-2.5.1/drivers/video/amifb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/amifb.c Mon Jan 14 23:58:39 2002 @@ -1102,6 +1102,10 @@ struct fb_info *info); static int amifb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static void ami_update_display(void); +static int amifb_blank(int blank, struct fb_info *info); static int amifb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info); @@ -1121,7 +1125,6 @@ static void amifb_deinit(void); static int amifbcon_switch(int con, struct fb_info *info); static int amifbcon_updatevar(int con, struct fb_info *info); -static void amifbcon_blank(int blank, struct fb_info *info); /* * Internal routines @@ -1153,8 +1156,6 @@ static int ami_update_par(void); static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void ami_update_display(void); static void ami_init_display(void); static void ami_do_blank(void); @@ -1177,7 +1178,9 @@ fb_set_var: amifb_set_var, fb_get_cmap: amifb_get_cmap, fb_set_cmap: amifb_set_cmap, + fb_setcolreg: amifb_setcolreg, fb_pan_display: amifb_pan_display, + fb_blank: amifb_blank, fb_ioctl: amifb_ioctl, }; @@ -1444,7 +1447,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, ami_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -1730,12 +1733,11 @@ strcpy(fb_info.modename, amifb_name); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &amifb_ops; fb_info.disp = &disp; fb_info.switch_con = &amifbcon_switch; fb_info.updatevar = &amifbcon_updatevar; - fb_info.blank = &amifbcon_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; memset(&var, 0, sizeof(var)); @@ -1844,9 +1846,10 @@ * Blank the display. */ -static void amifbcon_blank(int blank, struct fb_info *info) +static int amifb_blank(int blank, struct fb_info *info) { do_blank = blank ? blank : -1; + return 0; } /* @@ -1858,10 +1861,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, ami_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - 1, ami_setcolreg, info); + 1, info); } static int flash_cursor(void) @@ -2635,8 +2638,8 @@ * entries in the var structure). Return != 0 for invalid regno. */ -static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) { if (IS_AGA) { if (regno > 255) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/atafb.c linux-2.5/drivers/video/atafb.c --- linux-2.5.1/drivers/video/atafb.c Thu Oct 25 07:02:26 2001 +++ linux-2.5/drivers/video/atafb.c Mon Jan 14 23:58:39 2002 @@ -285,13 +285,6 @@ * void (*set_par)( struct atafb_par *par ) * Set the hardware according to 'par'. * - * int (*setcolreg)( unsigned regno, unsigned red, - * unsigned green, unsigned blue, - * unsigned transp, struct fb_info *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. - * * int (*getcolreg)( unsigned regno, unsigned *red, * unsigned *green, unsigned *blue, * unsigned *transp, struct fb_info *info ) @@ -324,9 +317,6 @@ int (*getcolreg)( unsigned regno, unsigned *red, unsigned *green, unsigned *blue, unsigned *transp, struct fb_info *info ); - int (*setcolreg)( unsigned regno, unsigned red, - unsigned green, unsigned blue, - unsigned transp, struct fb_info *info ); void (*set_screen_base)(void *s_base); int (*blank)( int blank_mode ); int (*pan_display)( struct fb_var_screeninfo *var, @@ -2326,7 +2316,7 @@ #ifdef ATAFB_TT static struct fb_hwswitch tt_switch = { tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var, - tt_get_par, tt_set_par, tt_getcolreg, tt_setcolreg, + tt_get_par, tt_set_par, tt_getcolreg, set_screen_base, NULL, pan_display }; #endif @@ -2335,14 +2325,14 @@ static struct fb_hwswitch falcon_switch = { falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var, falcon_get_par, falcon_set_par, falcon_getcolreg, - falcon_setcolreg, set_screen_base, falcon_blank, falcon_pan_display + set_screen_base, falcon_blank, falcon_pan_display }; #endif #ifdef ATAFB_STE static struct fb_hwswitch st_switch = { stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var, - stste_get_par, stste_set_par, stste_getcolreg, stste_setcolreg, + stste_get_par, stste_set_par, stste_getcolreg, stste_set_screen_base, NULL, pan_display }; #endif @@ -2350,7 +2340,7 @@ #ifdef ATAFB_EXT static struct fb_hwswitch ext_switch = { ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var, - ext_get_par, ext_set_par, ext_getcolreg, ext_setcolreg, NULL, NULL, NULL + ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL }; #endif @@ -2418,10 +2408,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - 1, fbhw->setcolreg, info); + 1, info); } static int @@ -2582,7 +2572,7 @@ return err; } if (con == currcon) /* current console ? */ - return fb_set_cmap(cmap, kspc, fbhw->setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -2644,6 +2634,7 @@ fb_get_cmap: atafb_get_cmap, fb_set_cmap: atafb_set_cmap, fb_pan_display: atafb_pan_display, + fb_blank: atafb_blank, fb_ioctl: atafb_ioctl, }; @@ -2709,7 +2700,7 @@ * 3 = suspend hsync * 4 = off */ -static void +static int atafb_blank(int blank, struct fb_info *info) { unsigned short black[16]; @@ -2724,10 +2715,11 @@ cmap.transp=NULL; cmap.start=0; cmap.len=16; - fb_set_cmap(&cmap, 1, fbhw->setcolreg, info); + fb_set_cmap(&cmap, 1, info); } else do_install_cmap(currcon, info); + return 0; } int __init atafb_init(void) @@ -2743,18 +2735,21 @@ #ifdef ATAFB_EXT if (external_addr) { fbhw = &ext_switch; + fb_info.fb_setcolreg = &ext_setcolreg; break; } #endif #ifdef ATAFB_TT if (ATARIHW_PRESENT(TT_SHIFTER)) { fbhw = &tt_switch; + fb_info.fb_setcolreg = &tt_setcolreg; break; } #endif #ifdef ATAFB_FALCON if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { fbhw = &falcon_switch; + fb_info.fb_setcolreg = &falcon_setcolreg; request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, "framebuffer/modeswitch", falcon_vbl_switcher); break; @@ -2764,9 +2759,11 @@ if (ATARIHW_PRESENT(STND_SHIFTER) || ATARIHW_PRESENT(EXTD_SHIFTER)) { fbhw = &st_switch; + fb_info.fb_setcolreg = &stste_setcolreg; break; } fbhw = &st_switch; + fb_info.fb_setcolreg = &stste_setcolreg; printk("Cannot determine video hardware; defaulting to ST(e)\n"); #else /* ATAFB_STE */ /* no default driver included */ @@ -2828,12 +2825,11 @@ strcpy(fb_info.modename, "Atari Builtin "); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &atafb_ops; fb_info.disp = &disp; fb_info.switch_con = &atafb_switch; fb_info.updatevar = &fb_update_var; - fb_info.blank = &atafb_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; do_fb_set_var(&atafb_predefined[default_par-1], 1); strcat(fb_info.modename, fb_var_names[default_par-1][0]); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/aty/atyfb_base.c linux-2.5/drivers/video/aty/atyfb_base.c --- linux-2.5.1/drivers/video/aty/atyfb_base.c Tue Oct 30 23:08:11 2001 +++ linux-2.5/drivers/video/aty/atyfb_base.c Mon Jan 14 23:58:39 2002 @@ -88,6 +88,9 @@ #include <linux/adb.h> #include <linux/pmu.h> #endif +#ifdef CONFIG_BOOTX_TEXT +#include <asm/btext.h> +#endif #ifdef CONFIG_NVRAM #include <linux/nvram.h> #endif @@ -149,10 +152,13 @@ struct fb_info *fb); static int atyfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *fb); +static int atyfb_blank(int blank, 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_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *fb); static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info); #ifdef __sparc__ @@ -168,8 +174,6 @@ 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 @@ -206,8 +210,6 @@ 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); @@ -234,7 +236,9 @@ fb_set_var: atyfb_set_var, fb_get_cmap: atyfb_get_cmap, fb_set_cmap: atyfb_set_cmap, + fb_setcolreg: atyfb_setcolreg, fb_pan_display: atyfb_pan_display, + fb_blank: atyfb_blank, fb_ioctl: atyfb_ioctl, #ifdef __sparc__ fb_mmap: atyfb_mmap, @@ -251,11 +255,11 @@ static int default_mclk __initdata = 0; #ifndef MODULE -static const char *mode_option __initdata = NULL; +static char *mode_option __initdata = NULL; #endif #ifdef CONFIG_PPC -#ifdef CONFIG_NVRAM_NOT_DEFINED +#ifndef CONFIG_NVRAM static int default_vmode __initdata = VMODE_NVRAM; static int default_cmode __initdata = CMODE_NVRAM; #else @@ -271,31 +275,35 @@ 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_xl[] __initdata = "3D RAGE (XL)"; -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)"; +#ifdef CONFIG_FB_ATY_GX +static char m64n_gx[] __initdata = "mach64GX (ATI888GX00)"; +static char m64n_cx[] __initdata = "mach64CX (ATI888CX00)"; +#endif /* CONFIG_FB_ATY_GX */ +#ifdef CONFIG_FB_ATY_CT +static char m64n_ct[] __initdata = "mach64CT (ATI264CT)"; +static char m64n_et[] __initdata = "mach64ET (ATI264ET)"; +static char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)"; +static char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)"; +static char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)"; +static char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)"; +static char m64n_gt[] __initdata = "3D RAGE (GT)"; +static char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)"; +static char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)"; +static char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)"; +static char m64n_lt[] __initdata = "3D RAGE LT"; +static char m64n_ltg[] __initdata = "3D RAGE LT-G"; +static char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)"; +static char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)"; +static char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)"; +static char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)"; +static char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)"; +static char m64n_xl[] __initdata = "3D RAGE (XL)"; +static char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)"; +static char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)"; +static char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)"; +static char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)"; +#endif /* CONFIG_FB_ATY_CT */ static const struct { u16 pci_id, chip_type; @@ -357,24 +365,32 @@ #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"; +#if defined(CONFIG_FB_ATY_GX) || defined(CONFIG_FB_ATY_CT) +static char ram_dram[] __initdata = "DRAM"; +static char ram_resv[] __initdata = "RESV"; +#endif /* CONFIG_FB_ATY_GX || CONFIG_FB_ATY_CT */ + +#ifdef CONFIG_FB_ATY_GX +static char ram_vram[] __initdata = "VRAM"; +#endif /* CONFIG_FB_ATY_GX */ + +#ifdef CONFIG_FB_ATY_CT +static char ram_edo[] __initdata = "EDO"; +static char ram_sdram[] __initdata = "SDRAM"; +static char ram_sgram[] __initdata = "SGRAM"; +static char ram_wram[] __initdata = "WRAM"; +static char ram_off[] __initdata = "OFF"; +#endif /* CONFIG_FB_ATY_CT */ #ifdef CONFIG_FB_ATY_GX -static const char *aty_gx_ram[8] __initdata = { +static 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 = { +static char *aty_ct_ram[8] __initdata = { ram_off, ram_dram, ram_edo, ram_edo, ram_sdram, ram_sgram, ram_wram, ram_resv }; @@ -819,6 +835,13 @@ display_info.disp_reg_address = info->ati_regbase_phys; } #endif /* CONFIG_FB_COMPAT_XPMAC */ +#ifdef CONFIG_BOOTX_TEXT + btext_update_display(info->frame_buffer_phys, + (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8, + ((par->crtc.v_tot_disp>>16) & 0x7ff)+1, + par->crtc.bpp, + par->crtc.vxres*par->crtc.bpp/8); +#endif /* CONFIG_BOOTX_TEXT */ } static int atyfb_decode_var(const struct fb_var_screeninfo *var, @@ -1212,7 +1235,7 @@ return err; } if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */ - return fb_set_cmap(cmap, kspc, atyfb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); return 0; @@ -1638,6 +1661,8 @@ } break; case PBOOK_SLEEP_NOW: + if (currcon >= 0) + fb_display[currcon].dispsw = &fbcon_dummy; if (info->blitter_may_be_busy) wait_for_idle(info); /* Stop accel engine (stop bus mastering) */ @@ -1650,7 +1675,7 @@ (void *)info->frame_buffer, nb); /* Blank display and LCD */ - atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); + atyfb_blank(VESA_POWERDOWN+1, (struct fb_info *)info); /* Set chip to "suspend" mode */ result = aty_power_mgmt(1, info); @@ -1667,8 +1692,12 @@ info->save_framebuffer = 0; } /* Restore display */ - atyfb_set_par(&info->current_par, info); - atyfbcon_blank(0, (struct fb_info *)info); + if (currcon >= 0) { + atyfb_set_dispsw(&fb_display[currcon], + info, info->current_par.crtc.bpp, + info->current_par.accel_flags & FB_ACCELF_TEXT); + } + atyfb_blank(0, (struct fb_info *)info); break; } } @@ -1986,14 +2015,13 @@ disp = &info->disp; strcpy(info->fb_info.modename, atyfb_name); - info->fb_info.node = -1; + info->fb_info.node = NODEV; 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 @@ -2020,13 +2048,6 @@ 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 */ @@ -2139,11 +2160,16 @@ return -ENXIO; #else u16 tmp; + int aux_app; + unsigned long raddr; #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; +#ifndef __sparc__ + struct resource *rrp; +#endif for (i = sizeof(aty_chips)/sizeof(*aty_chips)-1; i >= 0; i--) if (pdev->device == aty_chips[i].pci_id) @@ -2375,9 +2401,19 @@ } #else /* __sparc__ */ - info->ati_regbase_phys = 0x7ff000 + addr; - info->ati_regbase = (unsigned long) - ioremap(info->ati_regbase_phys, 0x1000); + aux_app = 0; + raddr = addr + 0x7ff000UL; + rrp = &pdev->resource[2]; + if ((rrp->flags & IORESOURCE_MEM) + && request_mem_region(rrp->start, rrp->end - rrp->start + 1, + "atyfb")) { + aux_app = 1; + raddr = rrp->start; + printk(KERN_INFO "atyfb: using auxiliary register aperture\n"); + } + + info->ati_regbase_phys = raddr; + info->ati_regbase = (unsigned long) ioremap(raddr, 0x1000); if(!info->ati_regbase) { kfree(info); @@ -2385,8 +2421,8 @@ return -ENOMEM; } - info->ati_regbase_phys += 0xc00; - info->ati_regbase += 0xc00; + info->ati_regbase_phys += aux_app? 0x400: 0xc00; + info->ati_regbase += aux_app? 0x400: 0xc00; /* * Enable memory-space accesses using config-space @@ -2677,7 +2713,7 @@ * Blank the display. */ -static void atyfbcon_blank(int blank, struct fb_info *fb) +static int atyfb_blank(int blank, struct fb_info *fb) { struct fb_info_aty *info = (struct fb_info_aty *)fb; u8 gen_cntl; @@ -2711,6 +2747,7 @@ if ((_machine == _MACH_Pmac) && !blank) set_backlight_enable(1); #endif /* CONFIG_PMAC_BACKLIGHT */ + return 0; } @@ -2794,10 +2831,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, atyfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, 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); + fb_set_cmap(fb_default_cmap(size), 1, info); } } @@ -2891,3 +2928,4 @@ } #endif +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/aty128.h linux-2.5/drivers/video/aty128.h --- linux-2.5.1/drivers/video/aty128.h Sun Sep 17 16:48:04 2000 +++ linux-2.5/drivers/video/aty128.h Tue Jan 8 01:17:10 2002 @@ -13,6 +13,7 @@ #define CLOCK_CNTL_DATA 0x000c #define BIOS_0_SCRATCH 0x0010 #define BUS_CNTL 0x0030 +#define BUS_CNTL1 0x0034 #define GEN_INT_CNTL 0x0040 #define CRTC_GEN_CNTL 0x0050 #define CRTC_EXT_CNTL 0x0054 @@ -24,6 +25,7 @@ #define GEN_RESET_CNTL 0x00f0 #define CONFIG_MEMSIZE 0x00f8 #define MEM_CNTL 0x0140 +#define MEM_POWER_MISC 0x015c #define AGP_BASE 0x0170 #define AGP_CNTL 0x0174 #define AGP_APER_OFFSET 0x0178 @@ -37,6 +39,9 @@ #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_OFFSET 0x0224 #define CRTC_OFFSET_CNTL 0x0228 #define CRTC_PITCH 0x022c @@ -48,6 +53,20 @@ #define DDA_ON_OFF 0x02e4 #define VGA_DDA_CONFIG 0x02e8 #define VGA_DDA_ON_OFF 0x02ec +#define CRTC2_H_TOTAL_DISP 0x0300 +#define CRTC2_H_SYNC_STRT_WID 0x0304 +#define CRTC2_V_TOTAL_DISP 0x0308 +#define CRTC2_V_SYNC_STRT_WID 0x030c +#define CRTC2_VLINE_CRNT_VLINE 0x0310 +#define CRTC2_CRNT_FRAME 0x0314 +#define CRTC2_GUI_TRIG_VLINE 0x0318 +#define CRTC2_OFFSET 0x0324 +#define CRTC2_OFFSET_CNTL 0x0328 +#define CRTC2_PITCH 0x032c +#define DDA2_CONFIG 0x03e0 +#define DDA2_ON_OFF 0x03e4 +#define CRTC2_GEN_CNTL 0x03f8 +#define CRTC2_STATUS 0x03fc #define OV0_SCALE_CNTL 0x0420 #define SUBPIC_CNTL 0x0540 #define PM4_BUFFER_OFFSET 0x0700 @@ -237,6 +256,10 @@ #define AGP_PLL_CNTL 0x0010 #define FCP_CNTL 0x0012 #define PLL_TEST_CNTL 0x0013 +#define P2PLL_CNTL 0x002a +#define P2PLL_REF_DIV 0x002b +#define P2PLL_DIV_0 0x002b +#define POWER_MANAGEMENT 0x002f #define PPLL_RESET 0x01 #define PPLL_ATOMIC_UPDATE_EN 0x10000 @@ -254,6 +277,14 @@ /* CRTC control values (CRTC_GEN_CNTL) */ #define CRTC_CSYNC_EN 0x00000010 +#define CRTC2_DBL_SCAN_EN 0x00000001 +#define CRTC2_DISPLAY_DIS 0x00800000 +#define CRTC2_FIFO_EXTSENSE 0x00200000 +#define CRTC2_ICON_EN 0x00100000 +#define CRTC2_CUR_EN 0x00010000 +#define CRTC2_EN 0x02000000 +#define CRTC2_DISP_REQ_EN_B 0x04000000 + #define CRTC_PIX_WIDTH_MASK 0x00000700 #define CRTC_PIX_WIDTH_4BPP 0x00000100 #define CRTC_PIX_WIDTH_8BPP 0x00000200 @@ -267,10 +298,14 @@ #define DAC_MASK 0xFF000000 #define DAC_BLANKING 0x00000004 #define DAC_RANGE_CNTL 0x00000003 -#define DAC_RANGE_CNTL 0x00000003 +#define DAC_CLK_SEL 0x00000010 #define DAC_PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_PALETTE2_SNOOP_EN 0x00000040 #define DAC_PDWN 0x00008000 +/* CRTC_EXT_CNTL */ +#define CRT_CRTC_ON 0x00008000 + /* GEN_RESET_CNTL bit constants */ #define SOFT_RESET_GUI 0x00000001 #define SOFT_RESET_VCLK 0x00000100 @@ -348,5 +383,37 @@ #define LVDS_BL_MOD_EN 0x00010000 #define LVDS_DIGION 0x00040000 #define LVDS_BLON 0x00080000 +#define LVDS_ON 0x00000001 +#define LVDS_DISPLAY_DIS 0x00000002 +#define LVDS_PANEL_TYPE_2PIX_PER_CLK 0x00000004 +#define LVDS_PANEL_24BITS_TFT 0x00000008 +#define LVDS_FRAME_MOD_NO 0x00000000 +#define LVDS_FRAME_MOD_2_LEVELS 0x00000010 +#define LVDS_FRAME_MOD_4_LEVELS 0x00000020 +#define LVDS_RST_FM 0x00000040 +#define LVDS_EN 0x00000080 + +/* CRTC2_GEN_CNTL constants */ +#define CRTC2_EN 0x02000000 + +/* POWER_MANAGEMENT constants */ +#define PWR_MGT_ON 0x00000001 +#define PWR_MGT_MODE_MASK 0x00000006 +#define PWR_MGT_MODE_PIN 0x00000000 +#define PWR_MGT_MODE_REGISTER 0x00000002 +#define PWR_MGT_MODE_TIMER 0x00000004 +#define PWR_MGT_MODE_PCI 0x00000006 +#define PWR_MGT_AUTO_PWR_UP_EN 0x00000008 +#define PWR_MGT_ACTIVITY_PIN_ON 0x00000010 +#define PWR_MGT_STANDBY_POL 0x00000020 +#define PWR_MGT_SUSPEND_POL 0x00000040 +#define PWR_MGT_SELF_REFRESH 0x00000080 +#define PWR_MGT_ACTIVITY_PIN_EN 0x00000100 +#define PWR_MGT_KEYBD_SNOOP 0x00000200 +#define PWR_MGT_TRISTATE_MEM_EN 0x00000800 +#define PWR_MGT_SELW4MS 0x00001000 +#define PWR_MGT_SLOWDOWN_MCLK 0x00002000 + +#define PMI_PMSCR_REG 0x60 #endif /* REG_RAGE128_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/aty128fb.c linux-2.5/drivers/video/aty128fb.c --- linux-2.5.1/drivers/video/aty128fb.c Sun Nov 11 18:09:37 2001 +++ linux-2.5/drivers/video/aty128fb.c Mon Jan 14 23:58:39 2002 @@ -7,13 +7,19 @@ * Ani Joshi / Jeff Garzik * - Code cleanup * + * Michel Dänzer <michdaen@iiic.ethz.ch> + * - 15/16 bit cleanup + * - fix panning + * + * Benjamin Herrenschmidt + * - pmac-specific PM stuff + * * Andreas Hundt <andi@convergence.de> * - FB_ACTIVATE fixes * * Based off of Geert's atyfb.c and vfb.c. * * TODO: - * - panning * - monitor sensing (DDC) * - virtual display * - other platform support (only ppc/x86 supported) @@ -70,6 +76,9 @@ #ifdef CONFIG_FB_COMPAT_XPMAC #include <asm/vc_ioctl.h> #endif +#ifdef CONFIG_BOOTX_TEXT +#include <asm/btext.h> +#endif /* CONFIG_BOOTX_TEXT */ #include <video/fbcon.h> #include <video/fbcon-cfb8.h> @@ -154,6 +163,7 @@ {"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}, + {"Rage128 Pro TR (AGP)", PCI_DEVICE_ID_ATI_RAGE128_U3, 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} @@ -227,6 +237,11 @@ static int default_cmode __initdata = CMODE_8; #endif +#ifdef CONFIG_PMAC_PBOOK +static int default_crt_on __initdata = 0; +static int default_lcd_on __initdata = 1; +#endif + #ifdef CONFIG_MTRR static int mtrr = 1; #endif @@ -251,7 +266,7 @@ u32 offset, offset_cntl; u32 xoffset, yoffset; u32 vxres, vyres; - u32 bpp; + u32 depth, bpp; }; struct aty128_pll { @@ -307,10 +322,23 @@ int currcon; int blitter_may_be_busy; int fifo_slots; /* free slots in FIFO (64 max) */ +#ifdef CONFIG_PMAC_PBOOK + unsigned char *save_framebuffer; + int pm_reg; + int crt_on, lcd_on; + u32 save_lcd_gen_cntl; +#endif }; static struct fb_info_aty128 *board_list = NULL; +#ifdef CONFIG_PMAC_PBOOK + int aty128_sleep_notify(struct pmu_sleep_notifier *self, int when); + static struct pmu_sleep_notifier aty128_sleep_notifier = { + aty128_sleep_notify, SLEEP_LEVEL_VIDEO, + }; +#endif + #define round_div(n, d) ((n+(d/2))/d) /* @@ -329,8 +357,13 @@ struct fb_info *info); static int aty128fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); static int aty128fb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *fb); +static int aty128fb_blank(int blank, struct fb_info *fb); +static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info); static int aty128fb_rasterimg(struct fb_info *info, int start); @@ -340,7 +373,6 @@ int aty128fb_init(void); static int aty128fbcon_switch(int con, struct fb_info *fb); -static void aty128fbcon_blank(int blank, struct fb_info *fb); /* * Internal routines @@ -353,8 +385,6 @@ struct fb_info_aty128 *info, int bpp, int accel); static int aty128_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); static int aty128_encode_var(struct fb_var_screeninfo *var, const struct aty128fb_par *par, @@ -379,7 +409,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; @@ -422,6 +452,9 @@ fb_get_cmap: aty128fb_get_cmap, fb_set_cmap: aty128fb_set_cmap, fb_pan_display: aty128fb_pan_display, + fb_setcolreg: aty128fb_setcolreg, + fb_blank: aty128fb_blank, + fb_ioctl: aty128fb_ioctl, fb_rasterimg: aty128fb_rasterimg, }; @@ -496,7 +529,7 @@ _aty_ld_pll(unsigned int pll_index, const struct fb_info_aty128 *info) { - aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F); + aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F); return aty_ld_le32(CLOCK_CNTL_DATA); } @@ -505,7 +538,7 @@ _aty_st_pll(unsigned int pll_index, u32 val, const struct fb_info_aty128 *info) { - aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN); + aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN); aty_st_le32(CLOCK_CNTL_DATA, val); } @@ -698,7 +731,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 | @@ -731,18 +764,20 @@ } -/* convert bpp values to their register representation */ +/* convert depth values to their register representation */ static u32 -bpp_to_depth(u32 bpp) -{ - if (bpp <= 8) - return DST_8BPP; - else if (bpp <= 16) - return DST_15BPP; - else if (bpp <= 24) - return DST_24BPP; - else if (bpp <= 32) - return DST_32BPP; +depth_to_dst(u32 depth) + { + if (depth <= 8) + return DST_8BPP; + else if (depth <= 15) + return DST_15BPP; + else if (depth == 16) + return DST_16BPP; + else if (depth <= 24) + return DST_24BPP; + else if (depth <= 32) + return DST_32BPP; return -EINVAL; } @@ -765,12 +800,8 @@ 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 + /* Disable ATOMIC updating. Is this the right place? */ + aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~(0x00030000)); } @@ -779,7 +810,7 @@ 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; @@ -804,6 +835,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) @@ -819,17 +855,16 @@ 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"); + if (dst == -EINVAL) { + 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) { @@ -870,7 +905,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); @@ -893,6 +928,7 @@ crtc->vyres = vyres; crtc->xoffset = xoffset; crtc->yoffset = yoffset; + crtc->depth = depth; crtc->bpp = bpp; return 0; @@ -900,7 +936,7 @@ static int -aty128_bpp_to_var(int pix_width, struct fb_var_screeninfo *var) +aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var) { /* fill in pixel info */ @@ -917,7 +953,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; @@ -928,6 +963,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; @@ -996,7 +1042,7 @@ (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); - aty128_bpp_to_var(pix_width, var); + aty128_pix_width_to_var(pix_width, var); var->xres = xres; var->yres = yres; @@ -1017,6 +1063,42 @@ } static void +aty128_set_crt_enable(struct fb_info_aty128 *info, int on) +{ + if (on) { + aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON); + aty_st_le32(DAC_CNTL, (aty_ld_le32(DAC_CNTL) | DAC_PALETTE2_SNOOP_EN)); + } else + aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON); +} + +static void +aty128_set_lcd_enable(struct fb_info_aty128 *info, int on) +{ + u32 reg; + + if (on) { + reg = aty_ld_le32(LVDS_GEN_CNTL); + reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION; + reg &= ~LVDS_DISPLAY_DIS; + aty_st_le32(LVDS_GEN_CNTL, reg); +#ifdef CONFIG_PMAC_BACKLIGHT + aty128_set_backlight_enable(get_backlight_enable(), get_backlight_level(), info); +#endif + } else { +#ifdef CONFIG_PMAC_BACKLIGHT + aty128_set_backlight_enable(0, 0, info); +#endif + reg = aty_ld_le32(LVDS_GEN_CNTL); + reg |= LVDS_DISPLAY_DIS; + aty_st_le32(LVDS_GEN_CNTL, reg); + mdelay(100); + reg &= ~(LVDS_ON /*| LVDS_EN*/); + aty_st_le32(LVDS_GEN_CNTL, reg); + } +} + +static void aty128_set_pll(struct aty128_pll *pll, const struct fb_info_aty128 *info) { u32 div3; @@ -1053,6 +1135,23 @@ /* clear the reset, just in case */ aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET); + +#if 0 + if (info->chip_gen == rage_M3) { + /* XXX energy saving, disable VCLK during blanking */ + aty_pll_wait_readupdate(info); + aty_st_pll(VCLK_ECP_CNTL, aty_ld_pll(VCLK_ECP_CNTL) | 0xc0); + aty_pll_writeupdate(info); + + /* Set PM clocks */ + aty_pll_wait_readupdate(info); + aty_st_pll(XCLK_CNTL, aty_ld_pll(XCLK_CNTL) | 0x00330000); + aty_pll_writeupdate(info); + aty_pll_wait_readupdate(info); + aty_st_pll(MCLK_CNTL, aty_ld_pll(MCLK_CNTL) | 0x00000700); + aty_pll_writeupdate(info); + } +#endif } @@ -1121,7 +1220,7 @@ 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; @@ -1129,11 +1228,10 @@ 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 up to multiple of 8 */ + bpp = (depth+7) & ~7; n = xclk * fifo_width; d = pll->vclk * bpp; @@ -1214,15 +1312,21 @@ config = aty_ld_le32(CONFIG_CNTL) & ~3; #if defined(__BIG_ENDIAN) - if (par->crtc.bpp >= 24) - config |= 2; /* make aperture do 32 byte swapping */ - else if (par->crtc.bpp > 8) - config |= 1; /* make aperture do 16 byte swapping */ + if (par->crtc.bpp == 32) + config |= 2; /* make aperture do 32 bit swapping */ + else if (par->crtc.bpp == 16) + config |= 1; /* make aperture do 16 bit swapping */ #endif aty_st_le32(CONFIG_CNTL, config); aty_st_8(CRTC_EXT_CNTL + 1, 0); /* turn the video back on */ +#ifdef CONFIG_PMAC_PBOOK + if (info->chip_gen == rage_M3) { + aty128_set_crt_enable(info, info->crt_on); + aty128_set_lcd_enable(info, info->lcd_on); + } +#endif if (par->accel_flags & FB_ACCELF_TEXT) aty128_init_engine(par, info); @@ -1247,6 +1351,13 @@ display_info.disp_reg_address = info->regbase_phys; } #endif /* CONFIG_FB_COMPAT_XPMAC */ +#if defined(CONFIG_BOOTX_TEXT) + btext_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 */ } /* @@ -1265,7 +1376,7 @@ 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) @@ -1333,7 +1444,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; @@ -1378,11 +1489,13 @@ 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) { + oldgreen != var->green.length || oldbpp != var->bits_per_pixel || + oldaccel != var->accel_flags) { struct fb_fix_screeninfo fix; @@ -1412,7 +1525,7 @@ 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); @@ -1433,7 +1546,6 @@ 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; @@ -1475,7 +1587,7 @@ 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->visual = par->crtc.bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; fix->ywrapstep = 0; fix->xpanstep = 8; @@ -1509,8 +1621,6 @@ /* * Pan or Wrap the Display - * - * Not supported (yet!) */ static int aty128fb_pan_display(struct fb_var_screeninfo *var, int con, @@ -1534,7 +1644,10 @@ par->crtc.xoffset = xoffset; par->crtc.yoffset = yoffset; - offset = ((yoffset * par->crtc.vxres + xoffset) * par->crtc.bpp) >> 6; + offset = ((yoffset * par->crtc.vxres + xoffset)*(par->crtc.bpp >> 3)) & ~7; + + if (par->crtc.bpp == 24) + offset += 8 * (offset % 3); /* Must be multiple of 8 and 3 */ aty_st_le32(CRTC_OFFSET, offset); @@ -1550,20 +1663,16 @@ 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; + struct display *disp = (con < 0) ? info->disp : (fb_display + con); 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; - fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); - } -#endif + return fb_get_cmap(cmap, kspc, aty128_getcolreg, info); + else if (disp->cmap.len) /* non default colormap? */ + fb_copy_cmap(&disp->cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap((disp->var.bits_per_pixel==8) ? 256 : 32), + cmap, kspc ? 0 : 2); return 0; } @@ -1576,29 +1685,54 @@ 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; + struct display *disp = (con < 0) ? info->disp : (fb_display + con); + unsigned int cmap_len = (disp->var.bits_per_pixel==8) ? 256 : 32; - if (con >= 0) - disp = &fb_display[con]; - else - disp = info->disp; + if (disp->cmap.len != cmap_len) { + int err = fb_alloc_cmap(&disp->cmap, cmap_len, 0); - if (!disp->cmap.len) { /* no colormap allocated? */ - int size = (disp->var.bits_per_pixel <= 8) ? 256 : 32; - if ((err = fb_alloc_cmap(&disp->cmap, size, 0))) - return err; + if (!disp->cmap.len) { /* no colormap allocated? */ + int size = (disp->var.bits_per_pixel <= 8) ? 256 : 32; + if ((err = fb_alloc_cmap(&disp->cmap, size, 0))) + return err; + } + if (err) return err; } if (con == fb->currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, aty128_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); return 0; } + /* + * Helper function to store a single palette register + */ +static __inline__ void +aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue, + struct fb_info_aty128 *info) +{ + /* Note: For now, on M3, we set palette on both heads, which may + * be useless. Can someone with a M3 check this ? + * + * This code would still be useful if using the second CRTC to + * do mirroring + */ + + if (info->chip_gen == rage_M3) { +#if 0 + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); + aty_st_8(PALETTE_INDEX, regno); + aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue); +#endif + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); + } + aty_st_8(PALETTE_INDEX, regno); + aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue); +} static int aty128fb_rasterimg(struct fb_info *info, int start) @@ -1620,7 +1754,7 @@ if (!options || !*options) return 0; - while (this_opt = strsep(&options, ",")) { + while ((this_opt = strsep(&options, ",")) != 0) { if (!strncmp(this_opt, "font:", 5)) { char *p; int i; @@ -1633,6 +1767,12 @@ fontname[i] = 0; } else if (!strncmp(this_opt, "noaccel", 7)) { noaccel = 1; +#ifdef CONFIG_PMAC_PBOOK + } else if (!strncmp(this_opt, "lcd:", 4)) { + default_lcd_on = simple_strtoul(this_opt+4, NULL, 0); + } else if (!strncmp(this_opt, "crt:", 4)) { + default_crt_on = simple_strtoul(this_opt+4, NULL, 0); +#endif } #ifdef CONFIG_MTRR else if(!strncmp(this_opt, "nomtrr", 6)) { @@ -1704,16 +1844,19 @@ /* fill in info */ strcpy(info->fb_info.modename, aty128fb_name); - info->fb_info.node = -1; + info->fb_info.node = NODEV; 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 CONFIG_PMAC_PBOOK + info->lcd_on = default_lcd_on; + info->crt_on = default_crt_on; +#endif + var = default_var; #ifdef CONFIG_PPC if (_machine == _MACH_Pmac) { @@ -1724,6 +1867,29 @@ 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 january 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; + + /* iBook SE */ + if (machine_is_compatible("PowerBook2,2")) + default_vmode = VMODE_800_600_60; + + /* PowerBook Firewire (Pismo), iBook Dual USB */ + if (machine_is_compatible("PowerBook3,1") || + machine_is_compatible("PowerBook4,1")) + default_vmode = VMODE_1024_768_60; + + /* PowerBook Titanium */ + if (machine_is_compatible("PowerBook3,2")) + default_vmode = VMODE_1152_768_60; + if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; @@ -1760,6 +1926,8 @@ dac = aty_ld_le32(DAC_CNTL); dac |= (DAC_8BIT_EN | DAC_RANGE_CNTL); dac |= DAC_MASK; + if (info->chip_gen == rage_M3) + dac |= DAC_PALETTE2_SNOOP_EN; aty_st_le32(DAC_CNTL, dac); /* turn off bus mastering, just in case */ @@ -1778,6 +1946,14 @@ if (info->chip_gen == rage_M3) register_backlight_controller(&aty128_backlight_controller, info, "ati"); #endif /* CONFIG_PMAC_BACKLIGHT */ +#ifdef CONFIG_PMAC_PBOOK + if (!info->pdev) + printk(KERN_WARNING "aty128fb: Not a PCI card, can't enable power management\n"); + else { + info->pm_reg = pci_find_capability(info->pdev, PCI_CAP_ID_PM); + pmu_register_sleep_notifier(&aty128_sleep_notifier); + } +#endif printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", GET_FB_IDX(info->fb_info.node), aty128fb_name, name); @@ -1843,7 +2019,7 @@ if ((err = pci_enable_device(pdev))) { printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n", err); - goto err_out; + return -ENODEV; } fb_addr = pci_resource_start(pdev, 0); @@ -2142,8 +2318,8 @@ /* * Blank the display. */ -static void -aty128fbcon_blank(int blank, struct fb_info *fb) +static int +aty128fb_blank(int blank, struct fb_info *fb) { struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; u8 state = 0; @@ -2162,10 +2338,17 @@ aty_st_8(CRTC_EXT_CNTL+1, state); +#ifdef CONFIG_PMAC_PBOOK + if (info->chip_gen == rage_M3) { + aty128_set_crt_enable(info, info->crt_on && !blank); + aty128_set_lcd_enable(info, info->lcd_on && !blank); + } +#endif #ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && !blank) set_backlight_enable(1); #endif /* CONFIG_PMAC_BACKLIGHT */ + return 0; } @@ -2196,11 +2379,11 @@ * entries in the var structure). Return != 0 for invalid regno. */ static int -aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue, +aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *fb) { struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; - u32 col; + u32 palreg; if (regno > 255) return 1; @@ -2220,65 +2403,47 @@ if ((info->current_par.crtc.bpp > 8) && (regno == 0)) { int i; - if (info->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); - - for (i=16; 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); - - for (i=16; i<256; i++) { - aty_st_8(PALETTE_INDEX, i); - col = (i << 16) | (i << 8) | i; - aty_st_le32(PALETTE_DATA, col); - } - } + for (i=0; i<256; i++) + aty128_st_pal(i, i, i, i, info); } /* initialize palette */ - if (info->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); + palreg = regno; if (info->current_par.crtc.bpp == 16) - aty_st_8(PALETTE_INDEX, (regno << 3)); - else - aty_st_8(PALETTE_INDEX, regno); - col = (red << 16) | (green << 8) | blue; - 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(PALETTE_DATA, col); + palreg = regno * 8; + + if (info->current_par.crtc.depth == 16) { + aty128_st_pal(palreg/2, info->palette[regno/2].red, green, + info->palette[regno/2].blue, info); + green = info->palette[regno*2].green; } + if (info->current_par.crtc.bpp == 8 || regno < 32) + aty128_st_pal(palreg, red, green, blue, info); + if (regno < 16) - switch (info->current_par.crtc.bpp) { + switch (info->current_par.crtc.depth) { #ifdef FBCON_HAS_CFB16 - case 9 ... 16: + case 15: info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno; break; + case 16: + info->fbcon_cmap.cfb16[regno] = (regno << 11) | (regno << 5) | + regno; + break; #endif #ifdef FBCON_HAS_CFB24 - case 17 ... 24: + case 24: info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | regno; break; #endif #ifdef FBCON_HAS_CFB32 - case 25 ... 32: { - u32 i; - - i = (regno << 8) | regno; + case 32: { + u32 i = (regno << 8) | regno; info->fbcon_cmap.cfb32[regno] = (i << 16) | i; break; } @@ -2291,41 +2456,115 @@ static void do_install_cmap(int con, struct fb_info *info) { - struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info; + struct display *disp = (con < 0) ? info->disp : (fb_display + con); - if (con != fb->currcon) - return; + if (disp->cmap.len) + fb_set_cmap(&disp->cmap, 1, info); + else + fb_set_cmap(fb_default_cmap((disp->var.bits_per_pixel==8) ? 256 :32), + 1, info); +} - 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; - fb_set_cmap(fb_default_cmap(size), 1, aty128_setcolreg, info); +#define ATY_MIRROR_LCD_ON 0x00000001 +#define ATY_MIRROR_CRT_ON 0x00000002 + +/* out param: u32* backlight value: 0 to 15 */ +#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, sizeof(__u32*)) +/* in param: u32* backlight value: 0 to 15 */ +#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, sizeof(__u32*)) + +static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg, int con, struct fb_info *info) +{ + struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info; + u32 value; + int rc; + + switch (cmd) { +#ifdef CONFIG_PMAC_PBOOK + case FBIO_ATY128_SET_MIRROR: + if (fb->chip_gen != rage_M3) + return -EINVAL; + rc = get_user(value, (__u32*)arg); + if (rc) + return rc; + fb->lcd_on = (value & 0x01) != 0; + fb->crt_on = (value & 0x02) != 0; + if (!fb->crt_on && !fb->lcd_on) + fb->lcd_on = 1; + aty128_set_crt_enable(fb, fb->crt_on); + aty128_set_lcd_enable(fb, fb->lcd_on); + break; + case FBIO_ATY128_GET_MIRROR: + if (fb->chip_gen != rage_M3) + return -EINVAL; + value = (fb->crt_on << 1) | fb->lcd_on; + return put_user(value, (__u32*)arg); +#endif + default: + return -EINVAL; } + return 0; } - #ifdef CONFIG_PMAC_BACKLIGHT static int backlight_conv[] = { 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 }; +/* We turn off the LCD completely instead of just dimming the backlight. + * This provides greater power saving and the display is useless without + * backlight anyway + */ +#define BACKLIGHT_LVDS_OFF +/* That one prevents proper CRT output with LCD off */ +#undef BACKLIGHT_DAC_OFF + static int aty128_set_backlight_enable(int on, int level, void* data) { struct fb_info_aty128 *info = (struct fb_info_aty128 *)data; unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); - + + if (!info->lcd_on) + on = 0; reg |= LVDS_BL_MOD_EN | LVDS_BLON; if (on && level > BACKLIGHT_OFF) { + reg |= LVDS_DIGION; + if (!reg & LVDS_ON) { + reg &= ~LVDS_BLON; + aty_st_le32(LVDS_GEN_CNTL, reg); + (void)aty_ld_le32(LVDS_GEN_CNTL); + mdelay(10); + reg |= LVDS_BLON; + aty_st_le32(LVDS_GEN_CNTL, reg); + } reg &= ~LVDS_BL_MOD_LEVEL_MASK; reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT); +#ifdef BACKLIGHT_LVDS_OFF + reg |= LVDS_ON | LVDS_EN; + reg &= ~LVDS_DISPLAY_DIS; +#endif + aty_st_le32(LVDS_GEN_CNTL, reg); +#ifdef BACKLIGHT_DAC_OFF + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN)); +#endif } else { reg &= ~LVDS_BL_MOD_LEVEL_MASK; reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT); +#ifdef BACKLIGHT_LVDS_OFF + reg |= LVDS_DISPLAY_DIS; + aty_st_le32(LVDS_GEN_CNTL, reg); + (void)aty_ld_le32(LVDS_GEN_CNTL); + udelay(10); + reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION); +#endif + aty_st_le32(LVDS_GEN_CNTL, reg); +#ifdef BACKLIGHT_DAC_OFF + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN); +#endif } - aty_st_le32(LVDS_GEN_CNTL, reg); return 0; } @@ -2346,18 +2585,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 +2608,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); @@ -2594,6 +2833,139 @@ fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) }; #endif + +#ifdef CONFIG_PMAC_PBOOK +static void +aty128_set_suspend(struct fb_info_aty128 *info, int suspend) +{ + u32 pmgt; + u16 pwr_command; + + if (!info->pm_reg) + return; + + /* Set the chip into the appropriate suspend mode (we use D2, + * D3 would require a complete re-initialisation of the chip, + * including PCI config registers, clocks, AGP configuration, ...) + */ + if (suspend) { + /* Make sure CRTC2 is reset. Remove that the day we decide to + * actually use CRTC2 and replace it with real code for disabling + * the CRTC2 output during sleep + */ + aty_st_le32(CRTC2_GEN_CNTL, aty_ld_le32(CRTC2_GEN_CNTL) & + ~(CRTC2_EN)); + + /* Set the power management mode to be PCI based */ + pmgt = aty_ld_pll(POWER_MANAGEMENT); +#if 0 + pmgt &= ~PWR_MGT_MODE_MASK; + pmgt |= PWR_MGT_MODE_PCI | PWR_MGT_ON | PWR_MGT_TRISTATE_MEM_EN | PWR_MGT_AUTO_PWR_UP_EN; +#else /* Use this magic value for now */ + pmgt = 0x0c005407; +#endif + aty_st_pll(POWER_MANAGEMENT, pmgt); + (void)aty_ld_pll(POWER_MANAGEMENT); + aty_st_le32(BUS_CNTL1, 0x00000010); + aty_st_le32(MEM_POWER_MISC, 0x0c830000); + mdelay(100); + pci_read_config_word(info->pdev, info->pm_reg+PCI_PM_CTRL, &pwr_command); + /* Switch PCI power management to D2 */ + pci_write_config_word(info->pdev, info->pm_reg+PCI_PM_CTRL, + (pwr_command & ~PCI_PM_CTRL_STATE_MASK) | 2); + pci_read_config_word(info->pdev, info->pm_reg+PCI_PM_CTRL, &pwr_command); + } else { + /* Switch back PCI power management to D0 */ + mdelay(100); + pci_write_config_word(info->pdev, info->pm_reg+PCI_PM_CTRL, 0); + mdelay(100); + pci_read_config_word(info->pdev, info->pm_reg+PCI_PM_CTRL, &pwr_command); + mdelay(100); + } +} + +extern struct display_switch fbcon_dummy; + +/* + * Save the contents of the frame buffer when we go to sleep, + * and restore it when we wake up again. + */ +int +aty128_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + struct fb_info_aty128 *info; + int result; + + result = PBOOK_SLEEP_OK; + + for (info = board_list; info != NULL; info = info->next) { + struct fb_fix_screeninfo fix; + int nb; + + aty128fb_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->currcon >= 0) + fb_display[info->currcon].dispsw = &fbcon_dummy; + + wait_for_idle(info); + aty128_reset_engine(info); + wait_for_idle(info); + + /* Backup fb content */ + if (info->save_framebuffer) + memcpy_fromio(info->save_framebuffer, + (void *)info->frame_buffer, nb); + + /* Blank display and LCD */ + aty128fbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); + + /* Sleep the chip */ + aty128_set_suspend(info, 1); + + break; + case PBOOK_WAKE: + /* Wake the chip */ + aty128_set_suspend(info, 0); + + aty128_reset_engine(info); + wait_for_idle(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; + } + + if (info->currcon >= 0) { + aty128_set_dispsw( + &fb_display[info->currcon], + info, + info->current_par.crtc.bpp, + info->current_par.accel_flags & FB_ACCELF_TEXT); + } + aty128fbcon_blank(0, (struct fb_info *)info); + break; + } + } + return result; +} +#endif /* CONFIG_PMAC_PBOOK */ #ifdef MODULE MODULE_AUTHOR("(c)1999-2000 Brad Douglas <brad@neruo.com>"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/bwtwofb.c linux-2.5/drivers/video/bwtwofb.c --- linux-2.5.1/drivers/video/bwtwofb.c Thu Sep 20 21:11:58 2001 +++ linux-2.5/drivers/video/bwtwofb.c Fri Jan 11 11:07:03 2002 @@ -83,7 +83,7 @@ { 0, 0, 0 } }; -static void bw2_blank (struct fb_info_sbusfb *fb) +static int bw2_blank (struct fb_info_sbusfb *fb) { unsigned long flags; u8 tmp; @@ -93,9 +93,10 @@ tmp &= ~BWTWO_CTL_ENABLE_VIDEO; sbus_writeb(tmp, &fb->s.bw2.regs->control); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } -static void bw2_unblank (struct fb_info_sbusfb *fb) +static int bw2_unblank (struct fb_info_sbusfb *fb) { unsigned long flags; u8 tmp; @@ -105,6 +106,7 @@ tmp |= BWTWO_CTL_ENABLE_VIDEO; sbus_writeb(tmp, &fb->s.bw2.regs->control); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } static void bw2_margins (struct fb_info_sbusfb *fb, struct display *p, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/cgsixfb.c linux-2.5/drivers/video/cgsixfb.c --- linux-2.5.1/drivers/video/cgsixfb.c Wed Oct 17 21:16:39 2001 +++ linux-2.5/drivers/video/cgsixfb.c Fri Jan 11 11:07:03 2002 @@ -582,7 +582,7 @@ spin_unlock_irqrestore(&fb->lock, flags); } -static void cg6_blank (struct fb_info_sbusfb *fb) +static int cg6_blank (struct fb_info_sbusfb *fb) { unsigned long flags; u32 tmp; @@ -592,9 +592,10 @@ tmp &= ~CG6_THC_MISC_VIDEO; sbus_writel(tmp, &fb->s.cg6.thc->thc_misc); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } -static void cg6_unblank (struct fb_info_sbusfb *fb) +static int cg6_unblank (struct fb_info_sbusfb *fb) { unsigned long flags; u32 tmp; @@ -604,6 +605,7 @@ tmp |= CG6_THC_MISC_VIDEO; sbus_writel(tmp, &fb->s.cg6.thc->thc_misc); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } static void cg6_reset (struct fb_info_sbusfb *fb) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/cgthreefb.c linux-2.5/drivers/video/cgthreefb.c --- linux-2.5.1/drivers/video/cgthreefb.c Thu Sep 20 21:11:58 2001 +++ linux-2.5/drivers/video/cgthreefb.c Fri Jan 11 11:07:03 2002 @@ -110,7 +110,7 @@ spin_unlock_irqrestore(&fb->lock, flags); } -static void cg3_blank (struct fb_info_sbusfb *fb) +static int cg3_blank (struct fb_info_sbusfb *fb) { unsigned long flags; u8 tmp; @@ -120,9 +120,10 @@ tmp &= ~CG3_CR_ENABLE_VIDEO; sbus_writeb(tmp, &fb->s.cg3.regs->control); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } -static void cg3_unblank (struct fb_info_sbusfb *fb) +static int cg3_unblank (struct fb_info_sbusfb *fb) { unsigned long flags; u8 tmp; @@ -132,6 +133,7 @@ tmp |= CG3_CR_ENABLE_VIDEO; sbus_writeb(tmp, &fb->s.cg3.regs->control); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } static void cg3_margins (struct fb_info_sbusfb *fb, struct display *p, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/chipsfb.c linux-2.5/drivers/video/chipsfb.c --- linux-2.5.1/drivers/video/chipsfb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/chipsfb.c Mon Jan 14 23:58:39 2002 @@ -129,6 +129,9 @@ struct fb_info *info); static int chips_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int chipsfb_blank(int blank, struct fb_info *info); static struct fb_ops chipsfb_ops = { owner: THIS_MODULE, @@ -137,12 +140,12 @@ fb_set_var: chips_set_var, fb_get_cmap: chips_get_cmap, fb_set_cmap: chips_set_cmap, + fb_setcolreg: chipsfb_setcolreg, + fb_blank: chipsfb_blank, }; static int chipsfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, int con, int bpp); @@ -210,7 +213,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, chipsfb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -241,7 +244,7 @@ return 0; } -static void chipsfb_blank(int blank, struct fb_info *info) +static int chipsfb_blank(int blank, struct fb_info *info) { struct fb_info_chips *p = (struct fb_info_chips *) info; int i; @@ -279,6 +282,7 @@ outb(p->palette[i].blue, 0x3c9); } } + return 0; } static int chipsfb_getcolreg(u_int regno, u_int *red, u_int *green, @@ -328,10 +332,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, chipsfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), 1, chipsfb_setcolreg, info); + fb_set_cmap(fb_default_cmap(size), 1, info); } } @@ -578,14 +582,13 @@ p->disp.scrollmode = SCROLL_YREDRAW; strcpy(p->info.modename, p->fix.id); - p->info.node = -1; + p->info.node = NODEV; p->info.fbops = &chipsfb_ops; p->info.disp = &p->disp; p->info.fontname[0] = 0; p->info.changevar = NULL; p->info.switch_con = &chipsfbcon_switch; p->info.updatevar = &chipsfb_updatevar; - p->info.blank = &chipsfb_blank; p->info.flags = FBINFO_FLAG_DEFAULT; for (i = 0; i < 16; ++i) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/clgenfb.c linux-2.5/drivers/video/clgenfb.c --- linux-2.5.1/drivers/video/clgenfb.c Mon Nov 19 23:19:42 2001 +++ linux-2.5/drivers/video/clgenfb.c Mon Jan 14 23:58:39 2002 @@ -492,6 +492,9 @@ static int clgenfb_open (struct fb_info *info, int user); static int clgenfb_release (struct fb_info *info, int user); +static int clgenfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info); /* function table of the above functions */ static struct fb_ops clgenfb_ops = { @@ -503,7 +506,9 @@ fb_set_var: fbgen_set_var, fb_get_cmap: fbgen_get_cmap, fb_set_cmap: fbgen_set_cmap, + fb_setcolreg: clgenfb_setcolreg, fb_pan_display: fbgen_pan_display, + fb_blank: fbgen_blank, }; /*--- Hardware Specific Routines -------------------------------------------*/ @@ -519,9 +524,6 @@ static int clgen_getcolreg (unsigned regno, unsigned *red, unsigned *green, unsigned *blue, unsigned *transp, struct fb_info *info); -static int clgen_setcolreg (unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info); static int clgen_pan_display (const struct fb_var_screeninfo *var, struct fb_info_gen *info); static int clgen_blank (int blank_mode, struct fb_info_gen *info); @@ -539,7 +541,6 @@ clgen_get_par, clgen_set_par, clgen_getcolreg, - clgen_setcolreg, clgen_pan_display, clgen_blank, clgen_set_disp @@ -1673,7 +1674,7 @@ } -static int clgen_setcolreg (unsigned regno, unsigned red, unsigned green, +static int clgenfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { @@ -2758,13 +2759,12 @@ sizeof (fb_info->gen.info.modename)); fb_info->gen.info.modename [sizeof (fb_info->gen.info.modename) - 1] = 0; - fb_info->gen.info.node = -1; + fb_info->gen.info.node = NODEV; fb_info->gen.info.fbops = &clgenfb_ops; fb_info->gen.info.disp = &disp; fb_info->gen.info.changevar = NULL; fb_info->gen.info.switch_con = &fbgen_switch; fb_info->gen.info.updatevar = &fbgen_update_var; - fb_info->gen.info.blank = &fbgen_blank; fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT; for (j = 0; j < 256; j++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/controlfb.c linux-2.5/drivers/video/controlfb.c --- linux-2.5.1/drivers/video/controlfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/controlfb.c Mon Jan 14 23:58:39 2002 @@ -151,6 +151,9 @@ struct fb_info *info); static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, 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); +static int controlfb_blank(int blank_mode, struct fb_info *info); static int control_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma); @@ -159,15 +162,12 @@ */ 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); -static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); /* * inititialization @@ -229,7 +229,9 @@ fb_set_var: control_set_var, fb_get_cmap: control_get_cmap, fb_set_cmap: control_set_cmap, + fb_setcolreg: controlfb_setcolreg, fb_pan_display: control_pan_display, + fb_blank: controlfb_blank, fb_mmap: control_mmap, }; @@ -400,7 +402,7 @@ return err; } if (con == currcon) - return fb_set_cmap(cmap, kspc, controlfb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); return 0; } @@ -489,7 +491,7 @@ } -static void controlfb_blank(int blank_mode, struct fb_info *info) +static int controlfb_blank(int blank_mode, struct fb_info *info) { struct fb_info_control *p = (struct fb_info_control *) info; unsigned ctrl; @@ -517,8 +519,7 @@ ctrl |= 0x33; } out_le32(CNTRL_REG(p,ctrl), ctrl); - - return; + return 0; } @@ -583,12 +584,10 @@ static void do_install_cmap(struct display *disp, struct fb_info *info) { if (disp->cmap.len) - fb_set_cmap(&disp->cmap, 1, controlfb_setcolreg, - info); + fb_set_cmap(&disp->cmap, 1, info); else { int size = disp->var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), 1, controlfb_setcolreg, - info); + fb_set_cmap(fb_default_cmap(size), 1, info); } } @@ -621,14 +620,10 @@ full = p->total_vram == 0x400000; +#ifdef CONFIG_NVRAM /* Try to pick a video mode out of NVRAM if we have one. */ - if (default_cmode == CMODE_NVRAM){ + if (default_cmode == CMODE_NVRAM) cmode = nvram_read_byte(NV_CMODE); - if(cmode < CMODE_8 || cmode > CMODE_32) - cmode = CMODE_8; - } else - cmode=default_cmode; - if (default_vmode == VMODE_NVRAM) { vmode = nvram_read_byte(NV_VMODE); if (vmode < 1 || vmode > VMODE_MAX || @@ -639,15 +634,16 @@ 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; - } } +#endif + + /* If we didn't get something from NVRAM, pick a + * sane default. + */ + if (vmode <= 0 || vmode > VMODE_MAX) + vmode = VMODE_640_480_67; + if (cmode < CMODE_8 || cmode > CMODE_32) + cmode = CMODE_8; if (mac_vmode_to_var(vmode, cmode, &var) < 0) { /* This shouldn't happen! */ @@ -1376,14 +1372,13 @@ static void __init control_init_info(struct fb_info *info, struct fb_info_control *p) { strcpy(info->modename, "control"); - info->node = -1; /* ??? danj */ + info->node = NODEV; info->fbops = &controlfb_ops; info->disp = &p->display; strcpy(info->fontname, fontname); info->changevar = NULL; info->switch_con = &controlfb_switch; info->updatevar = &controlfb_updatevar; - info->blank = &controlfb_blank; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/creatorfb.c linux-2.5/drivers/video/creatorfb.c --- linux-2.5.1/drivers/video/creatorfb.c Wed Oct 17 21:16:39 2001 +++ linux-2.5/drivers/video/creatorfb.c Fri Jan 11 11:07:03 2002 @@ -589,7 +589,7 @@ } #if 0 -static void ffb_blank(struct fb_info_sbusfb *fb) +static int ffb_blank(struct fb_info_sbusfb *fb) { struct ffb_dac *dac = fb->s.ffb.dac; unsigned long flags; @@ -601,10 +601,11 @@ upa_writel(0x6000, &dac->type); upa_writel(tmp, &dac->value); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } #endif -static void ffb_unblank(struct fb_info_sbusfb *fb) +static int ffb_unblank(struct fb_info_sbusfb *fb) { struct ffb_dac *dac = fb->s.ffb.dac; unsigned long flags; @@ -616,6 +617,7 @@ upa_writel(0x6000, &dac->type); upa_writel(tmp, &dac->value); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } static void ffb_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/cyber2000fb.c linux-2.5/drivers/video/cyber2000fb.c --- linux-2.5.1/drivers/video/cyber2000fb.c Thu Oct 25 20:53:52 2001 +++ linux-2.5/drivers/video/cyber2000fb.c Mon Jan 14 23:58:39 2002 @@ -308,8 +308,8 @@ * Set a single color register. Return != 0 for invalid regno. */ static int -cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) { struct cfb_info *cfb = (struct cfb_info *)info; @@ -563,7 +563,7 @@ * "improved" --rmk */ if (!err && con == cfb->currcon) { - err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg, &cfb->fb); + err = fb_set_cmap(cmap, kspc, &cfb->fb); dcmap = &cfb->fb.cmap; } @@ -992,7 +992,7 @@ cyber2000fb_update_start(cfb, var); cyber2000fb_set_timing(cfb, &hw); - fb_set_cmap(&cfb->fb.cmap, 1, cyber2000_setcolreg, &cfb->fb); + fb_set_cmap(&cfb->fb.cmap, 1, &cfb->fb); return 0; } @@ -1093,7 +1093,7 @@ /* * (Un)Blank the display. */ -static void cyber2000fb_blank(int blank, struct fb_info *info) +static int cyber2000fb_blank(int blank, struct fb_info *info) { struct cfb_info *cfb = (struct cfb_info *)info; int i; @@ -1143,6 +1143,7 @@ } break; } + return 0; } /* @@ -1183,6 +1184,8 @@ fb_get_fix: gen_get_fix, fb_get_var: gen_get_var, fb_get_cmap: gen_get_cmap, + fb_setcolreg: cyber2000fb_setcolreg, + fb_blank: cyber2000fb_blank, }; /* @@ -1462,7 +1465,6 @@ cfb->fb.changevar = NULL; cfb->fb.switch_con = cyber2000fb_switch; cfb->fb.updatevar = cyber2000fb_updatevar; - cfb->fb.blank = cyber2000fb_blank; cfb->fb.flags = FBINFO_FLAG_DEFAULT; cfb->fb.disp = (struct display *)(cfb + 1); cfb->fb.pseudo_palette = (void *)(cfb->fb.disp + 1); @@ -1683,7 +1685,7 @@ static struct pci_driver cyberpro_driver = { name: "CyberPro", probe: cyberpro_probe, - remove: cyberpro_remove, + remove: __devexit_p(cyberpro_remove), suspend: cyberpro_suspend, resume: cyberpro_resume, id_table: cyberpro_pci_table diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/cyberfb.c linux-2.5/drivers/video/cyberfb.c --- linux-2.5.1/drivers/video/cyberfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/cyberfb.c Mon Jan 14 23:58:39 2002 @@ -249,6 +249,9 @@ struct fb_info *info); static int cyberfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int cyberfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int cyberfb_blank(int blank, struct fb_info *info); /* * Interface to the low level console driver @@ -257,7 +260,6 @@ int cyberfb_init(void); static int Cyberfb_switch(int con, struct fb_info *info); static int Cyberfb_updatevar(int con, struct fb_info *info); -static void Cyberfb_blank(int blank, struct fb_info *info); /* * Text console acceleration @@ -295,8 +297,6 @@ struct cyberfb_par *par); static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); /* * Internal routines @@ -379,8 +379,8 @@ *(CursorBase+3+(i*4)) = 0xffff0000; } - Cyber_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */); - Cyber_setcolreg (254, 0, 0, 0, 0, NULL /* unused */); + cyberfb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */); + cyberfb_setcolreg (254, 0, 0, 0, 0, NULL /* unused */); DPRINTK("EXIT\n"); return 0; @@ -517,8 +517,8 @@ * Set a single color register. Return != 0 for invalid regno. */ -static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +static int cyberfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) { volatile unsigned char *regs = CyberRegs; @@ -581,7 +581,7 @@ * 0 = restore fb cmap from local cmap */ -void Cyberfb_blank(int blank, struct fb_info *info) +static int cyberfb_blank(int blank, struct fb_info *info) { volatile unsigned char *regs = CyberRegs; int i; @@ -609,6 +609,7 @@ } #endif DPRINTK("EXIT\n"); + return 0; } @@ -810,11 +811,11 @@ } if (fb_display[con].cmap.len) { DPRINTK("Use console cmap\n"); - fb_set_cmap(&fb_display[con].cmap, 1, Cyber_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); } else { DPRINTK("Use default cmap\n"); fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - 1, Cyber_setcolreg, info); + 1, info); } DPRINTK("EXIT\n"); } @@ -992,7 +993,7 @@ } if (con == currcon) { /* current console? */ DPRINTK("EXIT - Current console\n"); - return(fb_set_cmap(cmap, kspc, Cyber_setcolreg, info)); + return(fb_set_cmap(cmap, kspc, info)); } else { fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); } @@ -1006,6 +1007,7 @@ fb_get_fix: cyberfb_get_fix, fb_get_var: cyberfb_get_var, fb_set_var: cyberfb_set_var, + fb_setcolreg: cyberfb_setcolreg, fb_get_cmap: cyberfb_get_cmap, fb_set_cmap: cyberfb_set_cmap, }; @@ -1085,12 +1087,11 @@ strcpy(fb_info.modename, cyberfb_name); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &cyberfb_ops; fb_info.disp = &disp; fb_info.switch_con = &Cyberfb_switch; fb_info.updatevar = &Cyberfb_updatevar; - fb_info.blank = &Cyberfb_blank; Cyber_init(); /* ++Andre: set cyberfb default mode */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/dn_cfb4.c linux-2.5/drivers/video/dn_cfb4.c --- linux-2.5.1/drivers/video/dn_cfb4.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/dn_cfb4.c Fri Jan 11 11:07:03 2002 @@ -7,7 +7,6 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <asm/setup.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/irq.h> #include <asm/amigahw.h> @@ -119,10 +118,10 @@ struct fb_info *info); static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con, struct fb_info *info); +static int dnfb_blank(int blank, struct fb_info *info); static int dnfbcon_switch(int con,struct fb_info *info); static int dnfbcon_updatevar(int con,struct fb_info *info); -static void dnfbcon_blank(int blank,struct fb_info *info); static void dn_fb_set_disp(int con,struct fb_info *info); @@ -135,6 +134,7 @@ fb_set_var: dn_fb_set_var, fb_get_cmap: dn_fb_get_cmap, fb_set_cmap: dn_fb_set_cmap, + fb_blank: dnfb_blank, }; static int currcon=0; @@ -305,8 +305,7 @@ fb_info.disp=disp; fb_info.switch_con=&dnfbcon_switch; fb_info.updatevar=&dnfbcon_updatevar; - fb_info.blank=&dnfbcon_blank; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &dn_fb_ops; fb_info.flags = FBINFO_FLAG_DEFAULT; @@ -349,7 +348,7 @@ } -static void dnfbcon_blank(int blank, struct fb_info *info) { +static int dnfb_blank(int blank, struct fb_info *info) { if(blank) { outb(0x0, AP_CONTROL_3A); @@ -357,8 +356,7 @@ else { outb(0x1, AP_CONTROL_3A); } - - return ; + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/dn_cfb8.c linux-2.5/drivers/video/dn_cfb8.c --- linux-2.5.1/drivers/video/dn_cfb8.c Mon Oct 15 20:47:13 2001 +++ linux-2.5/drivers/video/dn_cfb8.c Fri Jan 11 11:07:03 2002 @@ -7,7 +7,6 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <asm/setup.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/irq.h> #include <asm/amigahw.h> @@ -120,10 +119,10 @@ struct fb_info *info); static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con, struct fb_info *info); +static int dnfb_blank(int blank,struct fb_info *info); static int dnfbcon_switch(int con,struct fb_info *info); static int dnfbcon_updatevar(int con,struct fb_info *info); -static void dnfbcon_blank(int blank,struct fb_info *info); static void dn_fb_set_disp(int con,struct fb_info *info); @@ -136,6 +135,7 @@ fb_set_var: dn_fb_set_var, fb_get_cmap: dn_fb_get_cmap, fb_set_cmap: dn_fb_set_cmap, + fb_blank: dnfb_blank, }; static int currcon=0; @@ -292,8 +292,7 @@ fb_info.disp=disp; fb_info.switch_con=&dnfbcon_switch; fb_info.updatevar=&dnfbcon_updatevar; - fb_info.blank=&dnfbcon_blank; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &dn_fb_ops; printk("dn_fb_init: register\n"); @@ -338,7 +337,7 @@ } -static void dnfbcon_blank(int blank, struct fb_info *info) { +static int dnfb_blank(int blank, struct fb_info *info) { if(blank) { outb(0x0, AP_CONTROL_3A); @@ -346,9 +345,7 @@ else { outb(0x1, AP_CONTROL_3A); } - - return ; - + return 0; } void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/dnfb.c linux-2.5/drivers/video/dnfb.c --- linux-2.5.1/drivers/video/dnfb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/dnfb.c Fri Jan 11 11:07:03 2002 @@ -7,7 +7,6 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <asm/setup.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/irq.h> #include <asm/amigahw.h> @@ -125,10 +124,10 @@ struct fb_info *info); static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con, struct fb_info *info); +static int dnfb_blank(int blank,struct fb_info *info); static int dnfbcon_switch(int con,struct fb_info *info); static int dnfbcon_updatevar(int con,struct fb_info *info); -static void dnfbcon_blank(int blank,struct fb_info *info); static void dn_fb_set_disp(int con,struct fb_info *info); @@ -141,6 +140,7 @@ fb_set_var: dn_fb_set_var, fb_get_cmap: dn_fb_get_cmap, fb_set_cmap: dn_fb_set_cmap, + fb_blank: dnfb_blank, }; static int currcon=0; @@ -307,8 +307,7 @@ fb_info.disp=disp; fb_info.switch_con=&dnfbcon_switch; fb_info.updatevar=&dnfbcon_updatevar; - fb_info.blank=&dnfbcon_blank; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &dn_fb_ops; dn_fb_get_var(&disp[0].var,0, &fb_info); @@ -351,7 +350,7 @@ } -static void dnfbcon_blank(int blank, struct fb_info *info) { +static int dnfb_blank(int blank, struct fb_info *info) { if(blank) { outb(0x0, AP_CONTROL_3A); @@ -359,9 +358,7 @@ else { outb(0x1, AP_CONTROL_3A); } - - return ; - + return 0; } void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/epson1355fb.c linux-2.5/drivers/video/epson1355fb.c --- linux-2.5.1/drivers/video/epson1355fb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/epson1355fb.c Mon Jan 14 23:58:39 2002 @@ -361,9 +361,9 @@ return 0; } -static int e1355_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) +static int e1355fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) { u8 r = (red >> 8) & 0xf0; u8 g = (green>>8) & 0xf0; @@ -467,7 +467,6 @@ get_par: e1355_get_par, set_par: e1355_set_par, getcolreg: e1355_getcolreg, - setcolreg: e1355_setcolreg, pan_display: e1355_pan_display, blank: e1355_blank, set_disp: e1355_set_disp, @@ -484,7 +483,9 @@ fb_set_var: fbgen_set_var, fb_get_cmap: fbgen_get_cmap, fb_set_cmap: fbgen_set_cmap, + fb_setcolreg: e1355fb_setcolreg, fb_pan_display: fbgen_pan_display, + fb_blank: fbgen_blank, }; static struct e1355fb_info fb_info; @@ -500,13 +501,12 @@ fb_info.gen.fbhw->detect(); strcpy(fb_info.gen.info.modename, "SED1355"); fb_info.gen.info.changevar = NULL; - fb_info.gen.info.node = -1; + fb_info.gen.info.node = NODEV; fb_info.gen.info.fbops = &e1355fb_ops; fb_info.gen.info.disp = &disp; fb_info.gen.parsize = sizeof(struct e1355_par); fb_info.gen.info.switch_con = &fbgen_switch; fb_info.gen.info.updatevar = &fbgen_update_var; - fb_info.gen.info.blank = &fbgen_blank; fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; /* This should give a reasonable default video mode */ fbgen_get_var(&disp.var, -1, &fb_info.gen.info); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/fbcmap.c linux-2.5/drivers/video/fbcmap.c --- linux-2.5.1/drivers/video/fbcmap.c Sat Mar 3 02:38:39 2001 +++ linux-2.5/drivers/video/fbcmap.c Mon Jan 14 23:58:39 2002 @@ -249,10 +249,7 @@ * */ -int fb_set_cmap(struct fb_cmap *cmap, int kspc, - int (*setcolreg)(u_int, u_int, u_int, u_int, u_int, - struct fb_info *), - struct fb_info *info) +int fb_set_cmap(struct fb_cmap *cmap, int kspc, struct fb_info *info) { int i, start; u16 *red, *green, *blue, *transp; @@ -264,7 +261,7 @@ transp = cmap->transp; start = cmap->start; - if (start < 0) + if (start < 0 || !info->fbops->fb_setcolreg) return -EINVAL; for (i = 0; i < cmap->len; i++) { if (kspc) { @@ -286,7 +283,7 @@ blue++; if (transp) transp++; - if (setcolreg(start++, hred, hgreen, hblue, htransp, info)) + if (info->fbops->fb_setcolreg(start++, hred, hgreen, hblue, htransp, info)) return 0; } return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/fbcon.c linux-2.5/drivers/video/fbcon.c --- linux-2.5.1/drivers/video/fbcon.c Mon Oct 15 20:47:13 2001 +++ linux-2.5/drivers/video/fbcon.c Sun Jan 13 20:03:26 2002 @@ -75,6 +75,7 @@ #include <linux/selection.h> #include <linux/smp.h> #include <linux/init.h> +#include <linux/pm.h> #include <asm/irq.h> #include <asm/system.h> @@ -137,6 +138,12 @@ static void fbcon_free_font(struct display *); static int fbcon_set_origin(struct vc_data *); +#ifdef CONFIG_PM +static int pm_fbcon_request(struct pm_dev *dev, pm_request_t rqst, void *data); +static struct pm_dev *pm_fbcon; +static int fbcon_sleeping; +#endif + /* * Emmanuel: fbcon will now use a hardware cursor if the * low-level driver provides a non-NULL dispsw->cursor pointer, @@ -233,6 +240,7 @@ static struct timer_list cursor_timer = { function: cursor_timer_handler }; +static int use_timer_cursor; static void cursor_timer_handler(unsigned long dev_addr) { @@ -271,10 +279,10 @@ /* XXX Should report error here? */ return fgc; - if (MINOR(current->tty->device) < 1) + if (minor(current->tty->device) < 1) return fgc; - return MINOR(current->tty->device) - 1; + return minor(current->tty->device) - 1; } @@ -457,11 +465,16 @@ #endif if (irqres) { + use_timer_cursor = 1; cursor_blink_rate = DEFAULT_CURSOR_BLINK_RATE; cursor_timer.expires = jiffies+HZ/50; add_timer(&cursor_timer); } +#ifdef CONFIG_PM + pm_fbcon = pm_register(PM_SYS_DEV, PM_SYS_VGA, pm_fbcon_request); +#endif + return display_desc; } @@ -1558,6 +1571,10 @@ if (blank < 0) /* Entering graphics mode */ return 0; +#ifdef CONFIG_PM + if (fbcon_sleeping) + return 0; +#endif /* CONFIG_PM */ fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW); @@ -1590,7 +1607,9 @@ return 1; } } - (*info->blank)(blank, info); + + if (info->fbops->fb_blank) + (*info->fbops->fb_blank)(blank, info); return 0; } @@ -2446,6 +2465,39 @@ return done ? (LOGO_H + fontheight(p) - 1) / fontheight(p) : 0 ; } + +#ifdef CONFIG_PM +/* console.c doesn't do enough here */ +static int +pm_fbcon_request(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + unsigned long flags; + + switch (rqst) + { + case PM_RESUME: + acquire_console_sem(); + fbcon_sleeping = 0; + if (use_timer_cursor) { + cursor_timer.expires = jiffies+HZ/50; + add_timer(&cursor_timer); + } + release_console_sem(); + break; + case PM_SUSPEND: + acquire_console_sem(); + save_flags(flags); + cli(); + if (use_timer_cursor) + del_timer(&cursor_timer); + fbcon_sleeping = 1; + restore_flags(flags); + release_console_sem(); + break; + } + return 0; +} +#endif /* CONFIG_PM */ /* * The console `switch' structure for the frame buffer based console diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/fbgen.c linux-2.5/drivers/video/fbgen.c --- linux-2.5.1/drivers/video/fbgen.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/video/fbgen.c Mon Jan 14 23:58:39 2002 @@ -185,8 +185,6 @@ int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - struct fb_info_gen *info2 = (struct fb_info_gen *)info; - struct fbgen_hwswitch *fbhw = info2->fbhw; int err; if (!fb_display[con].cmap.len) { /* no colormap allocated ? */ @@ -195,7 +193,7 @@ return err; } if (con == currcon) /* current console ? */ - return fb_set_cmap(cmap, kspc, fbhw->setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -343,14 +341,13 @@ void fbgen_install_cmap(int con, struct fb_info_gen *info) { - struct fbgen_hwswitch *fbhw = info->fbhw; if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, &info->info); + fb_set_cmap(&fb_display[con].cmap, 1, &info->info); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256; - fb_set_cmap(fb_default_cmap(size), 1, fbhw->setcolreg, &info->info); + fb_set_cmap(fb_default_cmap(size), 1, &info->info); } } @@ -419,7 +416,7 @@ * */ -void fbgen_blank(int blank, struct fb_info *info) +int fbgen_blank(int blank, struct fb_info *info) { struct fb_info_gen *info2 = (struct fb_info_gen *)info; struct fbgen_hwswitch *fbhw = info2->fbhw; @@ -427,7 +424,7 @@ struct fb_cmap cmap; if (fbhw->blank && !fbhw->blank(blank, info2)) - return; + return 0; if (blank) { memset(black, 0, 16*sizeof(u16)); cmap.red = black; @@ -436,8 +433,9 @@ cmap.transp = NULL; cmap.start = 0; cmap.len = 16; - fb_set_cmap(&cmap, 1, fbhw->setcolreg, info); + fb_set_cmap(&cmap, 1, info); } else fbgen_install_cmap(currcon, info2); + return 0; } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/fbmem.c linux-2.5/drivers/video/fbmem.c --- linux-2.5.1/drivers/video/fbmem.c Wed Nov 14 23:41:37 2001 +++ linux-2.5/drivers/video/fbmem.c Fri Jan 11 11:07:03 2002 @@ -21,6 +21,7 @@ #include <linux/kernel.h> #include <linux/major.h> #include <linux/slab.h> +#include <linux/mm.h> #include <linux/mman.h> #include <linux/tty.h> #include <linux/console.h> @@ -507,10 +508,9 @@ set_con2fb_map(i, con2fb.framebuffer); return 0; case FBIOBLANK: - if (info->blank == 0) + if (fb->fb_blank == NULL) return -EINVAL; - (*info->blank)(arg, info); - return 0; + return fb->fb_blank(arg, info); default: if (fb->fb_ioctl == NULL) return -EINVAL; @@ -576,12 +576,13 @@ 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; #if defined(__sparc_v9__) vma->vm_flags |= (VM_SHM | VM_LOCKED); if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot, 0)) return -EAGAIN; - vma->vm_flags |= VM_IO; #else #if defined(__mc68000__) #if defined(CONFIG_SUN3) @@ -607,8 +608,6 @@ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; #elif defined(__arm__) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - /* This is an IO map - tell maydump to skip this VMA */ - vma->vm_flags |= VM_IO; #elif defined(__sh__) pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE; #else @@ -625,7 +624,7 @@ #if 1 /* to go away in 2.5.0 */ int GET_FB_IDX(kdev_t rdev) { - int fbidx = MINOR(rdev); + int fbidx = minor(rdev); if (fbidx >= 32) { int newfbidx = fbidx >> 5; static int warned; @@ -719,7 +718,7 @@ for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) break; - fb_info->node = MKDEV(FB_MAJOR, i); + fb_info->node = mk_kdev(FB_MAJOR, i); registered_fb[i] = fb_info; if (!fb_ever_opened[i]) { struct module *owner = fb_info->fbops->owner; @@ -931,3 +930,5 @@ #if 1 /* to go away in 2.5.0 */ EXPORT_SYMBOL(GET_FB_IDX); #endif + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/fm2fb.c linux-2.5/drivers/video/fm2fb.c --- linux-2.5.1/drivers/video/fm2fb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/fm2fb.c Mon Jan 14 23:58:39 2002 @@ -191,7 +191,9 @@ struct fb_info *info); static int fm2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); - +static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int fm2fb_blank(int blank, struct fb_info *info); /* * Interface to the low level console driver @@ -200,8 +202,6 @@ int fm2fb_init(void); static int fm2fbcon_switch(int con, struct fb_info *info); static int fm2fbcon_updatevar(int con, struct fb_info *info); -static void fm2fbcon_blank(int blank, struct fb_info *info); - /* * Internal routines @@ -209,8 +209,6 @@ static int fm2fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); @@ -221,6 +219,8 @@ fb_set_var: fm2fb_set_var, fb_get_cmap: fm2fb_get_cmap, fb_set_cmap: fm2fb_set_cmap, + fb_setcolreg: fm2fb_setcolreg, + fb_blank: fm2fb_blank, }; /* @@ -314,7 +314,7 @@ return err; } if (con == currcon) { /* current console? */ - err = fb_set_cmap(cmap, kspc, fm2fb_setcolreg, info); + err = fb_set_cmap(cmap, kspc, info); return err; } else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); @@ -361,7 +361,7 @@ for (x = 0; x < 96; x++) *ptr++ = 0x0000ff; /* blue */ for (x = 0; x < 96; x++) *ptr++ = 0x000000; /* black */ } - fm2fbcon_blank(0, NULL); + fm2fb_blank(0, NULL); if (fm2fb_mode == -1) fm2fb_mode = FM2FB_MODE_PAL; @@ -401,14 +401,13 @@ disp.scrollmode = SCROLL_YREDRAW; strcpy(fb_info.modename, fb_fix.id); - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &fm2fb_ops; fb_info.disp = &disp; fb_info.fontname[0] = '\0'; fb_info.changevar = NULL; fb_info.switch_con = &fm2fbcon_switch; fb_info.updatevar = &fm2fbcon_updatevar; - fb_info.blank = &fm2fbcon_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; fm2fb_set_var(&fb_var, -1, &fb_info); @@ -466,13 +465,14 @@ * Blank the display. */ -static void fm2fbcon_blank(int blank, struct fb_info *info) +static int fm2fb_blank(int blank, struct fb_info *info) { unsigned char t = FRAMEMASTER_ROM; if (!blank) t |= FRAMEMASTER_ENABLE | FRAMEMASTER_NOLACE; fm2fb_reg[0] = t; + return 0; } /* @@ -523,9 +523,9 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, fm2fb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else - fb_set_cmap(fb_default_cmap(256), 1, fm2fb_setcolreg, info); + fb_set_cmap(fb_default_cmap(256), 1, info); } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/g364fb.c linux-2.5/drivers/video/g364fb.c --- linux-2.5.1/drivers/video/g364fb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/g364fb.c Mon Jan 14 23:58:39 2002 @@ -101,6 +101,9 @@ struct fb_info *info); static int g364fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int g364fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int g364fb_blank(int blank, struct fb_info *info); /* @@ -109,16 +112,12 @@ int g364fb_init(void); static int g364fbcon_switch(int con, struct fb_info *info); static int g364fbcon_updatevar(int con, struct fb_info *info); -static void g364fbcon_blank(int blank, struct fb_info *info); - /* * Internal routines */ static int g364fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int g364fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); @@ -129,7 +128,9 @@ fb_set_var: g364fb_set_var, fb_get_cmap: g364fb_get_cmap, fb_set_cmap: g364fb_set_cmap, + fb_setcolreg: g364fb_setcolreg, fb_pan_display: g364fb_pan_display, + fb_blank: g364fb_blank, }; @@ -265,7 +266,7 @@ return err; } if (con == currcon) { /* current console? */ - return fb_set_cmap(cmap, kspc, g364fb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); } else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -385,7 +386,6 @@ fb_info.changevar = NULL; fb_info.switch_con = &g364fbcon_switch; fb_info.updatevar = &g364fbcon_updatevar; - fb_info.blank = &g364fbcon_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; g364fb_set_var(&fb_var, -1, &fb_info); @@ -429,12 +429,13 @@ /* * Blank the display. */ -static void g364fbcon_blank(int blank, struct fb_info *info) +static int g364fb_blank(int blank, struct fb_info *info) { if (blank) *(unsigned int *) CTLA_REG |= FORCE_BLANK; else *(unsigned int *) CTLA_REG &= ~FORCE_BLANK; + return 0; } /* @@ -482,10 +483,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, g364fb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1, - g364fb_setcolreg, info); + info); } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/hgafb.c linux-2.5/drivers/video/hgafb.c --- linux-2.5.1/drivers/video/hgafb.c Mon Nov 12 17:46:25 2001 +++ linux-2.5/drivers/video/hgafb.c Mon Jan 14 23:58:39 2002 @@ -511,7 +511,7 @@ } /** - * hga_setcolreg - set color registers + * hgafb_setcolreg - set color registers * @regno:register index to set * @red:red value, unused * @green:green value, unused @@ -524,8 +524,8 @@ * A zero is returned on success and 1 for failure. */ -static int hga_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +static int hgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) { if (regno > 1) return 1; @@ -540,7 +540,7 @@ * @info:pointer to fb_info object containing info for current hga board * * This wrapper function passes it's input parameters to fb_set_cmap(). - * Callback function hga_setcolreg() is used to set the color registers. + * Callback function hgafb_setcolreg() is used to set the color registers. */ int hga_set_cmap(struct fb_cmap *cmap, int kspc, int con, @@ -548,7 +548,7 @@ { CHKINFO(-EINVAL); DPRINTK("hga_set_cmap: con:%d\n", con); - return fb_set_cmap(cmap, kspc, hga_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); } /** @@ -592,6 +592,28 @@ return 0; } +/** + * hgafb_blank - (un)blank the screen + * @blank_mode:blanking method to use + * @info:unused + * + * Blank the screen if blank_mode != 0, else unblank. + * Implements VESA suspend and powerdown modes on hardware that supports + * disabling hsync/vsync: + * @blank_mode == 2 means suspend vsync, + * @blank_mode == 3 means suspend hsync, + * @blank_mode == 4 means powerdown. + * A zero is returned on success and %-EINVAL for failure. + */ + +static int hgafb_blank(int blank_mode, struct fb_info *info) +{ + CHKINFO( ); + DPRINTK("hga_blank: blank_mode:%d, info:%x, fb_info:%x\n", blank_mode, (unsigned)info, (unsigned)&fb_info); + + hga_blank(blank_mode); + return 0; +} static struct fb_ops hgafb_ops = { owner: THIS_MODULE, @@ -600,7 +622,9 @@ fb_set_var: hga_set_var, fb_get_cmap: hga_get_cmap, fb_set_cmap: hga_set_cmap, + fb_setcolreg: hgafb_setcolreg, fb_pan_display: hga_pan_display, + fb_blank: hgafb_blank, }; @@ -642,7 +666,7 @@ */ #if 0 fb_copy_cmap(&fb_display[con].cmap, &info->cmap, 0); - fb_set_cmap(&info->cmap, 1, hga_setcolreg, info); + fb_set_cmap(&info->cmap, 1, info); #endif memcpy(&info->var, &fb_display[con].var, @@ -673,28 +697,6 @@ return (con < 0) ? -EINVAL : hga_pan_display(&fb_display[con].var, con, info); } -/** - * hgafbcon_blank - (un)blank the screen - * @blank_mode:blanking method to use - * @info:unused - * - * Blank the screen if blank_mode != 0, else unblank. - * Implements VESA suspend and powerdown modes on hardware that supports - * disabling hsync/vsync: - * @blank_mode == 2 means suspend vsync, - * @blank_mode == 3 means suspend hsync, - * @blank_mode == 4 means powerdown. - */ - -static void hgafbcon_blank(int blank_mode, struct fb_info *info) -{ - CHKINFO( ); - DPRINTK("hga_blank: blank_mode:%d, info:%x, fb_info:%x\n", blank_mode, (unsigned)info, (unsigned)&fb_info); - - hga_blank(blank_mode); -} - - /* ------------------------------------------------------------------------- */ /* @@ -742,7 +744,7 @@ disp.scrollmode = SCROLL_YREDRAW; strcpy (fb_info.modename, hga_fix.id); - fb_info.node = -1; + fb_info.node = NODEV; fb_info.flags = FBINFO_FLAG_DEFAULT; /* fb_info.open = ??? */ fb_info.var = hga_default_var; @@ -760,7 +762,6 @@ fb_info.changevar = NULL; fb_info.switch_con = hgafbcon_switch; fb_info.updatevar = hgafbcon_updatevar; - fb_info.blank = hgafbcon_blank; fb_info.pseudo_palette = NULL; /* ??? */ fb_info.par = NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/hitfb.c linux-2.5/drivers/video/hitfb.c --- linux-2.5.1/drivers/video/hitfb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/hitfb.c Mon Jan 14 23:58:39 2002 @@ -323,7 +323,6 @@ hitfb_get_par, hitfb_set_par, hitfb_getcolreg, - hitfb_setcolreg, hitfb_pan_display, hitfb_blank, hitfb_set_disp @@ -337,21 +336,22 @@ fb_set_var: fbgen_set_var, fb_get_cmap: fbgen_get_cmap, fb_set_cmap: fbgen_set_cmap, + fb_setcolreg: hitfb_setcolreg, fb_pan_display: fbgen_pan_display, + fb_blank: fbgen_blank, }; int __init hitfb_init(void) { strcpy(fb_info.gen.info.modename, "Hitachi HD64461"); - fb_info.gen.info.node = -1; + fb_info.gen.info.node = NODEV; fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; fb_info.gen.info.fbops = &hitfb_ops; 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; - fb_info.gen.info.blank = &fbgen_blank; fb_info.gen.parsize = sizeof(struct hitfb_par); fb_info.gen.fbhw = &hitfb_switch; fb_info.gen.fbhw->detect(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/hpfb.c linux-2.5/drivers/video/hpfb.c --- linux-2.5.1/drivers/video/hpfb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/hpfb.c Fri Jan 11 11:07:03 2002 @@ -230,13 +230,6 @@ return 0; } -/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ - -static void hpfb_blank(int blank, struct fb_info *info) -{ - /* Not supported */ -} - static void hpfb_set_disp(int con) { struct fb_fix_screeninfo fix; @@ -328,12 +321,11 @@ */ strcpy(fb_info.modename, "Topcat"); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &hpfb_ops; fb_info.disp = &disp; fb_info.switch_con = &hpfb_switch; fb_info.updatevar = &fb_update_var; - fb_info.blank = &hpfb_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; do_fb_set_var(&hpfb_defined, 1); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/igafb.c linux-2.5/drivers/video/igafb.c --- linux-2.5.1/drivers/video/igafb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/igafb.c Mon Jan 14 23:58:39 2002 @@ -331,9 +331,9 @@ return 0; } -static int iga_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *fb_info) +static int igafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info) { /* * Set a single color register. The values supplied are @@ -390,11 +390,10 @@ if (con != info->currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, - iga_setcolreg, &info->fb_info); + fb_set_cmap(&fb_display[con].cmap, 1, &info->fb_info); else fb_set_cmap(fb_default_cmap(info->video_cmap_len), 1, - iga_setcolreg, &info->fb_info); + &info->fb_info); } static int igafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, @@ -425,7 +424,7 @@ return err; } if (con == fb->currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, iga_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -441,6 +440,7 @@ fb_set_var: igafb_set_var, fb_get_cmap: igafb_get_cmap, fb_set_cmap: igafb_set_cmap, + fb_setcolreg: igafb_setcolreg, #ifdef __sparc__ fb_mmap: igafb_mmap, #endif @@ -525,16 +525,6 @@ return 1; } - - -/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ - -static void igafb_blank(int blank, struct fb_info *info) -{ - /* Not supported */ -} - - static int __init iga_init(struct fb_info_iga *info) { char vramsz = iga_inb(info, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) @@ -568,14 +558,13 @@ } strcpy(info->fb_info.modename, igafb_name); - info->fb_info.node = -1; + info->fb_info.node = NODEV; info->fb_info.fbops = &igafb_ops; info->fb_info.disp = &info->disp; strcpy(info->fb_info.fontname, fontname); info->fb_info.changevar = NULL; info->fb_info.switch_con = &igafb_switch; info->fb_info.updatevar = &igafb_update_var; - info->fb_info.blank = &igafb_blank; info->fb_info.flags=FBINFO_FLAG_DEFAULT; igafb_set_disp(-1, info); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/imsttfb.c linux-2.5/drivers/video/imsttfb.c --- linux-2.5.1/drivers/video/imsttfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/imsttfb.c Mon Jan 14 23:58:39 2002 @@ -371,7 +371,6 @@ TVP = 1 }; -#define USE_NV_MODES 1 #define INIT_BPP 8 #define INIT_XRES 640 #define INIT_YRES 480 @@ -384,7 +383,8 @@ static char curblink __initdata = 1; static char noaccel __initdata = 0; #if defined(CONFIG_PPC) -static signed char init_vmode __initdata = -1, init_cmode __initdata = -1; +static signed char init_vmode __initdata = VMODE_NVRAM; +static signed char init_cmode __initdata = CMODE_NVRAM; #endif static struct imstt_regvals tvp_reg_init_2 = { @@ -1293,10 +1293,10 @@ do_install_cmap (int con, struct fb_info *info) { if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, imsttfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else { u_int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), 1, imsttfb_setcolreg, info); + fb_set_cmap(fb_default_cmap(size), 1, info); } } @@ -1561,7 +1561,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, imsttfb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); @@ -1643,7 +1643,7 @@ name: "imsttfb", id_table: imsttfb_pci_tbl, probe: imsttfb_probe, - remove: imsttfb_remove, + remove: __devexit_p(imsttfb_remove), }; static struct fb_ops imsttfb_ops = { @@ -1653,7 +1653,9 @@ fb_set_var: imsttfb_set_var, fb_get_cmap: imsttfb_get_cmap, fb_set_cmap: imsttfb_set_cmap, + fb_setcolreg: imsttfb_setcolreg, fb_pan_display: imsttfb_pan_display, + fb_blank: imsttfb_blank, fb_ioctl: imsttfb_ioctl, }; @@ -1714,8 +1716,8 @@ return 0; } -static void -imsttfbcon_blank (int blank, struct fb_info *info) +static int +imsttfb_blank (int blank, struct fb_info *info) { struct fb_info_imstt *p = (struct fb_info_imstt *)info; __u32 ctrl; @@ -1765,6 +1767,7 @@ ctrl |= 0x00001780; } out_le32(&p->dc_regs[STGCTL], ctrl); + return 0; } static void __init @@ -1804,20 +1807,25 @@ } } -#if USE_NV_MODES && defined(CONFIG_PPC) +#ifdef CONFIG_ALL_PPC { int vmode = init_vmode, cmode = init_cmode; - if (vmode == -1) { +#ifdef CONFIG_NVRAM + /* Attempt to read vmode/cmode from NVRAM */ + if (vmode == VMODE_NVRAM) vmode = nvram_read_byte(NV_VMODE); - if (vmode <= 0 || vmode > VMODE_MAX) - vmode = VMODE_640_480_67; - } - if (cmode == -1) { + if (cmode == CMODE_NVRAM) cmode = nvram_read_byte(NV_CMODE); - if (cmode < CMODE_8 || cmode > CMODE_32) - cmode = CMODE_8; - } +#endif + /* If we didn't get something from NVRAM, pick a + * sane default. + */ + if (vmode <= 0 || vmode > VMODE_MAX) + vmode = VMODE_640_480_67; + if (cmode < CMODE_8 || cmode > CMODE_32) + cmode = CMODE_8; + if (mac_vmode_to_var(vmode, cmode, &p->disp.var)) { p->disp.var.xres = p->disp.var.xres_virtual = INIT_XRES; p->disp.var.yres = p->disp.var.yres_virtual = INIT_YRES; @@ -1866,13 +1874,12 @@ strcpy(p->info.modename, p->fix.id); strcpy(p->info.fontname, fontname); - p->info.node = -1; + p->info.node = NODEV; p->info.fbops = &imsttfb_ops; p->info.disp = &p->disp; p->info.changevar = 0; p->info.switch_con = &imsttfbcon_switch; p->info.updatevar = &imsttfbcon_updatevar; - p->info.blank = &imsttfbcon_blank; p->info.flags = FBINFO_FLAG_DEFAULT; for (i = 0; i < 16; i++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/leofb.c linux-2.5/drivers/video/leofb.c --- linux-2.5.1/drivers/video/leofb.c Wed Oct 17 21:16:39 2001 +++ linux-2.5/drivers/video/leofb.c Fri Jan 11 11:07:03 2002 @@ -535,7 +535,7 @@ spin_unlock_irqrestore(&fb->lock, flags); } -static void leo_blank (struct fb_info_sbusfb *fb) +static int leo_blank (struct fb_info_sbusfb *fb) { unsigned long flags; u32 tmp; @@ -547,9 +547,10 @@ tmp &= ~LEO_KRN_CSR_ENABLE; sbus_writel(tmp, &fb->s.leo.lx_krn->krn_csr); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } -static void leo_unblank (struct fb_info_sbusfb *fb) +static int leo_unblank (struct fb_info_sbusfb *fb) { unsigned long flags; u32 tmp; @@ -563,6 +564,7 @@ sbus_writel(tmp, &fb->s.leo.lx_krn->krn_csr); } spin_unlock_irqrestore(&fb->lock, flags); + return 0; } static int __init diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/macfb.c linux-2.5/drivers/video/macfb.c --- linux-2.5.1/drivers/video/macfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/macfb.c Mon Jan 14 23:58:39 2002 @@ -794,10 +794,9 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, macfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else - fb_set_cmap(fb_default_cmap(video_cmap_len), 1, - macfb_setcolreg, info); + fb_set_cmap(fb_default_cmap(video_cmap_len), 1, info); } static int macfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, @@ -824,7 +823,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, macfb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -837,6 +836,7 @@ fb_set_var: macfb_set_var, fb_get_cmap: macfb_get_cmap, fb_set_cmap: macfb_set_cmap, + fb_setcolreg: macfb_setcolreg, }; void __init macfb_setup(char *options, int *ints) @@ -875,11 +875,6 @@ return 1; } -static void macfb_blank(int blank, struct fb_info *info) -{ - /* Not supported */ -} - void __init macfb_init(void) { struct nubus_dev* ndev = NULL; @@ -1221,12 +1216,11 @@ } fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &macfb_ops; fb_info.disp = &disp; fb_info.switch_con = &macfb_switch; fb_info.updatevar = &macfb_update_var; - fb_info.blank = &macfb_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; macfb_set_disp(-1); do_install_cmap(0, &fb_info); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/matrox/matroxfb_base.c linux-2.5/drivers/video/matrox/matroxfb_base.c --- linux-2.5.1/drivers/video/matrox/matroxfb_base.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/matrox/matroxfb_base.c Mon Jan 14 23:58:39 2002 @@ -108,6 +108,7 @@ #endif static void matroxfb_unregister_device(struct matrox_fb_info* minfo); +int matroxfb_switch(int con, struct fb_info *info); /* --------------------------------------------------------------------- */ @@ -570,16 +571,16 @@ return 0; } -static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *fb_info) +static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info) { struct display* p; #ifdef CONFIG_FB_MATROX_MULTIHEAD struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info; #endif - DBG("matrox_setcolreg") + DBG("matroxfb_setcolreg") /* * Set a single color register. The values supplied are @@ -659,10 +660,10 @@ DBG("do_install_cmap") if (dsp->cmap.len) - fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon)); + fb_set_cmap(&dsp->cmap, 1, &ACCESS_FBINFO(fbcon)); else fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)), - 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon)); + 1, &ACCESS_FBINFO(fbcon)); } static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con, @@ -981,7 +982,7 @@ return err; } if (con == ACCESS_FBINFO(currcon)) { /* current console? */ - return fb_set_cmap(cmap, kspc, matrox_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); } else fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1); return 0; @@ -1168,6 +1169,40 @@ #undef minfo } +/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ + +static int matroxfb_blank(int blank, struct fb_info *info) +{ +#define minfo ((struct matrox_fb_info*)info) + int seq; + int crtc; + CRITFLAGS + + DBG("matroxfb_blank") + + if (ACCESS_FBINFO(dead)) + return 1; + + switch (blank) { + case 1: seq = 0x20; crtc = 0x00; break; /* works ??? */ + case 2: seq = 0x20; crtc = 0x10; break; + case 3: seq = 0x20; crtc = 0x20; break; + case 4: seq = 0x20; crtc = 0x30; break; + default: seq = 0x00; crtc = 0x00; break; + } + + CRITBEGIN + + mga_outb(M_SEQ_INDEX, 1); + mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq); + mga_outb(M_EXTVGA_INDEX, 1); + mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc); + + CRITEND + return 0; +#undef minfo +} + static struct fb_ops matroxfb_ops = { owner: THIS_MODULE, fb_open: matroxfb_open, @@ -1177,7 +1212,9 @@ fb_set_var: matroxfb_set_var, fb_get_cmap: matroxfb_get_cmap, fb_set_cmap: matroxfb_set_cmap, + fb_setcolreg: matroxfb_setcolreg, fb_pan_display: matroxfb_pan_display, + fb_blank: matroxfb_blank, fb_ioctl: matroxfb_ioctl, }; @@ -1231,40 +1268,6 @@ #undef minfo } -/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ - -static void matroxfb_blank(int blank, struct fb_info *info) -{ -#define minfo ((struct matrox_fb_info*)info) - int seq; - int crtc; - CRITFLAGS - - DBG("matroxfb_blank") - - if (ACCESS_FBINFO(dead)) - return; - - switch (blank) { - case 1: seq = 0x20; crtc = 0x00; break; /* works ??? */ - case 2: seq = 0x20; crtc = 0x10; break; - case 3: seq = 0x20; crtc = 0x20; break; - case 4: seq = 0x20; crtc = 0x30; break; - default: seq = 0x00; crtc = 0x00; break; - } - - CRITBEGIN - - mga_outb(M_SEQ_INDEX, 1); - mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq); - mga_outb(M_EXTVGA_INDEX, 1); - mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc); - - CRITEND - -#undef minfo -} - #define RSDepth(X) (((X) >> 8) & 0x0F) #define RS8bpp 0x1 #define RS15bpp 0x2 @@ -1789,12 +1792,11 @@ strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA"); ACCESS_FBINFO(fbcon.changevar) = NULL; - ACCESS_FBINFO(fbcon.node) = -1; + ACCESS_FBINFO(fbcon.node) = NODEV; ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops; ACCESS_FBINFO(fbcon.disp) = d; ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch; ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar; - ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank; /* after __init time we are like module... no logo */ ACCESS_FBINFO(fbcon.flags) = hotplug ? FBINFO_FLAG_MODULE : FBINFO_FLAG_DEFAULT; ACCESS_FBINFO(video.len_usable) &= PAGE_MASK; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/matrox/matroxfb_crtc2.c linux-2.5/drivers/video/matrox/matroxfb_crtc2.c --- linux-2.5.1/drivers/video/matrox/matroxfb_crtc2.c Fri Nov 9 22:07:41 2001 +++ linux-2.5/drivers/video/matrox/matroxfb_crtc2.c Mon Jan 14 23:58:39 2002 @@ -84,9 +84,9 @@ static void do_install_cmap(struct matroxfb_dh_fb_info* m2info, struct display* p) { if (p->cmap.len) - fb_set_cmap(&p->cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon); + fb_set_cmap(&p->cmap, 1, &m2info->fbcon); else - fb_set_cmap(fb_default_cmap(16), 1, matroxfb_dh_setcolreg, &m2info->fbcon); + fb_set_cmap(fb_default_cmap(16), 1, &m2info->fbcon); } static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, @@ -494,7 +494,7 @@ return err; } if (con == m2info->currcon) - return fb_set_cmap(cmap, kspc, matroxfb_dh_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1); return 0; @@ -604,6 +604,20 @@ #undef m2info } +static int matroxfb_dh_blank(int blank, struct fb_info* info) { +#define m2info ((struct matroxfb_dh_fb_info*)info) + switch (blank) { + case 1: + case 2: + case 3: + case 4: + default:; + } + /* do something... */ +#undef m2info + return 0; +} + static struct fb_ops matroxfb_dh_ops = { owner: THIS_MODULE, fb_open: matroxfb_dh_open, @@ -613,7 +627,9 @@ fb_set_var: matroxfb_dh_set_var, fb_get_cmap: matroxfb_dh_get_cmap, fb_set_cmap: matroxfb_dh_set_cmap, + fb_setcolreg: matroxfb_dh_setcolreg, fb_pan_display: matroxfb_dh_pan_display, + fb_blank: matroxfb_dh_blank, fb_ioctl: matroxfb_dh_ioctl, }; @@ -647,19 +663,6 @@ #undef m2info } -static void matroxfb_dh_blank(int blank, struct fb_info* info) { -#define m2info ((struct matroxfb_dh_fb_info*)info) - switch (blank) { - case 1: - case 2: - case 3: - case 4: - default:; - } - /* do something... */ -#undef m2info -} - static struct fb_var_screeninfo matroxfb_dh_defined = { 640,480,640,480,/* W,H, virtual W,H */ 0,0, /* offset */ @@ -693,12 +696,11 @@ strcpy(m2info->fbcon.modename, "MATROX CRTC2"); m2info->fbcon.changevar = NULL; - m2info->fbcon.node = -1; + m2info->fbcon.node = NODEV; m2info->fbcon.fbops = &matroxfb_dh_ops; m2info->fbcon.disp = d; m2info->fbcon.switch_con = &matroxfb_dh_switch; m2info->fbcon.updatevar = &matroxfb_dh_updatevar; - m2info->fbcon.blank = &matroxfb_dh_blank; m2info->fbcon.flags = FBINFO_FLAG_DEFAULT; m2info->currcon = -1; m2info->currcon_display = d; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/matrox/matroxfb_g450.c linux-2.5/drivers/video/matrox/matroxfb_g450.c --- linux-2.5.1/drivers/video/matrox/matroxfb_g450.c Fri Nov 9 22:07:41 2001 +++ linux-2.5/drivers/video/matrox/matroxfb_g450.c Thu Jan 3 01:41:40 2002 @@ -16,6 +16,8 @@ #include <linux/matroxfb.h> #include <asm/uaccess.h> +extern int matroxfb_switch(int con, struct fb_info *info); + static int matroxfb_g450_get_reg(WPMINFO int reg) { int val; unsigned long flags; @@ -103,7 +105,7 @@ m->regs[0x80] = a; m->regs[0x81] = b; m->regs[0x82] = c; - printk(KERN_DEBUG "PLL: %02X %02X %02X\n", a, b, c); + //printk(KERN_DEBUG "PLL: %02X %02X %02X\n", a, b, c); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/maxinefb.c linux-2.5/drivers/video/maxinefb.c --- linux-2.5.1/drivers/video/maxinefb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/maxinefb.c Fri Jan 11 11:07:03 2002 @@ -358,12 +358,11 @@ 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.node = NODEV; 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 = NULL; fb_info.flags = FBINFO_FLAG_DEFAULT; maxinefb_do_fb_set_var(&maxinefb_defined, 1); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/mdacon.c linux-2.5/drivers/video/mdacon.c --- linux-2.5.1/drivers/video/mdacon.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/mdacon.c Mon Jan 14 22:39:45 2002 @@ -24,6 +24,7 @@ * * Changelog: * Paul G. (03/2001) Fix mdacon= boot prompt to use __setup(). + * 20011230 Jan.Schubert@GMX.li - consider non-Hercules MDA compatible */ #include <linux/types.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/modedb.c linux-2.5/drivers/video/modedb.c --- linux-2.5.1/drivers/video/modedb.c Wed Nov 28 01:06:50 2001 +++ linux-2.5/drivers/video/modedb.c Thu Dec 13 16:32:36 2001 @@ -41,7 +41,7 @@ #define DEFAULT_MODEDB_INDEX 0 -static const struct fb_videomode modedb[] __initdata = { +static struct fb_videomode modedb[] __initdata = { { /* 640x400 @ 70 Hz, 31.5 kHz hsync */ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/offb.c linux-2.5/drivers/video/offb.c --- linux-2.5.1/drivers/video/offb.c Tue Oct 2 16:10:31 2001 +++ linux-2.5/drivers/video/offb.c Mon Jan 14 23:58:39 2002 @@ -52,7 +52,8 @@ cmap_r128, /* ATI Rage128 */ cmap_M3A, /* ATI Rage Mobility M3 Head A */ cmap_M3B, /* ATI Rage Mobility M3 Head B */ - cmap_radeon /* ATI Radeon */ + cmap_radeon, /* ATI Radeon */ + cmap_gxt2000 /* IBM GXT2000 */ }; struct fb_info_offb { @@ -64,6 +65,7 @@ volatile unsigned char *cmap_adr; volatile unsigned char *cmap_data; int cmap_type; + int blanked; union { #ifdef FBCON_HAS_CFB16 u16 cfb16[16]; @@ -97,6 +99,9 @@ struct fb_info *info); static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int offb_blank(int blank, struct fb_info *info); #ifdef CONFIG_BOOTX_TEXT extern boot_infos_t *boot_infos; #endif @@ -112,8 +117,6 @@ static int offbcon_switch(int con, struct fb_info *info); static int offbcon_updatevar(int con, struct fb_info *info); -static void offbcon_blank(int blank, struct fb_info *info); - /* * Internal routines @@ -121,8 +124,6 @@ static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); @@ -133,6 +134,8 @@ fb_set_var: offb_set_var, fb_get_cmap: offb_get_cmap, fb_set_cmap: offb_set_cmap, + fb_setcolreg: offb_setcolreg, + fb_blank: offb_blank, }; /* @@ -210,9 +213,11 @@ static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - if (con == currcon) /* current console? */ + struct fb_info_offb *info2 = (struct fb_info_offb *)info; + + if (con == currcon && !info2->blanked) /* current console? */ return fb_get_cmap(cmap, kspc, offb_getcolreg, info); - else if (fb_display[con].cmap.len) /* non default colormap? */ + if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else { @@ -240,8 +245,8 @@ if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0))) return err; } - if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, offb_setcolreg, info); + if (con == currcon && !info2->blanked) /* current console? */ + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -426,7 +431,7 @@ info->cmap_type = cmap_unknown; if (depth == 8) { - /* XXX kludge for ati */ + /* XXX kludge for ati's */ if (dp && !strncmp(name, "ATY,Rage128", 11)) { unsigned long regbase = dp->addrs[2].address; info->cmap_adr = ioremap(regbase, 0x1FFF); @@ -445,10 +450,19 @@ info->cmap_adr = ioremap(regbase, 0x1FFF); info->cmap_type = cmap_radeon; } else if (!strncmp(name, "ATY,", 4)) { + /* Hrm... this is bad... any recent ATI not covered + * by the previous cases will get there, while this + * cose is only good for mach64's. Gotta figure out + * a proper fix... --BenH. + */ unsigned long base = address & 0xff000000UL; info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0; info->cmap_data = info->cmap_adr + 1; info->cmap_type = cmap_m64; + } else if (dp && device_is_compatible(dp, "pci1014,b7")) { + unsigned long regbase = dp->addrs[0].address; + info->cmap_adr = ioremap(regbase + 0x6000, 0x1000); + info->cmap_type = cmap_gxt2000; } fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; @@ -566,14 +580,13 @@ strcpy(info->info.modename, "OFfb "); strncat(info->info.modename, full_name, sizeof(info->info.modename)); - info->info.node = -1; + info->info.node = NODEV; info->info.fbops = &offb_ops; info->info.disp = disp; info->info.fontname[0] = '\0'; info->info.changevar = NULL; info->info.switch_con = &offbcon_switch; info->info.updatevar = &offbcon_updatevar; - info->info.blank = &offbcon_blank; info->info.flags = FBINFO_FLAG_DEFAULT; for (i = 0; i < 16; i++) { @@ -620,8 +633,10 @@ static int offbcon_switch(int con, struct fb_info *info) { + struct fb_info_offb *info2 = (struct fb_info_offb *)info; + /* Do we have to save the colormap? */ - if (fb_display[currcon].cmap.len) + if (fb_display[currcon].cmap.len && !info2->blanked) fb_get_cmap(&fb_display[currcon].cmap, 1, offb_getcolreg, info); currcon = con; @@ -644,7 +659,7 @@ * Blank the display. */ -static void offbcon_blank(int blank, struct fb_info *info) +static int offb_blank(int blank, struct fb_info *info) { struct fb_info_offb *info2 = (struct fb_info_offb *)info; int i, j; @@ -652,6 +667,15 @@ if (!info2->cmap_adr) return; + if (!info2->blanked) { + if (!blank) + return; + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, 1, offb_getcolreg, info); + } + + info2->blanked = blank; + if (blank) for (i = 0; i < 256; i++) { switch(info2->cmap_type) { @@ -664,30 +688,34 @@ } break; case cmap_M3A: - /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ - out_le32((unsigned *)(info2->cmap_adr + 0x58), - in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20); + /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32((unsigned *)(info2->cmap_adr + 0x58), + in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20); case cmap_r128: - /* Set palette index & data */ - out_8(info2->cmap_adr + 0xb0, i); - out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0); - break; + /* Set palette index & data */ + out_8(info2->cmap_adr + 0xb0, i); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0); + break; case cmap_M3B: - /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ - out_le32((unsigned *)(info2->cmap_adr + 0x58), - in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20); - /* Set palette index & data */ - out_8(info2->cmap_adr + 0xb0, i); - out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0); - break; + /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32((unsigned *)(info2->cmap_adr + 0x58), + in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20); + /* Set palette index & data */ + 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; + out_8(info2->cmap_adr + 0xb0, i); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0); + break; + case cmap_gxt2000: + out_le32((unsigned *)info2->cmap_adr + i, 0); + break; } } else do_install_cmap(currcon, info); + return 0; } /* @@ -769,6 +797,10 @@ out_le32((unsigned *)(info2->cmap_adr + 0xb4), (red << 16 | green << 8 | blue)); break; + case cmap_gxt2000: + out_le32((unsigned *)info2->cmap_adr + regno, + (red << 16 | green << 8 | blue)); + break; } if (regno < 16) @@ -797,11 +829,11 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, offb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), 1, offb_setcolreg, info); + fb_set_cmap(fb_default_cmap(size), 1, info); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/p9100fb.c linux-2.5/drivers/video/p9100fb.c --- linux-2.5.1/drivers/video/p9100fb.c Fri Feb 9 19:30:23 2001 +++ linux-2.5/drivers/video/p9100fb.c Fri Jan 11 11:07:03 2002 @@ -87,7 +87,7 @@ spin_unlock_irqrestore(&fb->lock, flags); } -static void p9100_blank (struct fb_info_sbusfb *fb) +static int p9100_blank (struct fb_info_sbusfb *fb) { unsigned long flags; u32 val; @@ -97,9 +97,10 @@ val &= ~ SCREENPAINT_TIMECTL1_ENABLE_VIDEO; WRITECTL(vid_screenpaint_timectl1, val); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } -static void p9100_unblank (struct fb_info_sbusfb *fb) +static int p9100_unblank (struct fb_info_sbusfb *fb) { unsigned long flags; u32 val; @@ -109,6 +110,7 @@ val |= SCREENPAINT_TIMECTL1_ENABLE_VIDEO; WRITECTL(vid_screenpaint_timectl1, val); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } static void p9100_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/platinumfb.c linux-2.5/drivers/video/platinumfb.c --- linux-2.5.1/drivers/video/platinumfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/platinumfb.c Mon Jan 14 23:58:39 2002 @@ -110,6 +110,9 @@ struct fb_info *info); static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *fb); +static int platinum_blank(int blank, struct fb_info *fb); /* @@ -118,15 +121,15 @@ static int platinum_switch(int con, struct fb_info *fb); static int platinum_updatevar(int con, struct fb_info *fb); -static void platinum_blank(int blank, struct fb_info *fb); - /* * internal functions */ static void platinum_of_init(struct device_node *dp); -static inline int platinum_vram_reqd(int video_mode, int color_mode); +static inline int platinum_vram_reqd(const struct fb_info_platinum* info, + int video_mode, + int color_mode); static int read_platinum_sense(struct fb_info_platinum *info); static void set_platinum_clock(struct fb_info_platinum *info); static void platinum_set_par(const struct fb_par_platinum *par, struct fb_info_platinum *info); @@ -144,8 +147,6 @@ int accel); static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *fb); -static int platinum_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); @@ -163,6 +164,8 @@ fb_set_var: platinum_set_var, fb_get_cmap: platinum_get_cmap, fb_set_cmap: platinum_set_cmap, + fb_setcolreg: platinum_setcolreg, + fb_blank: platinum_blank, }; static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con, @@ -321,7 +324,7 @@ if (!info->display_fg || info->display_fg->vc_num == con) /* current console? */ - return fb_set_cmap(cmap, kspc, platinum_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); return 0; @@ -351,7 +354,7 @@ return 0; } -static void platinum_blank(int blank, struct fb_info *fb) +static int platinum_blank(int blank, struct fb_info *fb) { /* * Blank the screen if blank_mode != 0, else unblank. If blank == NULL @@ -434,19 +437,19 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, platinum_setcolreg, - info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), 1, platinum_setcolreg, - info); + fb_set_cmap(fb_default_cmap(size), 1, info); } } -static inline int platinum_vram_reqd(int video_mode, int color_mode) +static inline int platinum_vram_reqd(const struct fb_info_platinum *info, int video_mode, int color_mode) { - return vmode_attrs[video_mode-1].vres * - (vmode_attrs[video_mode-1].hres * (1<<color_mode) + 0x20) +0x1000; + unsigned int pitch = + (vmode_attrs[video_mode-1].hres * (1<<color_mode) + 0x20); + fixup_pitch(pitch, info, color_mode); + return vmode_attrs[video_mode-1].vres * pitch; } #define STORE_D2(a, d) { \ @@ -487,7 +490,7 @@ volatile struct cmap_regs *cmap_regs = info->cmap_regs; struct platinum_regvals *init; int i; - int vmode, cmode; + int vmode, cmode, pitch; info->current_par = *par; @@ -506,7 +509,9 @@ init->offset[cmode] + 4 - cmode : init->offset[cmode])); out_be32(&platinum_regs->reg[16].r, (unsigned) info->frame_buffer_phys+init->fb_offset+0x10); - out_be32(&platinum_regs->reg[18].r, init->pitch[cmode]); + pitch = init->pitch[cmode]; + fixup_pitch(pitch, info, cmode); + out_be32(&platinum_regs->reg[18].r, pitch); out_be32(&platinum_regs->reg[19].r, (info->total_vram == 0x100000 ? init->mode[cmode+1] : init->mode[cmode])); @@ -535,6 +540,7 @@ display_info.depth = ( (cmode == CMODE_32) ? 32 : ((cmode == CMODE_16) ? 16 : 8)); display_info.pitch = vmode_attrs[vmode-1].hres * (1<<cmode) + 0x20; + fixup_pitch(display_info.pitch, info, cmode); display_info.mode = vmode; strncpy(display_info.name, "platinum", sizeof(display_info.name)); @@ -558,25 +564,27 @@ sense = read_platinum_sense(info); printk(KERN_INFO "Monitor sense value = 0x%x, ", sense); +#ifdef CONFIG_NVRAM if (default_vmode == VMODE_NVRAM) { default_vmode = nvram_read_byte(NV_VMODE); if (default_vmode <= 0 || default_vmode > VMODE_MAX || !platinum_reg_init[default_vmode-1]) default_vmode = VMODE_CHOOSE; } - if (default_vmode == VMODE_CHOOSE) { + if (default_cmode == CMODE_NVRAM) + default_cmode = nvram_read_byte(NV_CMODE); +#endif + if (default_vmode == VMODE_CHOOSE) default_vmode = mac_map_monitor_sense(sense); - } if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_640_480_60; - if (default_cmode == CMODE_NVRAM) - default_cmode = nvram_read_byte(NV_CMODE); if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; /* * Reduce the pixel size if we don't have enough VRAM. */ - while(default_cmode > CMODE_8 && platinum_vram_reqd(default_vmode, default_cmode) > info->total_vram) + while(default_cmode > CMODE_8 && platinum_vram_reqd(info, default_vmode, default_cmode) + > info->total_vram) default_cmode--; printk("using video mode %d and color mode %d.\n", default_vmode, default_cmode); @@ -591,14 +599,13 @@ disp = &info->disp; strcpy(info->fb_info.modename, "platinum"); - info->fb_info.node = -1; + info->fb_info.node = NODEV; info->fb_info.fbops = &platinumfb_ops; info->fb_info.disp = disp; strcpy(info->fb_info.fontname, fontname); info->fb_info.changevar = NULL; info->fb_info.switch_con = &platinum_switch; info->fb_info.updatevar = &platinum_updatevar; - info->fb_info.blank = &platinum_blank; info->fb_info.flags = FBINFO_FLAG_DEFAULT; for (j = 0; j < 16; j++) { @@ -782,7 +789,7 @@ return -EINVAL; } - if (platinum_vram_reqd(par->vmode, par->cmode) > info->total_vram) { + if (platinum_vram_reqd(info, par->vmode, par->cmode) > info->total_vram) { printk(KERN_ERR "platinum_var_to_par, not enough ram for vmode %d, cmode %d.\n", par->vmode, par->cmode); return -EINVAL; } @@ -826,7 +833,8 @@ fix->visual = (par->cmode == CMODE_8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; fix->line_length = vmode_attrs[par->vmode-1].hres * (1<<par->cmode) + 0x20; - + fixup_pitch(fix->line_length, info, par->cmode); + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/platinumfb.h linux-2.5/drivers/video/platinumfb.h --- linux-2.5.1/drivers/video/platinumfb.h Tue Jan 25 22:13:46 2000 +++ linux-2.5/drivers/video/platinumfb.h Thu Dec 27 16:32:31 2001 @@ -158,7 +158,7 @@ /* 832x624, 75Hz (13) */ static struct platinum_regvals platinum_reg_init_13 = { 0x70, - { 864, 1680, 3360 }, /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */ + { 864, 1696, 3360 }, { 0xff0, 4, 0, 0, 0, 0, 0x299, 0, 0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37, 0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52, @@ -310,6 +310,13 @@ { 2, 0, 0xff }, { 0x11, 0x15, 0x19 }, {{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }} }; + +/* MacOS does 1680 instead of 1696 to fit 832x624@75-16bpp in 1MB */ +#define fixup_pitch(ll, info, cmode) \ + do { \ + if ((cmode) == CMODE_16 && (ll) == 1696 && info->total_vram == 0x100000) \ + (ll) = 1680; \ + } while(0) static struct platinum_regvals *platinum_reg_init[VMODE_MAX] = { &platinum_reg_init_1, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/pm2fb.c linux-2.5/drivers/video/pm2fb.c --- linux-2.5.1/drivers/video/pm2fb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/pm2fb.c Mon Jan 14 23:58:39 2002 @@ -375,7 +375,7 @@ static struct fbgen_hwswitch pm2fb_hwswitch={ pm2fb_detect, pm2fb_encode_fix, pm2fb_decode_var, pm2fb_encode_var, pm2fb_get_par, pm2fb_set_par, - pm2fb_getcolreg, pm2fb_setcolreg, pm2fb_pan_display, + pm2fb_getcolreg, pm2fb_pan_display, pm2fb_blank, pm2fb_set_disp }; @@ -386,7 +386,9 @@ fb_set_var: fbgen_set_var, fb_get_cmap: fbgen_get_cmap, fb_set_cmap: fbgen_set_cmap, + fb_setcolreg: pm2fb_setcolreg, fb_pan_display: fbgen_pan_display, + fb_blank: fbgen_blank, }; /*************************************************************************** @@ -2087,7 +2089,6 @@ strcpy(fb_info.gen.info.fontname, pm2fb_options.font); fb_info.gen.info.switch_con=&fbgen_switch; fb_info.gen.info.updatevar=&fbgen_update_var; - fb_info.gen.info.blank=&fbgen_blank; fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info); fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen); fbgen_set_disp(-1, &fb_info.gen); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/pmag-ba-fb.c linux-2.5/drivers/video/pmag-ba-fb.c --- linux-2.5.1/drivers/video/pmag-ba-fb.c Fri Sep 14 21:04:07 2001 +++ linux-2.5/drivers/video/pmag-ba-fb.c Fri Jan 11 11:07:03 2002 @@ -271,13 +271,6 @@ } -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); @@ -286,22 +279,6 @@ 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; @@ -328,24 +305,13 @@ 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 + owner: THIS_MODULE, + 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, }; int __init pmagbafb_init_one(int slot) @@ -386,12 +352,11 @@ */ strcpy(ip->info.modename, "PMAG-BA"); ip->info.changevar = NULL; - ip->info.node = -1; + ip->info.node = NODEV; 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); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/pmagb-b-fb.c linux-2.5/drivers/video/pmagb-b-fb.c --- linux-2.5.1/drivers/video/pmagb-b-fb.c Fri Sep 14 21:04:07 2001 +++ linux-2.5/drivers/video/pmagb-b-fb.c Fri Jan 11 11:07:03 2002 @@ -273,14 +273,6 @@ 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); @@ -289,22 +281,6 @@ 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; @@ -331,24 +307,13 @@ 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 + owner: THIS_MODULE, + 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, }; int __init pmagbbfb_init_one(int slot) @@ -389,12 +354,11 @@ */ strcpy(ip->info.modename, "PMAGB-BA"); ip->info.changevar = NULL; - ip->info.node = -1; + ip->info.node = NODEV; 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); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/pvr2fb.c linux-2.5/drivers/video/pvr2fb.c --- linux-2.5.1/drivers/video/pvr2fb.c Mon Oct 15 20:36:48 2001 +++ linux-2.5/drivers/video/pvr2fb.c Mon Jan 14 23:58:39 2002 @@ -214,6 +214,9 @@ struct fb_info *info); static int pvr2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int pvr2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int pvr2fb_blank(int blank, struct fb_info *info); /* * Interface to the low level console driver @@ -221,7 +224,6 @@ static int pvr2fbcon_switch(int con, struct fb_info *info); static int pvr2fbcon_updatevar(int con, struct fb_info *info); -static void pvr2fbcon_blank(int blank, struct fb_info *info); /* * Internal/hardware-specific routines @@ -232,8 +234,6 @@ static void set_color_bitfields(struct fb_var_screeninfo *var); static int pvr2_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int pvr2_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static int pvr2_encode_fix(struct fb_fix_screeninfo *fix, struct pvr2fb_par *par); @@ -260,7 +260,9 @@ fb_set_var: pvr2fb_set_var, fb_get_cmap: pvr2fb_get_cmap, fb_set_cmap: pvr2fb_set_cmap, + fb_setcolreg: pvr2fb_setcolreg, fb_pan_display: pvr2fb_pan_display, + fb_blank: pvr2fb_blank, }; static struct fb_videomode pvr2_modedb[] __initdata = { @@ -489,7 +491,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, pvr2_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); @@ -515,7 +517,7 @@ return 0; } -static void pvr2fbcon_blank(int blank, struct fb_info *info) +static int pvr2fb_blank(int blank, struct fb_info *info) { do_blank = blank ? blank : -1; } @@ -527,10 +529,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, pvr2_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - 1, pvr2_setcolreg, info); + 1, info); } static inline u_long get_line_length(int xres_virtual, int bpp) @@ -575,7 +577,7 @@ return 0; } -static int pvr2_setcolreg(u_int regno, u_int red, u_int green, u_int blue, +static int pvr2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { if (regno > 255) @@ -1034,12 +1036,11 @@ strcpy(fb_info.modename, pvr2fb_name); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &pvr2fb_ops; fb_info.disp = &disp; fb_info.switch_con = &pvr2fbcon_switch; fb_info.updatevar = &pvr2fbcon_updatevar; - fb_info.blank = &pvr2fbcon_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; memset(&var, 0, sizeof(var)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/q40fb.c linux-2.5/drivers/video/q40fb.c --- linux-2.5.1/drivers/video/q40fb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/q40fb.c Mon Jan 14 23:58:39 2002 @@ -9,7 +9,6 @@ #include <asm/uaccess.h> #include <asm/setup.h> -#include <asm/segment.h> #include <asm/system.h> /*#include <asm/irq.h>*/ #include <asm/q40_master.h> @@ -39,13 +38,12 @@ struct fb_info *info); static int q40fb_set_cmap(struct fb_cmap *cmap,int kspc,int con, struct fb_info *info); -static int q40fb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con, - struct fb_info *info); +static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + const struct fb_info *info); static int q40con_switch(int con, struct fb_info *info); static int q40con_updatevar(int con, struct fb_info *info); -static void q40con_blank(int blank, struct fb_info *info); static void q40fb_set_disp(int con, struct fb_info *info); @@ -58,7 +56,7 @@ fb_set_var: q40fb_set_var, fb_get_cmap: q40fb_get_cmap, fb_set_cmap: q40fb_set_cmap, - fb_ioctl: q40fb_ioctl, + fb_setcolreg: q40fb_setcolreg, }; static int currcon=0; @@ -186,9 +184,9 @@ return 0; } -static int q40_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - const struct fb_info *info) +static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + const struct fb_info *info) { /* * Set a single color register. The values supplied have a 16 bit @@ -240,7 +238,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, q40_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -251,34 +249,6 @@ #endif } -static int q40fb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con, - struct fb_info *info) -{ -#if 0 - unsigned long i; - struct display *display; - - if (con>=0) - display = &fb_display[con]; - else - display = &disp[0]; - - if (cmd == FBIOSETSCROLLMODE) - { - i = verify_area(VERIFY_READ, (void *)arg, sizeof(unsigned long)); - if (!i) - { - copy_from_user(&i, (void *)arg, sizeof(unsigned long)); - display->scrollmode = i; - } - q40_updatescrollmode(display); - return i; - } -#endif - return -EINVAL; -} - static void q40fb_set_disp(int con, struct fb_info *info) { struct fb_fix_screeninfo fix; @@ -331,8 +301,7 @@ fb_info.disp=disp; fb_info.switch_con=&q40con_switch; fb_info.updatevar=&q40con_updatevar; - fb_info.blank=&q40con_blank; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &q40fb_ops; fb_info.flags = FBINFO_FLAG_DEFAULT; /* not as module for now */ @@ -363,10 +332,6 @@ static int q40con_updatevar(int con, struct fb_info *info) { return 0; -} - -static void q40con_blank(int blank, struct fb_info *info) -{ } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/radeon.h linux-2.5/drivers/video/radeon.h --- linux-2.5.1/drivers/video/radeon.h Thu Oct 25 20:53:52 2001 +++ linux-2.5/drivers/video/radeon.h Mon Jan 14 23:45:28 2002 @@ -96,7 +96,9 @@ #define MEM_VGA_WP_SEL 0x0038 #define MEM_VGA_RP_SEL 0x003C #define HDP_DEBUG 0x0138 -#define SW_SEMAPHORE 0x013C +#define SW_SEMAPHORE 0x013C +#define CRTC2_GEN_CNTL 0x03f8 +#define CRTC2_DISPLAY_BASE_ADDR 0x033c #define SURFACE_CNTL 0x0B00 #define SURFACE0_LOWER_BOUND 0x0B04 #define SURFACE1_LOWER_BOUND 0x0B14 @@ -337,6 +339,7 @@ #define DST_Y_X 0x1438 #define DST_WIDTH_HEIGHT 0x1598 #define DST_HEIGHT_WIDTH 0x143c +#define DST_OFFSET 0x1404 #define SRC_CLUT_ADDRESS 0x1780 #define SRC_CLUT_DATA 0x1784 #define SRC_CLUT_DATA_RD 0x1788 @@ -380,6 +383,7 @@ #define LVDS_GEN_CNTL 0x02d0 #define LVDS_PLL_CNTL 0x02d4 #define TMDS_CRC 0x02a0 +#define TMDS_TRANSMITTER_CNTL 0x02a4 #define RADEON_BASE_CODE 0x0f0b #define RADEON_BIOS_0_SCRATCH 0x0010 @@ -406,11 +410,11 @@ #define SPLL_CNTL 0x000c #define SCLK_CNTL 0x000d #define MPLL_CNTL 0x000e +#define MDLL_CKO 0x000f #define MCLK_CNTL 0x0012 #define AGP_PLL_CNTL 0x000b #define PLL_TEST_CNTL 0x0013 - /* MCLK_CNTL bit constants */ #define FORCEON_MCLKA (1 << 16) #define FORCEON_MCLKB (1 << 17) @@ -474,10 +478,17 @@ #define CRTC_INTERLACE_EN (1 << 1) #define CRTC_EXT_DISP_EN (1 << 24) #define CRTC_EN (1 << 25) +#define CRTC_DISP_REQ_EN_B (1 << 26) /* CRTC_STATUS bit constants */ #define CRTC_VBLANK 0x00000001 +/* CRTC2_GEN_CNTL bit constants */ +#define CRT2_ON (1 << 7) +#define CRTC2_DISPLAY_DIS (1 << 23) +#define CRTC2_EN (1 << 25) +#define CRTC2_DISP_REQ_EN_B (1 << 26) + /* CUR_OFFSET, CUR_HORZ_VERT_POSN, CUR_HORZ_VERT_OFF bit constants */ #define CUR_LOCK 0x80000000 @@ -523,14 +534,26 @@ #define LVDS_PANEL_TYPE (1 << 2) #define LVDS_PANEL_FORMAT (1 << 3) #define LVDS_EN (1 << 7) +#define LVDS_BL_MOD_LEVEL_MASK 0x0000ff00 +#define LVDS_BL_MOD_LEVEL_SHIFT 8 +#define LVDS_BL_MOD_EN (1 << 16) #define LVDS_DIGON (1 << 18) #define LVDS_BLON (1 << 19) #define LVDS_SEL_CRTC2 (1 << 23) +#define LVDS_STATE_MASK \ + (LVDS_ON | LVDS_DISPLAY_DIS | LVDS_BL_MOD_LEVEL_MASK | \ + LVDS_EN | LVDS_DIGON | LVDS_BLON) /* LVDS_PLL_CNTL bit constatns */ #define HSYNC_DELAY_SHIFT 0x1c #define HSYNC_DELAY_MASK (0xf << 0x1c) +/* TMDS_TRANSMITTER_CNTL bit constants */ +#define TMDS_PLL_EN (1 << 0) +#define TMDS_PLLRST (1 << 1) +#define TMDS_RAN_PAT_RST (1 << 7) +#define ICHCSEL (1 << 28) + /* FP_HORZ_STRETCH bit constants */ #define HORZ_STRETCH_RATIO_MASK 0xffff #define HORZ_STRETCH_RATIO_MAX 4096 @@ -561,6 +584,7 @@ #define DAC_4BPP_PIX_ORDER 0x00000200 #define DAC_CRC_EN 0x00080000 #define DAC_MASK_ALL (0xff << 24) +#define DAC_EXPAND_MODE (1 << 14) #define DAC_VGA_ADR_EN (1 << 13) #define DAC_RANGE_CNTL (3 << 0) #define DAC_BLANKING (1 << 2) @@ -742,6 +766,15 @@ #define DP_SRC_HOST 0x00000300 #define DP_SRC_HOST_BYTEALIGN 0x00000400 +/* MPLL_CNTL bit constants */ +#define MPLL_RESET 0x00000001 + +/* MDLL_CKO bit constants */ +#define MDLL_CKO__MCKOA_RESET 0x00000002 + +/* VCLK_ECP_CNTL constants */ +#define PIXCLK_ALWAYS_ONb 0x00000040 +#define PIXCLK_DAC_ALWAYS_ONb 0x00000080 /* masks */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/radeonfb.c linux-2.5/drivers/video/radeonfb.c --- linux-2.5.1/drivers/video/radeonfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/radeonfb.c Mon Jan 14 23:58:39 2002 @@ -15,13 +15,16 @@ * blanking, pan_display, and cmap fixes, 0.1.0 * 2001-10-10 Radeon 7500 and 8500 support, and experimental * flat panel support, 0.1.1 + * 2001-11-17 Radeon M6 (ppc) support, Daniel Berlin, 0.1.2 + * 2001-11-18 DFP fixes, Kevin Hendricks, 0.1.3 + * 2001-11-29 more cmap, backlight fixes, Benjamin Herrenschmidt * * Special thanks to ATI DevRel team for their hardware donations. * */ -#define RADEON_VERSION "0.1.1" +#define RADEON_VERSION "0.1.3" #include <linux/config.h> @@ -39,12 +42,33 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/vmalloc.h> #include <asm/io.h> #if defined(__powerpc__) #include <asm/prom.h> +#include <asm/pci-bridge.h> +#include <video/macmodes.h> + +#ifdef CONFIG_NVRAM +#include <linux/nvram.h> +#endif + +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif + +#ifdef CONFIG_BOOTX_TEXT +#include <asm/btext.h> +#endif + +#ifdef CONFIG_ADB_PMU +#include <linux/adb.h> +#include <linux/pmu.h> #endif +#endif /* __powerpc__ */ + #include <video/fbcon.h> #include <video/fbcon-cfb8.h> #include <video/fbcon-cfb16.h> @@ -65,17 +89,17 @@ enum radeon_chips { - RADEON_QD, - RADEON_QE, - RADEON_QF, - RADEON_QG, - RADEON_QY, - RADEON_QZ, - RADEON_QL, - RADEON_QW, - RADEON_LW, - RADEON_LY, - RADEON_LZ + RADEON_QD, /* Radeon R100 */ + RADEON_QE, /* Radeon R100 */ + RADEON_QF, /* Radeon R100 */ + RADEON_QG, /* Radeon R100 */ + RADEON_QY, /* Radeon RV100 (VE) */ + RADEON_QZ, /* Radeon RV100 (VE) */ + RADEON_QL, /* Radeon R200 (8500) */ + RADEON_QW, /* Radeon RV200 (7500) */ + RADEON_LW, /* Radeon Mobility M7 */ + RADEON_LY, /* Radeon Mobility M6 */ + RADEON_LZ /* Radeon Mobility M6 */ }; @@ -192,7 +216,6 @@ u32 flags; u32 pix_clock; int xres, yres; - int bpp; /* DDA regs */ u32 dda_config; @@ -214,6 +237,7 @@ u32 lvds_gen_cntl; u32 lvds_pll_cntl; u32 tmds_crc; + u32 tmds_transmitter_cntl; #if defined(__BIG_ENDIAN) u32 surface_cntl; @@ -238,6 +262,8 @@ struct pci_dev *pdev; + unsigned char *EDID; + struct display disp; int currcon; struct display *currcon_display; @@ -250,13 +276,18 @@ int pitch, bpp, depth; int xres, yres, pixclock; + int use_default_var; + int hasCRTC2; int crtDisp_type; int dviDisp_type; int panel_xres, panel_yres; + int clock; int hOver_plus, hSync_width, hblank; int vOver_plus, vSync_width, vblank; + int hAct_high, vAct_high, interlaced; + int synct, misc; u32 dp_gui_master_cntl; @@ -281,6 +312,13 @@ #endif } con_cmap; #endif + +#ifdef CONFIG_PMAC_PBOOK + unsigned char *save_framebuffer; + int pm_reg; +#endif + + struct radeonfb_info *next; }; @@ -433,6 +471,14 @@ } +static inline int var_to_depth(const struct fb_var_screeninfo *var) +{ + if (var->bits_per_pixel != 16) + return var->bits_per_pixel; + return (var->green.length == 6) ? 16 : 15; +} + + static void _radeon_engine_reset(struct radeonfb_info *rinfo) { u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset; @@ -546,7 +592,9 @@ static char fontname[40] __initdata; static char *mode_option __initdata; static char noaccel __initdata = 0; -static char panel_yres __initdata = 0; +static int panel_yres __initdata = 0; +static char force_dfp __initdata = 0; +static struct radeonfb_info *board_list = NULL; #ifdef FBCON_HAS_CFB8 static struct display_switch fbcon_radeon8; @@ -567,19 +615,20 @@ struct fb_info *info); static int radeonfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info); +static void radeon_set_dispsw (struct radeonfb_info *rinfo, struct display *disp); +static int radeonfb_blank (int blank, 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, struct display *disp); static void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *save); @@ -597,12 +646,32 @@ static char *radeon_find_rom(struct radeonfb_info *rinfo); static void radeon_get_pllinfo(struct radeonfb_info *rinfo, char *bios_seg); static void radeon_get_moninfo (struct radeonfb_info *rinfo); +static int radeon_get_bios_dfpinfo (struct radeonfb_info *rinfo); static int radeon_get_dfpinfo (struct radeonfb_info *rinfo); -static int radeon_read_OF (struct radeonfb_info *rinfo); +static void radeon_get_EDID(struct radeonfb_info *rinfo); +static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo); +static void radeon_update_default_var(struct radeonfb_info *rinfo); -#if defined(__powerpc__) + +#ifdef CONFIG_ALL_PPC +static int radeon_read_OF (struct radeonfb_info *rinfo); +static int radeon_get_EDID_OF(struct radeonfb_info *rinfo); extern struct device_node *pci_device_to_OF_node(struct pci_dev *dev); -#endif + +#ifdef CONFIG_PMAC_PBOOK +int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier radeon_sleep_notifier = { + radeon_sleep_notify, SLEEP_LEVEL_VIDEO, +}; +static int radeon_set_backlight_enable(int on, int level, void *data); +static int radeon_set_backlight_level(int level, void *data); +static struct backlight_controller radeon_backlight_controller = { + radeon_set_backlight_enable, + radeon_set_backlight_level +}; +#endif /* CONFIG_PMAC_PBOOK */ + +#endif /* CONFIG_ALL_PPC */ static struct fb_ops radeon_fb_ops = { fb_get_fix: radeonfb_get_fix, @@ -610,7 +679,9 @@ fb_set_var: radeonfb_set_var, fb_get_cmap: radeonfb_get_cmap, fb_set_cmap: radeonfb_set_cmap, + fb_setcolreg: radeonfb_setcolreg, fb_pan_display: radeonfb_pan_display, + fb_blank: radeonfb_blank, fb_ioctl: radeonfb_ioctl, }; @@ -656,6 +727,8 @@ memcpy(fontname, this_opt + 5, i); } else if (!strncmp(this_opt, "noaccel", 7)) { noaccel = 1; + } else if (!strncmp(this_opt, "dfp", 3)) { + force_dfp = 1; } else if (!strncmp(this_opt, "panel_yres:", 11)) { panel_yres = simple_strtoul((this_opt+11), NULL, 0); } else @@ -845,10 +918,27 @@ RTRACE("radeonfb: probed %s %dk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024)); +#if !defined(__powerpc__) radeon_get_moninfo(rinfo); +#else + switch (pdev->device) { + case PCI_DEVICE_ID_RADEON_LW: + case PCI_DEVICE_ID_RADEON_LY: + case PCI_DEVICE_ID_RADEON_LZ: + rinfo->dviDisp_type = MT_LCD; + break; + default: + radeon_get_moninfo(rinfo); + break; + } +#endif + + radeon_get_EDID(rinfo); + if ((rinfo->dviDisp_type == MT_DFP) || (rinfo->dviDisp_type == MT_LCD) || (rinfo->crtDisp_type == MT_DFP)) { - if (!radeon_get_dfpinfo(rinfo)) { + if (!radeon_get_dfpinfo(rinfo) && + !radeon_get_bios_dfpinfo(rinfo)) { iounmap ((void*)rinfo->mmio_base); release_mem_region (rinfo->mmio_base_phys, pci_resource_len(pdev, 2)); @@ -875,6 +965,9 @@ /* XXX turn off accel for now, blts aren't working right */ noaccel = 1; + /* currcon not yet configured, will be set by first switch */ + rinfo->currcon = -1; + /* set all the vital stuff */ radeon_set_fbinfo (rinfo); @@ -892,6 +985,8 @@ } pci_set_drvdata(pdev, rinfo); + rinfo->next = board_list; + board_list = rinfo; if (register_framebuffer ((struct fb_info *) rinfo) < 0) { printk ("radeonfb: could not register framebuffer\n"); @@ -910,6 +1005,19 @@ radeon_engine_init (rinfo); } +#ifdef CONFIG_PMAC_BACKLIGHT + if (rinfo->dviDisp_type == MT_LCD) + register_backlight_controller(&radeon_backlight_controller, + rinfo, "ati"); +#endif + +#ifdef CONFIG_PMAC_PBOOK + if (rinfo->dviDisp_type == MT_LCD) { + rinfo->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); + pmu_register_sleep_notifier(&radeon_sleep_notifier); + } +#endif + printk ("radeonfb: ATI %s %s %d MB\n", rinfo->name, rinfo->ram_type, (rinfo->video_ram/(1024*1024))); @@ -1054,7 +1162,7 @@ printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from BIOS\n", rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk); } else { -#if defined(__powerpc__) +#ifdef CONFIG_ALL_PPC if (radeon_read_OF(rinfo)) { unsigned int tmp, Nx, M, ref_div, xclk; @@ -1116,6 +1224,11 @@ { unsigned int tmp; + if (force_dfp) { + rinfo->dviDisp_type = MT_DFP; + return; + } + tmp = INREG(RADEON_BIOS_4_SCRATCH); if (rinfo->hasCRTC2) { @@ -1155,11 +1268,158 @@ } + +static void radeon_get_EDID(struct radeonfb_info *rinfo) +{ +#ifdef CONFIG_ALL_PPC + if (!radeon_get_EDID_OF(rinfo)) + RTRACE("radeonfb: could not retrieve EDID from OF\n"); +#else + /* XXX use other methods later */ +#endif +} + + +#ifdef CONFIG_ALL_PPC +static int radeon_get_EDID_OF(struct radeonfb_info *rinfo) +{ + struct device_node *dp; + unsigned char *pedid = NULL; + + dp = pci_device_to_OF_node(rinfo->pdev); + pedid = (unsigned char *) get_property(dp, "DFP,EDID", 0); + if (!pedid) + pedid = (unsigned char *) get_property(dp, "LCD,EDID", 0); + if (!pedid) + pedid = (unsigned char *) get_property(dp, "EDID", 0); + + if (pedid) { + rinfo->EDID = pedid; + return 1; + } else + return 0; +} +#endif /* CONFIG_ALL_PPC */ + + +static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo) +{ + unsigned char *block = rinfo->EDID; + + if (!block) + return 0; + + /* jump to the detailed timing block section */ + block += 54; + + rinfo->clock = (block[0] + (block[1] << 8)); + rinfo->panel_xres = (block[2] + ((block[4] & 0xf0) << 4)); + rinfo->hblank = (block[3] + ((block[4] & 0x0f) << 8)); + rinfo->panel_yres = (block[5] + ((block[7] & 0xf0) << 4)); + rinfo->vblank = (block[6] + ((block[7] & 0x0f) << 8)); + rinfo->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2)); + rinfo->hSync_width = (block[9] + ((block[11] & 0x30) << 4)); + rinfo->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2)); + rinfo->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4)); + rinfo->interlaced = ((block[17] & 0x80) >> 7); + rinfo->synct = ((block[17] & 0x18) >> 3); + rinfo->misc = ((block[17] & 0x06) >> 1); + rinfo->hAct_high = rinfo->vAct_high = 0; + if (rinfo->synct == 3) { + if (rinfo->misc & 2) + rinfo->hAct_high = 1; + if (rinfo->misc & 1) + rinfo->vAct_high = 1; + } + + return 1; +} + + +static void radeon_update_default_var(struct radeonfb_info *rinfo) +{ + struct fb_var_screeninfo *var = &radeonfb_default_var; + + var->xres = rinfo->panel_xres; + var->yres = rinfo->panel_yres; + var->xres_virtual = rinfo->panel_xres; + var->yres_virtual = rinfo->panel_yres; + var->xoffset = var->yoffset = 0; + var->bits_per_pixel = 8; + var->pixclock = 100000000 / rinfo->clock; + var->left_margin = (rinfo->hblank - rinfo->hOver_plus - rinfo->hSync_width); + var->right_margin = rinfo->hOver_plus; + var->upper_margin = (rinfo->vblank - rinfo->vOver_plus - rinfo->vSync_width); + var->lower_margin = rinfo->vOver_plus; + var->hsync_len = rinfo->hSync_width; + var->vsync_len = rinfo->vSync_width; + var->sync = 0; + if (rinfo->synct == 3) { + if (rinfo->hAct_high) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (rinfo->vAct_high) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + } + + var->vmode = 0; + if (rinfo->interlaced) + var->vmode |= FB_VMODE_INTERLACED; + + rinfo->use_default_var = 1; +} + + + +static int radeon_get_bios_dfpinfo (struct radeonfb_info *rinfo) +{ + char *biosstart, *fpbiosstart; + char *tmp, *tmp0; + int i; + char stmp[30]; + + if(!(biosstart = radeon_find_rom(rinfo))) goto out; + if(!(fpbiosstart = biosstart + readw(biosstart + 0x48))) goto out; + if(!(tmp = biosstart + readw(fpbiosstart + 0x40))) goto out; + + for(i=0; i<24; i++) stmp[i] = readb(tmp+i+1); + stmp[24] = 0; + printk("radeonfb: panel ID string: %s\n", stmp); + rinfo->panel_xres = readw(tmp + 25); + rinfo->panel_yres = readw(tmp + 27); + printk("radeonfb: detected DFP panel size from BIOS: %dx%d\n", + rinfo->panel_xres, rinfo->panel_yres); + for(i=0; i<20; i++) { + tmp0 = biosstart + readw(tmp+64+i*2); + if(tmp0 == 0) break; + if((readw(tmp0) == rinfo->panel_xres) && + (readw(tmp0+2) == rinfo->panel_yres)) { + rinfo->hblank = (readw(tmp0+17) - readw(tmp0+19)) * 8; + rinfo->hOver_plus = (readw(tmp0+21) - readw(tmp0+19) - 1) * 8; + rinfo->hSync_width = readb(tmp0+23) * 8; + rinfo->vblank = readw(tmp0+24) - readw(tmp0+26); + rinfo->vOver_plus = (readw(tmp0+28) & 0x7ff) - readw(tmp0+26); + rinfo->vSync_width = (readw(tmp0+28) & 0xf800) >> 11; + rinfo->clock = readw(tmp0+9); + radeon_update_default_var(rinfo); + radeonfb_default_var.bits_per_pixel = 32; + return 1; + } + } + out: + printk("radeonfb: Failed to detect DFP panel size using BIOS\n"); + return 0; +} + + + static int radeon_get_dfpinfo (struct radeonfb_info *rinfo) { unsigned int tmp; unsigned short a, b; + if (radeon_dfp_parse_EDID(rinfo)) + radeon_update_default_var(rinfo); + if (panel_yres) { rinfo->panel_yres = panel_yres; } else { @@ -1175,7 +1435,12 @@ case 600: rinfo->panel_xres = 800; break; - case 786: + case 768: +#if defined(__powerpc__) + if (rinfo->dviDisp_type == MT_LCD) + rinfo->panel_xres = 1152; + else +#endif rinfo->panel_xres = 1024; break; case 1024: @@ -1188,7 +1453,7 @@ rinfo->panel_xres = 1600; break; default: - printk("radeonfb: Failed to detect DFP panel size\n"); + printk("radeonfb: Failed to detect DFP panel size using EDID\n"); return 0; } @@ -1222,7 +1487,7 @@ } -#if defined(__powerpc__) +#ifdef CONFIG_ALL_PPC static int radeon_read_OF (struct radeonfb_info *rinfo) { struct device_node *dp; @@ -1255,7 +1520,7 @@ OUTREG(DSTCACHE_MODE, 0); /* XXX */ - rinfo->pitch = ((rinfo->xres * (rinfo->depth / 8) + 0x3f)) >> 6; + rinfo->pitch = ((rinfo->xres * (rinfo->bpp / 8) + 0x3f)) >> 6; radeon_fifo_wait (1); temp = INREG(DEFAULT_PITCH_OFFSET); @@ -1305,7 +1570,7 @@ info = &rinfo->info; strcpy (info->modename, rinfo->name); - info->node = -1; + info->node = NODEV; info->flags = FBINFO_FLAG_DEFAULT; info->fbops = &radeon_fb_ops; info->display_fg = NULL; @@ -1314,7 +1579,6 @@ info->changevar = NULL; info->switch_con = radeonfb_switch; info->updatevar = radeonfb_updatevar; - info->blank = radeonfb_blank; if (radeon_init_disp (rinfo) < 0) return -1; @@ -1333,6 +1597,16 @@ disp = &rinfo->disp; disp->var = radeonfb_default_var; +#if defined(__powerpc__) + if (rinfo->dviDisp_type == MT_LCD) { + if (mac_vmode_to_var(VMODE_1152_768_60, CMODE_8, &disp->var)) + disp->var = radeonfb_default_var; + } +#endif + + rinfo->depth = var_to_depth(&disp->var); + rinfo->bpp = disp->var.bits_per_pixel; + info->disp = disp; radeon_set_dispsw (rinfo, disp); @@ -1360,6 +1634,18 @@ NULL, 0, NULL, 8); else #endif +#if defined(__powerpc__) + if (rinfo->dviDisp_type == MT_LCD) { + if (mac_vmode_to_var(VMODE_1152_768_60, CMODE_8, &rinfo->disp.var)) + rinfo->disp.var = radeonfb_default_var; + } + else +#endif + if (rinfo->use_default_var) + /* We will use the modified default far */ + rinfo->disp.var = radeonfb_default_var; + else + fb_find_mode (&rinfo->disp.var, &rinfo->info, "640x480-8@60", NULL, 0, NULL, 0); @@ -1390,7 +1676,6 @@ disp->can_soft_blank = 1; disp->inverse = 0; - rinfo->depth = disp->var.bits_per_pixel; switch (disp->var.bits_per_pixel) { #ifdef FBCON_HAS_CFB8 case 8: @@ -1441,10 +1726,10 @@ return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, radeon_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else { - int size = fb_display[con].var.bits_per_pixel == 8 ? 256 : 32; - fb_set_cmap(fb_default_cmap(size), 1, radeon_setcolreg, info); + int size = radeon_get_cmap_len(&fb_display[con].var); + fb_set_cmap(fb_default_cmap(size), 1, info); } } @@ -1535,7 +1820,7 @@ fix->type_aux = disp->type_aux; fix->visual = disp->visual; - fix->xpanstep = 1; + fix->xpanstep = 8; fix->ypanstep = 1; fix->ywrapstep = 0; @@ -1592,6 +1877,23 @@ memcpy (&v, var, sizeof (v)); switch (v.bits_per_pixel) { + case 0 ... 8: + v.bits_per_pixel = 8; + break; + case 9 ... 16: + v.bits_per_pixel = 16; + break; + case 17 ... 24: + v.bits_per_pixel = 24; + break; + case 25 ... 32: + v.bits_per_pixel = 32; + break; + default: + return -EINVAL; + } + + switch (var_to_depth(&v)) { #ifdef FBCON_HAS_CFB8 case 8: nom = den = 1; @@ -1604,6 +1906,17 @@ #endif #ifdef FBCON_HAS_CFB16 + case 15: + 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.red.offset = 0; + v.red.length = v.green.length = v.blue.length = 5; + v.transp.offset = v.transp.length = 0; + break; case 16: nom = 2; den = 1; @@ -1742,7 +2055,7 @@ } if (con == rinfo->currcon) { - int rc = fb_set_cmap (cmap, kspc, radeon_setcolreg, info); + int rc = fb_set_cmap (cmap, kspc, info); return rc; } else fb_copy_cmap (cmap, &disp->cmap, kspc ? 0 : 1); @@ -1785,7 +2098,7 @@ struct radeonfb_info *rinfo = (struct radeonfb_info *) info; struct display *disp; struct fb_cmap *cmap; - int switchcon = 0; + int switchmode = 0; disp = (con < 0) ? rinfo->info.disp : &fb_display[con]; @@ -1795,17 +2108,13 @@ 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; + switchmode = (con != rinfo->currcon); + + rinfo->currcon = con; + rinfo->currcon_display = disp; + disp->var.activate = FB_ACTIVATE_NOW; + if (switchmode) { radeonfb_set_var (&disp->var, con, info); radeon_set_dispsw (rinfo, disp); do_install_cmap(con, info); @@ -1833,15 +2142,24 @@ return rc; } -static void radeonfb_blank (int blank, struct fb_info *info) +static int radeonfb_blank (int blank, struct fb_info *info) { struct radeonfb_info *rinfo = (struct radeonfb_info *) info; u32 val = INREG(CRTC_EXT_CNTL); + u32 val2 = INREG(LVDS_GEN_CNTL); + +#ifdef CONFIG_PMAC_BACKLIGHT + if (rinfo->dviDisp_type == MT_LCD && _machine == _MACH_Pmac) { + set_backlight_enable(!blank); + return; + } +#endif /* reset it */ val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | CRTC_VSYNC_DIS); - + val2 &= ~(LVDS_DISPLAY_DIS); + switch (blank) { case VESA_NO_BLANKING: break; @@ -1854,25 +2172,34 @@ case VESA_POWERDOWN: val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS); + val2 |= (LVDS_DISPLAY_DIS); break; } - - OUTREG(CRTC_EXT_CNTL, val); -} + switch (rinfo->dviDisp_type) { + case MT_LCD: + OUTREG(LVDS_GEN_CNTL, val2); + break; + case MT_CRT: + default: + OUTREG(CRTC_EXT_CNTL, val); + break; + } + return 0; +} static int radeon_get_cmap_len (const struct fb_var_screeninfo *var) { - int rc = 16; /* reasonable default */ + int rc = 256; /* reasonable default */ - switch (var->bits_per_pixel) { - case 8: - rc = 256; - break; - default: + switch (var_to_depth(var)) { + case 15: rc = 32; break; + case 16: + rc = 64; + break; } return rc; @@ -1899,8 +2226,8 @@ -static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, struct fb_info *info) +static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) { struct radeonfb_info *rinfo = (struct radeonfb_info *) info; u32 pindex; @@ -1915,40 +2242,38 @@ rinfo->palette[regno].green = green; rinfo->palette[regno].blue = blue; - /* init gamma for hicolor */ - if ((rinfo->depth > 8) && (regno == 0)) { - int i; - - for (i=0; i<255; i++) { - OUTREG(PALETTE_INDEX, i); - OUTREG(PALETTE_DATA, (i << 16) | (i << 8) | i); - } - } - /* default */ pindex = regno; - /* XXX actually bpp, fixme */ - if (rinfo->depth == 16) - pindex = regno * 8; - - if (rinfo->depth == 16) { - OUTREG(PALETTE_INDEX, pindex/2); - OUTREG(PALETTE_DATA, (rinfo->palette[regno/2].red << 16) | - (green << 8) | (rinfo->palette[regno/2].blue)); - green = rinfo->palette[regno/2].green; - } - - if ((rinfo->depth == 8) || (regno < 32)) { - OUTREG(PALETTE_INDEX, pindex); - OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue); - } + if (rinfo->bpp == 16) { + pindex = regno * 8; + if (rinfo->depth == 16 && regno > 63) + return 1; + if (rinfo->depth == 15 && regno > 31) + return 1; -#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) - if (regno < 32) { + /* For 565, the green component is mixed one order below */ + if (rinfo->depth == 16) { + OUTREG(PALETTE_INDEX, pindex>>1); + OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) | + (green << 8) | (rinfo->palette[regno>>1].blue)); + green = rinfo->palette[regno<<1].green; + } + } + + if (rinfo->depth != 16 || regno < 32) { + OUTREG(PALETTE_INDEX, pindex); + OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue); + } + + if (regno < 16) { switch (rinfo->depth) { #ifdef FBCON_HAS_CFB16 + case 15: + rinfo->con_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | + regno; + break; case 16: rinfo->con_cmap.cfb16[regno] = (regno << 11) | (regno << 5) | regno; @@ -1970,7 +2295,6 @@ #endif } } -#endif return 0; } @@ -2003,6 +2327,7 @@ save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL); save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL); save->tmds_crc = INREG(TMDS_CRC); + save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL); } @@ -2023,6 +2348,7 @@ int min_bits, format = 0; int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; int primary_mon = PRIMARY_MONITOR(rinfo); + int depth = var_to_depth(mode); rinfo->xres = mode->xres; rinfo->yres = mode->yres; @@ -2042,13 +2368,13 @@ if (rinfo->panel_yres < mode->yres) rinfo->yres = mode->yres = rinfo->panel_yres; - hTotal = mode->xres + rinfo->hblank + mode->left_margin; - hSyncStart = mode->xres + rinfo->hOver_plus + mode->right_margin; - hSyncEnd = hSyncStart + rinfo->hOver_plus + mode->hsync_len; - - vTotal = mode->yres + rinfo->vblank + mode->upper_margin; - vSyncStart = mode->yres + rinfo->vOver_plus + mode->lower_margin; - vSyncEnd = vSyncStart + rinfo->vSync_width + mode->vsync_len; + hTotal = mode->xres + rinfo->hblank; + hSyncStart = mode->xres + rinfo->hOver_plus; + hSyncEnd = hSyncStart + rinfo->hSync_width; + + vTotal = mode->yres + rinfo->vblank; + vSyncStart = mode->yres + rinfo->vOver_plus; + vSyncEnd = vSyncStart + rinfo->vSync_width; } sync = mode->sync; @@ -2066,7 +2392,7 @@ 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 */ @@ -2077,24 +2403,8 @@ cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; - switch (mode->bits_per_pixel) { - case 8: - format = DST_8BPP; - bytpp = 1; - break; - case 16: - format = DST_16BPP; - bytpp = 2; - break; - case 24: - format = DST_24BPP; - bytpp = 3; - break; - case 32: - format = DST_32BPP; - bytpp = 4; - break; - } + format = radeon_get_dstbpp(depth); + bytpp = mode->bits_per_pixel >> 3; if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) hsync_fudge = hsync_fudge_fp[format-1]; @@ -2118,7 +2428,7 @@ newmode.dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN | DAC_8BIT_EN; - newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0xffff) | + newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | (((mode->xres / 8) - 1) << 16)); newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | @@ -2158,6 +2468,7 @@ newmode.yres = mode->yres; rinfo->bpp = mode->bits_per_pixel; + rinfo->depth = depth; rinfo->hack_crtc_ext_cntl = newmode.crtc_ext_cntl; rinfo->hack_crtc_v_sync_strt_wid = newmode.crtc_v_sync_strt_wid; @@ -2234,50 +2545,38 @@ newmode.dda_on_off = (ron << 16) | roff; if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { - int hRatio, vRatio; - - if ((rinfo->panel_xres == 0) || (rinfo->panel_yres == 0)) { - hRatio = vRatio = 1; - } else { - if (mode->xres > rinfo->panel_xres) - mode->xres = rinfo->panel_xres; - if (mode->yres > rinfo->panel_yres) - mode->yres = rinfo->panel_yres; - - hRatio = mode->xres / rinfo->panel_xres; - vRatio = mode->yres / rinfo->panel_yres; - } + unsigned int hRatio, vRatio; - if (hRatio == 1) { - newmode.fp_horz_stretch = - rinfo->init_state.fp_horz_stretch; - newmode.fp_horz_stretch &= ~(HORZ_STRETCH_BLEND | - HORZ_STRETCH_ENABLE); - } else { - newmode.fp_horz_stretch = - ((((unsigned long)(hRatio * HORZ_STRETCH_RATIO_MAX + - (int)0.5)) & HORZ_STRETCH_RATIO_MASK)) | - (rinfo->init_state.fp_horz_stretch & - (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH | - HORZ_AUTO_RATIO_INC)); + if (mode->xres > rinfo->panel_xres) + mode->xres = rinfo->panel_xres; + if (mode->yres > rinfo->panel_yres) + mode->yres = rinfo->panel_yres; + + newmode.fp_horz_stretch = (((rinfo->panel_xres / 8) - 1) + << HORZ_PANEL_SHIFT); + newmode.fp_vert_stretch = ((rinfo->panel_yres - 1) + << VERT_PANEL_SHIFT); + + if (mode->xres != rinfo->panel_xres) { + hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX, + rinfo->panel_xres); + newmode.fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) | + (newmode.fp_horz_stretch & + (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH | + HORZ_AUTO_RATIO_INC))); newmode.fp_horz_stretch |= (HORZ_STRETCH_BLEND | HORZ_STRETCH_ENABLE); } newmode.fp_horz_stretch &= ~HORZ_AUTO_RATIO; - if (vRatio == 1) { - newmode.fp_vert_stretch = - rinfo->init_state.fp_vert_stretch; - newmode.fp_vert_stretch &= ~(VERT_STRETCH_BLEND | - VERT_STRETCH_ENABLE); - } else { - newmode.fp_vert_stretch = - ((((unsigned long)(vRatio * VERT_STRETCH_RATIO_MAX + - (int)0.5)) & VERT_STRETCH_RATIO_MASK)) | - (rinfo->init_state.fp_vert_stretch & - (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED)); - newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND | - VERT_STRETCH_ENABLE); + if (mode->yres != rinfo->panel_yres) { + vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX, + rinfo->panel_yres); + newmode.fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) | + (newmode.fp_vert_stretch & + (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED))); + newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND | + VERT_STRETCH_ENABLE); } newmode.fp_vert_stretch &= ~VERT_AUTO_RATIO_EN; @@ -2290,14 +2589,14 @@ FP_USE_SHADOW_EN | FP_CRTC_USE_SHADOW_VEND | FP_CRT_SYNC_ALT)); + newmode.fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR | FP_CRTC_DONT_SHADOW_HEND); newmode.lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl; newmode.lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl; newmode.tmds_crc = rinfo->init_state.tmds_crc; - - newmode.crtc_ext_cntl &= ~CRTC_CRT_ON; + newmode.tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl; if (primary_mon == MT_LCD) { newmode.lvds_gen_cntl |= (LVDS_ON | LVDS_BLON); @@ -2305,21 +2604,25 @@ } else { /* DFP */ newmode.fp_gen_cntl |= (FP_FPON | FP_TMDS_EN); + newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST | + ICHCSEL) & ~(TMDS_PLLRST); + newmode.crtc_ext_cntl &= ~CRTC_CRT_ON; } - newmode.fp_crtc_h_total_disp = - rinfo->init_state.fp_crtc_h_total_disp; - newmode.fp_crtc_v_total_disp = - rinfo->init_state.fp_crtc_v_total_disp; - newmode.fp_h_sync_strt_wid = - rinfo->init_state.fp_h_sync_strt_wid; - newmode.fp_v_sync_strt_wid = - rinfo->init_state.fp_v_sync_strt_wid; + newmode.fp_crtc_h_total_disp = newmode.crtc_h_total_disp; + newmode.fp_crtc_v_total_disp = newmode.crtc_v_total_disp; + newmode.fp_h_sync_strt_wid = newmode.crtc_h_sync_strt_wid; + newmode.fp_v_sync_strt_wid = newmode.crtc_v_sync_strt_wid; } /* do it! */ radeon_write_mode (rinfo, &newmode); +#if defined(CONFIG_BOOTX_TEXT) + btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres, + rinfo->depth, rinfo->pitch*64); +#endif + return; } @@ -2331,7 +2634,8 @@ int primary_mon = PRIMARY_MONITOR(rinfo); /* blank screen */ - OUTREG8(CRTC_EXT_CNTL + 1, 4); + OUTREGP(CRTC_EXT_CNTL, CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS, + ~(CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS)); for (i=0; i<9; i++) OUTREG(common_regs[i].reg, common_regs[i].val); @@ -2347,16 +2651,6 @@ OUTREG(CRTC_OFFSET, 0); OUTREG(CRTC_OFFSET_CNTL, 0); OUTREG(CRTC_PITCH, mode->crtc_pitch); -#if 1 - printk("CRTC_H_TOTAL_DISP = 0x%x, H_SYNC = 0x%x\n", - mode->crtc_h_total_disp, mode->crtc_h_sync_strt_wid); - printk("CRTC_V_TOTAL_DISP = 0x%x, V_SYNC = 0x%x\n", - mode->crtc_v_total_disp, mode->crtc_v_sync_strt_wid); - printk("PPLL_DIV_3 = 0x%x, PPLL_REF_DIV = 0x%x\n", - mode->ppll_div_3, mode->ppll_ref_div); - printk("DDA_CONFIG = 0x%x, DDA_ON_OFF = 0x%x\n", - mode->dda_config, mode->dda_on_off); -#endif #if defined(__BIG_ENDIAN) OUTREG(SURFACE_CNTL, mode->surface_cntl); @@ -2396,27 +2690,31 @@ OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp); OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid); OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid); - OUTREG(TMDS_CRC, mode->tmds_crc); OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch); OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch); OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl); + OUTREG(TMDS_CRC, mode->tmds_crc); + OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl); if (primary_mon == MT_LCD) { unsigned int tmp = INREG(LVDS_GEN_CNTL); + mode->lvds_gen_cntl &= ~LVDS_STATE_MASK; + mode->lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_STATE_MASK); + if ((tmp & (LVDS_ON | LVDS_BLON)) == - (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) - OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); - } else { - /* DVI */ - if (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) { - udelay(1000); + (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) { OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); } else { - OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl | - LVDS_BLON); - udelay(1000); - OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); + if (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) { + udelay(1000); + OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); + } else { + OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl | + LVDS_BLON); + udelay(1000); + OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); + } } } } @@ -2428,6 +2726,204 @@ } +#ifdef CONFIG_PMAC_BACKLIGHT + +static int backlight_conv[] = { + 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, + 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 +}; + +#define BACKLIGHT_LVDS_OFF +#undef BACKLIGHT_DAC_OFF + +/* We turn off the LCD completely instead of just dimming the backlight. + * This provides some greater power saving and the display is useless + * without backlight anyway. + */ + +static int radeon_set_backlight_enable(int on, int level, void *data) +{ + struct radeonfb_info *rinfo = (struct radeonfb_info *)data; + unsigned int lvds_gen_cntl = INREG(LVDS_GEN_CNTL); + + lvds_gen_cntl |= (LVDS_BL_MOD_EN | LVDS_BLON); + if (on && (level > BACKLIGHT_OFF)) { + lvds_gen_cntl |= LVDS_DIGON; + if (!lvds_gen_cntl & LVDS_ON) { + lvds_gen_cntl &= ~LVDS_BLON; + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + (void)INREG(LVDS_GEN_CNTL); + mdelay(10); + lvds_gen_cntl |= LVDS_BLON; + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + } + lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; + lvds_gen_cntl |= (backlight_conv[level] << + LVDS_BL_MOD_LEVEL_SHIFT); + lvds_gen_cntl |= (LVDS_ON | LVDS_EN); + lvds_gen_cntl &= ~LVDS_DISPLAY_DIS; + } else { + lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; + lvds_gen_cntl |= (backlight_conv[0] << + LVDS_BL_MOD_LEVEL_SHIFT); + lvds_gen_cntl |= LVDS_DISPLAY_DIS; + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + udelay(10); + lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGON); + } + + OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); + rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; + rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK); + + return 0; +} + +static int radeon_set_backlight_level(int level, void *data) +{ + return radeon_set_backlight_enable(1, level, data); +} +#endif /* CONFIG_PMAC_BACKLIGHT */ + + +#ifdef CONFIG_PMAC_PBOOK +static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend) +{ + u16 pwr_cmd; + + if (!rinfo->pm_reg) + return; + + /* Set the chip into appropriate suspend mode (we use D2, + * D3 would require a compete re-initialization of the chip, + * including PCI config registers, clocks, AGP conf, ...) + */ + if (suspend) { + /* Make sure CRTC2 is reset. Remove that the day + * we decide to actually use CRTC2 and replace it with + * real code for disabling the CRTC2 output during sleep. + */ + + pci_read_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, + &pwr_cmd); + + /* Switch PCI power managment to D2 */ + pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, + (pwr_cmd & ~PCI_PM_CTRL_STATE_MASK) + | 2); + pci_read_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, + &pwr_cmd); + } else { + /* Switch back PCI powermanagment to D0 */ + mdelay(100); + pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0); + mdelay(100); + pci_read_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, + &pwr_cmd); + mdelay(100); + } +} + +/* + * Save the contents of the framebuffer when we go to sleep, + * and restore it when we wake up again. + */ + +int radeon_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + struct radeonfb_info *rinfo; + + for (rinfo = board_list; rinfo != NULL; rinfo = rinfo->next) { + struct fb_fix_screeninfo fix; + int nb; + + switch (rinfo->chipset) { + case PCI_DEVICE_ID_RADEON_LW: + case PCI_DEVICE_ID_RADEON_LY: + case PCI_DEVICE_ID_RADEON_LZ: + break; + default: + return PBOOK_SLEEP_REFUSE; + } + + radeonfb_get_fix(&fix, fg_console, (struct fb_info *)rinfo); + nb = fb_display[fg_console].var.yres * fix.line_length; + + switch (when) { + case PBOOK_SLEEP_REQUEST: +#if 0 + rinfo->save_framebuffer = vmalloc(nb); + if (rinfo->save_framebuffer == NULL) + return PBOOK_SLEEP_REFUSE; +#endif + break; + case PBOOK_SLEEP_REJECT: +#if 0 + if (rinfo->save_framebuffer) { + vfree(rinfo->save_framebuffer); + rinfo->save_framebuffer = 0; + } +#endif + break; + case PBOOK_SLEEP_NOW: + radeon_engine_idle(); + radeon_engine_reset(); + radeon_engine_idle(); + +#if 0 + /* Backup framebuffer content */ + if (rinfo->save_framebuffer) + memcpy_fromio(rinfo->save_framebuffer, + (void *)rinfo->fb_base, + nb); +#endif + + /* Blank display and LCD */ + radeonfb_blank(VESA_POWERDOWN+1, + (struct fb_info *)rinfo); + + /* Sleep */ + radeon_set_suspend(rinfo, 1); + + break; + case PBOOK_WAKE: + /* Wakeup */ + radeon_set_suspend(rinfo, 0); + + radeon_engine_reset(); + if (!noaccel) { + radeon_engine_init(rinfo); + radeon_engine_reset(); + } + +#if 0 + /* Restore framebuffer content */ + if (rinfo->save_framebuffer) { + memcpy_toio((void *)rinfo->fb_base, + rinfo->save_framebuffer, + nb); + vfree(rinfo->save_framebuffer); + rinfo->save_framebuffer = 0; + } +#endif + + if (rinfo->currcon_display) { + radeonfb_set_var(&rinfo->currcon_display->var, rinfo->currcon, + (struct fb_info *) rinfo); + radeon_set_dispsw(rinfo, rinfo->currcon_display); + do_install_cmap(rinfo->currcon, + (struct fb_info *)rinfo); + } + + radeonfb_blank(0, (struct fb_info *)rinfo); + break; + } + } + + return PBOOK_SLEEP_OK; +} + +#endif /* CONFIG_PMAC_PBOOK */ /* * text console acceleration diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/retz3fb.c linux-2.5/drivers/video/retz3fb.c --- linux-2.5.1/drivers/video/retz3fb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/retz3fb.c Mon Jan 14 23:58:39 2002 @@ -275,7 +275,10 @@ struct fb_info *info); static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); - +static int retz3fb_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info); +static int retz3fb_blank(int blank, struct fb_info *info); /* * Interface to the low level console driver @@ -284,8 +287,6 @@ int retz3fb_init(void); static int z3fb_switch(int con, struct fb_info *info); static int z3fb_updatevar(int con, struct fb_info *info); -static void z3fb_blank(int blank, struct fb_info *info); - /* * Text console acceleration @@ -320,9 +321,6 @@ static int retz3_getcolreg(unsigned int regno, unsigned int *red, unsigned int *green, unsigned int *blue, unsigned int *transp, struct fb_info *info); -static int retz3_setcolreg(unsigned int regno, unsigned int red, - unsigned int green, unsigned int blue, - unsigned int transp, struct fb_info *info); /* * Internal routines @@ -896,9 +894,9 @@ * Set a single color register. Return != 0 for invalid regno. */ -static int retz3_setcolreg(unsigned int regno, unsigned int red, - unsigned int green, unsigned int blue, - unsigned int transp, struct fb_info *info) +static int retz3fb_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info) { struct retz3_fb_info *zinfo = retz3info(info); volatile unsigned char *regs = zinfo->regs; @@ -1107,10 +1105,10 @@ if (con != zinfo->currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, retz3_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - 1, retz3_setcolreg, info); + 1, info); } /* @@ -1324,7 +1322,7 @@ return err; } if (con == zinfo->currcon) /* current console? */ - return(fb_set_cmap(cmap, kspc, retz3_setcolreg, info)); + return(fb_set_cmap(cmap, kspc, info)); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -1338,6 +1336,8 @@ fb_set_var: retz3fb_set_var, fb_get_cmap: retz3fb_get_cmap, fb_set_cmap: retz3fb_set_cmap, + fb_setcolreg: retz3fb_setcolreg, + fb_blank: retz3fb_blank, }; @@ -1417,17 +1417,16 @@ /* Disable hardware cursor */ seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00); - retz3_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info); - retz3_setcolreg (254, 0, 0, 0, 0, fb_info); + retz3fb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info); + retz3fb_setcolreg (254, 0, 0, 0, 0, fb_info); strcpy(fb_info->modename, retz3fb_name); fb_info->changevar = NULL; - fb_info->node = -1; + fb_info->node = NODEV; fb_info->fbops = &retz3fb_ops; fb_info->disp = &zinfo->disp; fb_info->switch_con = &z3fb_switch; fb_info->updatevar = &z3fb_updatevar; - fb_info->blank = &z3fb_blank; fb_info->flags = FBINFO_FLAG_DEFAULT; strncpy(fb_info->fontname, fontname, 40); @@ -1494,7 +1493,7 @@ * Blank the display. */ -static void z3fb_blank(int blank, struct fb_info *info) +static int retz3fb_blank(int blank, struct fb_info *info) { struct retz3_fb_info *zinfo = retz3info(info); volatile unsigned char *regs = retz3info(info)->regs; @@ -1514,6 +1513,7 @@ reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]); reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]); } + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/riva/fbdev.c linux-2.5/drivers/video/riva/fbdev.c --- linux-2.5.1/drivers/video/riva/fbdev.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/riva/fbdev.c Mon Jan 14 23:58:39 2002 @@ -107,7 +107,7 @@ * * ------------------------------------------------------------------------- */ -static void rivafb_blank(int blank, struct fb_info *info); +static int rivafb_blank(int blank, struct fb_info *info); extern void riva_setup_accel(struct rivafb_info *rinfo); extern inline void wait_for_idle(struct rivafb_info *rinfo); @@ -136,6 +136,11 @@ CH_GEFORCE2_GTS, CH_GEFORCE2_ULTRA, CH_QUADRO2_PRO, + CH_GEFORCE2_GO, + CH_GEFORCE3, + CH_GEFORCE3_1, + CH_GEFORCE3_2, + CH_QUADRO_DDC }; /* directly indexed by riva_chips enum, above */ @@ -158,6 +163,11 @@ { "GeForce2-GTS", NV_ARCH_10}, { "GeForce2-ULTRA", NV_ARCH_10}, { "Quadro2-PRO", NV_ARCH_10}, + { "GeForce2-Go", NV_ARCH_10}, + { "GeForce3", NV_ARCH_20}, + { "GeForce3 Ti 200", NV_ARCH_20}, + { "GeForce3 Ti 500", NV_ARCH_20}, + { "Quadro DDC", NV_ARCH_20} }; static struct pci_device_id rivafb_pci_tbl[] __devinitdata = { @@ -195,6 +205,16 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_ULTRA }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GO }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_1 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC }, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl); @@ -725,7 +745,7 @@ * Sets color register @regnum. * * CALLED FROM: - * riva_setcolreg() + * rivafb_setcolreg() */ static void riva_wclut(RIVA_HW_INST *chip, unsigned char regnum, unsigned char red, @@ -1092,7 +1112,7 @@ * * CALLED FROM: * riva_getcolreg() - * riva_setcolreg() + * rivafb_setcolreg() * rivafb_get_cmap() * rivafb_set_cmap() */ @@ -1170,7 +1190,7 @@ } /** - * riva_setcolreg + * rivafb_setcolreg * @regno: register index * @red: red component * @green: green component @@ -1195,9 +1215,9 @@ * fbgen.c:fbgen_blank() * fbgen.c:fbgen_blank() */ -static int riva_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) +static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) { struct rivafb_info *rivainfo = (struct rivafb_info *)info; RIVA_HW_INST *chip = &rivainfo->riva; @@ -1315,6 +1335,7 @@ fix->accel = FB_ACCEL_NV4; break; case NV_ARCH_10: /* FIXME: ID for GeForce */ + case NV_ARCH_20: fix->accel = FB_ACCEL_NV4; break; @@ -1557,7 +1578,7 @@ } } if (con == rivainfo->currcon) { /* current console? */ - int rc = fb_set_cmap(cmap, kspc, riva_setcolreg, info); + int rc = fb_set_cmap(cmap, kspc, info); DPRINTK("EXIT - returning %d\n", rc); return rc; } else @@ -1699,7 +1720,7 @@ return rc; } -static void rivafb_blank(int blank, struct fb_info *info) +static int rivafb_blank(int blank, struct fb_info *info) { unsigned char tmp, vesa; struct rivafb_info *rinfo = (struct rivafb_info *)info; @@ -1732,6 +1753,7 @@ CRTCout(rinfo, 0x1a, vesa); DPRINTK("EXIT\n"); + return 0; } @@ -1750,7 +1772,9 @@ fb_set_var: rivafb_set_var, fb_get_cmap: rivafb_get_cmap, fb_set_cmap: rivafb_set_cmap, + fb_setcolreg: rivafb_setcolreg, fb_pan_display: rivafb_pan_display, + fb_blank: rivafb_blank, fb_ioctl: rivafb_ioctl, fb_rasterimg: rivafb_rasterimg, }; @@ -1811,7 +1835,7 @@ info = &rinfo->info; strcpy(info->modename, rinfo->drvr_name); - info->node = -1; + info->node = NODEV; info->flags = FBINFO_FLAG_DEFAULT; info->fbops = &riva_fb_ops; @@ -1824,7 +1848,6 @@ info->changevar = NULL; info->switch_con = rivafb_switch; info->updatevar = rivafb_updatevar; - info->blank = rivafb_blank; if (riva_init_disp(rinfo) < 0) /* must be done last */ return -1; @@ -1930,6 +1953,7 @@ break; case NV_ARCH_04: case NV_ARCH_10: + case NV_ARCH_20: rinfo->riva.PCRTC = (unsigned *)(rinfo->ctrl_base + 0x00600000); rinfo->riva.PRAMIN = (unsigned *)(rinfo->ctrl_base + 0x00710000); break; @@ -2082,7 +2106,7 @@ name: "rivafb", id_table: rivafb_pci_tbl, probe: rivafb_init_one, - remove: rivafb_remove_one, + remove: __devexit_p(rivafb_remove_one), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/riva/riva_hw.c linux-2.5/drivers/video/riva/riva_hw.c --- linux-2.5.1/drivers/video/riva/riva_hw.c Tue Feb 13 21:15:05 2001 +++ linux-2.5/drivers/video/riva/riva_hw.c Tue Jan 8 01:17:10 2002 @@ -1220,6 +1220,7 @@ state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; break; case NV_ARCH_10: + case NV_ARCH_20: nv10UpdateArbitrationSettings(VClk, pixelDepth * 8, &(state->arbitration0), @@ -1285,6 +1286,7 @@ chip->Tri05 = (RivaTexturedTriangle05 *)&(chip->FIFO[0x0000E000/4]); break; case NV_ARCH_10: + case NV_ARCH_20: /* * Initialize state for the RivaTriangle3D05 routines. */ @@ -1393,6 +1395,7 @@ chip->PGRAPH[0x0000067C/4] = state->pitch3; break; case NV_ARCH_10: + case NV_ARCH_20: LOAD_FIXED_STATE(nv10,PFIFO); LOAD_FIXED_STATE(nv10,PRAMIN); LOAD_FIXED_STATE(nv10,PGRAPH); @@ -1421,15 +1424,31 @@ chip->Tri03 = 0L; break; } - chip->PGRAPH[0x00000640/4] = state->offset0; - chip->PGRAPH[0x00000644/4] = state->offset1; - chip->PGRAPH[0x00000648/4] = state->offset2; - chip->PGRAPH[0x0000064C/4] = state->offset3; - chip->PGRAPH[0x00000670/4] = state->pitch0; - chip->PGRAPH[0x00000674/4] = state->pitch1; - chip->PGRAPH[0x00000678/4] = state->pitch2; - chip->PGRAPH[0x0000067C/4] = state->pitch3; - chip->PGRAPH[0x00000680/4] = state->pitch3; + + if (chip->Architecture == NV_ARCH_10) { + chip->PGRAPH[0x00000640/4] = state->offset0; + chip->PGRAPH[0x00000644/4] = state->offset1; + chip->PGRAPH[0x00000648/4] = state->offset2; + chip->PGRAPH[0x0000064C/4] = state->offset3; + chip->PGRAPH[0x00000670/4] = state->pitch0; + chip->PGRAPH[0x00000674/4] = state->pitch1; + chip->PGRAPH[0x00000678/4] = state->pitch2; + chip->PGRAPH[0x0000067C/4] = state->pitch3; + chip->PGRAPH[0x00000680/4] = state->pitch3; + } else { + chip->PGRAPH[0x00000820/4] = state->offset0; + chip->PGRAPH[0x00000824/4] = state->offset1; + chip->PGRAPH[0x00000828/4] = state->offset2; + chip->PGRAPH[0x0000082C/4] = state->offset3; + chip->PGRAPH[0x00000850/4] = state->pitch0; + chip->PGRAPH[0x00000854/4] = state->pitch1; + chip->PGRAPH[0x00000858/4] = state->pitch2; + chip->PGRAPH[0x0000085C/4] = state->pitch3; + chip->PGRAPH[0x00000860/4] = state->pitch3; + chip->PGRAPH[0x00000864/4] = state->pitch3; + chip->PGRAPH[0x000009A4/4] = chip->PFB[0x00000200/4]; + chip->PGRAPH[0x000009A8/4] = chip->PFB[0x00000204/4]; + } chip->PGRAPH[0x00000B00/4] = chip->PFB[0x00000240/4]; chip->PGRAPH[0x00000B04/4] = chip->PFB[0x00000244/4]; chip->PGRAPH[0x00000B08/4] = chip->PFB[0x00000248/4]; @@ -1607,6 +1626,7 @@ state->pitch3 = chip->PGRAPH[0x0000067C/4]; break; case NV_ARCH_10: + case NV_ARCH_20: state->offset0 = chip->PGRAPH[0x00000640/4]; state->offset1 = chip->PGRAPH[0x00000644/4]; state->offset2 = chip->PGRAPH[0x00000648/4]; @@ -1970,6 +1990,7 @@ nv4GetConfig(chip); break; case NV_ARCH_10: + case NV_ARCH_20: nv10GetConfig(chip); break; default: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/riva/riva_hw.h linux-2.5/drivers/video/riva/riva_hw.h --- linux-2.5.1/drivers/video/riva/riva_hw.h Tue Feb 13 21:15:05 2001 +++ linux-2.5/drivers/video/riva/riva_hw.h Tue Jan 8 01:17:10 2002 @@ -74,6 +74,8 @@ #define NV_ARCH_03 0x03 #define NV_ARCH_04 0x04 #define NV_ARCH_10 0x10 +#define NV_ARCH_20 0x20 + /***************************************************************************\ * * * FIFO registers. * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/sa1100fb.c linux-2.5/drivers/video/sa1100fb.c --- linux-2.5.1/drivers/video/sa1100fb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/sa1100fb.c Mon Jan 14 23:58:39 2002 @@ -1195,7 +1195,7 @@ fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; - fb_set_cmap(&fbi->fb.cmap, 1, sa1100fb_setcolreg, &fbi->fb); + fb_set_cmap(&fbi->fb.cmap, 1, &fbi->fb); /* Set board control register to handle new color depth */ sa1100fb_set_truecolor(var->bits_per_pixel >= 16); @@ -1366,7 +1366,7 @@ err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0); if (!err && con == fbi->currcon) - err = fb_set_cmap(cmap, kspc, sa1100fb_setcolreg, info); + err = fb_set_cmap(cmap, kspc, info); if (!err) fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1); @@ -1421,6 +1421,8 @@ fb_set_var: sa1100fb_set_var, fb_get_cmap: sa1100fb_get_cmap, fb_set_cmap: sa1100fb_set_cmap, + fb_setcolreg: sa1100fb_setcolreg, + fb_blank: sa1100fb_blank, }; /* @@ -1510,7 +1512,7 @@ * 12 and 16 bpp modes don't really use the palette, so this will not * blank the display in all modes. */ -static void sa1100fb_blank(int blank, struct fb_info *info) +static int sa1100fb_blank(int blank, struct fb_info *info) { struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; int i; @@ -1536,9 +1538,10 @@ sa1100fb_blank_helper(blank); if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR || fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) - fb_set_cmap(&fbi->fb.cmap, 1, sa1100fb_setcolreg, info); + fb_set_cmap(&fbi->fb.cmap, 1, info); sa1100fb_schedule_task(fbi, C_ENABLE); } + return 0; } static int sa1100fb_updatevar(int con, struct fb_info *info) @@ -2243,9 +2246,8 @@ fbi->fb.changevar = NULL; fbi->fb.switch_con = sa1100fb_switch; fbi->fb.updatevar = sa1100fb_updatevar; - fbi->fb.blank = sa1100fb_blank; fbi->fb.flags = FBINFO_FLAG_DEFAULT; - fbi->fb.node = -1; + fbi->fb.node = NODEV; fbi->fb.monspecs = monspecs; fbi->fb.disp = (struct display *)(fbi + 1); fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/sbusfb.c linux-2.5/drivers/video/sbusfb.c --- linux-2.5.1/drivers/video/sbusfb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/sbusfb.c Mon Jan 14 23:58:39 2002 @@ -89,6 +89,9 @@ struct fb_info *info); static int sbusfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int sbusfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int sbusfb_blank(int blank, struct fb_info *info); static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info); static void sbusfb_cursor(struct display *p, int mode, int x, int y); @@ -101,8 +104,6 @@ static int sbusfbcon_switch(int con, struct fb_info *info); static int sbusfbcon_updatevar(int con, struct fb_info *info); -static void sbusfbcon_blank(int blank, struct fb_info *info); - /* * Internal routines @@ -110,8 +111,6 @@ static int sbusfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int sbusfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); static struct fb_ops sbusfb_ops = { @@ -123,6 +122,8 @@ fb_set_var: sbusfb_set_var, fb_get_cmap: sbusfb_get_cmap, fb_set_cmap: sbusfb_set_cmap, + fb_setcolreg: sbusfb_setcolreg, + fb_blank: sbusfb_blank, fb_ioctl: sbusfb_ioctl, fb_mmap: sbusfb_mmap, }; @@ -524,7 +525,7 @@ return err; } if (con == currcon) { /* current console? */ - err = fb_set_cmap(cmap, kspc, sbusfb_setcolreg, info); + err = fb_set_cmap(cmap, kspc, info); if (!err) { struct fb_info_sbusfb *fb = sbusfbinfo(info); @@ -800,7 +801,7 @@ * Blank the display. */ -static void sbusfbcon_blank(int blank, struct fb_info *info) +static int sbusfb_blank(int blank, struct fb_info *info) { struct fb_info_sbusfb *fb = sbusfbinfo(info); @@ -860,10 +861,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, sbusfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - 1, sbusfb_setcolreg, info); + 1, info); if (fb->loadcmap) (*fb->loadcmap)(fb, &fb_display[con], 0, 256); } @@ -1019,14 +1020,13 @@ fix->type = FB_TYPE_PACKED_PIXELS; fix->visual = FB_VISUAL_PSEUDOCOLOR; - fb->info.node = -1; + fb->info.node = NODEV; fb->info.fbops = &sbusfb_ops; fb->info.disp = disp; strcpy(fb->info.fontname, fontname); fb->info.changevar = NULL; fb->info.switch_con = &sbusfbcon_switch; fb->info.updatevar = &sbusfbcon_updatevar; - fb->info.blank = &sbusfbcon_blank; fb->info.flags = FBINFO_FLAG_DEFAULT; fb->cursor.hwsize.fbx = 32; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/sgivwfb.c linux-2.5/drivers/video/sgivwfb.c --- linux-2.5.1/drivers/video/sgivwfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/sgivwfb.c Mon Jan 14 23:58:39 2002 @@ -101,6 +101,8 @@ struct fb_info *info); static int sgivwfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); static int sgivwfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma); @@ -111,6 +113,7 @@ fb_set_var: sgivwfb_set_var, fb_get_cmap: sgivwfb_get_cmap, fb_set_cmap: sgivwfb_set_cmap, + fb_setcolreg: sgivwfb_setcolreg, fb_mmap: sgivwfb_mmap, }; @@ -120,7 +123,6 @@ int sgivwfb_init(void); static int sgivwfbcon_switch(int con, struct fb_info *info); static int sgivwfbcon_updatevar(int con, struct fb_info *info); -static void sgivwfbcon_blank(int blank, struct fb_info *info); /* * Internal routines @@ -132,8 +134,6 @@ struct fb_var_screeninfo *var); static int sgivwfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); static unsigned long get_line_length(int xres_virtual, int bpp) @@ -561,10 +561,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, sgivwfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1, - sgivwfb_setcolreg, info); + info); } /* ---------------------------------------------------- */ @@ -829,7 +829,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, sgivwfb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -890,12 +890,11 @@ strcpy(fb_info.modename, sgivwfb_name); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &sgivwfb_ops; fb_info.disp = &disp; fb_info.switch_con = &sgivwfbcon_switch; fb_info.updatevar = &sgivwfbcon_updatevar; - fb_info.blank = &sgivwfbcon_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; fbmem = ioremap_nocache((unsigned long)sgivwfb_mem_phys, sgivwfb_mem_size); @@ -944,14 +943,6 @@ { /* Nothing */ return 0; -} - -/* - * Blank the display. - */ -static void sgivwfbcon_blank(int blank, struct fb_info *info) -{ - /* Nothing */ } #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/sis/sis_main.c linux-2.5/drivers/video/sis/sis_main.c --- linux-2.5.1/drivers/video/sis/sis_main.c Fri Nov 9 22:11:14 2001 +++ linux-2.5/drivers/video/sis/sis_main.c Mon Jan 14 23:58:39 2002 @@ -399,8 +399,8 @@ return 0; } -static int sis_setcolreg (unsigned regno, unsigned red, unsigned green, unsigned blue, - unsigned transp, struct fb_info *fb_info) +static int sisfb_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *fb_info) { if (regno >= video_cmap_len) @@ -635,10 +635,9 @@ return; if (fb_display[con].cmap.len) - fb_set_cmap (&fb_display[con].cmap, 1, sis_setcolreg, info); + fb_set_cmap (&fb_display[con].cmap, 1, info); else - fb_set_cmap (fb_default_cmap (video_cmap_len), 1, - sis_setcolreg, info); + fb_set_cmap (fb_default_cmap (video_cmap_len), 1, info); } /* --------------- Chip-dependent Routines --------------------------- */ @@ -2082,7 +2081,7 @@ return err; } if (con == currcon) - return fb_set_cmap (cmap, kspc, sis_setcolreg, info); + return fb_set_cmap (cmap, kspc, info); else fb_copy_cmap (cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -2182,14 +2181,16 @@ } 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, + 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_setcolreg: sisfb_setcolreg, + fb_blank: sisfb_blank, + fb_ioctl: sisfb_ioctl, + fb_mmap: sisfb_mmap, }; /* ------------ Interface to the low level console driver -------------*/ @@ -2231,7 +2232,7 @@ } -static void sisfb_blank (int blank, struct fb_info *info) +static int sisfb_blank (int blank, struct fb_info *info) { u8 reg; @@ -2245,6 +2246,7 @@ vgawb (CRTC_ADR, 0x17); vgawb (CRTC_DATA, reg); + return 0; } int sisfb_setup (char *options) @@ -2766,12 +2768,11 @@ sisfb_crtc_to_var (&default_var); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &sisfb_ops; fb_info.disp = &disp; fb_info.switch_con = &sisfb_switch; fb_info.updatevar = &sisfb_update_var; - fb_info.blank = &sisfb_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; sisfb_set_disp (-1, &default_var); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/sis/sis_main.h linux-2.5/drivers/video/sis/sis_main.h --- linux-2.5.1/drivers/video/sis/sis_main.h Fri Nov 9 22:11:14 2001 +++ linux-2.5/drivers/video/sis/sis_main.h Mon Jan 14 23:58:39 2002 @@ -601,6 +601,10 @@ struct fb_info *info); static int sisfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int sisfb_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info); +static int sisfb_blank (int blank, 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); @@ -609,7 +613,6 @@ 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); @@ -629,9 +632,6 @@ 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); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/skeletonfb.c linux-2.5/drivers/video/skeletonfb.c --- linux-2.5.1/drivers/video/skeletonfb.c Thu Sep 13 23:04:43 2001 +++ linux-2.5/drivers/video/skeletonfb.c Mon Jan 14 23:58:39 2002 @@ -176,9 +176,9 @@ return 0; } -static int xxx_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - const struct fb_info *info) +static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + const struct fb_info *info) { /* * Set a single color register. The values supplied have a 16 bit @@ -287,7 +287,7 @@ struct fbgen_hwswitch xxx_switch = { xxx_detect, xxx_encode_fix, xxx_decode_var, xxx_encode_var, xxx_get_par, - xxx_set_par, xxx_getcolreg, xxx_setcolreg, xxx_pan_display, xxx_blank, + xxx_set_par, xxx_getcolreg, xxx_pan_display, xxx_blank, xxx_set_disp }; @@ -306,7 +306,7 @@ fb_info.gen.fbhw->detect(); strcpy(fb_info.gen.info.modename, "XXX"); fb_info.gen.info.changevar = NULL; - fb_info.gen.info.node = -1; + fb_info.gen.info.node = NODEV; fb_info.gen.info.fbops = &xxxfb_ops; fb_info.gen.info.disp = &disp; fb_info.gen.info.switch_con = &xxxfb_switch; @@ -389,6 +389,7 @@ fb_set_var: fbgen_set_var, fb_get_cmap: fbgen_get_cmap, fb_set_cmap: fbgen_set_cmap, + fb_setcolreg: xxxfb_setcolreg, fb_pan_display: fbgen_pan_display, fb_ioctl: xxxfb_ioctl, /* optional */ }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/sstfb.c linux-2.5/drivers/video/sstfb.c --- linux-2.5.1/drivers/video/sstfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/sstfb.c Mon Jan 14 23:58:39 2002 @@ -226,6 +226,8 @@ int con, struct fb_info *info); static int sstfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); static int sstfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info); static int sstfb_ioctl(struct inode *inode, struct file *file, @@ -235,15 +237,11 @@ /* Interface to the low level console driver */ static int sstfbcon_switch(int con, struct fb_info *info); static int sstfbcon_updatevar(int con, struct fb_info *info); -static void sstfbcon_blank(int blank, struct fb_info *info); /* Internal routines */ static void sstfb_install_cmap(int con, struct fb_info *info); static int sstfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); - static int sstfb_set_par(const struct sstfb_par *par, struct sstfb_info *sst_info); static int sstfb_decode_var (const struct fb_var_screeninfo *var, @@ -285,6 +283,7 @@ fb_set_var: sstfb_set_var, fb_get_cmap: sstfb_get_cmap, fb_set_cmap: sstfb_set_cmap, + fb_setcolreg: sstfb_setcolreg, fb_pan_display: sstfb_pan_display, fb_ioctl: sstfb_ioctl, }; @@ -513,11 +512,11 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, sstfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap( fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - 1, sstfb_setcolreg, info); + 1, info); } static int sstfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, @@ -896,7 +895,7 @@ if (err) return err; } if (con == currcon) { - return fb_set_cmap(cmap, kspc, sstfb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); } else { fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1); } @@ -1797,14 +1796,13 @@ f_ddprintk("membase_phys: %#lx\n", fb_info.video.base); f_ddprintk("fbbase_virt: %#lx\n", fb_info.video.vbase); - fb_info.info.node = -1 ; + fb_info.info.node = NODEV; fb_info.info.flags = FBINFO_FLAG_DEFAULT; fb_info.info.fbops = &sstfb_ops; fb_info.info.disp = &disp; fb_info.info.changevar = NULL; fb_info.info.switch_con = &sstfbcon_switch; fb_info.info.updatevar = &sstfbcon_updatevar; - fb_info.info.blank = &sstfbcon_blank; if ( !mode_option && !fb_find_mode(&var, &fb_info.info, mode_option, NULL, 0, NULL, 16)) { @@ -1875,12 +1873,6 @@ f_dprintk("sstfbcon_updatevar\n"); return -EINVAL; } - -static void sstfbcon_blank(int blank, struct fb_info *info) -{ - f_dprintk("sstfbcon_blank(level %d)\n", blank); -} - /* print some squares on the fb (presuming 16bpp) */ static void sstfb_test16(struct sstfb_info *sst_info) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/stifb.c linux-2.5/drivers/video/stifb.c --- linux-2.5.1/drivers/video/stifb.c Fri Feb 9 19:30:23 2001 +++ linux-2.5/drivers/video/stifb.c Mon Jan 14 23:58:39 2002 @@ -108,13 +108,6 @@ return 0; } -static int -sti_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, struct fb_info *info) -{ - return 0; -} - static void sti_set_disp(const void *par, struct display *disp, struct fb_info_gen *info) @@ -145,7 +138,6 @@ get_par: sti_get_par, set_par: sti_set_par, getcolreg: sti_getcolreg, - setcolreg: sti_setcolreg, pan_display: NULL, blank: sti_blank, set_disp: sti_set_disp @@ -166,14 +158,13 @@ if ((fb_info.sti = sti_init_roms()) == NULL) return -ENXIO; - fb_info.gen.info.node = -1; + fb_info.gen.info.node = NODEV; fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; fb_info.gen.info.fbops = &stifb_ops; fb_info.gen.info.disp = &disp; fb_info.gen.info.changevar = NULL; fb_info.gen.info.switch_con = &fbgen_switch; fb_info.gen.info.updatevar = &fbgen_update_var; - fb_info.gen.info.blank = &fbgen_blank; strcpy(fb_info.gen.info.modename, "STI Generic"); fb_info.gen.fbhw = &sti_switch; fb_info.gen.fbhw->detect(); @@ -218,13 +209,11 @@ static struct fb_ops stifb_ops = { owner: THIS_MODULE, - fb_open: NULL, - fb_release: NULL, 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, - fb_ioctl: NULL + fb_blank: fbgen_blank, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/sun3fb.c linux-2.5/drivers/video/sun3fb.c --- linux-2.5.1/drivers/video/sun3fb.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/drivers/video/sun3fb.c Mon Jan 14 23:58:39 2002 @@ -80,6 +80,10 @@ struct fb_info *info); static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int sun3fb_blank(int blank, struct fb_info *info); + static void sun3fb_cursor(struct display *p, int mode, int x, int y); static void sun3fb_clear_margin(struct display *p, int s); @@ -90,8 +94,6 @@ static int sun3fbcon_switch(int con, struct fb_info *info); static int sun3fbcon_updatevar(int con, struct fb_info *info); -static void sun3fbcon_blank(int blank, struct fb_info *info); - /* * Internal routines @@ -99,8 +101,6 @@ static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); static struct fb_ops sun3fb_ops = { @@ -108,6 +108,7 @@ fb_get_fix: sun3fb_get_fix, fb_get_var: sun3fb_get_var, fb_set_var: sun3fb_set_var, + fb_setcolreg: sun3fb_setcolreg, fb_get_cmap: sun3fb_get_cmap, fb_set_cmap: sun3fb_set_cmap, }; @@ -317,7 +318,7 @@ return err; } if (con == currcon) { /* current console? */ - err = fb_set_cmap(cmap, kspc, sun3fb_setcolreg, info); + err = fb_set_cmap(cmap, kspc, info); if (!err) { struct fb_info_sbusfb *fb = sbusfbinfo(info); @@ -402,7 +403,7 @@ * Blank the display. */ -static void sun3fbcon_blank(int blank, struct fb_info *info) +static int sun3fb_blank(int blank, struct fb_info *info) { struct fb_info_sbusfb *fb = sbusfbinfo(info); @@ -462,10 +463,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, sun3fb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - 1, sun3fb_setcolreg, info); + 1, info); if (fb->loadcmap) (*fb->loadcmap)(fb, &fb_display[con], 0, 256); } @@ -573,14 +574,13 @@ fix->type = FB_TYPE_PACKED_PIXELS; fix->visual = FB_VISUAL_PSEUDOCOLOR; - fb->info.node = -1; + fb->info.node = NODEV; fb->info.fbops = &sun3fb_ops; fb->info.disp = disp; strcpy(fb->info.fontname, fontname); fb->info.changevar = NULL; fb->info.switch_con = &sun3fbcon_switch; fb->info.updatevar = &sun3fbcon_updatevar; - fb->info.blank = &sun3fbcon_blank; fb->info.flags = FBINFO_FLAG_DEFAULT; fb->cursor.hwsize.fbx = 32; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/tcxfb.c linux-2.5/drivers/video/tcxfb.c --- linux-2.5.1/drivers/video/tcxfb.c Thu Sep 20 21:11:58 2001 +++ linux-2.5/drivers/video/tcxfb.c Fri Jan 11 11:07:03 2002 @@ -198,7 +198,7 @@ spin_unlock_irqrestore(&fb->lock, flags); } -static void tcx_blank (struct fb_info_sbusfb *fb) +static int tcx_blank (struct fb_info_sbusfb *fb) { unsigned long flags; u32 tmp; @@ -211,9 +211,10 @@ tmp |= TCX_THC_MISC_HSYNC_DIS; sbus_writel(tmp, &fb->s.tcx.thc->thc_misc); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } -static void tcx_unblank (struct fb_info_sbusfb *fb) +static int tcx_unblank (struct fb_info_sbusfb *fb) { unsigned long flags; u32 tmp; @@ -225,6 +226,7 @@ tmp |= TCX_THC_MISC_VIDEO; sbus_writel(tmp, &fb->s.tcx.thc->thc_misc); spin_unlock_irqrestore(&fb->lock, flags); + return 0; } static void tcx_reset (struct fb_info_sbusfb *fb) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/tdfxfb.c linux-2.5/drivers/video/tdfxfb.c --- linux-2.5.1/drivers/video/tdfxfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/tdfxfb.c Mon Jan 14 23:58:39 2002 @@ -175,9 +175,9 @@ #define BIT(x) (1UL << (x)) /* COMMAND_2D reg. values */ -#define ROP_COPY 0xcc // src -#define ROP_INVERT 0x55 // NOT dst -#define ROP_XOR 0x66 // src XOR dst +#define TDFX_ROP_COPY 0xcc // src +#define TDFX_ROP_INVERT 0x55 // NOT dst +#define TDFX_ROP_XOR 0x66 // src XOR dst #define AUTOINC_DSTX BIT(10) #define AUTOINC_DSTY BIT(11) @@ -376,6 +376,14 @@ static int tdfxfb_set_var(struct fb_var_screeninfo* var, int con, struct fb_info* fb); +static int tdfxfb_setcolreg(u_int regno, + u_int red, + u_int green, + u_int blue, + u_int transp, + struct fb_info* fb); +static void tdfxfb_install_cmap(struct display *d, + struct fb_info *info); static int tdfxfb_pan_display(struct fb_var_screeninfo* var, int con, struct fb_info* fb); @@ -395,13 +403,13 @@ struct fb_info* fb); static int tdfxfb_updatevar(int con, struct fb_info* fb); -static void tdfxfb_blank(int blank, +static int tdfxfb_blank(int blank, struct fb_info* fb); /* * Internal routines */ -static void tdfxfb_set_par(const struct tdfxfb_par* par, +static void tdfxfb_set_par(struct tdfxfb_par* par, struct fb_info_tdfx* info); static int tdfxfb_decode_var(const struct fb_var_screeninfo *var, @@ -423,12 +431,6 @@ u_int* blue, u_int* transp, struct fb_info* fb); -static int tdfxfb_setcolreg(u_int regno, - u_int red, - u_int green, - u_int blue, - u_int transp, - struct fb_info* fb); static void tdfxfb_install_cmap(struct display *d, struct fb_info *info); @@ -475,7 +477,9 @@ fb_set_var: tdfxfb_set_var, fb_get_cmap: tdfxfb_get_cmap, fb_set_cmap: tdfxfb_set_cmap, + fb_setcolreg: tdfxfb_setcolreg, fb_pan_display: tdfxfb_pan_display, + fb_blank: tdfxfb_blank, }; static struct pci_device_id tdfxfb_id_table[] __devinitdata = { @@ -495,7 +499,7 @@ name: "tdfxfb", id_table: tdfxfb_id_table, probe: tdfxfb_probe, - remove: tdfxfb_remove, + remove: __devexit_p(tdfxfb_remove), }; MODULE_DEVICE_TABLE(pci, tdfxfb_id_table); @@ -715,7 +719,7 @@ u32 stride, u32 bpp) { - u32 blitcmd = COMMAND_2D_S2S_BITBLT | (ROP_COPY << 24); + u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24); u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); if (curx <= dstx) { @@ -761,7 +765,7 @@ tdfx_outl(COLORBACK, bgx); tdfx_outl(SRCXY, 0); tdfx_outl(DSTXY, xx | (yy << 16)); - tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (ROP_COPY << 24)); + tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24)); tdfx_outl(SRCFORMAT, 0x400000); tdfx_outl(DSTFORMAT, fmt); tdfx_outl(DSTSIZE, fontwidth(p) | (fontheight(p) << 16)); @@ -824,7 +828,7 @@ tdfx_outl(DSTFORMAT, fmt); tdfx_outl(DSTSIZE, w | (h << 16)); tdfx_outl(SRCXY, 0); - tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (ROP_COPY << 24)); + tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24)); while (count--) { u8 *chardata=p->fontdata+(scr_readw(s++) & p->charmask)*h*fw; @@ -1029,14 +1033,14 @@ do_fillrect( p->var.xoffset+rs, 0, rw, p->var.yres_virtual, 0, fb_info.current_par.lpitch, - fb_info.current_par.bpp, ROP_COPY); + fb_info.current_par.bpp, TDFX_ROP_COPY); } if (bh) { do_fillrect( p->var.xoffset, p->var.yoffset+bs, rs, bh, 0, fb_info.current_par.lpitch, - fb_info.current_par.bpp, ROP_COPY); + fb_info.current_par.bpp, TDFX_ROP_COPY); } } static void tdfx_cfbX_bmove(struct display* p, @@ -1127,7 +1131,7 @@ fontheight(p)*height, bg, fb_info.current_par.lpitch, - fb_info.current_par.bpp,ROP_COPY); + fb_info.current_par.bpp, TDFX_ROP_COPY); } static void tdfx_cfb16_clear(struct vc_data* conp, @@ -1145,7 +1149,7 @@ fontheight(p)*height, bg, fb_info.current_par.lpitch, - fb_info.current_par.bpp,ROP_COPY); + fb_info.current_par.bpp, TDFX_ROP_COPY); } static void tdfx_cfb32_clear(struct vc_data* conp, @@ -1163,7 +1167,7 @@ fontheight(p)*height, bg, fb_info.current_par.lpitch, - fb_info.current_par.bpp,ROP_COPY); + fb_info.current_par.bpp, TDFX_ROP_COPY); } static void tdfx_cfbX_revc(struct display *p, int xx, int yy) { @@ -1172,7 +1176,7 @@ do_fillrect( xx * fontwidth(p), yy * fontheight(p), fontwidth(p), fontheight(p), (bpp==8) ? 0x0f : 0xffffffff, - fb_info.current_par.lpitch, bpp, ROP_XOR); + fb_info.current_par.lpitch, bpp, TDFX_ROP_XOR); } static void tdfx_cfbX_cursor(struct display *p, int mode, int x, int y) @@ -1275,7 +1279,7 @@ /* ------------------------------------------------------------------------- */ -static void tdfxfb_set_par(const struct tdfxfb_par* par, +static void tdfxfb_set_par(struct tdfxfb_par* par, struct fb_info_tdfx* info) { struct fb_info_tdfx* i = (struct fb_info_tdfx*)info; struct banshee_reg reg; @@ -1290,6 +1294,28 @@ cpp = (par->bpp + 7)/8; + reg.vidcfg = + VIDCFG_VIDPROC_ENABLE | + VIDCFG_DESK_ENABLE | + VIDCFG_CURS_X11 | + ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | + (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0); + + /* PLL settings */ + freq = par->pixclock; + + reg.dacmode = 0; + reg.vidcfg &= ~VIDCFG_2X; + + if(freq > i->max_pixclock/2) { + freq = freq > i->max_pixclock ? i->max_pixclock : freq; + reg.dacmode |= DACMODE_2X; + reg.vidcfg |= VIDCFG_2X; + par->hdispend >>= 1; + par->hsyncsta >>= 1; + par->hsyncend >>= 1; + par->htotal >>= 1; + } wd = (par->hdispend >> 3) - 1; hd = (par->hdispend >> 3) - 1; @@ -1356,9 +1382,7 @@ reg.crt[0x02] = hbs; reg.crt[0x03] = 0x80 | (hbe & 0x1f); reg.crt[0x04] = hs; - reg.crt[0x05] = - ((hbe & 0x20) << 2) | - (he & 0x1f); + reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f); reg.crt[0x06] = vt; reg.crt[0x07] = ((vs & 0x200) >> 2) | @@ -1380,9 +1404,7 @@ reg.crt[0x0e] = 0x00; reg.crt[0x0f] = 0x00; reg.crt[0x10] = vs; - reg.crt[0x11] = - (ve & 0x0f) | - 0x20; + reg.crt[0x11] = (ve & 0x0f) | 0x20; reg.crt[0x12] = vd; reg.crt[0x13] = wd; reg.crt[0x14] = 0x00; @@ -1411,13 +1433,6 @@ VGAINIT0_EXTSHIFTOUT; reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff; - reg.vidcfg = - VIDCFG_VIDPROC_ENABLE | - VIDCFG_DESK_ENABLE | - VIDCFG_CURS_X11 | - ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | - (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0); - fb_info.cursor.enable=reg.vidcfg | VIDCFG_HWCURSOR_ENABLE; fb_info.cursor.disable=reg.vidcfg; @@ -1433,16 +1448,6 @@ reg.srcbase = reg.startaddr; reg.dstbase = reg.startaddr; - /* PLL settings */ - freq = par->pixclock; - - reg.dacmode &= ~DACMODE_2X; - reg.vidcfg &= ~VIDCFG_2X; - if(freq > i->max_pixclock/2) { - freq = freq > i->max_pixclock ? i->max_pixclock : freq; - reg.dacmode |= DACMODE_2X; - reg.vidcfg |= VIDCFG_2X; - } reg.vidpll = do_calc_pll(freq, &fout); #if 0 reg.mempll = do_calc_pll(..., &fout); @@ -1473,9 +1478,13 @@ #endif do_write_regs(®); - + if (reg.vidcfg & VIDCFG_2X) { + par->hdispend <<= 1; + par->hsyncsta <<= 1; + par->hsyncend <<= 1; + par->htotal <<= 1; + } i->current_par = *par; - } static int tdfxfb_decode_var(const struct fb_var_screeninfo* var, @@ -1881,7 +1890,7 @@ } if(con == currcon) { /* current console? */ - return fb_set_cmap(cmap, kspc, tdfxfb_setcolreg, fb); + return fb_set_cmap(cmap, kspc, fb); } else { fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1); } @@ -1975,13 +1984,12 @@ strcpy(fb_info.fb_info.modename, "3Dfx "); strcat(fb_info.fb_info.modename, name); fb_info.fb_info.changevar = NULL; - fb_info.fb_info.node = -1; + fb_info.fb_info.node = NODEV; fb_info.fb_info.fbops = &tdfxfb_ops; fb_info.fb_info.disp = &fb_info.disp; strcpy(fb_info.fb_info.fontname, fontname); fb_info.fb_info.switch_con = &tdfxfb_switch_con; fb_info.fb_info.updatevar = &tdfxfb_updatevar; - fb_info.fb_info.blank = &tdfxfb_blank; fb_info.fb_info.flags = FBINFO_FLAG_DEFAULT; memset(&var, 0, sizeof(var)); @@ -2162,7 +2170,7 @@ } /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ -static void tdfxfb_blank(int blank, +static int tdfxfb_blank(int blank, struct fb_info *fb) { u32 dacmode, state = 0, vgablank = 0; @@ -2199,8 +2207,7 @@ vga_disable_video(); else vga_enable_video(); - - return; + return 0; } static int tdfxfb_updatevar(int con, @@ -2291,10 +2298,9 @@ struct fb_info_tdfx* i = (struct fb_info_tdfx*)info; if(d->cmap.len) { - fb_set_cmap(&(d->cmap), 1, tdfxfb_setcolreg, info); + fb_set_cmap(&(d->cmap), 1, info); } else { - fb_set_cmap(fb_default_cmap(i->current_par.cmap_len), 1, - tdfxfb_setcolreg, info); + fb_set_cmap(fb_default_cmap(i->current_par.cmap_len), 1, info); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/tgafb.c linux-2.5/drivers/video/tgafb.c --- linux-2.5.1/drivers/video/tgafb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/tgafb.c Mon Jan 14 23:58:39 2002 @@ -749,7 +749,7 @@ return err; } if (con == currcon) { /* current console? */ - err = fb_set_cmap(cmap, kspc, tgafb_setcolreg, info); + err = fb_set_cmap(cmap, kspc, info); #if 1 if (fb_info.tga_type != TGA_TYPE_8PLANE) tgafb_update_palette(); @@ -855,7 +855,7 @@ struct fbgen_hwswitch tgafb_hwswitch = { tgafb_detect, tgafb_encode_fix, tgafb_decode_var, tgafb_encode_var, tgafb_get_par, - tgafb_set_par, tgafb_getcolreg, tgafb_setcolreg, NULL, tgafb_blank, + tgafb_set_par, tgafb_getcolreg, NULL, tgafb_blank, tgafb_set_disp }; @@ -876,6 +876,8 @@ fb_set_var: fbgen_set_var, fb_get_cmap: fbgen_get_cmap, fb_set_cmap: tgafb_set_cmap, + fb_setcolreg: tgafb_setcolreg, + fb_blank: fbgen_blank, }; @@ -937,14 +939,13 @@ /* setup framebuffer */ - fb_info.gen.info.node = -1; + fb_info.gen.info.node = NODEV; fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; fb_info.gen.info.fbops = &tgafb_ops; fb_info.gen.info.disp = &disp; fb_info.gen.info.changevar = NULL; fb_info.gen.info.switch_con = &fbgen_switch; fb_info.gen.info.updatevar = &fbgen_update_var; - fb_info.gen.info.blank = &fbgen_blank; strcpy(fb_info.gen.info.fontname, default_fontname); fb_info.gen.parsize = sizeof (struct tgafb_par); fb_info.gen.fbhw = &tgafb_hwswitch; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/tx3912fb.c linux-2.5/drivers/video/tx3912fb.c --- linux-2.5.1/drivers/video/tx3912fb.c Fri Sep 7 16:28:38 2001 +++ linux-2.5/drivers/video/tx3912fb.c Mon Jan 14 23:58:39 2002 @@ -46,6 +46,8 @@ struct fb_info *info); static int tx3912fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info); +static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); static int tx3912fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); static int tx3912fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, @@ -59,7 +61,6 @@ int tx3912fb_init(void); static int tx3912fbcon_switch(int con, struct fb_info *info); static int tx3912fbcon_updatevar(int con, struct fb_info *info); -static void tx3912fbcon_blank(int blank, struct fb_info *info); /* * Macros @@ -72,8 +73,6 @@ */ static int tx3912fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void tx3912fb_install_cmap(int con, struct fb_info *info); @@ -87,6 +86,7 @@ fb_set_var: tx3912fb_set_var, fb_get_cmap: tx3912fb_get_cmap, fb_set_cmap: tx3912fb_set_cmap, + fb_setcolreg: tx3912fb_setcolreg, fb_ioctl: tx3912fb_ioctl, }; @@ -322,7 +322,7 @@ return err; if (con == currcon) - return fb_set_cmap(cmap, kspc, tx3912fb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); @@ -397,12 +397,11 @@ strcpy(fb_info.modename, TX3912FB_NAME); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &tx3912fb_ops; fb_info.disp = &global_disp; fb_info.switch_con = &tx3912fbcon_switch; fb_info.updatevar = &tx3912fbcon_updatevar; - fb_info.blank = &tx3912fbcon_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; tx3912fb_set_var(&tx3912fb_info, -1, &fb_info); @@ -445,15 +444,6 @@ } /* - * Blank the display - */ -static void tx3912fbcon_blank(int blank, struct fb_info *info) -{ - /* FIXME */ - printk("tx3912fbcon_blank\n"); -} - -/* * Read a single color register */ static int tx3912fb_getcolreg(u_int regno, u_int *red, u_int *green, @@ -521,9 +511,9 @@ return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, tx3912fb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else - fb_set_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel), 1, tx3912fb_setcolreg, info); + fb_set_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel), 1, info); } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/valkyriefb.c linux-2.5/drivers/video/valkyriefb.c --- linux-2.5.1/drivers/video/valkyriefb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/valkyriefb.c Mon Jan 14 23:58:39 2002 @@ -7,6 +7,8 @@ * Vmode-switching changes and vmode 15/17 modifications created 29 August * 1998 by Barry K. Nathan <barryn@pobox.com>. * + * Ported to m68k Macintosh by David Huggins-Daines <dhd@debian.org> + * * Derived directly from: * * controlfb.c -- frame buffer device for the PowerMac 'control' display @@ -59,7 +61,12 @@ #include <linux/adb.h> #include <linux/cuda.h> #include <asm/io.h> +#ifdef CONFIG_MAC +#include <asm/bootinfo.h> +#include <asm/macintosh.h> +#else #include <asm/prom.h> +#endif #include <asm/pgtable.h> #include <video/fbcon.h> @@ -71,8 +78,15 @@ static int can_soft_blank = 1; +#ifdef CONFIG_MAC +/* We don't yet have functions to read the PRAM... perhaps we can + adapt them from the PPC code? */ +static int default_vmode = VMODE_640_480_67; +static int default_cmode = CMODE_8; +#else static int default_vmode = VMODE_NVRAM; static int default_cmode = CMODE_NVRAM; +#endif static char fontname[40] __initdata = { 0 }; static int currcon = 0; @@ -117,7 +131,6 @@ int valkyriefb_init(void); int valkyriefb_setup(char*); -static void valkyrie_of_init(struct device_node *dp); static int valkyrie_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info); static int valkyrie_get_var(struct fb_var_screeninfo *var, int con, @@ -128,6 +141,9 @@ struct fb_info *info); static int valkyrie_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int valkyriefb_blank(int blank_mode, struct fb_info *info); static int read_valkyrie_sense(struct fb_info_valkyrie *p); static inline int valkyrie_vram_reqd(int video_mode, int color_mode); @@ -152,12 +168,12 @@ fb_set_var: valkyrie_set_var, fb_get_cmap: valkyrie_get_cmap, fb_set_cmap: valkyrie_set_cmap, + fb_setcolreg: valkyriefb_setcolreg, + fb_blank: valkyriefb_blank, }; static int valkyriefb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); static int valkyrie_get_fix(struct fb_fix_screeninfo *fix, int con, @@ -266,7 +282,7 @@ } if (con == currcon) { - return fb_set_cmap(cmap, kspc, valkyriefb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); } fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); return 0; @@ -302,7 +318,7 @@ return 0; } -static void valkyriefb_blank(int blank_mode, struct fb_info *info) +static int valkyriefb_blank(int blank_mode, struct fb_info *info) { /* * Blank the screen if blank_mode != 0, else unblank. If blank_mode == NULL @@ -342,6 +358,7 @@ break; } } + return 0; } static int valkyriefb_getcolreg(u_int regno, u_int *red, u_int *green, @@ -396,13 +413,11 @@ if (con != currcon) return; if (fb_display[con].cmap.len) { - fb_set_cmap(&fb_display[con].cmap, 1, valkyriefb_setcolreg, - info); + fb_set_cmap(&fb_display[con].cmap, 1, info); } else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), 1, valkyriefb_setcolreg, - info); + fb_set_cmap(fb_default_cmap(size), 1, info); } } @@ -444,6 +459,7 @@ p->sense = read_valkyrie_sense(p); printk(KERN_INFO "Monitor sense value = 0x%x, ", p->sense); +#ifdef CONFIG_NVRAM /* Try to pick a video mode out of NVRAM if we have one. */ if (default_vmode == VMODE_NVRAM) { default_vmode = nvram_read_byte(NV_VMODE); @@ -452,12 +468,13 @@ || !valkyrie_reg_init[default_vmode - 1]) default_vmode = VMODE_CHOOSE; } + if (default_cmode == CMODE_NVRAM) + default_cmode = nvram_read_byte(NV_CMODE); +#endif if (default_vmode == VMODE_CHOOSE) default_vmode = mac_map_monitor_sense(p->sense); if (!valkyrie_reg_init[default_vmode - 1]) default_vmode = VMODE_640_480_67; - if (default_cmode == CMODE_NVRAM) - default_cmode = nvram_read_byte(NV_CMODE); /* * Reduce the pixel size if we don't have enough VRAM or bandwitdh. @@ -550,48 +567,57 @@ int __init valkyriefb_init(void) { + struct fb_info_valkyrie *p; + unsigned long frame_buffer_phys, cmap_regs_phys, flags; + +#ifdef CONFIG_MAC + if (!MACH_IS_MAC) + return 0; + if (!(mac_bi_data.id == MAC_MODEL_Q630 + /* I'm not sure about this one */ + || mac_bi_data.id == MAC_MODEL_P588)) + return 0; + + /* Hardcoded addresses... welcome to 68k Macintosh country :-) */ + frame_buffer_phys = 0xf9000000; + cmap_regs_phys = 0x50f24000; + flags = IOMAP_NOCACHE_SER; /* IOMAP_WRITETHROUGH?? */ +#else /* ppc (!CONFIG_MAC) */ struct device_node *dp; dp = find_devices("valkyrie"); - if (dp != 0) - valkyrie_of_init(dp); - return 0; -} + if (dp == 0) + return 0; -static void __init valkyrie_of_init(struct device_node *dp) -{ - struct fb_info_valkyrie *p; - unsigned long addr; - if(dp->n_addrs != 1) { printk(KERN_ERR "expecting 1 address for valkyrie (got %d)", dp->n_addrs); - return; + return 0; } + frame_buffer_phys = dp->addrs[0].address; + cmap_regs_phys = dp->addrs[0].address+0x304000; + flags = _PAGE_WRITETHRU; +#endif /* ppc (!CONFIG_MAC) */ + p = kmalloc(sizeof(*p), GFP_ATOMIC); if (p == 0) - return; + return 0; memset(p, 0, sizeof(*p)); /* Map in frame buffer and registers */ - addr = dp->addrs[0].address; - if (!request_mem_region(addr, dp->addrs[0].size, "valkyriefb")) { + if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) { kfree(p); - return; + return 0; } - p->frame_buffer_phys = addr; - p->frame_buffer = __ioremap(addr, 0x100000, _PAGE_WRITETHRU); - p->cmap_regs_phys = addr + 0x304000; - p->cmap_regs = ioremap(p->cmap_regs_phys,4096); - p->valkyrie_regs_phys = addr + 0x30a000; - p->valkyrie_regs = ioremap(p->valkyrie_regs_phys, 4096); - - /* - * kps: As far as I know, all Valkyries have fixed usable VRAM. - */ p->total_vram = 0x100000; - + p->frame_buffer_phys = frame_buffer_phys; + p->frame_buffer = __ioremap(frame_buffer_phys, p->total_vram, flags); + p->cmap_regs_phys = cmap_regs_phys; + p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); + p->valkyrie_regs_phys = cmap_regs_phys+0x6000; + p->valkyrie_regs = ioremap(p->valkyrie_regs_phys, 0x1000); init_valkyrie(p); + return 0; } /* @@ -779,14 +805,13 @@ static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p) { strcpy(info->modename, p->fix.id); - info->node = -1; /* ??? danj */ + info->node = NODEV; info->fbops = &valkyriefb_ops; info->disp = &p->disp; strcpy(info->fontname, fontname); info->changevar = NULL; info->switch_con = &valkyriefb_switch; info->updatevar = &valkyriefb_updatevar; - info->blank = &valkyriefb_blank; info->flags = FBINFO_FLAG_DEFAULT; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/valkyriefb.h linux-2.5/drivers/video/valkyriefb.h --- linux-2.5.1/drivers/video/valkyriefb.h Sat Aug 5 01:06:34 2000 +++ linux-2.5/drivers/video/valkyriefb.h Thu Dec 27 16:32:31 2001 @@ -9,6 +9,8 @@ * * vmode 10 changed by Steven Borley <sjb@salix.demon.co.uk>, 14 mai 2000 * + * Ported to 68k Macintosh by David Huggins-Daines <dhd@debian.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 @@ -37,12 +39,19 @@ * Copyright (C) 1998 Jon Howell */ +#ifdef CONFIG_MAC +/* Valkyrie registers are word-aligned on m68k */ +#define VALKYRIE_REG_PADSIZE 3 +#else +#define VALKYRIE_REG_PADSIZE 7 +#endif + /* * Structure of the registers for the Valkyrie colormap registers. */ struct cmap_regs { unsigned char addr; - char pad1[7]; + char pad1[VALKYRIE_REG_PADSIZE]; unsigned char lut; }; @@ -52,7 +61,7 @@ struct vpreg { /* padded register */ unsigned char r; - char pad[7]; + char pad[VALKYRIE_REG_PADSIZE]; }; @@ -81,6 +90,7 @@ int vres; }; +#ifndef CONFIG_MAC /* Register values for 1024x768, 75Hz mode (17) */ /* I'm not sure which mode this is (16 or 17), so I'm defining it as 17, * since the equivalent mode in controlfb (which I adapted this from) is @@ -125,14 +135,6 @@ 1024, 768 }; -/* Register values for 832x624, 75Hz mode (13) */ -static struct valkyrie_regvals valkyrie_reg_init_13 = { - 9, - { 23, 42, 3 }, /* pixel clock = 57.07MHz for V=74.27Hz */ - { 832, 0 }, - 832, 624 -}; - /* Register values for 800x600, 72Hz mode (11) */ static struct valkyrie_regvals valkyrie_reg_init_11 = { 13, @@ -140,6 +142,15 @@ { 800, 0 }, 800, 600 }; +#endif /* CONFIG_MAC */ + +/* Register values for 832x624, 75Hz mode (13) */ +static struct valkyrie_regvals valkyrie_reg_init_13 = { + 9, + { 23, 42, 3 }, /* pixel clock = 57.07MHz for V=74.27Hz */ + { 832, 0 }, + 832, 624 +}; /* Register values for 800x600, 60Hz mode (10) */ static struct valkyrie_regvals valkyrie_reg_init_10 = { @@ -177,6 +188,15 @@ NULL, NULL, &valkyrie_reg_init_10, +#ifdef CONFIG_MAC + NULL, + NULL, + &valkyrie_reg_init_13, + NULL, + NULL, + NULL, + NULL, +#else &valkyrie_reg_init_11, NULL, &valkyrie_reg_init_13, @@ -184,6 +204,7 @@ &valkyrie_reg_init_15, NULL, &valkyrie_reg_init_17, +#endif NULL, NULL, NULL diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/vesafb.c linux-2.5/drivers/video/vesafb.c --- linux-2.5.1/drivers/video/vesafb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/vesafb.c Mon Jan 14 23:58:39 2002 @@ -329,9 +329,9 @@ #endif -static int vesa_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *fb_info) +static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info) { /* * Set a single color register. The values supplied are @@ -402,10 +402,9 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, vesa_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else - fb_set_cmap(fb_default_cmap(video_cmap_len), 1, vesa_setcolreg, - info); + fb_set_cmap(fb_default_cmap(video_cmap_len), 1, info); } static int vesafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, @@ -432,7 +431,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, vesa_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -445,6 +444,7 @@ fb_set_var: vesafb_set_var, fb_get_cmap: vesafb_get_cmap, fb_set_cmap: vesafb_set_cmap, + fb_setcolreg: vesafb_setcolreg, fb_pan_display: vesafb_pan_display, }; @@ -494,13 +494,6 @@ return 1; } -/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ - -static void vesafb_blank(int blank, struct fb_info *info) -{ - /* Not supported */ -} - int __init vesafb_init(void) { int i,j; @@ -648,12 +641,11 @@ strcpy(fb_info.modename, "VESA VGA"); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &vesafb_ops; fb_info.disp=&disp; fb_info.switch_con=&vesafb_switch; fb_info.updatevar=&vesafb_update_var; - fb_info.blank=&vesafb_blank; fb_info.flags=FBINFO_FLAG_DEFAULT; vesafb_set_disp(-1); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/vfb.c linux-2.5/drivers/video/vfb.c --- linux-2.5.1/drivers/video/vfb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/vfb.c Mon Jan 14 23:58:39 2002 @@ -83,6 +83,8 @@ struct fb_info *info); static int vfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info); +static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); static int vfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info); static int vfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, @@ -90,7 +92,6 @@ static int vfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); - /* * Interface to the low level console driver */ @@ -98,8 +99,6 @@ int vfb_init(void); static int vfbcon_switch(int con, struct fb_info *info); static int vfbcon_updatevar(int con, struct fb_info *info); -static void vfbcon_blank(int blank, struct fb_info *info); - /* * Internal routines @@ -111,8 +110,6 @@ static void set_color_bitfields(struct fb_var_screeninfo *var); static int vfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void do_install_cmap(int con, struct fb_info *info); @@ -123,6 +120,7 @@ fb_set_var: vfb_set_var, fb_get_cmap: vfb_get_cmap, fb_set_cmap: vfb_set_cmap, + fb_setcolreg: vfb_setcolreg, fb_pan_display: vfb_pan_display, }; @@ -364,7 +362,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, vfb_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -404,12 +402,11 @@ strcpy(fb_info.modename, vfb_name); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &vfb_ops; fb_info.disp = &disp; fb_info.switch_con = &vfbcon_switch; fb_info.updatevar = &vfbcon_updatevar; - fb_info.blank = &vfbcon_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; vfb_set_var(&vfb_default, -1, &fb_info); @@ -447,15 +444,6 @@ return 0; } - /* - * Blank the display. - */ - -static void vfbcon_blank(int blank, struct fb_info *info) -{ - /* Nothing */ -} - static u_long get_line_length(int xres_virtual, int bpp) { u_long length; @@ -592,7 +580,7 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, vfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1, vfb_setcolreg, info); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/vga16fb.c linux-2.5/drivers/video/vga16fb.c --- linux-2.5.1/drivers/video/vga16fb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/vga16fb.c Mon Jan 14 23:58:39 2002 @@ -582,9 +582,9 @@ outb(blue >> 10, dac_val); } -static int vga16_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *fb_info) +static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info) { int gray; @@ -623,10 +623,9 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, vga16_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else - fb_set_cmap(fb_default_cmap(16), 1, vga16_setcolreg, - info); + fb_set_cmap(fb_default_cmap(16), 1, info); } static int vga16fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, @@ -653,7 +652,7 @@ return err; } if (con == currcon) /* current console? */ - return fb_set_cmap(cmap, kspc, vga16_setcolreg, info); + return fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; @@ -673,16 +672,6 @@ return 0; } -static struct fb_ops vga16fb_ops = { - owner: THIS_MODULE, - fb_get_fix: vga16fb_get_fix, - fb_get_var: vga16fb_get_var, - fb_set_var: vga16fb_set_var, - fb_get_cmap: vga16fb_get_cmap, - fb_set_cmap: vga16fb_set_cmap, - fb_pan_display: vga16fb_pan_display, -}; - int vga16fb_setup(char *options) { char *this_opt; @@ -862,7 +851,7 @@ } /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ -static void vga16fb_blank(int blank, struct fb_info *fb_info) +static int vga16fb_blank(int blank, struct fb_info *fb_info) { struct vga16fb_info *info = (struct vga16fb_info*)fb_info; @@ -886,8 +875,21 @@ info->vesa_blanked = 1; break; } + return 0; } +static struct fb_ops vga16fb_ops = { + owner: THIS_MODULE, + fb_get_fix: vga16fb_get_fix, + fb_get_var: vga16fb_get_var, + fb_set_var: vga16fb_set_var, + fb_get_cmap: vga16fb_get_cmap, + fb_set_cmap: vga16fb_set_cmap, + fb_setcolreg: vga16fb_setcolreg, + fb_pan_display: vga16fb_pan_display, + fb_blank: vga16fb_blank, +}; + int __init vga16fb_init(void) { int i,j; @@ -926,12 +928,11 @@ /* name should not depend on EGA/VGA */ strcpy(vga16fb.fb_info.modename, "VGA16 VGA"); vga16fb.fb_info.changevar = NULL; - vga16fb.fb_info.node = -1; + vga16fb.fb_info.node = NODEV; vga16fb.fb_info.fbops = &vga16fb_ops; vga16fb.fb_info.disp=&disp; vga16fb.fb_info.switch_con=&vga16fb_switch; vga16fb.fb_info.updatevar=&vga16fb_update_var; - vga16fb.fb_info.blank=&vga16fb_blank; vga16fb.fb_info.flags=FBINFO_FLAG_DEFAULT; vga16fb_set_disp(-1, &vga16fb); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/drivers/video/virgefb.c linux-2.5/drivers/video/virgefb.c --- linux-2.5.1/drivers/video/virgefb.c Wed Nov 14 22:52:20 2001 +++ linux-2.5/drivers/video/virgefb.c Mon Jan 14 23:58:39 2002 @@ -136,8 +136,6 @@ int (*encode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par); int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); - int (*setcolreg)(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); void (*blank)(int blank); } *fbhw; @@ -306,7 +304,9 @@ struct fb_info *info); static int virgefb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); - +static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int virgefb_blank(int blank, struct fb_info *info); /* * Interface to the low level console driver @@ -315,8 +315,6 @@ int virgefb_init(void); static int Cyberfb_switch(int con, struct fb_info *info); static int Cyberfb_updatevar(int con, struct fb_info *info); -static void Cyberfb_blank(int blank, struct fb_info *info); - /* * Text console acceleration @@ -343,8 +341,6 @@ struct virgefb_par *par); static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void Cyber_blank(int blank); @@ -573,8 +569,8 @@ * entries in the var structure). Return != 0 for invalid regno. */ -static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) { if (((current_par.bpp==8) && (regno>255)) || ((current_par.bpp!=8) && (regno>15))) @@ -817,7 +813,7 @@ static struct fb_hwswitch Cyber_switch = { Cyber_init, Cyber_encode_fix, Cyber_decode_var, Cyber_encode_var, - Cyber_getcolreg, Cyber_setcolreg, Cyber_blank + Cyber_getcolreg, Cyber_blank }; @@ -884,10 +880,10 @@ if (con != currcon) return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - 1, fbhw->setcolreg, info); + 1, info); } /* @@ -1059,7 +1055,7 @@ return(err); } if (con == currcon) /* current console? */ - return(fb_set_cmap(cmap, kspc, fbhw->setcolreg, info)); + return(fb_set_cmap(cmap, kspc, info)); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return(0); @@ -1073,6 +1069,8 @@ fb_set_var: virgefb_set_var, fb_get_cmap: virgefb_get_cmap, fb_set_cmap: virgefb_set_cmap, + fb_setcolreg: virgefb_setcolreg, + fb_blank: virgefb_blank, }; @@ -1168,12 +1166,11 @@ strcpy(fb_info.modename, virgefb_name); fb_info.changevar = NULL; - fb_info.node = -1; + fb_info.node = NODEV; fb_info.fbops = &virgefb_ops; fb_info.disp = &disp; fb_info.switch_con = &Cyberfb_switch; fb_info.updatevar = &Cyberfb_updatevar; - fb_info.blank = &Cyberfb_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; fbhw->init(); @@ -1234,9 +1231,10 @@ * Blank the display. */ -static void Cyberfb_blank(int blank, struct fb_info *info) +static int virgefb_blank(int blank, struct fb_info *info) { fbhw->blank(blank); + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/Config.in linux-2.5/fs/Config.in --- linux-2.5.1/fs/Config.in Fri Nov 30 01:39:02 2001 +++ linux-2.5/fs/Config.in Thu Dec 27 15:56:12 2001 @@ -45,7 +45,7 @@ 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 +define_bool CONFIG_RAMFS y tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS dep_mbool ' Microsoft Joliet CDROM extensions' CONFIG_JOLIET $CONFIG_ISO9660_FS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/adfs/inode.c linux-2.5/fs/adfs/inode.c --- linux-2.5.1/fs/adfs/inode.c Sun Dec 16 20:22:46 2001 +++ linux-2.5/fs/adfs/inode.c Sun Dec 30 20:01:41 2001 @@ -37,11 +37,8 @@ goto abort_toobig; block = __adfs_block_map(inode->i_sb, inode->i_ino, block); - if (block) { - bh->b_dev = inode->i_dev; - bh->b_blocknr = block; - bh->b_state |= (1UL << BH_Mapped); - } + if (block) + map_bh(bh, inode->i_sb, block); return 0; } /* don't support allocation of blocks yet */ @@ -251,7 +248,6 @@ if (!inode) goto out; - inode->i_version = ++event; inode->i_uid = sb->u.adfs_sb.s_uid; inode->i_gid = sb->u.adfs_sb.s_gid; inode->i_ino = obj->file_id; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/adfs/super.c linux-2.5/fs/adfs/super.c --- linux-2.5.1/fs/adfs/super.c Sun Dec 16 20:22:46 2001 +++ linux-2.5/fs/adfs/super.c Sat Jan 5 16:38:08 2002 @@ -39,7 +39,7 @@ va_end(args); printk(KERN_CRIT "ADFS-fs error (device %s)%s%s: %s\n", - bdevname(sb->s_dev), function ? ": " : "", + sb->s_id, function ? ": " : "", function ? function : "", error_buf); } @@ -308,7 +308,6 @@ struct buffer_head *bh; struct object_info root_obj; unsigned char *b_data; - kdev_t dev = sb->s_dev; /* set default options */ sb->u.adfs_sb.s_uid = 0; @@ -319,8 +318,7 @@ if (parse_options(sb, data)) goto error; - sb->s_blocksize = BLOCK_SIZE; - set_blocksize(dev, BLOCK_SIZE); + sb_set_blocksize(sb, BLOCK_SIZE); if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) { adfs_error(sb, "unable to read superblock"); goto error; @@ -331,7 +329,7 @@ if (adfs_checkbblk(b_data)) { if (!silent) printk("VFS: Can't find an adfs filesystem on dev " - "%s.\n", bdevname(dev)); + "%s.\n", sb->s_id); goto error_free_bh; } @@ -343,18 +341,12 @@ if (adfs_checkdiscrecord(dr)) { if (!silent) printk("VPS: Can't find an adfs filesystem on dev " - "%s.\n", bdevname(dev)); + "%s.\n", sb->s_id); goto error_free_bh; } - sb->s_blocksize_bits = dr->log2secsize; - sb->s_blocksize = 1 << sb->s_blocksize_bits; - if (sb->s_blocksize != BLOCK_SIZE && - (sb->s_blocksize == 512 || sb->s_blocksize == 1024 || - sb->s_blocksize == 2048 || sb->s_blocksize == 4096)) { - - brelse(bh); - set_blocksize(dev, sb->s_blocksize); + brelse(bh); + if (sb_set_blocksize(sb, 1 << dr->log2secsize)) { bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize); if (!bh) { adfs_error(sb, "couldn't read superblock on " @@ -367,12 +359,11 @@ goto error_free_bh; } dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET); - } - if (sb->s_blocksize != bh->b_size) { + } else { if (!silent) printk(KERN_ERR "VFS: Unsupported blocksize on dev " - "%s.\n", bdevname(dev)); - goto error_free_bh; + "%s.\n", sb->s_id); + goto error; } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/affs/amigaffs.c linux-2.5/fs/affs/amigaffs.c --- linux-2.5.1/fs/affs/amigaffs.c Tue Sep 11 15:19:35 2001 +++ linux-2.5/fs/affs/amigaffs.c Sat Jan 5 16:38:08 2002 @@ -453,7 +453,7 @@ vsprintf(ErrorBuffer,fmt,args); va_end(args); - printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n", bdevname(sb->s_dev), + printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n", sb->s_id, function,ErrorBuffer); if (!(sb->s_flags & MS_RDONLY)) printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n"); @@ -470,7 +470,7 @@ vsprintf(ErrorBuffer,fmt,args); va_end(args); - printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n", bdevname(sb->s_dev), + printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n", sb->s_id, function,ErrorBuffer); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/affs/bitmap.c linux-2.5/fs/affs/bitmap.c --- linux-2.5.1/fs/affs/bitmap.c Wed Apr 25 21:57:09 2001 +++ linux-2.5/fs/affs/bitmap.c Sat Jan 5 16:38:08 2002 @@ -282,7 +282,7 @@ if (!AFFS_ROOT_TAIL(sb, AFFS_SB->s_root_bh)->bm_flag) { printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n", - kdevname(sb->s_dev)); + sb->s_id); sb->s_flags |= MS_RDONLY; return 0; } @@ -316,7 +316,7 @@ } if (affs_checksum_block(sb, bh)) { printk(KERN_WARNING "AFFS: Bitmap %u invalid - mounting %s read only.\n", - bm->bm_key, kdevname(sb->s_dev)); + bm->bm_key, sb->s_id); sb->s_flags |= MS_RDONLY; goto out; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/affs/file.c linux-2.5/fs/affs/file.c --- linux-2.5.1/fs/affs/file.c Sun Dec 16 20:22:46 2001 +++ linux-2.5/fs/affs/file.c Thu Dec 27 22:10:28 2001 @@ -355,9 +355,7 @@ ext_bh = affs_get_extblock(inode, ext); if (IS_ERR(ext_bh)) goto err_ext; - bh_result->b_blocknr = be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block)); - bh_result->b_dev = inode->i_dev; - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh_result, sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block))); if (create) { u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/affs/super.c linux-2.5/fs/affs/super.c --- linux-2.5.1/fs/affs/super.c Sun Dec 16 20:22:46 2001 +++ linux-2.5/fs/affs/super.c Sat Jan 5 16:38:08 2002 @@ -262,7 +262,7 @@ * blocks, we will have to change it. */ - blocks = blk_size[MAJOR(dev)] ? blk_size[MAJOR(dev)][MINOR(dev)] : 0; + blocks = blk_size[major(dev)] ? blk_size[major(dev)][minor(dev)] : 0; if (!blocks) { printk(KERN_ERR "AFFS: Could not determine device size\n"); goto out_error; @@ -300,7 +300,7 @@ for (num_bm = 0; num_bm < 2; num_bm++) { pr_debug("AFFS: Dev %s, trying root=%u, bs=%d, " "size=%d, reserved=%d\n", - kdevname(dev), + sb->s_id, AFFS_SB->s_root_block + num_bm, blocksize, size, reserved); root_bh = affs_bread(sb, AFFS_SB->s_root_block + num_bm); @@ -320,17 +320,13 @@ } if (!silent) printk(KERN_ERR "AFFS: No valid root block on device %s\n", - kdevname(dev)); + sb->s_id); goto out_error; /* N.B. after this point bh must be released */ got_root: root_block = AFFS_SB->s_root_block; - sb->s_blocksize_bits = blocksize == 512 ? 9 : - blocksize == 1024 ? 10 : - blocksize == 2048 ? 11 : 12; - /* Find out which kind of FS we have */ boot_bh = sb_bread(sb, 0); if (!boot_bh) { @@ -347,7 +343,7 @@ if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS || chksum == MUFS_DCOFS) && !(sb->s_flags & MS_RDONLY)) { printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n", - kdevname(dev)); + sb->s_id); sb->s_flags |= MS_RDONLY; AFFS_SB->s_flags |= SF_READONLY; } @@ -383,7 +379,7 @@ break; default: printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n", - kdevname(dev), chksum); + sb->s_id, chksum); goto out_error; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/autofs/inode.c linux-2.5/fs/autofs/inode.c --- linux-2.5.1/fs/autofs/inode.c Thu Oct 25 07:02:26 2001 +++ linux-2.5/fs/autofs/inode.c Sun Dec 30 20:01:41 2001 @@ -11,6 +11,7 @@ * ------------------------------------------------------------------------- */ #include <linux/kernel.h> +#include <linux/mm.h> #include <linux/slab.h> #include <linux/file.h> #include <linux/locks.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/autofs4/inode.c linux-2.5/fs/autofs4/inode.c --- linux-2.5.1/fs/autofs4/inode.c Fri Nov 9 22:11:14 2001 +++ linux-2.5/fs/autofs4/inode.c Tue Jan 1 23:42:42 2002 @@ -308,7 +308,7 @@ } inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; - inode->i_rdev = 0; + inode->i_rdev = NODEV; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; if (S_ISDIR(inf->mode)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/bfs/dir.c linux-2.5/fs/bfs/dir.c --- linux-2.5.1/fs/bfs/dir.c Sun Dec 16 20:22:46 2001 +++ linux-2.5/fs/bfs/dir.c Sat Jan 5 16:38:08 2002 @@ -28,13 +28,12 @@ struct inode * dir = f->f_dentry->d_inode; struct buffer_head * bh; struct bfs_dirent * de; - kdev_t dev = dir->i_dev; unsigned int offset; int block; if (f->f_pos & (BFS_DIRENT_SIZE-1)) { printf("Bad f_pos=%08lx for %s:%08lx\n", (unsigned long)f->f_pos, - bdevname(dev), dir->i_ino); + dir->i_sb->s_id, dir->i_ino); return -EBADF; } @@ -169,12 +168,11 @@ goto out_brelse; if (!inode->i_nlink) { - printf("unlinking non-existent file %s:%lu (nlink=%d)\n", bdevname(inode->i_dev), + printf("unlinking non-existent file %s:%lu (nlink=%d)\n", inode->i_sb->s_id, inode->i_ino, inode->i_nlink); inode->i_nlink = 1; } de->ino = 0; - dir->i_version = ++event; mark_buffer_dirty(bh); dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); @@ -227,7 +225,6 @@ } old_de->ino = 0; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; - old_dir->i_version = ++event; mark_inode_dirty(old_dir); if (new_inode) { new_inode->i_nlink--; @@ -256,7 +253,6 @@ struct buffer_head * bh; struct bfs_dirent * de; int block, sblock, eblock, off; - kdev_t dev; int i; dprintf("name=%s, namelen=%d\n", name, namelen); @@ -266,7 +262,6 @@ if (namelen > BFS_NAMELEN) return -ENAMETOOLONG; - dev = dir->i_dev; sblock = dir->iu_sblock; eblock = dir->iu_eblock; for (block=sblock; block<=eblock; block++) { @@ -282,7 +277,6 @@ } dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); - dir->i_version = ++event; de->ino = ino; for (i=0; i<BFS_NAMELEN; i++) de->name[i] = (i < namelen) ? name[i] : 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/bfs/file.c linux-2.5/fs/bfs/file.c --- linux-2.5.1/fs/bfs/file.c Sun Dec 16 20:22:53 2001 +++ linux-2.5/fs/bfs/file.c Thu Dec 27 22:10:28 2001 @@ -25,14 +25,14 @@ mmap: generic_file_mmap, }; -static int bfs_move_block(unsigned long from, unsigned long to, kdev_t dev) +static int bfs_move_block(unsigned long from, unsigned long to, struct super_block *sb) { struct buffer_head *bh, *new; - bh = bread(dev, from, BFS_BSIZE); + bh = sb_bread(sb, from); if (!bh) return -EIO; - new = getblk(dev, to, BFS_BSIZE); + new = sb_getblk(sb, to); memcpy(new->b_data, bh->b_data, bh->b_size); mark_buffer_dirty(new); bforget(bh); @@ -40,14 +40,14 @@ return 0; } -static int bfs_move_blocks(kdev_t dev, unsigned long start, unsigned long end, +static int bfs_move_blocks(struct super_block *sb, unsigned long start, unsigned long end, unsigned long where) { unsigned long i; dprintf("%08lx-%08lx->%08lx\n", start, end, where); for (i = start; i <= end; i++) - if(bfs_move_block(i, where + i, dev)) { + if(bfs_move_block(i, where + i, sb)) { dprintf("failed to move block %08lx -> %08lx\n", i, where + i); return -EIO; } @@ -69,9 +69,7 @@ if (!create) { if (phys <= inode->iu_eblock) { dprintf("c=%d, b=%08lx, phys=%08lx (granted)\n", create, block, phys); - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh_result, sb, phys); } return 0; } @@ -81,9 +79,7 @@ if (inode->i_size && phys <= inode->iu_eblock) { dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", create, block, phys); - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh_result, sb, phys); return 0; } @@ -95,9 +91,7 @@ if (inode->iu_eblock == sb->su_lf_eblk) { dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", create, block, phys); - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh_result, sb, phys); sb->su_freeb -= phys - inode->iu_eblock; sb->su_lf_eblk = inode->iu_eblock = phys; mark_inode_dirty(inode); @@ -109,7 +103,7 @@ /* Ok, we have to move this entire file to the next free block */ phys = sb->su_lf_eblk + 1; if (inode->iu_sblock) { /* if data starts on block 0 then there is no data */ - err = bfs_move_blocks(inode->i_dev, inode->iu_sblock, + err = bfs_move_blocks(inode->i_sb, inode->iu_sblock, inode->iu_eblock, phys); if (err) { dprintf("failed to move ino=%08lx -> fs corruption\n", inode->i_ino); @@ -128,9 +122,7 @@ sb->su_freeb -= inode->iu_eblock - inode->iu_sblock + 1 - inode->i_blocks; mark_inode_dirty(inode); mark_buffer_dirty(sbh); - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh_result, sb, phys); out: unlock_kernel(); return err; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/bfs/inode.c linux-2.5/fs/bfs/inode.c --- linux-2.5.1/fs/bfs/inode.c Sun Dec 16 20:22:53 2001 +++ linux-2.5/fs/bfs/inode.c Sat Jan 5 16:38:08 2002 @@ -35,13 +35,12 @@ static void bfs_read_inode(struct inode * inode) { unsigned long ino = inode->i_ino; - kdev_t dev = inode->i_dev; struct bfs_inode * di; struct buffer_head * bh; int block, off; if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) { - printf("Bad inode number %s:%08lx\n", bdevname(dev), ino); + printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino); make_bad_inode(inode); return; } @@ -49,7 +48,7 @@ block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1; bh = sb_bread(inode->i_sb, block); if (!bh) { - printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino); + printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id, ino); make_bad_inode(inode); return; } @@ -88,13 +87,12 @@ static void bfs_write_inode(struct inode * inode, int unused) { unsigned long ino = inode->i_ino; - kdev_t dev = inode->i_dev; struct bfs_inode * di; struct buffer_head * bh; int block, off; if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) { - printf("Bad inode number %s:%08lx\n", bdevname(dev), ino); + printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino); return; } @@ -102,7 +100,7 @@ block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1; bh = sb_bread(inode->i_sb, block); if (!bh) { - printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino); + printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id, ino); unlock_kernel(); return; } @@ -135,7 +133,6 @@ static void bfs_delete_inode(struct inode * inode) { unsigned long ino = inode->i_ino; - kdev_t dev = inode->i_dev; struct bfs_inode * di; struct buffer_head * bh; int block, off; @@ -155,7 +152,7 @@ block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1; bh = sb_bread(s, block); if (!bh) { - printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino); + printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id, ino); unlock_kernel(); return; } @@ -241,16 +238,12 @@ static struct super_block * bfs_read_super(struct super_block * s, void * data, int silent) { - kdev_t dev; struct buffer_head * bh; struct bfs_super_block * bfs_sb; struct inode * inode; int i, imap_len; - dev = s->s_dev; - set_blocksize(dev, BFS_BSIZE); - s->s_blocksize = BFS_BSIZE; - s->s_blocksize_bits = BFS_BSIZE_BITS; + sb_set_blocksize(s, BFS_BSIZE); bh = sb_bread(s, 0); if(!bh) @@ -259,11 +252,11 @@ if (bfs_sb->s_magic != BFS_MAGIC) { if (!silent) printf("No BFS filesystem on %s (magic=%08x)\n", - bdevname(dev), bfs_sb->s_magic); + s->s_id, bfs_sb->s_magic); goto out; } if (BFS_UNCLEAN(bfs_sb, s) && !silent) - printf("%s is unclean, continuing\n", bdevname(dev)); + printf("%s is unclean, continuing\n", s->s_id); s->s_magic = BFS_MAGIC; s->su_bfs_sb = bfs_sb; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/binfmt_elf.c linux-2.5/fs/binfmt_elf.c --- linux-2.5.1/fs/binfmt_elf.c Sun Oct 21 02:16:59 2001 +++ linux-2.5/fs/binfmt_elf.c Mon Jan 14 22:39:45 2002 @@ -32,7 +32,7 @@ #include <linux/highuid.h> #include <linux/smp_lock.h> #include <linux/compiler.h> -#include <linux/limits.h> +#include <linux/highmem.h> #include <asm/uaccess.h> #include <asm/param.h> @@ -138,6 +138,22 @@ } else u_platform = p; +#if defined(__i386__) && defined(CONFIG_SMP) + /* + * In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions + * by the processes running on the same package. One thing we can do + * is to shuffle the initial stack for them. + * + * The conditionals here are unneeded, but kept in to make the + * code behaviour the same as pre change unless we have hyperthreaded + * processors. This keeps Mr Marcelo Person happier but should be + * removed for 2.5 + */ + + if(smp_num_siblings > 1) + u_platform = u_platform - ((current->pid % 64) << 7); +#endif + /* * Force 16 byte _final_ alignment here for generality. */ @@ -505,30 +521,10 @@ #if 0 printk("Using ELF interpreter %s\n", elf_interpreter); #endif -#ifdef __sparc__ - if (ibcs2_interpreter) { - unsigned long old_pers = current->personality; - struct exec_domain *old_domain = current->exec_domain; - struct exec_domain *new_domain; - struct fs_struct *old_fs = current->fs, *new_fs; - get_exec_domain(old_domain); - atomic_inc(&old_fs->count); - - set_personality(PER_SVR4); - interpreter = open_exec(elf_interpreter); - - new_domain = current->exec_domain; - new_fs = current->fs; - current->personality = old_pers; - current->exec_domain = old_domain; - current->fs = old_fs; - put_exec_domain(new_domain); - put_fs_struct(new_fs); - } else -#endif - { - interpreter = open_exec(elf_interpreter); - } + + SET_PERSONALITY(elf_ex, ibcs2_interpreter); + + interpreter = open_exec(elf_interpreter); retval = PTR_ERR(interpreter); if (IS_ERR(interpreter)) goto out_free_interp; @@ -602,10 +598,6 @@ current->flags &= ~PF_FORKNOEXEC; elf_entry = (unsigned long) elf_ex.e_entry; - /* Do this immediately, since STACK_TOP as used in setup_arg_pages - may depend on the personality. */ - SET_PERSONALITY(elf_ex, ibcs2_interpreter); - /* Do this so that we can load the interpreter, if need be. We will change some of these later */ current->mm->rss = 0; @@ -1032,6 +1024,42 @@ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ + /* first copy the parameters from user space */ + memset(&psinfo, 0, sizeof(psinfo)); + { + int i, len; + + len = current->mm->arg_end - current->mm->arg_start; + if (len >= ELF_PRARGSZ) + len = ELF_PRARGSZ-1; + copy_from_user(&psinfo.pr_psargs, + (const char *)current->mm->arg_start, len); + for(i = 0; i < len; i++) + if (psinfo.pr_psargs[i] == 0) + psinfo.pr_psargs[i] = ' '; + psinfo.pr_psargs[len] = 0; + + } + + memset(&prstatus, 0, sizeof(prstatus)); + /* + * This transfers the registers from regs into the standard + * coredump arrangement, whatever that is. + */ +#ifdef ELF_CORE_COPY_REGS + ELF_CORE_COPY_REGS(prstatus.pr_reg, regs) +#else + if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) + { + printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n", + (long)sizeof(elf_gregset_t), (long)sizeof(struct pt_regs)); + } + else + *(struct pt_regs *)&prstatus.pr_reg = *regs; +#endif + + /* now stop all vm operations */ + down_write(¤t->mm->mmap_sem); segs = current->mm->map_count; #ifdef DEBUG @@ -1073,8 +1101,6 @@ * Set up the notes in similar form to SVR4 core dumps made * with info from their /proc. */ - memset(&psinfo, 0, sizeof(psinfo)); - memset(&prstatus, 0, sizeof(prstatus)); notes[0].name = "CORE"; notes[0].type = NT_PRSTATUS; @@ -1096,22 +1122,6 @@ prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime); prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime); - /* - * This transfers the registers from regs into the standard - * coredump arrangement, whatever that is. - */ -#ifdef ELF_CORE_COPY_REGS - ELF_CORE_COPY_REGS(prstatus.pr_reg, regs) -#else - if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) - { - printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n", - (long)sizeof(elf_gregset_t), (long)sizeof(struct pt_regs)); - } - else - *(struct pt_regs *)&prstatus.pr_reg = *regs; -#endif - #ifdef DEBUG dump_regs("Passed in regs", (elf_greg_t *)regs); dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg); @@ -1125,27 +1135,10 @@ psinfo.pr_state = i; psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i]; psinfo.pr_zomb = psinfo.pr_sname == 'Z'; - psinfo.pr_nice = current->nice; + psinfo.pr_nice = current->__nice; psinfo.pr_flag = current->flags; psinfo.pr_uid = NEW_TO_OLD_UID(current->uid); psinfo.pr_gid = NEW_TO_OLD_GID(current->gid); - { - int i, len; - - set_fs(fs); - - len = current->mm->arg_end - current->mm->arg_start; - if (len >= ELF_PRARGSZ) - len = ELF_PRARGSZ-1; - copy_from_user(&psinfo.pr_psargs, - (const char *)current->mm->arg_start, len); - for(i = 0; i < len; i++) - if (psinfo.pr_psargs[i] == 0) - psinfo.pr_psargs[i] = ' '; - psinfo.pr_psargs[len] = 0; - - set_fs(KERNEL_DS); - } strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); notes[2].name = "CORE"; @@ -1217,8 +1210,6 @@ if (!writenote(¬es[i], file)) goto end_coredump; - set_fs(fs); - DUMP_SEEK(dataoff); for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { @@ -1226,28 +1217,32 @@ if (!maydump(vma)) continue; + #ifdef DEBUG - printk("elf_core_dump: writing %08lx %lx\n", addr, len); + printk("elf_core_dump: writing %08lx-%08lx\n", vma->vm_start, vma->vm_end); #endif + for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - pgd = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgd)) - goto nextpage_coredump; - pmd = pmd_offset(pgd, addr); - if (pmd_none(*pmd)) - goto nextpage_coredump; - pte = pte_offset(pmd, addr); - if (pte_none(*pte)) { -nextpage_coredump: + struct page* page; + struct vm_area_struct *vma; + + if (get_user_pages(current, current->mm, addr, 1, 0, 1, + &page, &vma) <= 0) { DUMP_SEEK (file->f_pos + PAGE_SIZE); } else { - DUMP_WRITE((void*)addr, PAGE_SIZE); + if (page == ZERO_PAGE(addr)) { + DUMP_SEEK (file->f_pos + PAGE_SIZE); + } else { + void *kaddr; + flush_cache_page(vma, addr); + kaddr = kmap(page); + DUMP_WRITE(kaddr, PAGE_SIZE); + flush_page_to_ram(page); + kunmap(page); + } + put_page(page); } } } @@ -1260,6 +1255,7 @@ end_coredump: set_fs(fs); + up_write(¤t->mm->mmap_sem); return has_dumped; } #endif /* USE_ELF_CORE_DUMP */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/bio.c linux-2.5/fs/bio.c --- linux-2.5.1/fs/bio.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/fs/bio.c Thu Dec 27 22:10:28 2001 @@ -142,6 +142,7 @@ bio->bi_io_vec = bvl; return bio; } + mempool_free(bio, bio_pool); return NULL; } @@ -311,28 +312,6 @@ return NULL; } -#ifdef BIO_PAGEIO -static int bio_end_io_page(struct bio *bio) -{ - struct page *page = bio_page(bio); - - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) - SetPageError(page); - if (!PageError(page)) - SetPageUptodate(page); - - /* - * Run the hooks that have to be done when a page I/O has completed. - */ - if (PageTestandClearDecrAfter(page)) - atomic_dec(&nr_async_pages); - - UnlockPage(page); - bio_put(bio); - return 1; -} -#endif - static int bio_end_io_kio(struct bio *bio, int nr_sectors) { struct kiobuf *kio = (struct kiobuf *) bio->bi_private; @@ -465,7 +444,10 @@ else clear_bit(BIO_UPTODATE, &bio->bi_flags); - return bio->bi_end_io(bio, nr_sectors); + if (bio->bi_end_io) + return bio->bi_end_io(bio, nr_sectors); + + return 0; } static void __init biovec_init_pool(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/block_dev.c linux-2.5/fs/block_dev.c --- linux-2.5.1/fs/block_dev.c Wed Dec 12 00:47:44 2001 +++ linux-2.5/fs/block_dev.c Sun Jan 13 22:25:59 2002 @@ -27,10 +27,10 @@ static unsigned long max_block(kdev_t dev) { unsigned int retval = ~0U; - int major = MAJOR(dev); + int major = major(dev); if (blk_size[major]) { - int minor = MINOR(dev); + int minor = minor(dev); unsigned int blocks = blk_size[major][minor]; if (blocks) { unsigned int size = block_size(dev); @@ -47,10 +47,10 @@ static loff_t blkdev_size(kdev_t dev) { unsigned int blocks = ~0U; - int major = MAJOR(dev); + int major = major(dev); if (blk_size[major]) { - int minor = MINOR(dev); + int minor = minor(dev); blocks = blk_size[major][minor]; } return (loff_t) blocks << BLOCK_SIZE_BITS; @@ -77,31 +77,51 @@ return -EINVAL; /* No blocksize array? Implies hardcoded BLOCK_SIZE */ - if (!blksize_size[MAJOR(dev)]) { + if (!blksize_size[major(dev)]) { if (size == BLOCK_SIZE) return 0; return -EINVAL; } - oldsize = blksize_size[MAJOR(dev)][MINOR(dev)]; + oldsize = blksize_size[major(dev)][minor(dev)]; if (oldsize == size) return 0; if (!oldsize && size == BLOCK_SIZE) { - blksize_size[MAJOR(dev)][MINOR(dev)] = size; + blksize_size[major(dev)][minor(dev)] = size; return 0; } /* Ok, we're actually changing the blocksize.. */ - bdev = bdget(dev); + bdev = bdget(kdev_t_to_nr(dev)); sync_buffers(dev, 2); - blksize_size[MAJOR(dev)][MINOR(dev)] = size; + blksize_size[major(dev)][minor(dev)] = size; bdev->bd_inode->i_blkbits = blksize_bits(size); kill_bdev(bdev); bdput(bdev); return 0; } +int sb_set_blocksize(struct super_block *sb, int size) +{ + int bits; + if (set_blocksize(sb->s_dev, size) < 0) + return 0; + sb->s_blocksize = size; + for (bits = 9, size >>= 9; size >>= 1; bits++) + ; + sb->s_blocksize_bits = bits; + return sb->s_blocksize; +} + +int sb_min_blocksize(struct super_block *sb, int size) +{ + int minsize = get_hardsect_size(sb->s_dev); + if (size < minsize) + size = minsize; + return sb_set_blocksize(sb, size); +} + static int blkdev_get_block(struct inode * inode, sector_t iblock, struct buffer_head * bh, int create) { if (iblock >= max_block(inode->i_rdev)) @@ -171,11 +191,15 @@ static int __block_fsync(struct inode * inode) { - int ret; + int ret, err; - filemap_fdatasync(inode->i_mapping); - ret = sync_buffers(inode->i_rdev, 1); - filemap_fdatawait(inode->i_mapping); + ret = filemap_fdatasync(inode->i_mapping); + err = sync_buffers(inode->i_rdev, 1); + if (err && !ret) + ret = err; + err = filemap_fdatawait(inode->i_mapping); + if (err && !ret) + ret = err; return ret; } @@ -330,6 +354,7 @@ inode->i_bdev = new_bdev; inode->i_data.a_ops = &def_blk_aops; inode->i_data.gfp_mask = GFP_USER; + inode->i_mode = S_IFBLK; spin_lock(&bdev_lock); bdev = bdfind(dev, head); if (!bdev) { @@ -491,15 +516,18 @@ int i; const struct block_device_operations * bdops = NULL; - i = MAJOR(dev); + i = major(dev); if (i < MAX_BLKDEV) bdops = blkdevs[i].bdops; if (bdops == NULL) { devfs_handle_t de; - de = devfs_find_handle (NULL, NULL, i, MINOR (dev), + de = devfs_find_handle (NULL, NULL, i, minor(dev), DEVFS_SPECIAL_BLK, 0); - if (de) bdops = devfs_get_ops (de); + if (de) { + bdops = devfs_get_ops (de); + devfs_put_ops (de); /* We're running in owner module */ + } } if (bdops == NULL) return 0; @@ -540,7 +568,7 @@ down(&bdev->bd_sem); lock_kernel(); if (!bdev->bd_op) - bdev->bd_op = get_blkfops(MAJOR(dev)); + bdev->bd_op = get_blkfops(major(dev)); if (bdev->bd_op) { ret = 0; if (bdev->bd_op->owner) @@ -604,7 +632,6 @@ int blkdev_put(struct block_device *bdev, int kind) { int ret = 0; - kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */ struct inode *bd_inode = bdev->bd_inode; down(&bdev->bd_sem); @@ -612,7 +639,7 @@ if (kind == BDEV_FILE) __block_fsync(bd_inode); else if (kind == BDEV_FS) - fsync_no_super(rdev); + fsync_no_super(bdev); if (!--bdev->bd_openers) kill_bdev(bdev); if (bdev->bd_op->release) @@ -663,11 +690,11 @@ const char * bdevname(kdev_t dev) { static char buffer[32]; - const char * name = blkdevs[MAJOR(dev)].name; + const char * name = blkdevs[major(dev)].name; if (!name) name = "unknown-block"; - sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev)); + sprintf(buffer, "%s(%d,%d)", name, major(dev), minor(dev)); return buffer; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/buffer.c linux-2.5/fs/buffer.c --- linux-2.5.1/fs/buffer.c Tue Dec 11 18:51:43 2001 +++ linux-2.5/fs/buffer.c Sun Jan 13 23:00:07 2002 @@ -52,7 +52,7 @@ #include <asm/uaccess.h> #include <asm/io.h> #include <asm/bitops.h> -#include <asm/mmu_context.h> +#include <asm/sched.h> #define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512) #define NR_RESERVED (10*MAX_BUF_PER_PAGE) @@ -203,7 +203,7 @@ struct buffer_head * bh = next; next = bh->b_next_free; - if (dev && bh->b_dev != dev) + if (!kdev_none(dev) && !kdev_same(bh->b_dev, dev)) continue; if (test_and_set_bit(BH_Lock, &bh->b_state)) continue; @@ -261,7 +261,7 @@ __refile_buffer(bh); continue; } - if (dev && bh->b_dev != dev) + if (!kdev_none(dev) && !kdev_same(bh->b_dev, dev)) continue; get_bh(bh); @@ -324,7 +324,7 @@ lock_kernel(); sync_inodes_sb(sb); - DQUOT_SYNC(dev); + DQUOT_SYNC(sb); lock_super(sb); if (sb->s_dirt && sb->s_op && sb->s_op->write_super) sb->s_op->write_super(sb); @@ -334,8 +334,9 @@ return sync_buffers(dev, 1); } -int fsync_no_super(kdev_t dev) +int fsync_no_super(struct block_device *bdev) { + kdev_t dev = to_kdev_t(bdev->bd_dev); sync_buffers(dev, 0); return sync_buffers(dev, 1); } @@ -346,7 +347,14 @@ lock_kernel(); sync_inodes(dev); - DQUOT_SYNC(dev); + if (!kdev_none(dev)) { + struct super_block *sb = get_super(dev); + if (sb) { + DQUOT_SYNC(sb); + drop_super(sb); + } + } else + DQUOT_SYNC(NULL); sync_supers(dev); unlock_kernel(); @@ -364,7 +372,7 @@ asmlinkage long sys_sync(void) { - fsync_dev(0); + fsync_dev(NODEV); return 0; } @@ -402,9 +410,9 @@ struct file * file; struct dentry * dentry; struct inode * inode; - int err; + int ret, err; - err = -EBADF; + ret = -EBADF; file = fget(fd); if (!file) goto out; @@ -412,21 +420,27 @@ dentry = file->f_dentry; inode = dentry->d_inode; - err = -EINVAL; - if (!file->f_op || !file->f_op->fsync) + ret = -EINVAL; + if (!file->f_op || !file->f_op->fsync) { + /* Why? We can still call filemap_fdatasync */ goto out_putf; + } /* We need to protect against concurrent writers.. */ down(&inode->i_sem); - filemap_fdatasync(inode->i_mapping); + ret = filemap_fdatasync(inode->i_mapping); err = file->f_op->fsync(file, dentry, 0); - filemap_fdatawait(inode->i_mapping); + if (err && !ret) + ret = err; + err = filemap_fdatawait(inode->i_mapping); + if (err && !ret) + ret = err; up(&inode->i_sem); out_putf: fput(file); out: - return err; + return ret; } asmlinkage long sys_fdatasync(unsigned int fd) @@ -434,9 +448,9 @@ struct file * file; struct dentry * dentry; struct inode * inode; - int err; + int ret, err; - err = -EBADF; + ret = -EBADF; file = fget(fd); if (!file) goto out; @@ -444,20 +458,24 @@ dentry = file->f_dentry; inode = dentry->d_inode; - err = -EINVAL; + ret = -EINVAL; if (!file->f_op || !file->f_op->fsync) goto out_putf; down(&inode->i_sem); - filemap_fdatasync(inode->i_mapping); + ret = filemap_fdatasync(inode->i_mapping); err = file->f_op->fsync(file, dentry, 1); - filemap_fdatawait(inode->i_mapping); + if (err && !ret) + ret = err; + err = filemap_fdatawait(inode->i_mapping); + if (err && !ret) + ret = err; up(&inode->i_sem); out_putf: fput(file); out: - return err; + return ret; } /* After several hours of tedious analysis, the following hash @@ -564,7 +582,7 @@ continue; if (bh->b_size != size) continue; - if (bh->b_dev != dev) + if (!kdev_same(bh->b_dev, dev)) continue; get_bh(bh); break; @@ -668,7 +686,7 @@ bh_next = bh->b_next_free; /* Another device? */ - if (bh->b_dev != dev) + if (!kdev_same(bh->b_dev, dev)) continue; /* Not hashed? */ if (!bh->b_pprev) @@ -711,7 +729,7 @@ void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers) { - struct block_device *bdev = bdget(dev); + struct block_device *bdev = bdget(kdev_t_to_nr(dev)); if (bdev) { invalidate_bdev(bdev, destroy_dirty_buffers); bdput(bdev); @@ -726,9 +744,7 @@ wakeup_bdflush(); try_to_free_pages(zone, GFP_NOFS, 0); run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - __set_current_state(TASK_RUNNING); - schedule(); + yield(); } void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private) @@ -1016,8 +1032,9 @@ * 14.02.92: changed it to sync dirty buffers a bit: better performance * when the filesystem starts to get full of dirty blocks (I hope). */ -struct buffer_head * getblk(kdev_t dev, sector_t block, int size) +struct buffer_head * __getblk(struct block_device *bdev, sector_t block, int size) { + kdev_t dev = to_kdev_t(bdev->bd_dev); for (;;) { struct buffer_head * bh; @@ -1046,7 +1063,7 @@ /* First, check for the "real" dirty limit. */ if (dirty > soft_dirty_limit) { - if (dirty > hard_dirty_limit) + if (dirty > hard_dirty_limit && !(current->flags & PF_NOIO)) return 1; return 0; } @@ -1169,11 +1186,10 @@ * Reads a specified block, and returns buffer head that * contains it. It returns NULL if the block was unreadable. */ -struct buffer_head * bread(kdev_t dev, int block, int size) +struct buffer_head * __bread(struct block_device *bdev, int block, int size) { - struct buffer_head * bh; + struct buffer_head * bh = __getblk(bdev, block, size); - bh = getblk(dev, block, size); touch_buffer(bh); if (buffer_uptodate(bh)) return bh; @@ -1444,7 +1460,7 @@ return 1; } -void create_empty_buffers(struct page *page, kdev_t dev, unsigned long blocksize) +void create_empty_buffers(struct page *page, unsigned long blocksize) { struct buffer_head *bh, *head, *tail; @@ -1455,8 +1471,6 @@ bh = head; do { - bh->b_dev = dev; - bh->b_blocknr = 0; bh->b_end_io = NULL; tail = bh; bh = bh->b_this_page; @@ -1513,12 +1527,13 @@ int err, i; unsigned long block; struct buffer_head *bh, *head; + int need_unlock; if (!PageLocked(page)) BUG(); if (!page->buffers) - create_empty_buffers(page, inode->i_dev, 1 << inode->i_blkbits); + create_empty_buffers(page, 1 << inode->i_blkbits); head = page->buffers; block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); @@ -1568,8 +1583,34 @@ return 0; out: + /* + * ENOSPC, or some other error. We may already have added some + * blocks to the file, so we need to write these out to avoid + * exposing stale data. + */ ClearPageUptodate(page); - UnlockPage(page); + bh = head; + need_unlock = 1; + /* Recovery: lock and submit the mapped buffers */ + do { + if (buffer_mapped(bh)) { + lock_buffer(bh); + set_buffer_async_io(bh); + need_unlock = 0; + } + bh = bh->b_this_page; + } while (bh != head); + do { + struct buffer_head *next = bh->b_this_page; + if (buffer_mapped(bh)) { + set_bit(BH_Uptodate, &bh->b_state); + clear_bit(BH_Dirty, &bh->b_state); + submit_bh(WRITE, bh); + } + bh = next; + } while (bh != head); + if (need_unlock) + UnlockPage(page); return err; } @@ -1585,7 +1626,7 @@ blocksize = 1 << inode->i_blkbits; if (!page->buffers) - create_empty_buffers(page, inode->i_dev, blocksize); + create_empty_buffers(page, blocksize); head = page->buffers; bbits = inode->i_blkbits; @@ -1600,6 +1641,7 @@ continue; if (block_start >= to) break; + clear_bit(BH_New, &bh->b_state); if (!buffer_mapped(bh)) { err = get_block(inode, block, bh, 1); if (err) @@ -1634,12 +1676,34 @@ */ while(wait_bh > wait) { wait_on_buffer(*--wait_bh); - err = -EIO; if (!buffer_uptodate(*wait_bh)) - goto out; + return -EIO; } return 0; out: + /* + * Zero out any newly allocated blocks to avoid exposing stale + * data. If BH_New is set, we know that the block was newly + * allocated in the above loop. + */ + bh = head; + block_start = 0; + do { + block_end = block_start+blocksize; + if (block_end <= from) + continue; + if (block_start >= to) + break; + if (buffer_new(bh)) { + if (buffer_uptodate(bh)) + printk(KERN_ERR "%s: zeroing uptodate buffer!\n", __FUNCTION__); + memset(kaddr+block_start, 0, bh->b_size); + set_bit(BH_Uptodate, &bh->b_state); + mark_buffer_dirty(bh); + } + block_start = block_end; + bh = bh->b_this_page; + } while (bh != head); return err; } @@ -1702,7 +1766,7 @@ PAGE_BUG(page); blocksize = 1 << inode->i_blkbits; if (!page->buffers) - create_empty_buffers(page, inode->i_dev, blocksize); + create_empty_buffers(page, blocksize); head = page->buffers; blocks = PAGE_CACHE_SIZE >> inode->i_blkbits; @@ -1907,7 +1971,7 @@ goto out; if (!page->buffers) - create_empty_buffers(page, inode->i_dev, blocksize); + create_empty_buffers(page, blocksize); /* Find the buffer that contains "offset" */ bh = page->buffers; @@ -2123,13 +2187,14 @@ panic("brw_page: page not locked for I/O"); if (!page->buffers) - create_empty_buffers(page, dev, size); + create_empty_buffers(page, size); head = bh = page->buffers; /* Stage 1: lock all the buffers */ do { lock_buffer(bh); bh->b_blocknr = *(b++); + bh->b_dev = dev; set_bit(BH_Mapped, &bh->b_state); set_buffer_async_io(bh); bh = bh->b_this_page; @@ -2308,7 +2373,7 @@ return 1; } -static int sync_page_buffers(struct buffer_head *head, unsigned int gfp_mask) +static int sync_page_buffers(struct buffer_head *head) { struct buffer_head * bh = head; int tryagain = 0; @@ -2390,7 +2455,7 @@ struct buffer_head * p = tmp; tmp = tmp->b_this_page; - if (p->b_dev == B_FREE) BUG(); + if (kdev_same(p->b_dev, B_FREE)) BUG(); remove_inode_queue(p); __remove_from_queues(p); @@ -2412,9 +2477,10 @@ /* Uhhuh, start writeback so that we don't end up with all dirty pages */ write_unlock(&hash_table_lock); spin_unlock(&lru_list_lock); + gfp_mask = pf_gfp_mask(gfp_mask); if (gfp_mask & __GFP_IO) { if ((gfp_mask & __GFP_HIGHIO) || !PageHighMem(page)) { - if (sync_page_buffers(bh, gfp_mask)) { + if (sync_page_buffers(bh)) { /* no IO or waiting next time */ gfp_mask = 0; goto cleaned_buffers_try_again; @@ -2556,7 +2622,7 @@ { lock_kernel(); sync_unlocked_inodes(); - sync_supers(0); + sync_supers(NODEV); unlock_kernel(); for (;;) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/char_dev.c linux-2.5/fs/char_dev.c --- linux-2.5.1/fs/char_dev.c Fri Nov 2 19:48:21 2001 +++ linux-2.5/fs/char_dev.c Sun Dec 30 20:01:41 2001 @@ -6,6 +6,7 @@ #include <linux/config.h> #include <linux/init.h> +#include <linux/fs.h> #include <linux/slab.h> #define HASH_BITS 6 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/coda/cache.c linux-2.5/fs/coda/cache.c --- linux-2.5.1/fs/coda/cache.c Wed Dec 5 21:02:14 2001 +++ linux-2.5/fs/coda/cache.c Sun Dec 30 21:17:30 2001 @@ -14,7 +14,6 @@ #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/string.h> #include <linux/list.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/coda/coda_linux.c linux-2.5/fs/coda/coda_linux.c --- linux-2.5.1/fs/coda/coda_linux.c Wed Apr 25 23:18:54 2001 +++ linux-2.5/fs/coda/coda_linux.c Sun Dec 30 21:17:30 2001 @@ -15,7 +15,6 @@ #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/string.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/coda/file.c linux-2.5/fs/coda/file.c --- linux-2.5.1/fs/coda/file.c Wed Dec 5 21:02:14 2001 +++ linux-2.5/fs/coda/file.c Sun Dec 30 21:17:30 2001 @@ -16,7 +16,6 @@ #include <linux/errno.h> #include <linux/locks.h> #include <linux/smp_lock.h> -#include <asm/segment.h> #include <linux/string.h> #include <asm/uaccess.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/coda/inode.c linux-2.5/fs/coda/inode.c --- linux-2.5.1/fs/coda/inode.c Wed Dec 5 21:02:14 2001 +++ linux-2.5/fs/coda/inode.c Sat Jan 12 12:32:41 2002 @@ -25,7 +25,6 @@ #include <linux/fs.h> #include <linux/vmalloc.h> -#include <asm/segment.h> #include <linux/coda.h> #include <linux/coda_linux.h> @@ -71,7 +70,7 @@ inode = file->f_dentry->d_inode; if(!inode || !S_ISCHR(inode->i_mode) || - MAJOR(inode->i_rdev) != CODA_PSDEV_MAJOR) { + major(inode->i_rdev) != CODA_PSDEV_MAJOR) { if(file) fput(file); @@ -79,7 +78,7 @@ return -1; } - idx = MINOR(inode->i_rdev); + idx = minor(inode->i_rdev); fput(file); if(idx < 0 || idx >= MAX_CODADEVS) { @@ -153,7 +152,7 @@ } printk("coda_read_super: rootinode is %ld dev %d\n", - root->i_ino, root->i_dev); + root->i_ino, kdev_t_to_nr(root->i_dev)); sb->s_root = d_alloc_root(root); return sb; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/coda/pioctl.c linux-2.5/fs/coda/pioctl.c --- linux-2.5.1/fs/coda/pioctl.c Wed Dec 5 21:02:14 2001 +++ linux-2.5/fs/coda/pioctl.c Sun Dec 30 21:17:30 2001 @@ -14,7 +14,6 @@ #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> -#include <asm/segment.h> #include <linux/string.h> #define __NO_VERSION__ #include <linux/module.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/coda/psdev.c linux-2.5/fs/coda/psdev.c --- linux-2.5.1/fs/coda/psdev.c Wed Dec 5 21:02:14 2001 +++ linux-2.5/fs/coda/psdev.c Wed Jan 2 12:17:31 2002 @@ -38,7 +38,6 @@ #include <linux/list.h> #include <linux/smp_lock.h> #include <asm/io.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/poll.h> #include <asm/uaccess.h> @@ -294,7 +293,7 @@ int idx; lock_kernel(); - idx = MINOR(inode->i_rdev); + idx = minor(inode->i_rdev); if(idx >= MAX_CODADEVS) { unlock_kernel(); return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/coda/sysctl.c linux-2.5/fs/coda/sysctl.c --- linux-2.5.1/fs/coda/sysctl.c Wed Dec 5 21:02:14 2001 +++ linux-2.5/fs/coda/sysctl.c Sun Dec 30 21:17:30 2001 @@ -21,7 +21,6 @@ #include <linux/stat.h> #include <linux/ctype.h> #include <asm/bitops.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/utsname.h> #define __NO_VERSION__ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/coda/upcall.c linux-2.5/fs/coda/upcall.c --- linux-2.5.1/fs/coda/upcall.c Wed Dec 5 21:02:14 2001 +++ linux-2.5/fs/coda/upcall.c Sun Dec 30 21:17:30 2001 @@ -15,7 +15,6 @@ */ #include <asm/system.h> -#include <asm/segment.h> #include <asm/signal.h> #include <linux/signal.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/cramfs/inode.c linux-2.5/fs/cramfs/inode.c --- linux-2.5.1/fs/cramfs/inode.c Sun Dec 16 20:22:53 2001 +++ linux-2.5/fs/cramfs/inode.c Wed Jan 2 17:22:01 2002 @@ -115,7 +115,7 @@ struct buffer_head * read_array[BLKS_PER_BUF]; unsigned i, blocknr, buffer, unread; unsigned long devsize; - int major, minor; + unsigned int major, minor; char *data; @@ -140,8 +140,8 @@ } devsize = ~0UL; - major = MAJOR(sb->s_dev); - minor = MINOR(sb->s_dev); + major = major(sb->s_dev); + minor = minor(sb->s_dev); if (blk_size[major]) devsize = blk_size[major][minor] >> 2; @@ -195,9 +195,7 @@ unsigned long root_offset; struct super_block * retval = NULL; - set_blocksize(sb->s_dev, PAGE_CACHE_SIZE); - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb_set_blocksize(sb, PAGE_CACHE_SIZE); /* Invalidate the read buffers on mount: think disk change.. */ for (i = 0; i < READ_BUFFERS; i++) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/dcache.c linux-2.5/fs/dcache.c --- linux-2.5.1/fs/dcache.c Mon Dec 10 22:13:25 2001 +++ linux-2.5/fs/dcache.c Mon Jan 14 23:55:29 2002 @@ -1262,7 +1262,7 @@ panic("Cannot create buffer head SLAB cache"); names_cachep = kmem_cache_create("names_cache", - PATH_MAX + 1, 0, + PATH_MAX, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!names_cachep) panic("Cannot create names SLAB cache"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/devfs/base.c linux-2.5/fs/devfs/base.c --- linux-2.5.1/fs/devfs/base.c Fri Nov 30 16:41:52 2001 +++ linux-2.5/fs/devfs/base.c Sat Jan 5 16:03:36 2002 @@ -427,7 +427,7 @@ Work sponsored by SGI. v0.92 20000306 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_FL_NO_PERSISTENCE flag. + Added DEVFS_ FL_NO_PERSISTENCE flag. Removed unnecessary call to <update_devfs_inode_from_entry> in <devfs_readdir>. Work sponsored by SGI. @@ -562,6 +562,45 @@ 20011122 Richard Gooch <rgooch@atnf.csiro.au> Use slab cache rather than fixed buffer for devfsd events. v1.1 + 20011125 Richard Gooch <rgooch@atnf.csiro.au> + Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>. + 20011127 Richard Gooch <rgooch@atnf.csiro.au> + Fixed locking bug in <devfs_d_revalidate_wait> due to typo. + Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from + devfsd or children. + v1.2 + 20011202 Richard Gooch <rgooch@atnf.csiro.au> + Fixed bug in <devfsd_read>: was dereferencing freed pointer. + v1.3 + 20011203 Richard Gooch <rgooch@atnf.csiro.au> + Fixed bug in <devfsd_close>: was dereferencing freed pointer. + Added process group check for devfsd privileges. + v1.4 + 20011204 Richard Gooch <rgooch@atnf.csiro.au> + Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>. + v1.5 + 20011211 Richard Gooch <rgooch@atnf.csiro.au> + Return old entry in <devfs_mk_dir> for 2.4.x kernels. + 20011212 Richard Gooch <rgooch@atnf.csiro.au> + Increment refcount on module in <check_disc_changed>. + 20011215 Richard Gooch <rgooch@atnf.csiro.au> + Created <devfs_get_handle> and exported <devfs_put>. + Increment refcount on module in <devfs_get_ops>. + Created <devfs_put_ops>. + v1.6 + 20011216 Richard Gooch <rgooch@atnf.csiro.au> + Added poisoning to <devfs_put>. + Improved debugging messages. + v1.7 + 20011221 Richard Gooch <rgooch@atnf.csiro.au> + Corrected (made useful) debugging message in <unregister>. + Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs> + 20011224 Richard Gooch <rgooch@atnf.csiro.au> + Added magic number to guard against scribbling drivers. + 20011226 Richard Gooch <rgooch@atnf.csiro.au> + Only return old entry in <devfs_mk_dir> if a directory. + Defined macros for error and debug messages. + v1.8 */ #include <linux/types.h> #include <linux/errno.h> @@ -594,13 +633,16 @@ #include <asm/bitops.h> #include <asm/atomic.h> -#define DEVFS_VERSION "1.1 (20011122)" +#define DEVFS_VERSION "1.8 (20011226)" #define DEVFS_NAME "devfs" #define FIRST_INODE 1 #define STRING_LENGTH 256 +#define FAKE_BLOCK_SIZE 1024 +#define POISON_PTR ( *(void **) poison_array ) +#define MAGIC_VALUE 0x327db823 #ifndef TRUE # define TRUE 1 @@ -637,9 +679,28 @@ #define OPTION_MOUNT 0x01 #define OPTION_ONLY 0x02 -#define OOPS(format, args...) {printk (format, ## args); \ - printk ("Forcing Oops\n"); \ - BUG();} +#define PRINTK(format, args...) \ + {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);} + +#define OOPS(format, args...) \ + {printk (KERN_CRIT "%s" format, __FUNCTION__ , ## args); \ + printk ("Forcing Oops\n"); \ + BUG();} + +#ifdef CONFIG_DEVFS_DEBUG +# define VERIFY_ENTRY(de) \ + {if ((de) && (de)->magic_number != MAGIC_VALUE) \ + OOPS ("(%p): bad magic value: %x\n", (de), (de)->magic_number);} +# define WRITE_ENTRY_MAGIC(de,magic) (de)->magic_number = (magic) +# define DPRINTK(flag, format, args...) \ + {if (devfs_debug & flag) \ + printk (KERN_INFO "%s" format, __FUNCTION__ , ## args);} +#else +# define VERIFY_ENTRY(de) +# define WRITE_ENTRY_MAGIC(de,magic) +# define DPRINTK(flag, format, args...) +#endif + struct directory_type { @@ -696,6 +757,9 @@ struct devfs_entry { +#ifdef CONFIG_DEVFS_DEBUG + unsigned int magic_number; +#endif void *info; atomic_t refcount; /* When this drops to zero, it's unused */ union @@ -740,6 +804,7 @@ struct devfsd_buf_entry *devfsd_last_event; volatile int devfsd_sleeping; volatile struct task_struct *devfsd_task; + volatile pid_t devfsd_pgrp; volatile struct file *devfsd_file; struct devfsd_notify_struct *devfsd_info; volatile unsigned long devfsd_event_mask; @@ -757,6 +822,8 @@ static unsigned int stat_num_entries; static unsigned int stat_num_bytes; #endif +static unsigned char poison_array[8] = + {0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a}; #ifdef CONFIG_DEVFS_MOUNT static unsigned int boot_options = OPTION_MOUNT; @@ -802,35 +869,35 @@ static struct devfs_entry *devfs_get (struct devfs_entry *de) { + VERIFY_ENTRY (de); if (de) atomic_inc (&de->refcount); return de; } /* End Function devfs_get */ /** * devfs_put - Put (release) a reference to a devfs entry. - * @de: The devfs entry. + * @de: The handle to the devfs entry. */ -static void devfs_put (struct devfs_entry *de) +void devfs_put (devfs_handle_t de) { if (!de) return; + VERIFY_ENTRY (de); + if (de->info == POISON_PTR) OOPS ("(%p): poisoned pointer\n", de); if ( !atomic_dec_and_test (&de->refcount) ) return; - if (de == root_entry) - OOPS ("%s: devfs_put(): root entry being freed\n", DEVFS_NAME); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_FREE) - printk ("%s: devfs_put(%s): de: %p, parent: %p \"%s\"\n", - DEVFS_NAME, de->name, de, de->parent, - de->parent ? de->parent->name : "no parent"); -#endif + if (de == root_entry) OOPS ("(%p): root entry being freed\n", de); + DPRINTK (DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n", + de->name, de, de->parent, + de->parent ? de->parent->name : "no parent"); if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname); if ( ( S_ISCHR (de->mode) || S_ISBLK (de->mode) ) && de->u.fcb.autogen ) { devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR : DEVFS_SPECIAL_BLK, - MKDEV (de->u.fcb.u.device.major, + mk_kdev(de->u.fcb.u.device.major, de->u.fcb.u.device.minor) ); } + WRITE_ENTRY_MAGIC (de, 0); #ifdef CONFIG_DEVFS_DEBUG spin_lock (&stat_lock); --stat_num_entries; @@ -838,6 +905,7 @@ if ( S_ISLNK (de->mode) ) stat_num_bytes -= de->u.symlink.length + 1; spin_unlock (&stat_lock); #endif + de->info = POISON_PTR; kfree (de); } /* End Function devfs_put */ @@ -860,7 +928,7 @@ if ( !S_ISDIR (dir->mode) ) { - printk ("%s: search_dir(%s): not a directory\n", DEVFS_NAME,dir->name); + PRINTK ("(%s): not a directory\n", dir->name); return NULL; } for (curr = dir->u.dir.first; curr != NULL; curr = curr->next) @@ -893,7 +961,7 @@ if ( name && (namelen < 1) ) namelen = strlen (name); if ( ( new = kmalloc (sizeof *new + namelen, GFP_KERNEL) ) == NULL ) return NULL; - memset (new, 0, sizeof *new + namelen); + memset (new, 0, sizeof *new + namelen); /* Will set '\0' on name */ new->mode = mode; if ( S_ISDIR (mode) ) rwlock_init (&new->u.dir.lock); atomic_set (&new->refcount, 1); @@ -902,6 +970,7 @@ spin_unlock (&counter_lock); if (name) memcpy (new->name, name, namelen); new->namelen = namelen; + WRITE_ENTRY_MAGIC (new, MAGIC_VALUE); #ifdef CONFIG_DEVFS_DEBUG spin_lock (&stat_lock); ++stat_num_entries; @@ -918,7 +987,7 @@ * @de: The devfs entry to append. * @removable: If TRUE, increment the count of removable devices for %dir. * @old_de: If an existing entry exists, it will be written here. This may - * be %NULL. + * be %NULL. An implicit devfs_get() is performed on this entry. * * Append a devfs entry to a directory's list of children, checking first to * see if an entry of the same name exists. The directory will be locked. @@ -934,8 +1003,7 @@ if (old_de) *old_de = NULL; if ( !S_ISDIR (dir->mode) ) { - printk ("%s: append_entry(%s): dir: \"%s\" is not a directory\n", - DEVFS_NAME, de->name, dir->name); + PRINTK ("(%s): dir: \"%s\" is not a directory\n", de->name, dir->name); devfs_put (de); return -ENOTDIR; } @@ -995,16 +1063,16 @@ if ( ( new = _devfs_alloc_entry (".devfsd", 0, S_IFCHR |S_IRUSR |S_IWUSR) ) == NULL ) return NULL; devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR); - new->u.fcb.u.device.major = MAJOR (devnum); - new->u.fcb.u.device.minor = MINOR (devnum); + new->u.fcb.u.device.major = major (devnum); + new->u.fcb.u.device.minor = minor (devnum); new->u.fcb.ops = &devfsd_fops; _devfs_append_entry (root_entry, new, FALSE, NULL); #ifdef CONFIG_DEVFS_DEBUG if ( ( new = _devfs_alloc_entry (".stat", 0, S_IFCHR | S_IRUGO | S_IWUGO) ) == NULL ) return NULL; devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR); - new->u.fcb.u.device.major = MAJOR (devnum); - new->u.fcb.u.device.minor = MINOR (devnum); + new->u.fcb.u.device.major = major (devnum); + new->u.fcb.u.device.minor = minor (devnum); new->u.fcb.ops = &stat_fops; _devfs_append_entry (root_entry, new, FALSE, NULL); #endif @@ -1105,15 +1173,13 @@ if ( ( *dir = _devfs_make_parent_for_leaf (*dir, name, namelen, &leaf_pos) ) == NULL ) { - printk ("%s: prepare_leaf(%s): could not create parent path\n", - DEVFS_NAME, name); + PRINTK ("(%s): could not create parent path\n", name); return NULL; } if ( ( de = _devfs_alloc_entry (name + leaf_pos, namelen - leaf_pos,mode) ) == NULL ) { - printk ("%s: prepare_leaf(%s): could not allocate entry\n", - DEVFS_NAME, name); + PRINTK ("(%s): could not allocate entry\n", name); devfs_put (*dir); return NULL; } @@ -1160,19 +1226,20 @@ /** - * find_by_dev - Find a devfs entry in a directory. + * _devfs_find_by_dev - Find a devfs entry in a directory. * @dir: The directory where to search * @major: The major number to search for. * @minor: The minor number to search for. * @type: The type of special file to search for. This may be either * %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK. * - * Returns the devfs_entry pointer on success, else %NULL. + * Returns the devfs_entry pointer on success, else %NULL. An implicit + * devfs_get() is performed. */ -static struct devfs_entry *find_by_dev (struct devfs_entry *dir, - unsigned int major, unsigned int minor, - char type) +static struct devfs_entry *_devfs_find_by_dev (struct devfs_entry *dir, + unsigned int major, + unsigned int minor, char type) { struct devfs_entry *entry, *de; @@ -1180,7 +1247,7 @@ if (dir == NULL) return NULL; if ( !S_ISDIR (dir->mode) ) { - printk ("%s: find_by_dev(): not a directory\n", DEVFS_NAME); + PRINTK ("(%p): not a directory\n", dir); devfs_put (dir); return NULL; } @@ -1205,7 +1272,7 @@ for (entry = dir->u.dir.first; entry != NULL; entry = entry->next) { if ( !S_ISDIR (entry->mode) ) continue; - de = find_by_dev (entry, major, minor, type); + de = _devfs_find_by_dev (entry, major, minor, type); if (de) { read_unlock (&dir->u.dir.lock); @@ -1216,51 +1283,51 @@ read_unlock (&dir->u.dir.lock); devfs_put (dir); return NULL; -} /* End Function find_by_dev */ +} /* End Function _devfs_find_by_dev */ /** - * find_entry - Find a devfs entry. + * _devfs_find_entry - Find a devfs entry. * @dir: The handle to the parent devfs directory entry. If this is %NULL the * name is relative to the root of the devfs. - * @name: The name of the entry. This is ignored if @handle is not %NULL. - * @namelen: The number of characters in @name, not including a %NULL - * terminator. If this is 0, then @name must be %NULL-terminated and the - * length is computed internally. - * @major: The major number. This is used if @handle and @name are %NULL. - * @minor: The minor number. This is used if @handle and @name are %NULL. + * @name: The name of the entry. This may be %NULL. + * @major: The major number. This is used if lookup by @name fails. + * @minor: The minor number. This is used if lookup by @name fails. * NOTE: If @major and @minor are both 0, searching by major and minor * numbers is disabled. * @type: The type of special file to search for. This may be either * %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK. * @traverse_symlink: If %TRUE then symbolic links are traversed. * - * Returns the devfs_entry pointer on success, else %NULL. + * Returns the devfs_entry pointer on success, else %NULL. An implicit + * devfs_get() is performed. */ -static struct devfs_entry *find_entry (devfs_handle_t dir, - const char *name, unsigned int namelen, - unsigned int major, unsigned int minor, - char type, int traverse_symlink) +static struct devfs_entry *_devfs_find_entry (devfs_handle_t dir, + const char *name, + unsigned int major, + unsigned int minor, + char type, int traverse_symlink) { struct devfs_entry *entry; if (name != NULL) { - if (namelen < 1) namelen = strlen (name); + unsigned int namelen = strlen (name); + if (name[0] == '/') { /* Skip leading pathname component */ if (namelen < 2) { - printk ("%s: find_entry(%s): too short\n", DEVFS_NAME, name); + PRINTK ("(%s): too short\n", name); return NULL; } for (++name, --namelen; (*name != '/') && (namelen > 0); ++name, --namelen); if (namelen < 2) { - printk ("%s: find_entry(%s): too short\n", DEVFS_NAME, name); + PRINTK ("(%s): too short\n", name); return NULL; } ++name; @@ -1271,12 +1338,13 @@ } /* Have to search by major and minor: slow */ if ( (major == 0) && (minor == 0) ) return NULL; - return find_by_dev (root_entry, major, minor, type); -} /* End Function find_entry */ + return _devfs_find_by_dev (root_entry, major, minor, type); +} /* End Function _devfs_find_entry */ static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode) { if (inode == NULL) return NULL; + VERIFY_ENTRY ( (struct devfs_entry *) inode->u.generic_ip ); return inode->u.generic_ip; } /* End Function get_devfs_entry_from_vfs_inode */ @@ -1315,10 +1383,14 @@ { struct task_struct *p; - for (p = current; p != &init_task; p = p->p_opptr) + if (current == fs_info->devfsd_task) return (TRUE); + if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1) + for (p = current->p_opptr; p != &init_task; p = p->p_opptr) { if (p == fs_info->devfsd_task) return (TRUE); } +#endif return (FALSE); } /* End Function is_devfsd_or_child */ @@ -1375,13 +1447,16 @@ static int devfsd_notify_de (struct devfs_entry *de, unsigned short type, umode_t mode, - uid_t uid, gid_t gid, struct fs_info *fs_info) + uid_t uid, gid_t gid, struct fs_info *fs_info, + int atomic) { struct devfsd_buf_entry *entry; struct devfs_entry *curr; if ( !( fs_info->devfsd_event_mask & (1 << type) ) ) return (FALSE); - if ( ( entry = kmem_cache_alloc (devfsd_buf_cache, 0) ) == NULL ) + if ( ( entry = kmem_cache_alloc (devfsd_buf_cache, + atomic ? SLAB_ATOMIC : SLAB_KERNEL) ) + == NULL ) { atomic_inc (&fs_info->devfsd_overrun_count); return (FALSE); @@ -1414,7 +1489,7 @@ static void devfsd_notify (struct devfs_entry *de,unsigned short type,int wait) { if (devfsd_notify_de (de, type, de->mode, current->euid, - current->egid, &fs_info) && wait) + current->egid, &fs_info, 0) && wait) wait_for_devfsd_finished (&fs_info); } /* End Function devfsd_notify */ @@ -1451,7 +1526,7 @@ if (name == NULL) { - printk ("%s: devfs_register(): NULL name pointer\n", DEVFS_NAME); + PRINTK ("(): NULL name pointer\n"); return NULL; } if (ops == NULL) @@ -1459,54 +1534,48 @@ if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major); if (ops == NULL) { - printk ("%s: devfs_register(%s): NULL ops pointer\n", - DEVFS_NAME, name); + PRINTK ("(%s): NULL ops pointer\n", name); return NULL; } - printk ("%s: devfs_register(%s): NULL ops, got %p from major table\n", - DEVFS_NAME, name, ops); + PRINTK ("(%s): NULL ops, got %p from major table\n", name, ops); } if ( S_ISDIR (mode) ) { - printk("%s: devfs_register(%s): creating directories is not allowed\n", - DEVFS_NAME, name); + PRINTK ("(%s): creating directories is not allowed\n", name); return NULL; } if ( S_ISLNK (mode) ) { - printk ("%s: devfs_register(%s): creating symlinks is not allowed\n", - DEVFS_NAME, name); + PRINTK ("(%s): creating symlinks is not allowed\n", name); return NULL; } if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) && (flags & DEVFS_FL_AUTO_DEVNUM) ) { - if ( ( devnum = devfs_alloc_devnum (devtype) ) == NODEV ) + if ( kdev_none( devnum = devfs_alloc_devnum (devtype) ) ) { - printk ("%s: devfs_register(%s): exhausted %s device numbers\n", - DEVFS_NAME, name, S_ISCHR (mode) ? "char" : "block"); + PRINTK ("(%s): exhausted %s device numbers\n", + name, S_ISCHR (mode) ? "char" : "block"); return NULL; } - major = MAJOR (devnum); - minor = MINOR (devnum); + major = major (devnum); + minor = minor (devnum); } if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL ) { - printk ("%s: devfs_register(%s): could not prepare leaf\n", - DEVFS_NAME, name); - if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum); + PRINTK ("(%s): could not prepare leaf\n", name); + if (!kdev_none(devnum)) devfs_dealloc_devnum (devtype, devnum); return NULL; } if ( S_ISCHR (mode) || S_ISBLK (mode) ) { de->u.fcb.u.device.major = major; de->u.fcb.u.device.minor = minor; - de->u.fcb.autogen = (devnum == NODEV) ? FALSE : TRUE; + de->u.fcb.autogen = kdev_none(devnum) ? FALSE : TRUE; } else if ( !S_ISREG (mode) ) { - printk ("%s: devfs_register(%s): illegal mode: %x\n", - DEVFS_NAME, name, mode); + PRINTK ("(%s): illegal mode: %x\n", name, mode); devfs_put (de); devfs_put (dir); return (NULL); @@ -1530,17 +1599,13 @@ if ( ( err = _devfs_append_entry (dir, de, de->u.fcb.removable, NULL) ) != 0 ) { - printk("%s: devfs_register(%s): could not append to parent, err: %d\n", - DEVFS_NAME, name, err); + PRINTK ("(%s): could not append to parent, err: %d\n", name, err); devfs_put (dir); - if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum); + if (!kdev_none(devnum)) devfs_dealloc_devnum (devtype, devnum); return NULL; } -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_REGISTER) - printk ("%s: devfs_register(%s): de: %p dir: %p \"%s\" pp: %p\n", - DEVFS_NAME, name, de, dir, dir->name, dir->parent); -#endif + DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\" pp: %p\n", + name, de, dir, dir->name, dir->parent); devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT); devfs_put (dir); return de; @@ -1576,7 +1641,7 @@ /** - * unregister - Unregister a device entry from it's parent. + * _devfs_unregister - Unregister a device entry from it's parent. * @dir: The parent directory. * @de: The entry to unregister. * @@ -1584,7 +1649,7 @@ * unlocked by this function. */ -static void unregister (struct devfs_entry *dir, struct devfs_entry *de) +static void _devfs_unregister (struct devfs_entry *dir, struct devfs_entry *de) { int unhooked = _devfs_unhook (de); @@ -1603,34 +1668,30 @@ write_lock (&de->u.dir.lock); de->u.dir.no_more_additions = TRUE; child = de->u.dir.first; - unregister (de, child); + VERIFY_ENTRY (child); + _devfs_unregister (de, child); if (!child) break; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_UNREGISTER) - printk ("%s: unregister(): child->name: \"%s\" child: %p\n", - DEVFS_NAME, child->name, child); -#endif + DPRINTK (DEBUG_UNREGISTER, "(%s): child: %p refcount: %d\n", + child->name, child, atomic_read (&child->refcount) ); devfs_put (child); } -} /* End Function unregister */ +} /* End Function _devfs_unregister */ /** * devfs_unregister - Unregister a device entry. * @de: A handle previously created by devfs_register() or returned from - * devfs_find_handle(). If this is %NULL the routine does nothing. + * devfs_get_handle(). If this is %NULL the routine does nothing. */ void devfs_unregister (devfs_handle_t de) { + VERIFY_ENTRY (de); if ( (de == NULL) || (de->parent == NULL) ) return; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_UNREGISTER) - printk ("%s: devfs_unregister(): de->name: \"%s\" de: %p\n", - DEVFS_NAME, de->name, de); -#endif + DPRINTK (DEBUG_UNREGISTER, "(%s): de: %p refcount: %d\n", + de->name, de, atomic_read (&de->refcount) ); write_lock (&de->parent->u.dir.lock); - unregister (de->parent, de); + _devfs_unregister (de->parent, de); devfs_put (de); } /* End Function devfs_unregister */ @@ -1646,16 +1707,12 @@ if (handle != NULL) *handle = NULL; if (name == NULL) { - printk ("%s: devfs_do_symlink(): NULL name pointer\n", DEVFS_NAME); + PRINTK ("(): NULL name pointer\n"); return -EINVAL; } -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_REGISTER) - printk ("%s: devfs_do_symlink(%s)\n", DEVFS_NAME, name); -#endif if (link == NULL) { - printk ("%s: devfs_do_symlink(): NULL link pointer\n", DEVFS_NAME); + PRINTK ("(%s): NULL link pointer\n", name); return -EINVAL; } linklength = strlen (link); @@ -1666,8 +1723,7 @@ if ( ( de = _devfs_prepare_leaf (&dir, name, S_IFLNK | S_IRUGO | S_IXUGO) ) == NULL ) { - printk ("%s: devfs_do_symlink(%s): could not prepare leaf\n", - DEVFS_NAME, name); + PRINTK ("(%s): could not prepare leaf\n", name); kfree (newlink); return -ENOTDIR; } @@ -1677,8 +1733,7 @@ de->u.symlink.length = linklength; if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 ) { - printk ("%s: devfs_do_symlink(%s): could not append to parent, err: %d\n", - DEVFS_NAME, name, err); + PRINTK ("(%s): could not append to parent, err: %d\n", name, err); devfs_put (dir); return err; } @@ -1713,6 +1768,7 @@ devfs_handle_t de; if (handle != NULL) *handle = NULL; + DPRINTK (DEBUG_REGISTER, "(%s)\n", name); err = devfs_do_symlink (dir, name, flags, link, &de, info); if (err) return err; if (handle != NULL) *handle = de; @@ -1738,39 +1794,47 @@ devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info) { int err; - struct devfs_entry *de; + struct devfs_entry *de, *old; if (name == NULL) { - printk ("%s: devfs_mk_dir(): NULL name pointer\n", DEVFS_NAME); + PRINTK ("(): NULL name pointer\n"); return NULL; } if ( ( de = _devfs_prepare_leaf (&dir, name, MODE_DIR) ) == NULL ) { - printk ("%s: devfs_mk_dir(%s): could not prepare leaf\n", - DEVFS_NAME, name); + PRINTK ("(%s): could not prepare leaf\n", name); return NULL; } de->info = info; - if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 ) + if ( ( err = _devfs_append_entry (dir, de, FALSE, &old) ) != 0 ) { - printk ("%s: devfs_mk_dir(%s): could not append to dir: %p \"%s\", err: %d\n", - DEVFS_NAME, name, dir, dir->name, err); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1) + if ( old && S_ISDIR (old->mode) ) + { + PRINTK ("(%s): using old entry in dir: %p \"%s\"\n", + name, dir, dir->name); + old->vfs_created = FALSE; + devfs_put (dir); + return old; + } +#endif + PRINTK ("(%s): could not append to dir: %p \"%s\", err: %d\n", + name, dir, dir->name, err); + devfs_put (old); devfs_put (dir); return NULL; } -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_REGISTER) - printk ("%s: devfs_mk_dir(%s): de: %p dir: %p \"%s\"\n", - DEVFS_NAME, name, de, dir, dir->name); -#endif + DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"\n", + name, de, dir, dir->name); + devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, 0); devfs_put (dir); return de; } /* End Function devfs_mk_dir */ /** - * devfs_find_handle - Find the handle of a devfs entry. + * devfs_get_handle - Find the handle of a devfs entry. * @dir: The handle to the parent devfs directory entry. If this is %NULL the * name is relative to the root of the devfs. * @name: The name of the entry. @@ -1782,20 +1846,31 @@ * traversed. Symlinks pointing out of the devfs namespace will cause a * failure. Symlink traversal consumes stack space. * - * Returns a handle which may later be used in a call to devfs_unregister(), - * devfs_get_flags(), or devfs_set_flags(). On failure %NULL is returned. + * Returns a handle which may later be used in a call to + * devfs_unregister(), devfs_get_flags(), or devfs_set_flags(). A + * subsequent devfs_put() is required to decrement the refcount. + * On failure %NULL is returned. */ +devfs_handle_t devfs_get_handle (devfs_handle_t dir, const char *name, + unsigned int major, unsigned int minor, + char type, int traverse_symlinks) +{ + if ( (name != NULL) && (name[0] == '\0') ) name = NULL; + return _devfs_find_entry (dir, name, major, minor, type,traverse_symlinks); +} /* End Function devfs_get_handle */ + + +/* Compatibility function. Will be removed in sometime in 2.5 */ + devfs_handle_t devfs_find_handle (devfs_handle_t dir, const char *name, unsigned int major, unsigned int minor, char type, int traverse_symlinks) { devfs_handle_t de; - if ( (name != NULL) && (name[0] == '\0') ) name = NULL; - de = find_entry (dir, name, 0, major, minor, type, traverse_symlinks); - devfs_put (de); /* FIXME: in 2.5 consider dropping this and require a - call to devfs_put() */ + de = devfs_get_handle (dir, name, major, minor, type, traverse_symlinks); + devfs_put (de); return de; } /* End Function devfs_find_handle */ @@ -1813,6 +1888,7 @@ unsigned int fl = 0; if (de == NULL) return -EINVAL; + VERIFY_ENTRY (de); if (de->hide) fl |= DEVFS_FL_HIDE; if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) ) { @@ -1836,11 +1912,8 @@ int devfs_set_flags (devfs_handle_t de, unsigned int flags) { if (de == NULL) return -EINVAL; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_SET_FLAGS) - printk ("%s: devfs_set_flags(): de->name: \"%s\"\n", - DEVFS_NAME, de->name); -#endif + VERIFY_ENTRY (de); + DPRINTK (DEBUG_SET_FLAGS, "(%s): flags: %x\n", de->name, flags); de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE; if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) ) { @@ -1864,6 +1937,7 @@ unsigned int *minor) { if (de == NULL) return -EINVAL; + VERIFY_ENTRY (de); if ( S_ISDIR (de->mode) ) return -EISDIR; if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) ) return -EINVAL; if (major != NULL) *major = de->u.fcb.u.device.major; @@ -1904,6 +1978,7 @@ #define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name ) if (de == NULL) return -EINVAL; + VERIFY_ENTRY (de); if (de->namelen >= buflen) return -ENAMETOOLONG; /* Must be first */ path[buflen - 1] = '\0'; if (de->parent == NULL) return buflen - 1; /* Don't prepend root */ @@ -1925,18 +2000,57 @@ * @de: The handle to the device entry. * * Returns a pointer to the device operations on success, else NULL. + * The use count for the module owning the operations will be incremented. */ void *devfs_get_ops (devfs_handle_t de) { + struct module *owner; + if (de == NULL) return NULL; - if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) ) - return de->u.fcb.ops; - return NULL; + VERIFY_ENTRY (de); + if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) ) + return NULL; + if (de->u.fcb.ops == NULL) return NULL; + read_lock (&de->parent->u.dir.lock); /* Prevent module from unloading */ + if (de->next == de) owner = NULL; /* Ops pointer is already stale */ + else if ( S_ISCHR (de->mode) || S_ISREG (de->mode) ) + owner = ( (struct file_operations *) de->u.fcb.ops )->owner; + else owner = ( (struct block_device_operations *) de->u.fcb.ops )->owner; + if ( (de->next == de) || !try_inc_mod_count (owner) ) + { /* Entry is already unhooked or module is unloading */ + read_unlock (&de->parent->u.dir.lock); + return NULL; + } + read_unlock (&de->parent->u.dir.lock); /* Module can continue unloading*/ + return de->u.fcb.ops; } /* End Function devfs_get_ops */ /** + * devfs_put_ops - Put the device operations for a devfs entry. + * @de: The handle to the device entry. + * + * The use count for the module owning the operations will be decremented. + */ + +void devfs_put_ops (devfs_handle_t de) +{ + struct module *owner; + + if (de == NULL) return; + VERIFY_ENTRY (de); + if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) ) + return; + if (de->u.fcb.ops == NULL) return; + if ( S_ISCHR (de->mode) || S_ISREG (de->mode) ) + owner = ( (struct file_operations *) de->u.fcb.ops )->owner; + else owner = ( (struct block_device_operations *) de->u.fcb.ops )->owner; + if (owner) __MOD_DEC_USE_COUNT (owner); +} /* End Function devfs_put_ops */ + + +/** * devfs_set_file_size - Set the file size for a devfs regular file. * @de: The handle to the device entry. * @size: The new file size. @@ -1947,6 +2061,7 @@ int devfs_set_file_size (devfs_handle_t de, unsigned long size) { if (de == NULL) return -EINVAL; + VERIFY_ENTRY (de); if ( !S_ISREG (de->mode) ) return -EINVAL; if (de->u.fcb.u.file.size == size) return 0; de->u.fcb.u.file.size = size; @@ -1966,6 +2081,7 @@ void *devfs_get_info (devfs_handle_t de) { if (de == NULL) return NULL; + VERIFY_ENTRY (de); return de->info; } /* End Function devfs_get_info */ @@ -1980,6 +2096,7 @@ int devfs_set_info (devfs_handle_t de, void *info) { if (de == NULL) return -EINVAL; + VERIFY_ENTRY (de); de->info = info; return 0; } /* End Function devfs_set_info */ @@ -1994,6 +2111,7 @@ devfs_handle_t devfs_get_parent (devfs_handle_t de) { if (de == NULL) return NULL; + VERIFY_ENTRY (de); return de->parent; } /* End Function devfs_get_parent */ @@ -2008,6 +2126,7 @@ devfs_handle_t devfs_get_first_child (devfs_handle_t de) { if (de == NULL) return NULL; + VERIFY_ENTRY (de); if ( !S_ISDIR (de->mode) ) return NULL; return de->u.dir.first; } /* End Function devfs_get_first_child */ @@ -2023,6 +2142,7 @@ devfs_handle_t devfs_get_next_sibling (devfs_handle_t de) { if (de == NULL) return NULL; + VERIFY_ENTRY (de); return de->next; } /* End Function devfs_get_next_sibling */ @@ -2038,14 +2158,15 @@ void devfs_auto_unregister (devfs_handle_t master, devfs_handle_t slave) { if (master == NULL) return; + VERIFY_ENTRY (master); + VERIFY_ENTRY (slave); if (master->slave != NULL) { /* Because of the dumbness of the layers above, ignore duplicates */ if (master->slave == slave) return; - printk ("%s: devfs_auto_unregister(): only one slave allowed\n", - DEVFS_NAME); - OOPS (" master: \"%s\" old slave: \"%s\" new slave: \"%s\"\n", - master->name, master->slave->name, slave->name); + PRINTK ("(%s): only one slave allowed\n", master->name); + OOPS ("(): old slave: \"%s\" new slave: \"%s\"\n", + master->slave->name, slave->name); } master->slave = slave; } /* End Function devfs_auto_unregister */ @@ -2061,6 +2182,7 @@ devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master) { if (master == NULL) return NULL; + VERIFY_ENTRY (master); return master->slave; } /* End Function devfs_get_unregister_slave */ @@ -2076,6 +2198,7 @@ const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen) { if (de == NULL) return NULL; + VERIFY_ENTRY (de); if (namelen != NULL) *namelen = de->namelen; return de->name; } /* End Function devfs_get_name */ @@ -2218,10 +2341,12 @@ __setup("devfs=", devfs_setup); +EXPORT_SYMBOL(devfs_put); EXPORT_SYMBOL(devfs_register); EXPORT_SYMBOL(devfs_unregister); EXPORT_SYMBOL(devfs_mk_symlink); EXPORT_SYMBOL(devfs_mk_dir); +EXPORT_SYMBOL(devfs_get_handle); EXPORT_SYMBOL(devfs_find_handle); EXPORT_SYMBOL(devfs_get_flags); EXPORT_SYMBOL(devfs_set_flags); @@ -2268,8 +2393,9 @@ buf->parent = parent; buf->namelen = namelen; buf->u.name = name; + WRITE_ENTRY_MAGIC (buf, MAGIC_VALUE); if ( !devfsd_notify_de (buf, DEVFSD_NOTIFY_LOOKUP, 0, - current->euid, current->egid, fs_info) ) + current->euid, current->egid, fs_info, 0) ) return -ENOENT; /* Possible success */ return 0; @@ -2286,14 +2412,17 @@ static int check_disc_changed (struct devfs_entry *de) { int tmp; - kdev_t dev = MKDEV (de->u.fcb.u.device.major, de->u.fcb.u.device.minor); - struct block_device_operations *bdops = de->u.fcb.ops; + int retval = 0; + kdev_t dev = mk_kdev (de->u.fcb.u.device.major, de->u.fcb.u.device.minor); + struct block_device_operations *bdops; extern int warn_no_part; if ( !S_ISBLK (de->mode) ) return 0; - if (bdops == NULL) return 0; - if (bdops->check_media_change == NULL) return 0; - if ( !bdops->check_media_change (dev) ) return 0; + bdops = devfs_get_ops (de); + if (!bdops) return 0; + if (bdops->check_media_change == NULL) goto out; + if ( !bdops->check_media_change (dev) ) goto out; + retval = 1; printk ( KERN_DEBUG "VFS: Disk change detected on device %s\n", kdevname (dev) ); if (invalidate_device(dev, 0)) @@ -2303,7 +2432,9 @@ warn_no_part = 0; if (bdops->revalidate) bdops->revalidate (dev); warn_no_part = tmp; - return 1; +out: + devfs_put_ops (de); + return retval; } /* End Function check_disc_changed */ @@ -2375,16 +2506,10 @@ if (retval != 0) return retval; retval = inode_setattr (inode, iattr); if (retval != 0) return retval; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_CHANGE) - { - printk ("%s: notify_change(%d): VFS inode: %p devfs_entry: %p\n", - DEVFS_NAME, (int) inode->i_ino, inode, de); - printk ("%s: mode: 0%o uid: %d gid: %d\n", - DEVFS_NAME, (int) inode->i_mode, - (int) inode->i_uid, (int) inode->i_gid); - } -#endif + DPRINTK (DEBUG_I_CHANGE, "(%d): VFS inode: %p devfs_entry: %p\n", + (int) inode->i_ino, inode, de); + DPRINTK (DEBUG_I_CHANGE, "(): mode: 0%o uid: %d gid: %d\n", + (int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid); /* Inode is not on hash chains, thus must save permissions here rather than in a write_inode() method */ if ( ( !S_ISREG (inode->i_mode) && !S_ISCHR (inode->i_mode) && @@ -2397,16 +2522,17 @@ de->inode.atime = inode->i_atime; de->inode.mtime = inode->i_mtime; de->inode.ctime = inode->i_ctime; - if ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) ) + if ( ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) ) && + !is_devfsd_or_child (fs_info) ) devfsd_notify_de (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); + inode->i_uid, inode->i_gid, fs_info, 0); return 0; } /* End Function devfs_notify_change */ static int devfs_statfs (struct super_block *sb, struct statfs *buf) { buf->f_type = DEVFS_SUPER_MAGIC; - buf->f_bsize = PAGE_SIZE / sizeof (long); + buf->f_bsize = FAKE_BLOCK_SIZE; buf->f_bfree = 0; buf->f_bavail = 0; buf->f_ffree = 0; @@ -2428,7 +2554,7 @@ /** - * get_vfs_inode - Get a VFS inode. + * _devfs_get_vfs_inode - Get a VFS inode. * @sb: The super block. * @de: The devfs inode. * @dentry: The dentry to register with the devfs inode. @@ -2437,9 +2563,9 @@ * performed if the inode is created. */ -static struct inode *get_vfs_inode (struct super_block *sb, - struct devfs_entry *de, - struct dentry *dentry) +static struct inode *_devfs_get_vfs_inode (struct super_block *sb, + struct devfs_entry *de, + struct dentry *dentry) { int is_fcb = FALSE; struct inode *inode; @@ -2447,8 +2573,7 @@ if (de->prev == de) return NULL; /* Quick check to see if unhooked */ if ( ( inode = new_inode (sb) ) == NULL ) { - printk ("%s: get_vfs_inode(%s): new_inode() failed, de: %p\n", - DEVFS_NAME, de->name, de); + PRINTK ("(%s): new_inode() failed, de: %p\n", de->name, de); return NULL; } if (de->parent) @@ -2465,34 +2590,30 @@ } inode->u.generic_ip = devfs_get (de); inode->i_ino = de->inode.ino; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_GET) - printk ("%s: get_vfs_inode(%d): VFS inode: %p devfs_entry: %p\n", - DEVFS_NAME, (int) inode->i_ino, inode, de); -#endif + DPRINTK (DEBUG_I_GET, "(%d): VFS inode: %p devfs_entry: %p\n", + (int) inode->i_ino, inode, de); inode->i_blocks = 0; - inode->i_blksize = 1024; + inode->i_blksize = FAKE_BLOCK_SIZE; inode->i_op = &devfs_iops; inode->i_fop = &devfs_fops; inode->i_rdev = NODEV; if ( S_ISCHR (de->mode) ) { - inode->i_rdev = MKDEV (de->u.fcb.u.device.major, + inode->i_rdev = mk_kdev (de->u.fcb.u.device.major, de->u.fcb.u.device.minor); inode->i_cdev = cdget ( kdev_t_to_nr (inode->i_rdev) ); is_fcb = TRUE; } else if ( S_ISBLK (de->mode) ) { - inode->i_rdev = MKDEV (de->u.fcb.u.device.major, + inode->i_rdev = mk_kdev (de->u.fcb.u.device.major, de->u.fcb.u.device.minor); if (bd_acquire (inode) == 0) { if (!inode->i_bdev->bd_op && de->u.fcb.ops) inode->i_bdev->bd_op = de->u.fcb.ops; } - else printk ("%s: get_vfs_inode(%d): no block device from bdget()\n", - DEVFS_NAME, (int) inode->i_ino); + else PRINTK ("(%d): no block device from bdget()\n",(int)inode->i_ino); is_fcb = TRUE; } else if ( S_ISFIFO (de->mode) ) inode->i_fop = &def_fifo_fops; @@ -2519,14 +2640,10 @@ inode->i_atime = de->inode.atime; inode->i_mtime = de->inode.mtime; inode->i_ctime = de->inode.ctime; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_GET) - printk ("%s: mode: 0%o uid: %d gid: %d\n", - DEVFS_NAME, (int) inode->i_mode, - (int) inode->i_uid, (int) inode->i_gid); -#endif + DPRINTK (DEBUG_I_GET, "(): mode: 0%o uid: %d gid: %d\n", + (int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid); return inode; -} /* End Function get_vfs_inode */ +} /* End Function _devfs_get_vfs_inode */ /* File operations for device entries follow */ @@ -2542,11 +2659,8 @@ fs_info = inode->i_sb->u.generic_sbp; parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode); if ( (long) file->f_pos < 0 ) return -EINVAL; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_F_READDIR) - printk ("%s: readdir(): fs_info: %p pos: %ld\n", DEVFS_NAME, - fs_info, (long) file->f_pos); -#endif + DPRINTK (DEBUG_F_READDIR, "(%s): fs_info: %p pos: %ld\n", + parent->name, fs_info, (long) file->f_pos); switch ( (long) file->f_pos ) { case 0: @@ -2637,9 +2751,9 @@ inode->i_uid = current->euid; inode->i_gid = current->egid; } - if (df->aopen_notify) + if ( df->aopen_notify && !is_devfsd_or_child (fs_info) ) devfsd_notify_de (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode, - current->euid, current->egid, fs_info); + current->euid, current->egid, fs_info, 0); return 0; } /* End Function devfs_open */ @@ -2666,13 +2780,7 @@ static void devfs_d_release (struct dentry *dentry) { -#ifdef CONFIG_DEVFS_DEBUG - struct inode *inode = dentry->d_inode; - - if (devfs_debug & DEBUG_D_RELEASE) - printk ("%s: d_release(): dentry: %p inode: %p\n", - DEVFS_NAME, dentry, inode); -#endif + DPRINTK (DEBUG_D_RELEASE, "(%p): inode: %p\n", dentry, dentry->d_inode); } /* End Function devfs_d_release */ /** @@ -2686,14 +2794,11 @@ struct devfs_entry *de; de = get_devfs_entry_from_vfs_inode (inode); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_D_IPUT) - printk ("%s: d_iput(): dentry: %p inode: %p de: %p de->dentry: %p\n", - DEVFS_NAME, dentry, inode, de, de->inode.dentry); -#endif + DPRINTK (DEBUG_D_IPUT,"(%s): dentry: %p inode: %p de: %p de->dentry: %p\n", + de->name, dentry, inode, de, de->inode.dentry); if ( de->inode.dentry && (de->inode.dentry != dentry) ) - OOPS ("%s: d_iput(%s): de: %p dentry: %p de->dentry: %p\n", - DEVFS_NAME, de->name, de, dentry, de->inode.dentry); + OOPS ("(%s): de: %p dentry: %p de->dentry: %p\n", + de->name, de, dentry, de->inode.dentry); de->inode.dentry = NULL; iput (inode); devfs_put (de); @@ -2733,20 +2838,13 @@ /* Unhash dentry if negative (has no inode) */ if (inode == NULL) { -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_D_DELETE) - printk ("%s: d_delete(): dropping negative dentry: %p\n", - DEVFS_NAME, dentry); -#endif + DPRINTK (DEBUG_D_DELETE, "(%p): dropping negative dentry\n", dentry); return 1; } fs_info = inode->i_sb->u.generic_sbp; de = get_devfs_entry_from_vfs_inode (inode); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_D_DELETE) - printk ("%s: d_delete(): dentry: %p inode: %p devfs_entry: %p\n", - DEVFS_NAME, dentry, inode, de); -#endif + DPRINTK (DEBUG_D_DELETE, "(%p): inode: %p devfs_entry: %p\n", + dentry, inode, de); if (de == NULL) return 0; if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) ) return 0; @@ -2754,7 +2852,7 @@ de->u.fcb.open = FALSE; if (de->u.fcb.aopen_notify) devfsd_notify_de (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode, - current->euid, current->egid, fs_info); + current->euid, current->egid, fs_info, 1); if (!de->u.fcb.auto_owner) return 0; /* Change the ownership/protection back */ inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO; @@ -2774,25 +2872,19 @@ devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir); struct inode *inode; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_LOOKUP) - printk ("%s: d_revalidate(%s): dentry: %p by: \"%s\"\n", - DEVFS_NAME, dentry->d_name.name, dentry, current->comm); -#endif + DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p by: \"%s\"\n", + dentry->d_name.name, dentry, current->comm); read_lock (&parent->u.dir.lock); de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len); - read_lock (&parent->u.dir.lock); + read_unlock (&parent->u.dir.lock); if (de == NULL) return 1; /* Create an inode, now that the driver information is available */ - inode = get_vfs_inode (dir->i_sb, de, dentry); + inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry); devfs_put (de); if (!inode) return 1; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_LOOKUP) - printk ("%s: d_revalidate(): new VFS inode(%u): %p devfs_entry: %p\n", - DEVFS_NAME, de->inode.ino, inode, de); -#endif + DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p\n", + de->name, de->inode.ino, inode, de); d_instantiate (dentry, inode); return 1; } @@ -2805,21 +2897,17 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) { - struct fs_info *fs_info; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; struct devfs_entry *parent, *de; struct inode *inode; /* Set up the dentry operations before anything else, to ensure cleaning up on any error */ dentry->d_op = &devfs_dops; - fs_info = dir->i_sb->u.generic_sbp; /* First try to get the devfs entry for this directory */ parent = get_devfs_entry_from_vfs_inode (dir); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_LOOKUP) - printk ("%s: lookup(%s): dentry: %p parent: %p by: \"%s\"\n", - DEVFS_NAME, dentry->d_name.name, dentry, parent,current->comm); -#endif + DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n", + dentry->d_name.name, dentry, parent, current->comm); if (parent == NULL) return ERR_PTR (-ENOENT); read_lock (&parent->u.dir.lock); de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len); @@ -2872,14 +2960,11 @@ d_add (dentry, NULL); /* Open the floodgates */ } /* Create an inode, now that the driver information is available */ - inode = get_vfs_inode (dir->i_sb, de, dentry); + inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry); devfs_put (de); if (!inode) return ERR_PTR (-ENOMEM); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_LOOKUP) - printk ("%s: lookup(): new VFS inode(%u): %p devfs_entry: %p\n", - DEVFS_NAME, de->inode.ino, inode, de); -#endif + DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p\n", + de->name, de->inode.ino, inode, de); d_instantiate (dentry, inode); if (dentry->d_op == &devfs_wait_dops) { /* Unlock directory semaphore, which will release any waiters. They @@ -2897,20 +2982,19 @@ int unhooked; struct devfs_entry *de; struct inode *inode = dentry->d_inode; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_UNLINK) - printk ("%s: unlink(%s)\n", DEVFS_NAME, dentry->d_name.name); -#endif de = get_devfs_entry_from_vfs_inode (inode); + DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de); if (de == NULL) return -ENOENT; if (!de->vfs_created) return -EPERM; write_lock (&de->parent->u.dir.lock); unhooked = _devfs_unhook (de); write_unlock (&de->parent->u.dir.lock); if (!unhooked) return -ENOENT; - devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode, - inode->i_uid, inode->i_gid, dir->i_sb->u.generic_sbp); + if ( !is_devfsd_or_child (fs_info) ) + devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode, + inode->i_uid, inode->i_gid, fs_info, 0); free_dentry (de); devfs_put (de); return 0; @@ -2920,21 +3004,17 @@ const char *symname) { int err; - struct fs_info *fs_info; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; struct devfs_entry *parent, *de; struct inode *inode; - fs_info = dir->i_sb->u.generic_sbp; /* First try to get the devfs entry for this directory */ parent = get_devfs_entry_from_vfs_inode (dir); if (parent == NULL) return -ENOENT; err = devfs_do_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE, symname, &de, NULL); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_DISABLED) - printk ("%s: symlink(): errcode from <devfs_do_symlink>: %d\n", - DEVFS_NAME, err); -#endif + DPRINTK (DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n", + dentry->d_name.name, err); if (err < 0) return err; de->vfs_created = TRUE; de->inode.uid = current->euid; @@ -2942,28 +3022,25 @@ de->inode.atime = CURRENT_TIME; de->inode.mtime = CURRENT_TIME; de->inode.ctime = CURRENT_TIME; - if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) + if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return -ENOMEM; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_DISABLED) - printk ("%s: symlink(): new VFS inode(%u): %p dentry: %p\n", - DEVFS_NAME, de->inode.ino, inode, dentry); -#endif + DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n", + dentry->d_name.name, de->inode.ino, inode, dentry); d_instantiate (dentry, inode); - devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); + if ( !is_devfsd_or_child (fs_info) ) + devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, + inode->i_uid, inode->i_gid, fs_info, 0); return 0; } /* End Function devfs_symlink */ static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) { int err; - struct fs_info *fs_info; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; struct devfs_entry *parent, *de; struct inode *inode; mode = (mode & ~S_IFMT) | S_IFDIR; /* VFS doesn't pass S_IFMT part */ - fs_info = dir->i_sb->u.generic_sbp; parent = get_devfs_entry_from_vfs_inode (dir); if (parent == NULL) return -ENOENT; de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode); @@ -2976,16 +3053,14 @@ de->inode.atime = CURRENT_TIME; de->inode.mtime = CURRENT_TIME; de->inode.ctime = CURRENT_TIME; - if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) + if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return -ENOMEM; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_DISABLED) - printk ("%s: mkdir(): new VFS inode(%u): %p dentry: %p\n", - DEVFS_NAME, de->inode.ino, inode, dentry); -#endif + DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n", + dentry->d_name.name, de->inode.ino, inode, dentry); d_instantiate (dentry, inode); - devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); + if ( !is_devfsd_or_child (fs_info) ) + devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, + inode->i_uid, inode->i_gid, fs_info, 0); return 0; } /* End Function devfs_mkdir */ @@ -2993,11 +3068,10 @@ { int err = 0; struct devfs_entry *de; - struct fs_info *fs_info; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; struct inode *inode = dentry->d_inode; if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL; - fs_info = dir->i_sb->u.generic_sbp; de = get_devfs_entry_from_vfs_inode (inode); if (de == NULL) return -ENOENT; if ( !S_ISDIR (de->mode) ) return -ENOTDIR; @@ -3013,8 +3087,9 @@ if ( !_devfs_unhook (de) ) err = -ENOENT; write_unlock (&de->parent->u.dir.lock); if (err) return err; - devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); + if ( !is_devfsd_or_child (fs_info) ) + devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode, + inode->i_uid, inode->i_gid, fs_info, 0); free_dentry (de); devfs_put (de); return 0; @@ -3024,16 +3099,12 @@ int rdev) { int err; - struct fs_info *fs_info; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; struct devfs_entry *parent, *de; struct inode *inode; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_MKNOD) - printk ("%s: mknod(%s): mode: 0%o dev: %d\n", - DEVFS_NAME, dentry->d_name.name, mode, rdev); -#endif - fs_info = dir->i_sb->u.generic_sbp; + DPRINTK (DEBUG_I_MKNOD, "(%s): mode: 0%o dev: %d\n", + dentry->d_name.name, mode, rdev); parent = get_devfs_entry_from_vfs_inode (dir); if (parent == NULL) return -ENOENT; de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode); @@ -3051,16 +3122,14 @@ de->inode.atime = CURRENT_TIME; de->inode.mtime = CURRENT_TIME; de->inode.ctime = CURRENT_TIME; - if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) + if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return -ENOMEM; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_MKNOD) - printk ("%s: new VFS inode(%u): %p dentry: %p\n", - DEVFS_NAME, de->inode.ino, inode, dentry); -#endif + DPRINTK (DEBUG_I_MKNOD, ": new VFS inode(%u): %p dentry: %p\n", + de->inode.ino, inode, dentry); d_instantiate (dentry, inode); - devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); + if ( !is_devfsd_or_child (fs_info) ) + devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, + inode->i_uid, inode->i_gid, fs_info, 0); return 0; } /* End Function devfs_mknod */ @@ -3124,15 +3193,11 @@ sb->s_blocksize_bits = 10; sb->s_magic = DEVFS_SUPER_MAGIC; sb->s_op = &devfs_sops; - if ( ( root_inode = get_vfs_inode (sb, root_entry, NULL) ) == NULL ) + if ( ( root_inode = _devfs_get_vfs_inode (sb, root_entry, NULL) ) == NULL ) goto out_no_root; sb->s_root = d_alloc_root (root_inode); if (!sb->s_root) goto out_no_root; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_S_READ) - printk ("%s: read super, made devfs ptr: %p\n", - DEVFS_NAME, sb->u.generic_sbp); -#endif + DPRINTK (DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->u.generic_sbp); return sb; out_no_root: @@ -3233,11 +3298,17 @@ tlen = rpos - *ppos; if (done) { + devfs_handle_t parent; + spin_lock (&fs_info->devfsd_buffer_lock); fs_info->devfsd_first_event = entry->next; if (entry->next == NULL) fs_info->devfsd_last_event = NULL; spin_unlock (&fs_info->devfsd_buffer_lock); - for (; de != NULL; de = de->parent) devfs_put (de); + for (; de != NULL; de = parent) + { + parent = de->parent; + devfs_put (de); + } kmem_cache_free (devfsd_buf_cache, entry); if (ival > 0) atomic_sub (ival, &fs_info->devfsd_overrun_count); *ppos = 0; @@ -3274,6 +3345,8 @@ } fs_info->devfsd_task = current; spin_unlock (&lock); + fs_info->devfsd_pgrp = (current->pgrp == current->pid) ? + current->pgrp : 0; fs_info->devfsd_file = file; fs_info->devfsd_info = kmalloc (sizeof *fs_info->devfsd_info, GFP_KERNEL); @@ -3304,7 +3377,7 @@ static int devfsd_close (struct inode *inode, struct file *file) { - struct devfsd_buf_entry *entry; + struct devfsd_buf_entry *entry, *next; struct fs_info *fs_info = inode->i_sb->u.generic_sbp; if (fs_info->devfsd_file != file) return 0; @@ -3320,10 +3393,14 @@ fs_info->devfsd_info = NULL; } spin_unlock (&fs_info->devfsd_buffer_lock); + fs_info->devfsd_pgrp = 0; fs_info->devfsd_task = NULL; wake_up (&fs_info->revalidate_wait_queue); - for (; entry; entry = entry->next) + for (; entry; entry = next) + { + next = entry->next; kmem_cache_free (devfsd_buf_cache, entry); + } return 0; } /* End Function devfsd_close */ @@ -3353,14 +3430,15 @@ printk ("%s: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", DEVFS_NAME, DEVFS_VERSION); + devfsd_buf_cache = kmem_cache_create ("devfsd_event", + sizeof (struct devfsd_buf_entry), + 0, 0, NULL, NULL); + if (!devfsd_buf_cache) OOPS ("(): unable to allocate event slab\n"); #ifdef CONFIG_DEVFS_DEBUG devfs_debug = devfs_debug_init; printk ("%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug); #endif printk ("%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options); - devfsd_buf_cache = kmem_cache_create ("devfsd_event", - sizeof (struct devfsd_buf_entry), - 0, 0, NULL, NULL); err = register_filesystem (&devfs_fs_type); if (!err) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/devfs/util.c linux-2.5/fs/devfs/util.c --- linux-2.5.1/fs/devfs/util.c Thu Oct 11 16:43:30 2001 +++ linux-2.5/fs/devfs/util.c Sat Jan 5 16:06:06 2002 @@ -61,67 +61,6 @@ /* Private functions follow */ /** - * _devfs_convert_name - Convert from an old style location-based name to new style. - * @new: The new name will be written here. - * @old: The old name. - * @disc: If true, disc partitioning information should be processed. - */ - -static void __init _devfs_convert_name (char *new, const char *old, int disc) -{ - int host, bus, target, lun; - char *ptr; - char part[8]; - - /* Decode "c#b#t#u#" */ - if (old[0] != 'c') return; - host = simple_strtol (old + 1, &ptr, 10); - if (ptr[0] != 'b') return; - bus = simple_strtol (ptr + 1, &ptr, 10); - if (ptr[0] != 't') return; - target = simple_strtol (ptr + 1, &ptr, 10); - if (ptr[0] != 'u') return; - lun = simple_strtol (ptr + 1, &ptr, 10); - if (disc) - { - /* Decode "p#" */ - if (ptr[0] == 'p') sprintf (part, "part%s", ptr + 1); - else strcpy (part, "disc"); - } - else part[0] = '\0'; - sprintf (new, "/host%d/bus%d/target%d/lun%d/%s", - host, bus, target, lun, part); -} /* End Function _devfs_convert_name */ - - -/* Public functions follow */ - -/** - * devfs_make_root - Create the root FS device entry if required. - * @name: The name of the root FS device, as passed by "root=". - */ - -void __init devfs_make_root (const char *name) -{ - char dest[64]; - - if ( (strncmp (name, "sd/", 3) == 0) || (strncmp (name, "sr/", 3) == 0) ) - { - strcpy (dest, "../scsi"); - _devfs_convert_name (dest + 7, name + 3, (name[1] == 'd') ? 1 : 0); - } - else if ( (strncmp (name, "ide/hd/", 7) == 0) || - (strncmp (name, "ide/cd/", 7) == 0) ) - { - strcpy (dest, ".."); - _devfs_convert_name (dest + 2, name + 7, (name[4] == 'h') ? 1 : 0); - } - else return; - devfs_mk_symlink (NULL, name, DEVFS_FL_DEFAULT, dest, NULL, NULL); -} /* End Function devfs_make_root */ - - -/** * devfs_register_tape - Register a tape device in the "/dev/tapes" hierarchy. * @de: Any tape device entry in the device directory. */ @@ -328,7 +267,7 @@ if (minor >= 256) continue; __set_bit (minor, entry->bits); up (semaphore); - return MKDEV (entry->major, minor); + return mk_kdev(entry->major, minor); } /* Need to allocate a new major */ if ( ( entry = kmalloc (sizeof *entry, GFP_KERNEL) ) == NULL ) @@ -350,7 +289,7 @@ else list->last->next = entry; list->last = entry; up (semaphore); - return MKDEV (entry->major, 0); + return mk_kdev(entry->major, 0); } /* End Function devfs_alloc_devnum */ EXPORT_SYMBOL(devfs_alloc_devnum); @@ -370,7 +309,7 @@ struct device_list *list; struct minor_list *entry; - if (devnum == NODEV) return; + if (kdev_none(devnum)) return; if (type == DEVFS_SPECIAL_CHR) { semaphore = &char_semaphore; @@ -381,8 +320,8 @@ semaphore = &block_semaphore; list = &block_list; } - major = MAJOR (devnum); - minor = MINOR (devnum); + major = major (devnum); + minor = minor (devnum); down (semaphore); for (entry = list->first; entry != NULL; entry = entry->next) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/devices.c linux-2.5/fs/devices.c --- linux-2.5.1/fs/devices.c Sun Sep 23 03:35:43 2001 +++ linux-2.5/fs/devices.c Tue Jan 1 23:42:42 2002 @@ -27,7 +27,7 @@ /* serial module kmod load support */ struct tty_driver *get_tty_driver(kdev_t device); #define isa_tty_dev(ma) (ma == TTY_MAJOR || ma == TTYAUX_MAJOR) -#define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL) +#define need_serial(ma,mi) (get_tty_driver(mk_kdev(ma,mi)) == NULL) #endif struct device_struct { @@ -145,7 +145,7 @@ { int ret = -ENODEV; - filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); + filp->f_op = get_chrfops(major(inode->i_rdev), minor(inode->i_rdev)); if (filp->f_op) { ret = 0; if (filp->f_op->open != NULL) { @@ -173,18 +173,18 @@ const char * kdevname(kdev_t dev) { static char buffer[32]; - sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev)); + sprintf(buffer, "%02x:%02x", major(dev), minor(dev)); return buffer; } const char * cdevname(kdev_t dev) { static char buffer[32]; - const char * name = chrdevs[MAJOR(dev)].name; + const char * name = chrdevs[major(dev)].name; if (!name) name = "unknown-char"; - sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev)); + sprintf(buffer, "%s(%d,%d)", name, major(dev), minor(dev)); return buffer; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/devpts/root.c linux-2.5/fs/devpts/root.c --- linux-2.5.1/fs/devpts/root.c Fri Aug 11 21:29:02 2000 +++ linux-2.5/fs/devpts/root.c Thu Dec 13 16:32:36 2001 @@ -101,7 +101,6 @@ int i; const char *p; - dentry->d_inode = NULL; /* Assume failure */ dentry->d_op = &devpts_dentry_operations; if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) { @@ -127,11 +126,10 @@ if ( entry >= sbi->max_ptys ) return NULL; - dentry->d_inode = sbi->inodes[entry]; - if ( dentry->d_inode ) - atomic_inc(&dentry->d_inode->i_count); + if ( sbi->inodes[entry] ) + atomic_inc(&sbi->inodes[entry]->i_count); - d_add(dentry, dentry->d_inode); + d_add(dentry, sbi->inodes[entry]); return NULL; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/dquot.c linux-2.5/fs/dquot.c --- linux-2.5.1/fs/dquot.c Mon Dec 10 22:13:25 2001 +++ linux-2.5/fs/dquot.c Wed Jan 2 17:23:52 2002 @@ -136,14 +136,14 @@ return is_enabled(sb_dqopt(sb), type); } -static inline int const hashfn(kdev_t dev, unsigned int id, short type) +static inline int const hashfn(struct super_block *sb, unsigned int id, short type) { - return((HASHDEV(dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; + return((HASHDEV(sb->s_dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; } static inline void insert_dquot_hash(struct dquot *dquot) { - struct list_head *head = dquot_hash + hashfn(dquot->dq_dev, dquot->dq_id, dquot->dq_type); + struct list_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type); list_add(&dquot->dq_hash, head); } @@ -153,14 +153,14 @@ INIT_LIST_HEAD(&dquot->dq_hash); } -static inline struct dquot *find_dquot(unsigned int hashent, kdev_t dev, unsigned int id, short type) +static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, short type) { struct list_head *head; struct dquot *dquot; 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) + if (dquot->dq_sb == sb && dquot->dq_id == id && dquot->dq_type == type) return dquot; } return NODQUOT; @@ -289,7 +289,7 @@ sizeof(struct dqblk), &offset); if (ret != sizeof(struct dqblk)) printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", - kdevname(dquot->dq_dev)); + kdevname(dquot->dq_sb->s_dev)); set_fs(fs); up(sem); @@ -359,7 +359,7 @@ } } -int sync_dquots(kdev_t dev, short type) +int sync_dquots(struct super_block *sb, short type) { struct list_head *head; struct dquot *dquot; @@ -368,7 +368,7 @@ restart: 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) + if (sb && dquot->dq_sb != sb) continue; if (type != -1 && dquot->dq_type != type) continue; @@ -440,7 +440,8 @@ if (!dquot->dq_count) { printk("VFS: dqput: trying to free free dquot\n"); printk("VFS: device %s, dquot of %s %d\n", - kdevname(dquot->dq_dev), quotatypes[dquot->dq_type], + kdevname(dquot->dq_sb->s_dev), + quotatypes[dquot->dq_type], dquot->dq_id); return; } @@ -493,7 +494,7 @@ static struct dquot *dqget(struct super_block *sb, unsigned int id, short type) { - unsigned int hashent = hashfn(sb->s_dev, id, type); + unsigned int hashent = hashfn(sb, id, type); struct dquot *dquot, *empty = NODQUOT; struct quota_mount_options *dqopt = sb_dqopt(sb); @@ -504,7 +505,7 @@ return NODQUOT; } - if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NODQUOT) { + if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) { if (empty == NODQUOT) { if ((empty = get_empty_dquot()) == NODQUOT) schedule(); /* Try to wait for a moment... */ @@ -513,7 +514,6 @@ dquot = empty; dquot->dq_id = id; dquot->dq_type = type; - dquot->dq_dev = sb->s_dev; dquot->dq_sb = sb; /* hash it first so it can be found */ insert_dquot_hash(dquot); @@ -1471,7 +1471,7 @@ flags |= SET_QLIMIT; break; case Q_SYNC: - ret = sync_dquots(dev, type); + ret = sync_dquots(sb, type); goto out; case Q_GETSTATS: ret = get_stats(addr); @@ -1483,7 +1483,7 @@ goto out; } - ret = -NODEV; + ret = -ENODEV; if (sb && sb_has_quota_enabled(sb, type)) ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr); out: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/efs/file.c linux-2.5/fs/efs/file.c --- linux-2.5.1/fs/efs/file.c Sun Dec 16 20:22:56 2001 +++ linux-2.5/fs/efs/file.c Thu Dec 27 22:10:28 2001 @@ -29,11 +29,8 @@ return 0; } phys = efs_map_block(inode, iblock); - if (phys) { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); - } + if (phys) + map_bh(bh_result, inode->i_sb, phys); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/efs/super.c linux-2.5/fs/efs/super.c --- linux-2.5.1/fs/efs/super.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/efs/super.c Thu Dec 27 15:56:12 2001 @@ -132,16 +132,13 @@ } struct super_block *efs_read_super(struct super_block *s, void *d, int silent) { - kdev_t dev = s->s_dev; struct efs_sb_info *sb; struct buffer_head *bh; sb = SUPER_INFO(s); s->s_magic = EFS_SUPER_MAGIC; - s->s_blocksize = EFS_BLOCKSIZE; - s->s_blocksize_bits = EFS_BLOCKSIZE_BITS; - set_blocksize(dev, EFS_BLOCKSIZE); + sb_set_blocksize(s, EFS_BLOCKSIZE); /* read the vh (volume header) block */ bh = sb_bread(s, 0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/exec.c linux-2.5/fs/exec.c --- linux-2.5.1/fs/exec.c Wed Nov 28 17:30:47 2001 +++ linux-2.5/fs/exec.c Sun Jan 13 18:08:45 2002 @@ -40,7 +40,7 @@ #include <asm/uaccess.h> #include <asm/pgalloc.h> -#include <asm/mmu_context.h> +#include <asm/sched.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> @@ -973,9 +973,7 @@ if (do_truncate(file->f_dentry, 0) != 0) goto close_fail; - down_read(¤t->mm->mmap_sem); retval = binfmt->core_dump(signr, regs, file); - up_read(¤t->mm->mmap_sem); close_fail: filp_close(file, NULL); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ext2/ialloc.c linux-2.5/fs/ext2/ialloc.c --- linux-2.5.1/fs/ext2/ialloc.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/ext2/ialloc.c Fri Dec 28 00:06:33 2001 @@ -393,7 +393,7 @@ if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) inode->i_flags |= S_SYNC; insert_inode_hash(inode); - inode->i_generation = event++; + inode->i_generation = sb->u.ext2_sb.s_next_generation++; mark_inode_dirty(inode); unlock_super (sb); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ext2/inode.c linux-2.5/fs/ext2/inode.c --- linux-2.5.1/fs/ext2/inode.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/ext2/inode.c Sat Jan 5 16:38:08 2002 @@ -524,9 +524,7 @@ /* Simplest case - block found, no allocation needed */ if (!partial) { got_it: - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key); - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); /* Clean up and exit */ partial = chain+depth-1; /* the whole chain */ goto cleanup; @@ -1137,9 +1135,8 @@ ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); if (buffer_req(bh) && !buffer_uptodate(bh)) { - printk ("IO error syncing ext2 inode [" - "%s:%08lx]\n", - bdevname(inode->i_dev), inode->i_ino); + printk ("IO error syncing ext2 inode [%s:%08lx]\n", + inode->i_sb->s_id, inode->i_ino); err = -EIO; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ext2/super.c linux-2.5/fs/ext2/super.c --- linux-2.5.1/fs/ext2/super.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/ext2/super.c Sat Jan 5 16:38:08 2002 @@ -25,9 +25,12 @@ #include <linux/init.h> #include <linux/locks.h> #include <linux/blkdev.h> +#include <linux/random.h> #include <asm/uaccess.h> +static void ext2_sync_super(struct super_block *sb, + struct ext2_super_block *es); static char error_buf[1024]; @@ -35,13 +38,13 @@ const char * fmt, ...) { va_list args; + struct ext2_super_block *es = EXT2_SB(sb)->s_es; if (!(sb->s_flags & MS_RDONLY)) { sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; - sb->u.ext2_sb.s_es->s_state = - cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh); - sb->s_dirt = 1; + es->s_state = + cpu_to_le16(le16_to_cpu(es->s_state) | EXT2_ERROR_FS); + ext2_sync_super(sb, es); } va_start (args, fmt); vsprintf (error_buf, fmt, args); @@ -50,9 +53,9 @@ (le16_to_cpu(sb->u.ext2_sb.s_es->s_errors) == EXT2_ERRORS_PANIC && !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO))) panic ("EXT2-fs panic (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); printk (KERN_CRIT "EXT2-fs error (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); if (test_opt (sb, ERRORS_RO) || (le16_to_cpu(sb->u.ext2_sb.s_es->s_errors) == EXT2_ERRORS_RO && !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) { @@ -78,7 +81,7 @@ va_end (args); sb->s_flags |= MS_RDONLY; panic ("EXT2-fs panic (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); } void ext2_warning (struct super_block * sb, const char * function, @@ -90,7 +93,7 @@ vsprintf (error_buf, fmt, args); va_end (args); printk (KERN_WARNING "EXT2-fs warning (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); } void ext2_update_dynamic_rev(struct super_block *sb) @@ -124,8 +127,10 @@ int i; if (!(sb->s_flags & MS_RDONLY)) { - sb->u.ext2_sb.s_es->s_state = le16_to_cpu(sb->u.ext2_sb.s_mount_state); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh); + struct ext2_super_block *es = EXT2_SB(sb)->s_es; + + es->s_state = le16_to_cpu(EXT2_SB(sb)->s_mount_state); + ext2_sync_super(sb, es); } db_count = EXT2_SB(sb)->s_gdb_count; for (i = 0; i < db_count; i++) @@ -305,13 +310,10 @@ (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME)) printk ("EXT2-fs warning: checktime reached, " "running e2fsck is recommended\n"); - es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS); if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); - es->s_mtime = cpu_to_le32(CURRENT_TIME); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh); - sb->s_dirt = 1; + ext2_write_super(sb); if (test_opt (sb, DEBUG)) printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " "bpg=%lu, ipg=%lu, mo=%04lx]\n", @@ -406,7 +408,6 @@ unsigned short resgid = EXT2_DEF_RESGID; unsigned long logic_sb_block = 1; unsigned long offset = 0; - kdev_t dev = sb->s_dev; int blocksize = BLOCK_SIZE; int db_count; int i, j; @@ -418,9 +419,6 @@ * This is important for devices that have a hardware * sectorsize that is larger than the default. */ - blocksize = get_hardsect_size(dev); - if(blocksize < BLOCK_SIZE ) - blocksize = BLOCK_SIZE; sb->u.ext2_sb.s_mount_opt = 0; if (!parse_options ((char *) data, &sb_block, &resuid, &resgid, @@ -428,11 +426,11 @@ return NULL; } - if (set_blocksize(dev, blocksize) < 0) { - printk ("EXT2-fs: unable to set blocksize %d\n", blocksize); + blocksize = sb_min_blocksize(sb, BLOCK_SIZE); + if (!blocksize) { + printk ("EXT2-fs: unable to set blocksize\n"); return NULL; } - sb->s_blocksize = blocksize; /* * If the superblock doesn't start on a sector boundary, @@ -458,7 +456,7 @@ if (sb->s_magic != EXT2_SUPER_MAGIC) { if (!silent) printk ("VFS: Can't find ext2 filesystem on dev %s.\n", - bdevname(dev)); + sb->s_id); goto failed_mount; } if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && @@ -475,28 +473,22 @@ if ((i = EXT2_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP))) { printk("EXT2-fs: %s: couldn't mount because of " "unsupported optional features (%x).\n", - bdevname(dev), i); + sb->s_id, i); goto failed_mount; } if (!(sb->s_flags & MS_RDONLY) && (i = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))){ printk("EXT2-fs: %s: couldn't mount RDWR because of " "unsupported optional features (%x).\n", - bdevname(dev), i); + sb->s_id, i); goto failed_mount; } - 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; - - sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); - + blocksize = BLOCK_SIZE << le32_to_cpu(EXT2_SB(sb)->s_es->s_log_block_size); /* If the blocksize doesn't match, re-read the thing.. */ if (sb->s_blocksize != blocksize) { - blocksize = sb->s_blocksize; brelse(bh); - if (set_blocksize(dev, blocksize) < 0) { + if (!sb_set_blocksize(sb, blocksize)) { printk(KERN_ERR "EXT2-fs: blocksize too small for device.\n"); return NULL; } @@ -517,6 +509,8 @@ } } + sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); + if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) { sb->u.ext2_sb.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; sb->u.ext2_sb.s_first_ino = EXT2_GOOD_OLD_FIRST_INO; @@ -563,13 +557,13 @@ if (!silent) printk ("VFS: Can't find an ext2 filesystem on dev " "%s.\n", - bdevname(dev)); + sb->s_id); goto failed_mount; } if (sb->s_blocksize != bh->b_size) { if (!silent) printk ("VFS: Unsupported blocksize on dev " - "%s.\n", bdevname(dev)); + "%s.\n", sb->s_id); goto failed_mount; } @@ -630,6 +624,7 @@ sb->u.ext2_sb.s_loaded_inode_bitmaps = 0; sb->u.ext2_sb.s_loaded_block_bitmaps = 0; sb->u.ext2_sb.s_gdb_count = db_count; + get_random_bytes(&sb->u.ext2_sb.s_next_generation, sizeof(u32)); /* * set up enough so that it can read an inode */ @@ -664,6 +659,15 @@ sb->s_dirt = 0; } +static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es) +{ + es->s_wtime = cpu_to_le32(CURRENT_TIME); + mark_buffer_dirty(EXT2_SB(sb)->s_sbh); + ll_rw_block(WRITE, 1, &EXT2_SB(sb)->s_sbh); + wait_on_buffer(EXT2_SB(sb)->s_sbh); + sb->s_dirt = 0; +} + /* * In the second extended file system, it is not necessary to * write the super block since we use a mapping of the @@ -682,13 +686,14 @@ if (!(sb->s_flags & MS_RDONLY)) { es = sb->u.ext2_sb.s_es; - ext2_debug ("setting valid to 0\n"); - if (le16_to_cpu(es->s_state) & EXT2_VALID_FS) { - es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS); + ext2_debug ("setting valid to 0\n"); + es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & + ~EXT2_VALID_FS); es->s_mtime = cpu_to_le32(CURRENT_TIME); - } - ext2_commit_super (sb, es); + ext2_sync_super(sb, es); + } else + ext2_commit_super (sb, es); } sb->s_dirt = 0; } @@ -725,17 +730,13 @@ */ es->s_state = cpu_to_le16(sb->u.ext2_sb.s_mount_state); es->s_mtime = cpu_to_le32(CURRENT_TIME); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh); - sb->s_dirt = 1; - ext2_commit_super (sb, es); - } - else { + } else { int ret; if ((ret = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))) { printk("EXT2-fs: %s: couldn't remount RDWR because of " "unsupported optional features (%x).\n", - bdevname(sb->s_dev), ret); + sb->s_id, ret); return -EROFS; } /* @@ -747,6 +748,7 @@ if (!ext2_setup_super (sb, es, 0)) sb->s_flags &= ~MS_RDONLY; } + ext2_sync_super(sb, es); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ext3/Makefile linux-2.5/fs/ext3/Makefile --- linux-2.5.1/fs/ext3/Makefile Fri Nov 9 22:25:04 2001 +++ linux-2.5/fs/ext3/Makefile Thu Dec 13 16:32:36 2001 @@ -9,7 +9,7 @@ O_TARGET := ext3.o -obj-y := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ +obj-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ ioctl.o namei.o super.o symlink.o obj-m := $(O_TARGET) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ext3/acl.c linux-2.5/fs/ext3/acl.c --- linux-2.5.1/fs/ext3/acl.c Fri Nov 9 22:25:04 2001 +++ linux-2.5/fs/ext3/acl.c Thu Jan 1 00:00:00 1970 @@ -1,17 +0,0 @@ -/* - * linux/fs/ext3/acl.c - * - * Copyright (C) 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - */ - -#include <linux/fs.h> -#include <linux/sched.h> - - -/* - * This file will contain the Access Control Lists management for the - * second extended file system. - */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ext3/ialloc.c linux-2.5/fs/ext3/ialloc.c --- linux-2.5.1/fs/ext3/ialloc.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/ext3/ialloc.c Sat Jan 5 16:38:08 2002 @@ -189,10 +189,6 @@ struct ext3_super_block * es; int fatal = 0, err; - if (!inode->i_dev) { - printk ("ext3_free_inode: inode has no device\n"); - return; - } if (atomic_read(&inode->i_count) > 1) { printk ("ext3_free_inode: inode has count=%d\n", atomic_read(&inode->i_count)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ext3/inode.c linux-2.5/fs/ext3/inode.c --- linux-2.5.1/fs/ext3/inode.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/ext3/inode.c Thu Dec 27 22:10:28 2001 @@ -32,7 +32,6 @@ #include <linux/quotaops.h> #include <linux/module.h> - /* * SEARCH_FROM_ZERO forces each block allocation to search from the start * of the filesystem. This is to force rapid reallocation of recently-freed @@ -715,6 +714,8 @@ * reachable from inode. * * akpm: `handle' can be NULL if create == 0. + * + * The BKL may not be held on entry here. Be sure to take it early. */ static int ext3_get_block_handle(handle_t *handle, struct inode *inode, @@ -743,9 +744,7 @@ if (!partial) { bh_result->b_state &= ~(1UL << BH_New); got_it: - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key); - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); /* Clean up and exit */ partial = chain+depth-1; /* the whole chain */ goto cleanup; @@ -1020,13 +1019,26 @@ ret = PTR_ERR(handle); goto out; } + unlock_kernel(); ret = block_prepare_write(page, from, to, ext3_get_block); + lock_kernel(); if (ret != 0) goto prepare_write_failed; - if (ext3_should_journal_data(inode)) + if (ext3_should_journal_data(inode)) { ret = walk_page_buffers(handle, page->buffers, from, to, NULL, do_journal_get_write_access); + if (ret) { + /* + * We're going to fail this prepare_write(), + * so commit_write() will not be called. + * We need to undo block_prepare_write()'s kmap(). + * AKPM: Do we need to clear PageUptodate? I don't + * think so. + */ + kunmap(page); + } + } prepare_write_failed: if (ret) ext3_journal_stop(handle, inode); @@ -1094,7 +1106,7 @@ kunmap(page); if (pos > inode->i_size) inode->i_size = pos; - set_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state); + EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; } else { if (ext3_should_order_data(inode)) { ret = walk_page_buffers(handle, page->buffers, @@ -1102,8 +1114,17 @@ } /* Be careful here if generic_commit_write becomes a * required invocation after block_prepare_write. */ - if (ret == 0) + if (ret == 0) { ret = generic_commit_write(file, page, from, to); + } else { + /* + * block_prepare_write() was called, but we're not + * going to call generic_commit_write(). So we + * need to perform generic_commit_write()'s kunmap + * by hand. + */ + kunmap(page); + } } if (inode->i_size > inode->u.ext3_i.i_disksize) { inode->u.ext3_i.i_disksize = inode->i_size; @@ -1138,7 +1159,7 @@ journal_t *journal; int err; - if (test_and_clear_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state)) { + if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) { /* * This is a REALLY heavyweight approach, but the use of * bmap on dirty files is expected to be extremely rare: @@ -1157,6 +1178,7 @@ * everything they get. */ + EXT3_I(inode)->i_state &= ~EXT3_STATE_JDATA; journal = EXT3_JOURNAL(inode); journal_lock_updates(journal); err = journal_flush(journal); @@ -1265,8 +1287,7 @@ /* bget() all the buffers */ if (order_data) { if (!page->buffers) - create_empty_buffers(page, - inode->i_dev, inode->i_sb->s_blocksize); + create_empty_buffers(page, inode->i_sb->s_blocksize); page_buffers = page->buffers; walk_page_buffers(handle, page_buffers, 0, PAGE_CACHE_SIZE, NULL, bget_one); @@ -1369,7 +1390,7 @@ goto out; if (!page->buffers) - create_empty_buffers(page, inode->i_dev, blocksize); + create_empty_buffers(page, blocksize); /* Find the buffer that contains "offset" */ bh = page->buffers; @@ -2198,7 +2219,7 @@ /* If we are not tracking these fields in the in-memory inode, * then preserve them on disk, but still initialise them to zero * for new inodes. */ - if (inode->u.ext3_i.i_state & EXT3_STATE_NEW) { + if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) { raw_inode->i_faddr = 0; raw_inode->i_frag = 0; raw_inode->i_fsize = 0; @@ -2244,7 +2265,7 @@ rc = ext3_journal_dirty_metadata(handle, bh); if (!err) err = rc; - inode->u.ext3_i.i_state &= ~EXT3_STATE_NEW; + EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW; out_brelse: brelse (bh); @@ -2328,12 +2349,20 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; - int error, rc; + int error, rc = 0; + const unsigned int ia_valid = attr->ia_valid; error = inode_change_ok(inode, attr); if (error) return 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) + return error; + } + if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { handle_t *handle; @@ -2351,7 +2380,7 @@ ext3_journal_stop(handle, inode); } - inode_setattr(inode, attr); + rc = inode_setattr(inode, attr); /* If inode_setattr's call to ext3_truncate failed to get a * transaction handle at all, we need to clean up the in-core @@ -2361,7 +2390,9 @@ err_out: ext3_std_error(inode->i_sb, error); - return 0; + if (!error) + error = rc; + return error; } @@ -2662,6 +2693,3 @@ * here, in ext3_aops_journal_start() to ensure that the forthcoming "see if we * need to extend" test in ext3_prepare_write() succeeds. */ - - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ext3/super.c linux-2.5/fs/ext3/super.c --- linux-2.5.1/fs/ext3/super.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/ext3/super.c Thu Jan 10 13:32:21 2002 @@ -47,19 +47,19 @@ struct ext3_super_block * es); #ifdef CONFIG_JBD_DEBUG -int journal_no_write[2]; +kdev_t journal_no_write[2]; /* * Debug code for turning filesystems "read-only" after a specified * amount of time. This is for crash/recovery testing. */ -static void make_rdonly(kdev_t dev, int *no_write) +static void make_rdonly(struct block_device *bdev, int *no_write) { - if (dev) { + if (bdev) { printk(KERN_WARNING "Turning device %s read-only\n", - bdevname(dev)); - *no_write = 0xdead0000 + dev; + bdevname(to_kdev_t(bdev->bd_dev))); + *no_write = 0xdead0000 + bdev->bd_dev; } } @@ -67,7 +67,7 @@ { struct super_block *sb = (struct super_block *)arg; - make_rdonly(sb->s_dev, &journal_no_write[0]); + make_rdonly(sb->s_bdev, &journal_no_write[0]); make_rdonly(EXT3_SB(sb)->s_journal->j_dev, &journal_no_write[1]); wake_up(&EXT3_SB(sb)->ro_wait_queue); } @@ -80,8 +80,8 @@ printk(KERN_DEBUG "fs will go read-only in %d jiffies\n", ext3_ro_after); init_waitqueue_head(&sbi->ro_wait_queue); - journal_no_write[0] = 0; - journal_no_write[1] = 0; + journal_no_write[0] = NODEV; + journal_no_write[1] = NODEV; sbi->turn_ro_timer.function = turn_fs_readonly; sbi->turn_ro_timer.data = (unsigned long)sb; sbi->turn_ro_timer.expires = jiffies + ext3_ro_after; @@ -93,8 +93,8 @@ static void clear_ro_after(struct super_block *sb) { del_timer_sync(&EXT3_SB(sb)->turn_ro_timer); - journal_no_write[0] = 0; - journal_no_write[1] = 0; + journal_no_write[0] = NODEV; + journal_no_write[1] = NODEV; ext3_ro_after = 0; } #else @@ -163,7 +163,7 @@ if (ext3_error_behaviour(sb) == EXT3_ERRORS_PANIC) panic ("EXT3-fs (device %s): panic forced after error\n", - bdevname(sb->s_dev)); + sb->s_id); if (ext3_error_behaviour(sb) == EXT3_ERRORS_RO) { printk (KERN_CRIT "Remounting filesystem read-only\n"); @@ -183,7 +183,7 @@ va_end (args); printk (KERN_CRIT "EXT3-fs error (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); ext3_handle_error(sb); } @@ -231,7 +231,7 @@ const char *errstr = ext3_decode_error(sb, errno, nbuf); printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n", - bdevname(sb->s_dev), function, errstr); + sb->s_id, function, errstr); ext3_handle_error(sb); } @@ -259,10 +259,10 @@ if (ext3_error_behaviour(sb) == EXT3_ERRORS_PANIC) panic ("EXT3-fs panic (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); printk (KERN_CRIT "EXT3-fs abort (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); if (sb->s_flags & MS_RDONLY) return; @@ -293,7 +293,7 @@ /* AKPM: is this sufficient? */ sb->s_flags |= MS_RDONLY; panic ("EXT3-fs panic (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); } void ext3_warning (struct super_block * sb, const char * function, @@ -305,7 +305,7 @@ vsprintf (error_buf, fmt, args); va_end (args); printk (KERN_WARNING "EXT3-fs warning (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); } void ext3_update_dynamic_rev(struct super_block *sb) @@ -389,8 +389,8 @@ list_for_each(l, &sbi->s_orphan) { struct inode *inode = orphan_list_entry(l); printk(KERN_ERR " " - "inode 0x%04x:%ld at %p: mode %o, nlink %d, next %d\n", - inode->i_dev, inode->i_ino, inode, + "inode %s:%ld at %p: mode %o, nlink %d, next %d\n", + inode->i_sb->s_id, inode->i_ino, inode, inode->i_mode, inode->i_nlink, le32_to_cpu(NEXT_ORPHAN(inode))); } @@ -400,7 +400,6 @@ { struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_super_block *es = sbi->s_es; - kdev_t j_dev = sbi->s_journal->j_dev; int i; journal_destroy(sbi->s_journal); @@ -429,15 +428,15 @@ dump_orphan_list(sb, sbi); J_ASSERT(list_empty(&sbi->s_orphan)); - invalidate_buffers(sb->s_dev); - if (j_dev != sb->s_dev) { + invalidate_bdev(sb->s_bdev, 0); + if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) { /* * Invalidate the journal device's buffers. We don't want them * floating about in memory - the physical journal device may * hotswapped, and it breaks the `ro-after' testing code. */ - fsync_no_super(j_dev); - invalidate_buffers(j_dev); + fsync_no_super(sbi->journal_bdev); + invalidate_bdev(sbi->journal_bdev, 0); ext3_blkdev_remove(sbi); } clear_ro_after(sb); @@ -712,10 +711,10 @@ EXT3_INODES_PER_GROUP(sb), sbi->s_mount_opt); printk(KERN_INFO "EXT3 FS " EXT3FS_VERSION ", " EXT3FS_DATE " on %s, ", - bdevname(sb->s_dev)); + sb->s_id); if (EXT3_SB(sb)->s_journal->j_inode == NULL) { printk("external journal on %s\n", - bdevname(EXT3_SB(sb)->s_journal->j_dev)); + bdevname(to_kdev_t(EXT3_SB(sb)->s_journal->j_dev->bd_dev))); } else { printk("internal journal\n"); } @@ -813,7 +812,7 @@ if (s_flags & MS_RDONLY) { printk(KERN_INFO "EXT3-fs: %s: orphan cleanup on readonly fs\n", - bdevname(sb->s_dev)); + sb->s_id); sb->s_flags &= ~MS_RDONLY; } @@ -859,10 +858,10 @@ if (nr_orphans) printk(KERN_INFO "EXT3-fs: %s: %d orphan inode%s deleted\n", - bdevname(sb->s_dev), PLURAL(nr_orphans)); + sb->s_id, PLURAL(nr_orphans)); if (nr_truncates) printk(KERN_INFO "EXT3-fs: %s: %d truncate%s cleaned up\n", - bdevname(sb->s_dev), PLURAL(nr_truncates)); + sb->s_id, PLURAL(nr_truncates)); sb->s_flags = s_flags; /* Restore MS_RDONLY status */ } @@ -912,21 +911,14 @@ * This is important for devices that have a hardware * sectorsize that is larger than the default. */ - blocksize = EXT3_MIN_BLOCK_SIZE; - hblock = get_hardsect_size(dev); - if (blocksize < hblock) - blocksize = hblock; sbi->s_mount_opt = 0; sbi->s_resuid = EXT3_DEF_RESUID; sbi->s_resgid = EXT3_DEF_RESGID; - if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) { - sb->s_dev = 0; + if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) goto out_fail; - } - sb->s_blocksize = blocksize; - set_blocksize (dev, blocksize); + blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); /* * The ext3 superblock will not be buffer aligned for other than 1kB @@ -952,7 +944,7 @@ if (!silent) printk(KERN_ERR "VFS: Can't find ext3 filesystem on dev %s.\n", - bdevname(dev)); + sb->s_id); goto failed_mount; } if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV && @@ -970,44 +962,42 @@ if ((i = EXT3_HAS_INCOMPAT_FEATURE(sb, ~EXT3_FEATURE_INCOMPAT_SUPP))) { printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of " "unsupported optional features (%x).\n", - bdevname(dev), i); + sb->s_id, i); goto failed_mount; } if (!(sb->s_flags & MS_RDONLY) && (i = EXT3_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP))){ printk(KERN_ERR "EXT3-fs: %s: couldn't mount RDWR because of " "unsupported optional features (%x).\n", - bdevname(dev), i); + sb->s_id, i); goto failed_mount; } - sb->s_blocksize_bits = le32_to_cpu(es->s_log_block_size) + 10; - sb->s_blocksize = 1 << sb->s_blocksize_bits; + blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); - if (sb->s_blocksize < EXT3_MIN_BLOCK_SIZE || - sb->s_blocksize > EXT3_MAX_BLOCK_SIZE) { + if (blocksize < EXT3_MIN_BLOCK_SIZE || + blocksize > EXT3_MAX_BLOCK_SIZE) { printk(KERN_ERR "EXT3-fs: Unsupported filesystem blocksize %d on %s.\n", - blocksize, bdevname(dev)); + blocksize, sb->s_id); goto failed_mount; } sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits); + hblock = get_hardsect_size(dev); if (sb->s_blocksize != blocksize) { - blocksize = sb->s_blocksize; - /* * Make sure the blocksize for the filesystem is larger * than the hardware sectorsize for the machine. */ - if (sb->s_blocksize < hblock) { + if (blocksize < hblock) { printk(KERN_ERR "EXT3-fs: blocksize %d too small for " "device blocksize %d.\n", blocksize, hblock); goto failed_mount; } brelse (bh); - set_blocksize (dev, sb->s_blocksize); + sb_set_blocksize(sb, blocksize); logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; bh = sb_bread(sb, logic_sb_block); @@ -1142,7 +1132,7 @@ if (!silent) printk (KERN_ERR "ext3: No journal on filesystem on %s\n", - bdevname(dev)); + sb->s_id); goto failed_mount2; } @@ -1257,13 +1247,16 @@ } journal = journal_init_inode(journal_inode); - if (!journal) + if (!journal) { + printk(KERN_ERR "EXT3-fs: Could not load journal inode\n"); iput(journal_inode); + } + return journal; } static journal_t *ext3_get_dev_journal(struct super_block *sb, - int dev) + kdev_t j_dev) { struct buffer_head * bh; journal_t *journal; @@ -1272,16 +1265,15 @@ int hblock, blocksize; unsigned long sb_block; unsigned long offset; - kdev_t journal_dev = to_kdev_t(dev); struct ext3_super_block * es; struct block_device *bdev; - bdev = ext3_blkdev_get(journal_dev); + bdev = ext3_blkdev_get(j_dev); if (bdev == NULL) return NULL; blocksize = sb->s_blocksize; - hblock = get_hardsect_size(journal_dev); + hblock = get_hardsect_size(j_dev); if (blocksize < hblock) { printk(KERN_ERR "EXT3-fs: blocksize too small for journal device.\n"); @@ -1290,8 +1282,8 @@ sb_block = EXT3_MIN_BLOCK_SIZE / blocksize; offset = EXT3_MIN_BLOCK_SIZE % blocksize; - set_blocksize(dev, blocksize); - if (!(bh = bread(dev, sb_block, blocksize))) { + set_blocksize(j_dev, blocksize); + if (!(bh = __bread(bdev, sb_block, blocksize))) { printk(KERN_ERR "EXT3-fs: couldn't read superblock of " "external journal\n"); goto out_bdev; @@ -1317,7 +1309,7 @@ start = sb_block + 1; brelse(bh); /* we're done with the superblock */ - journal = journal_init_dev(journal_dev, sb->s_dev, + journal = journal_init_dev(bdev, sb->s_bdev, start, len, blocksize); if (!journal) { printk(KERN_ERR "EXT3-fs: failed to create device journal\n"); @@ -1349,8 +1341,8 @@ { journal_t *journal; int journal_inum = le32_to_cpu(es->s_journal_inum); - int journal_dev = le32_to_cpu(es->s_journal_dev); - int err; + kdev_t journal_dev = to_kdev_t(le32_to_cpu(es->s_journal_dev)); + int err = 0; int really_read_only; really_read_only = is_read_only(sb->s_dev); @@ -1375,7 +1367,7 @@ } } - if (journal_inum && journal_dev) { + if (journal_inum && !kdev_none(journal_dev)) { printk(KERN_ERR "EXT3-fs: filesystem has both journal " "and inode journals!\n"); return -EINVAL; @@ -1400,9 +1392,10 @@ } if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) - journal_wipe(journal, !really_read_only); + err = journal_wipe(journal, !really_read_only); + if (!err) + err = journal_load(journal); - err = journal_load(journal); if (err) { printk(KERN_ERR "EXT3-fs: error loading journal.\n"); journal_destroy(journal); @@ -1658,7 +1651,7 @@ printk(KERN_WARNING "EXT3-fs: %s: couldn't " "remount RDWR because of unsupported " "optional features (%x).\n", - bdevname(sb->s_dev), ret); + sb->s_id, ret); return -EROFS; } /* @@ -1740,6 +1733,8 @@ EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); +MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions"); MODULE_LICENSE("GPL"); module_init(init_ext3_fs) module_exit(exit_ext3_fs) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/fat/cache.c linux-2.5/fs/fat/cache.c --- linux-2.5.1/fs/fat/cache.c Fri Oct 12 20:48:42 2001 +++ linux-2.5/fs/fat/cache.c Sat Jan 5 16:38:08 2002 @@ -144,7 +144,7 @@ } fat_cache = &cache[0]; for (count = 0; count < FAT_CACHE; count++) { - cache[count].device = 0; + cache[count].sb = NULL; cache[count].next = count == FAT_CACHE-1 ? NULL : &cache[count+1]; } @@ -162,7 +162,7 @@ return; spin_lock(&fat_cache_lock); for (walk = fat_cache; walk; walk = walk->next) - if (inode->i_dev == walk->device + if (inode->i_sb == walk->sb && walk->start_cluster == first && walk->file_cluster <= cluster && walk->file_cluster > *f_clu) { @@ -188,8 +188,8 @@ struct fat_cache *walk; for (walk = fat_cache; walk; walk = walk->next) { - if (walk->device) - printk("<%s,%d>(%d,%d) ", kdevname(walk->device), + if (walk->sb) + printk("<%s,%d>(%d,%d) ", walk->sb->s_dev->s_id, walk->start_cluster, walk->file_cluster, walk->disk_cluster); else printk("-- "); @@ -207,7 +207,7 @@ last = NULL; spin_lock(&fat_cache_lock); for (walk = fat_cache; walk->next; walk = (last = walk)->next) - if (inode->i_dev == walk->device + if (inode->i_sb == walk->sb && walk->start_cluster == first && walk->file_cluster == f_clu) { if (walk->disk_cluster != d_clu) { @@ -231,7 +231,7 @@ spin_unlock(&fat_cache_lock); return; } - walk->device = inode->i_dev; + walk->sb = inode->i_sb; walk->start_cluster = first; walk->file_cluster = f_clu; walk->disk_cluster = d_clu; @@ -255,21 +255,21 @@ spin_lock(&fat_cache_lock); for (walk = fat_cache; walk; walk = walk->next) - if (walk->device == inode->i_dev + if (walk->sb == inode->i_sb && walk->start_cluster == first) - walk->device = 0; + walk->sb = NULL; spin_unlock(&fat_cache_lock); } -void fat_cache_inval_dev(kdev_t device) +void fat_cache_inval_dev(struct super_block *sb) { struct fat_cache *walk; spin_lock(&fat_cache_lock); for (walk = fat_cache; walk; walk = walk->next) - if (walk->device == device) - walk->device = 0; + if (walk->sb == sb) + walk->sb = 0; spin_unlock(&fat_cache_lock); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/fat/file.c linux-2.5/fs/fat/file.c --- linux-2.5.1/fs/fat/file.c Fri Nov 30 16:30:48 2001 +++ linux-2.5/fs/fat/file.c Thu Dec 27 22:10:28 2001 @@ -55,9 +55,7 @@ phys = fat_bmap(inode, iblock); if (phys) { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh_result, inode->i_sb, phys); return 0; } if (!create) @@ -74,10 +72,8 @@ phys = fat_bmap(inode, iblock); if (!phys) BUG(); - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); bh_result->b_state |= (1UL << BH_New); + map_bh(bh_result, inode->i_sb, phys); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/fat/inode.c linux-2.5/fs/fat/inode.c --- linux-2.5.1/fs/fat/inode.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/fat/inode.c Sun Jan 13 18:06:42 2002 @@ -146,6 +146,7 @@ goto out; *res = 0; inode->i_ino = iunique(sb, MSDOS_ROOT_INO); + inode->i_version = 0; fat_fill_inode(inode, de); fat_attach(inode, ino); insert_inode_hash(inode); @@ -185,7 +186,7 @@ if (MSDOS_SB(sb)->fat_bits == 32) { fat_clusters_flush(sb); } - fat_cache_inval_dev(sb->s_dev); + fat_cache_inval_dev(sb); set_blocksize (sb->s_dev,BLOCK_SIZE); if (MSDOS_SB(sb)->nls_disk) { unload_nls(MSDOS_SB(sb)->nls_disk); @@ -383,7 +384,7 @@ MSDOS_I(inode)->i_fat_inode = inode; inode->i_uid = sbi->options.fs_uid; inode->i_gid = sbi->options.fs_gid; - inode->i_version = ++event; + inode->i_version++; inode->i_generation = 0; inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_umask) | S_IFDIR; inode->i_op = sbi->dir_ops; @@ -569,10 +570,6 @@ sb->s_maxbytes = MAX_NON_LFS; sb->s_op = &fat_sops; - hard_blksize = get_hardsect_size(sb->s_dev); - if (!hard_blksize) - hard_blksize = 512; - opts.isvfat = sbi->options.isvfat; if (!parse_options((char *) data, &fat, &debug, &opts, cvf_format, cvf_options)) @@ -582,8 +579,7 @@ fat_cache_init(); - sb->s_blocksize = hard_blksize; - set_blocksize(sb->s_dev, hard_blksize); + sb_min_blocksize(sb, 512); bh = sb_bread(sb, 0); if (bh == NULL) { printk("FAT: unable to read boot sector\n"); @@ -625,13 +621,15 @@ goto out_invalid; } - if (logical_sector_size < hard_blksize) { + if (logical_sector_size < sb->s_blocksize) { printk("FAT: logical sector size too small for device" " (logical sector size = %d)\n", logical_sector_size); brelse(bh); goto out_invalid; } + hard_blksize = sb->s_blocksize; + sbi->cluster_bits = ffs(logical_sector_size * sbi->cluster_size) - 1; sbi->fats = b->fats; sbi->fat_start = CF_LE_W(b->reserved); @@ -716,9 +714,7 @@ if (error) goto out_invalid; - sb->s_blocksize = logical_sector_size; - sb->s_blocksize_bits = ffs(logical_sector_size) - 1; - set_blocksize(sb->s_dev, sb->s_blocksize); + sb_set_blocksize(sb, logical_sector_size); sbi->cvf_format = &default_cvf; if (!strcmp(cvf_format, "none")) i = -1; @@ -781,6 +777,7 @@ if (!root_inode) goto out_unload_nls; root_inode->i_ino = MSDOS_ROOT_INO; + root_inode->i_version = 0; fat_read_root(root_inode); insert_inode_hash(root_inode); sb->s_root = d_alloc_root(root_inode); @@ -802,7 +799,7 @@ out_invalid: if (!silent) { printk("VFS: Can't find a valid FAT filesystem on dev %s.\n", - kdevname(sb->s_dev)); + sb->s_id); } out_fail: if (opts.iocharset) { @@ -892,7 +889,7 @@ MSDOS_I(inode)->i_fat_inode = inode; inode->i_uid = sbi->options.fs_uid; inode->i_gid = sbi->options.fs_gid; - inode->i_version = ++event; + inode->i_version++; inode->i_generation = CURRENT_TIME; if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) { @@ -976,7 +973,7 @@ } lock_kernel(); if (!(bh = fat_bread(sb, i_pos >> MSDOS_SB(sb)->dir_per_block_bits))) { - printk("dev = %s, ino = %d\n", kdevname(inode->i_dev), i_pos); + printk("dev = %s, ino = %d\n", sb->s_id, i_pos); fat_fs_panic(sb, "msdos_write_inode: unable to read i-node block"); unlock_kernel(); return; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/fat/misc.c linux-2.5/fs/fat/misc.c --- linux-2.5.1/fs/fat/misc.c Fri Oct 12 20:48:42 2001 +++ linux-2.5/fs/fat/misc.c Sat Jan 5 16:38:08 2002 @@ -44,7 +44,7 @@ not_ro = !(s->s_flags & MS_RDONLY); if (not_ro) s->s_flags |= MS_RDONLY; - printk("Filesystem panic (dev %s).\n %s\n", kdevname(s->s_dev), msg); + printk("Filesystem panic (dev %s).\n %s\n", s->s_id, msg); if (not_ro) printk(" File system has been set read-only\n"); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/freevxfs/vxfs.h linux-2.5/fs/freevxfs/vxfs.h --- linux-2.5.1/fs/freevxfs/vxfs.h Mon May 21 19:31:06 2001 +++ linux-2.5/fs/freevxfs/vxfs.h Sat Jan 5 16:38:08 2002 @@ -30,7 +30,7 @@ #ifndef _VXFS_SUPER_H_ #define _VXFS_SUPER_H_ -#ident "$Id: vxfs.h 1.11 2001/05/21 15:40:28 hch Exp hch $" +#ident "$Id: vxfs.h 1.12 2001/12/28 19:48:03 hch Exp $" /* * Veritas filesystem driver - superblock structure. @@ -39,6 +39,7 @@ * superblocks of the Veritas Filesystem. */ #include <linux/types.h> +#include "vxfs_kcompat.h" /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/freevxfs/vxfs_bmap.c linux-2.5/fs/freevxfs/vxfs_bmap.c --- linux-2.5.1/fs/freevxfs/vxfs_bmap.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/freevxfs/vxfs_bmap.c Sat Jan 5 16:38:08 2002 @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ -#ident "$Id: vxfs_bmap.c,v 1.23 2001/07/05 19:48:03 hch Exp hch $" +#ident "$Id: vxfs_bmap.c,v 1.25 2002/01/02 23:36:55 hch Exp hch $" /* * Veritas filesystem driver - filesystem to disk block mapping. @@ -64,48 +64,46 @@ * The physical block number on success, else Zero. */ static daddr_t -vxfs_bmap_ext4(struct inode *ip, long iblock) +vxfs_bmap_ext4(struct inode *ip, long bn) { - struct vxfs_inode_info *vip = VXFS_INO(ip); - struct super_block *sbp = ip->i_sb; - kdev_t dev = ip->i_dev; - u_long bsize = sbp->s_blocksize; - long size = 0; - int i; + struct super_block *sb = ip->i_sb; + struct vxfs_inode_info *vip = VXFS_INO(ip); + unsigned long bsize = sb->s_blocksize; + u32 indsize = vip->vii_ext4.ve4_indsize; + int i; - for (i = 0; i < VXFS_NDADDR; i++) { - struct direct *dp = vip->vii_ext4.ve4_direct + i; - -#ifdef DIAGNOSTIC - printk(KERN_DEBUG "iblock: %ld, %d (size: %lu)\n", iblock, i, size); - printk(KERN_DEBUG "dp->extent: %d, dp->size: %d\n", dp->extent, dp->size); -#endif + if (indsize > sb->s_blocksize) + goto fail_size; - if (iblock >= size && iblock < (size + dp->size)) - return ((iblock - size) + dp->extent); - size += dp->size; + for (i = 0; i < VXFS_NDADDR; i++) { + struct direct *d = vip->vii_ext4.ve4_direct + i; + if (bn >= 0 && bn < d->size) + return (bn + d->extent); + bn -= d->size; } - iblock -= size; + if ((bn / (indsize * indsize * bsize / 4)) == 0) { + struct buffer_head *buf; + daddr_t bno; + u32 *indir; + + buf = sb_bread(sb, vip->vii_ext4.ve4_indir[0]); + if (!buf || !buffer_mapped(buf)) + goto fail_buf; - if (!(iblock / (vip->vii_ext4.ve4_indsize * vip->vii_ext4.ve4_indsize * bsize >> 2))) { - struct buffer_head *bp; - daddr_t pblock; - - /* - * XXX: is the second indir only used for - * double indirect extents? - */ - bp = bread(dev, vip->vii_ext4.ve4_indir[0], - bsize * ((vip->vii_ext4.ve4_indsize) / bsize) + 1); - pblock = *(bp->b_data + ((iblock / vip->vii_ext4.ve4_indsize) % - (vip->vii_ext4.ve4_indsize * bsize))); + indir = (u32 *)buf->b_data; + bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize); - brelse(bp); - return (pblock + (iblock % vip->vii_ext4.ve4_indsize)); + brelse(buf); + return bno; } else printk(KERN_WARNING "no matching indir?"); + return 0; + +fail_size: + printk("vxfs: indirect extent to big!\n"); +fail_buf: return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/freevxfs/vxfs_extern.h linux-2.5/fs/freevxfs/vxfs_extern.h --- linux-2.5.1/fs/freevxfs/vxfs_extern.h Sun Sep 2 17:34:36 2001 +++ linux-2.5/fs/freevxfs/vxfs_extern.h Sat Jan 5 16:38:08 2002 @@ -30,7 +30,7 @@ #ifndef _VXFS_EXTERN_H_ #define _VXFS_EXTERN_H_ -#ident "$Id: vxfs_extern.h,v 1.21 2001/08/07 16:13:30 hch Exp hch $" +#ident "$Id: vxfs_extern.h,v 1.22 2001/12/28 20:50:47 hch Exp hch $" /* * Veritas filesystem driver - external prototypes. @@ -71,7 +71,7 @@ extern int vxfs_read_olt(struct super_block *, u_long); /* vxfs_subr.c */ -extern struct page * vxfs_get_page(struct inode *, u_long); +extern struct page * vxfs_get_page(struct address_space *, u_long); extern __inline__ void vxfs_put_page(struct page *); extern struct buffer_head * vxfs_bread(struct inode *, int); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/freevxfs/vxfs_fshead.c linux-2.5/fs/freevxfs/vxfs_fshead.c --- linux-2.5.1/fs/freevxfs/vxfs_fshead.c Sun Sep 2 17:34:36 2001 +++ linux-2.5/fs/freevxfs/vxfs_fshead.c Sat Jan 5 16:38:08 2002 @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ -#ident "$Id: vxfs_fshead.c,v 1.19 2001/08/07 16:14:10 hch Exp hch $" +#ident "$Id: vxfs_fshead.c,v 1.20 2002/01/02 22:02:12 hch Exp hch $" /* * Veritas filesystem driver - fileset header routines. @@ -81,9 +81,9 @@ if (buffer_mapped(bp)) { struct vxfs_fsh *fhp; - if (!(fhp = kmalloc(sizeof(struct vxfs_fsh), SLAB_KERNEL))) + if (!(fhp = kmalloc(sizeof(*fhp), SLAB_KERNEL))) return NULL; - memcpy(fhp, bp->b_data, sizeof(struct vxfs_fsh)); + memcpy(fhp, bp->b_data, sizeof(*fhp)); brelse(bp); return (fhp); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/freevxfs/vxfs_inode.c linux-2.5/fs/freevxfs/vxfs_inode.c --- linux-2.5.1/fs/freevxfs/vxfs_inode.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/freevxfs/vxfs_inode.c Sat Jan 5 16:38:08 2002 @@ -27,12 +27,13 @@ * SUCH DAMAGE. */ -#ident "$Id: vxfs_inode.c,v 1.37 2001/08/07 16:13:30 hch Exp hch $" +#ident "$Id: vxfs_inode.c,v 1.42 2002/01/02 23:51:36 hch Exp hch $" /* * Veritas filesystem driver - inode routines. */ #include <linux/fs.h> +#include <linux/pagemap.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -47,6 +48,7 @@ extern struct inode_operations vxfs_immed_symlink_iops; static struct file_operations vxfs_file_operations = { + .open = generic_file_open, .llseek = generic_file_llseek, .read = generic_file_read, .mmap = generic_file_mmap, @@ -113,7 +115,7 @@ if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, SLAB_KERNEL))) goto fail; dip = (struct vxfs_dinode *)(bp->b_data + offset); - memcpy(vip, dip, sizeof(struct vxfs_inode_info)); + memcpy(vip, dip, sizeof(*vip)); #ifdef DIAGNOSTIC vxfs_dumpi(vip, ino); #endif @@ -145,7 +147,7 @@ u_long offset; offset = (ino % (PAGE_SIZE / VXFS_ISIZE)) * VXFS_ISIZE; - pp = vxfs_get_page(ilistp, ino * VXFS_ISIZE / PAGE_SIZE); + pp = vxfs_get_page(ilistp->i_mapping, ino * VXFS_ISIZE / PAGE_SIZE); if (!IS_ERR(pp)) { struct vxfs_inode_info *vip; @@ -155,7 +157,7 @@ if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, SLAB_KERNEL))) goto fail; dip = (struct vxfs_dinode *)(kaddr + offset); - memcpy(vip, dip, sizeof(struct vxfs_inode_info)); + memcpy(vip, dip, sizeof(*vip)); #ifdef DIAGNOSTIC vxfs_dumpi(vip, ino); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/freevxfs/vxfs_kcompat.h linux-2.5/fs/freevxfs/vxfs_kcompat.h --- linux-2.5.1/fs/freevxfs/vxfs_kcompat.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/fs/freevxfs/vxfs_kcompat.h Sat Jan 5 16:38:08 2002 @@ -0,0 +1,49 @@ +#ifndef _VXFS_KCOMPAT_H +#define _VXFS_KCOMPAT_H + +#include <linux/version.h> + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + +#include <linux/blkdev.h> + +typedef long sector_t; + +/* From include/linux/fs.h (Linux 2.5.2-pre3) */ +static inline struct buffer_head * sb_bread(struct super_block *sb, int block) +{ + return bread(sb->s_dev, block, sb->s_blocksize); +} + +/* Dito. */ +static inline void map_bh(struct buffer_head *bh, struct super_block *sb, int block) +{ + bh->b_state |= 1 << BH_Mapped; + bh->b_dev = sb->s_dev; + bh->b_blocknr = block; +} + +/* From fs/block_dev.c (Linux 2.5.2-pre2) */ +static inline int sb_set_blocksize(struct super_block *sb, int size) +{ + int bits; + if (set_blocksize(sb->s_dev, size) < 0) + return 0; + sb->s_blocksize = size; + for (bits = 9, size >>= 9; size >>= 1; bits++) + ; + sb->s_blocksize_bits = bits; + return sb->s_blocksize; +} + +/* Dito. */ +static inline int sb_min_blocksize(struct super_block *sb, int size) +{ + int minsize = get_hardsect_size(sb->s_dev); + if (size < minsize) + size = minsize; + return sb_set_blocksize(sb, size); +} + +#endif /* Kernel 2.4 */ +#endif /* _VXFS_KCOMPAT_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/freevxfs/vxfs_lookup.c linux-2.5/fs/freevxfs/vxfs_lookup.c --- linux-2.5.1/fs/freevxfs/vxfs_lookup.c Thu Jun 28 00:10:55 2001 +++ linux-2.5/fs/freevxfs/vxfs_lookup.c Sat Jan 5 16:38:08 2002 @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ -#ident "$Id: vxfs_lookup.c,v 1.19 2001/05/30 19:50:20 hch Exp hch $" +#ident "$Id: vxfs_lookup.c,v 1.21 2002/01/02 22:00:13 hch Exp hch $" /* * Veritas filesystem driver - lookup and other directory related code. @@ -126,7 +126,7 @@ caddr_t kaddr; struct page *pp; - pp = vxfs_get_page(ip, page); + pp = vxfs_get_page(ip->i_mapping, page); if (IS_ERR(pp)) continue; kaddr = (caddr_t)page_address(pp); @@ -273,7 +273,7 @@ caddr_t kaddr; struct page *pp; - pp = vxfs_get_page(ip, page); + pp = vxfs_get_page(ip->i_mapping, page); if (IS_ERR(pp)) continue; kaddr = (caddr_t)page_address(pp); @@ -318,6 +318,5 @@ done: fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2; out: - fp->f_version = ip->i_version; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/freevxfs/vxfs_olt.c linux-2.5/fs/freevxfs/vxfs_olt.c --- linux-2.5.1/fs/freevxfs/vxfs_olt.c Sun Sep 2 17:34:36 2001 +++ linux-2.5/fs/freevxfs/vxfs_olt.c Sat Jan 5 16:38:08 2002 @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ -#ident "$Id: vxfs_olt.c,v 1.9 2001/08/07 16:14:45 hch Exp hch $" +#ident "$Id: vxfs_olt.c,v 1.10 2002/01/02 23:03:58 hch Exp hch $" /* * Veritas filesystem driver - object location table support. @@ -85,14 +85,23 @@ char *oaddr, *eaddr; - bp = bread(sbp->s_dev, - vxfs_oblock(sbp, infp->vsi_oltext, bsize), bsize); + bp = sb_bread(sbp, vxfs_oblock(sbp, infp->vsi_oltext, bsize)); if (!bp || !bp->b_data) goto fail; op = (struct vxfs_olt *)bp->b_data; if (op->olt_magic != VXFS_OLT_MAGIC) { printk(KERN_NOTICE "vxfs: ivalid olt magic number\n"); + goto fail; + } + + /* + * It is in theory possible that vsi_oltsize is > 1. + * I've not seen any such filesystem yet and I'm lazy.. --hch + */ + if (infp->vsi_oltsize > 1) { + printk(KERN_NOTICE "vxfs: oltsize > 1 detected.\n"); + printk(KERN_NOTICE "vxfs: please notify hch@caldera.de\n"); goto fail; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/freevxfs/vxfs_subr.c linux-2.5/fs/freevxfs/vxfs_subr.c --- linux-2.5.1/fs/freevxfs/vxfs_subr.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/freevxfs/vxfs_subr.c Sat Jan 5 16:38:08 2002 @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ -#ident "$Id: vxfs_subr.c,v 1.5 2001/04/26 22:49:51 hch Exp hch $" +#ident "$Id: vxfs_subr.c,v 1.8 2001/12/28 20:50:47 hch Exp hch $" /* * Veritas filesystem driver - shared subroutines. @@ -37,6 +37,7 @@ #include <linux/slab.h> #include <linux/pagemap.h> +#include "vxfs_kcompat.h" #include "vxfs_extern.h" @@ -62,9 +63,8 @@ * The wanted page on success, else a NULL pointer. */ struct page * -vxfs_get_page(struct inode *ip, u_long n) +vxfs_get_page(struct address_space *mapping, u_long n) { - struct address_space * mapping = ip->i_mapping; struct page * pp; pp = read_cache_page(mapping, n, @@ -142,10 +142,7 @@ pblock = vxfs_bmap1(ip, iblock); if (pblock != 0) { - bp->b_dev = ip->i_dev; - bp->b_blocknr = pblock; - bp->b_state |= (1UL << BH_Mapped); - + map_bh(bp, ip->i_sb, pblock); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/freevxfs/vxfs_super.c linux-2.5/fs/freevxfs/vxfs_super.c --- linux-2.5.1/fs/freevxfs/vxfs_super.c Thu Oct 11 16:43:38 2001 +++ linux-2.5/fs/freevxfs/vxfs_super.c Sat Jan 5 16:38:08 2002 @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ -#ident "$Id: vxfs_super.c,v 1.26 2001/08/07 16:13:30 hch Exp hch $" +#ident "$Id: vxfs_super.c,v 1.29 2002/01/02 22:02:12 hch Exp hch $" /* * Veritas filesystem driver - superblock related routines. @@ -62,19 +62,6 @@ .statfs = vxfs_statfs, }; -static __inline__ u_long -vxfs_validate_bsize(kdev_t dev) -{ - u_long bsize; - - bsize = get_hardsect_size(dev); - if (bsize < BLOCK_SIZE) - bsize = BLOCK_SIZE; - - set_blocksize(dev, bsize); - return (bsize); -} - /** * vxfs_put_super - free superblock resources * @sbp: VFS superblock. @@ -153,21 +140,24 @@ { struct vxfs_sb_info *infp; struct vxfs_sb *rsbp; - struct buffer_head *bp; + struct buffer_head *bp = NULL; u_long bsize; - kdev_t dev = sbp->s_dev; - infp = kmalloc(sizeof(struct vxfs_sb_info), GFP_KERNEL); + infp = kmalloc(sizeof(*infp), GFP_KERNEL); if (!infp) { printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n"); return NULL; } - memset(infp, 0, sizeof(struct vxfs_sb_info)); + memset(infp, 0, sizeof(*infp)); - bsize = vxfs_validate_bsize(dev); + bsize = sb_min_blocksize(sbp, BLOCK_SIZE); + if (!bsize) { + printk(KERN_WARNING "vxfs: unable to set blocksize\n"); + goto out; + } - bp = bread(dev, 1, bsize); - if (!bp) { + bp = sb_bread(sbp, 1); + if (!bp || !buffer_mapped(bp)) { if (!silent) { printk(KERN_WARNING "vxfs: unable to read disk superblock\n"); @@ -194,31 +184,15 @@ #endif sbp->s_magic = rsbp->vs_magic; - sbp->s_blocksize = rsbp->vs_bsize; sbp->u.generic_sbp = (void *)infp; infp->vsi_raw = rsbp; infp->vsi_bp = bp; infp->vsi_oltext = rsbp->vs_oltext[0]; infp->vsi_oltsize = rsbp->vs_oltsize; - - switch (rsbp->vs_bsize) { - case 1024: - sbp->s_blocksize_bits = 10; - break; - case 2048: - sbp->s_blocksize_bits = 11; - break; - case 4096: - sbp->s_blocksize_bits = 12; - break; - default: - if (!silent) { - printk(KERN_WARNING - "vxfs: unsupported blocksise: %d\n", - rsbp->vs_bsize); - } + if (!sb_set_blocksize(sbp, rsbp->vs_bsize)) { + printk(KERN_WARNING "vxfs: unable to set final block size\n"); goto out; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/hfs/dir.c linux-2.5/fs/hfs/dir.c --- linux-2.5.1/fs/hfs/dir.c Tue Feb 13 22:13:45 2001 +++ linux-2.5/fs/hfs/dir.c Sun Dec 30 20:01:41 2001 @@ -69,8 +69,8 @@ /* * update_dirs_plus() * - * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and - * 'i_version' of the inodes associated with a directory that has + * Update the fields 'i_size', 'i_nlink', 'i_ctime' and 'i_mtime' + * of the inodes associated with a directory that has * had a file ('is_dir'==0) or directory ('is_dir'!=0) added to it. */ static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir) @@ -88,7 +88,6 @@ ++(tmp->i_nlink); } tmp->i_size += HFS_I(tmp)->dir_size; - tmp->i_version = ++event; } tmp->i_ctime = tmp->i_mtime = CURRENT_TIME; mark_inode_dirty(tmp); @@ -100,7 +99,7 @@ * update_dirs_minus() * * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and - * 'i_version' of the inodes associated with a directory that has + * of the inodes associated with a directory that has * had a file ('is_dir'==0) or directory ('is_dir'!=0) removed. */ static inline void update_dirs_minus(struct hfs_cat_entry *dir, int is_dir) @@ -118,7 +117,6 @@ --(tmp->i_nlink); } tmp->i_size -= HFS_I(tmp)->dir_size; - tmp->i_version = ++event; } tmp->i_ctime = tmp->i_mtime = CURRENT_TIME; mark_inode_dirty(tmp); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/hfs/file.c linux-2.5/fs/hfs/file.c --- linux-2.5.1/fs/hfs/file.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/hfs/file.c Thu Jan 3 00:45:28 2002 @@ -112,11 +112,9 @@ phys = hfs_extent_map(HFS_I(inode)->fork, iblock, create); if (phys) { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); if (create) bh_result->b_state |= (1UL << BH_New); + map_bh(bh_result, inode->i_sb, phys); return 0; } @@ -312,8 +310,8 @@ bhb = bhe = buflist; if (reada) { - if (blocks < read_ahead[MAJOR(dev)] / (HFS_SECTOR_SIZE>>9)) { - blocks = read_ahead[MAJOR(dev)] / (HFS_SECTOR_SIZE>>9); + if (blocks < read_ahead[major(dev)] / (HFS_SECTOR_SIZE>>9)) { + blocks = read_ahead[major(dev)] / (HFS_SECTOR_SIZE>>9); } if (block + blocks > size) { blocks = size - block; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/hfs/file_cap.c linux-2.5/fs/hfs/file_cap.c --- linux-2.5.1/fs/hfs/file_cap.c Mon Sep 10 14:31:25 2001 +++ linux-2.5/fs/hfs/file_cap.c Sun Dec 30 20:01:41 2001 @@ -103,7 +103,6 @@ if (offset != file->f_pos) { file->f_pos = offset; file->f_reada = 0; - file->f_version = ++event; } retval = offset; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/hfs/file_hdr.c linux-2.5/fs/hfs/file_hdr.c --- linux-2.5.1/fs/hfs/file_hdr.c Sun Aug 12 17:56:56 2001 +++ linux-2.5/fs/hfs/file_hdr.c Sun Dec 30 20:01:41 2001 @@ -359,7 +359,6 @@ if (offset != file->f_pos) { file->f_pos = offset; file->f_reada = 0; - file->f_version = ++event; } retval = offset; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/hfs/inode.c linux-2.5/fs/hfs/inode.c --- linux-2.5.1/fs/hfs/inode.c Wed Sep 12 22:34:06 2001 +++ linux-2.5/fs/hfs/inode.c Sat Jan 5 16:07:42 2002 @@ -311,14 +311,11 @@ return NULL; } - if (inode->i_dev != sb->s_dev) { - iput(inode); /* automatically does an hfs_cat_put */ - inode = NULL; - } else if (!inode->i_mode || (*sys_entry == NULL)) { + if (!inode->i_mode || (*sys_entry == NULL)) { /* Initialize the inode */ struct hfs_sb_info *hsb = HFS_SB(sb); - inode->i_rdev = 0; + inode->i_rdev = NODEV; inode->i_ctime = inode->i_atime = inode->i_mtime = hfs_m_to_utime(entry->modify_date); inode->i_blksize = HFS_SECTOR_SIZE; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/hfs/super.c linux-2.5/fs/hfs/super.c --- linux-2.5.1/fs/hfs/super.c Sun Dec 16 20:23:00 2001 +++ linux-2.5/fs/hfs/super.c Sat Jan 5 16:38:08 2002 @@ -401,9 +401,7 @@ } /* set the device driver to 512-byte blocks */ - set_blocksize(dev, HFS_SECTOR_SIZE); - s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS; - s->s_blocksize = HFS_SECTOR_SIZE; + sb_set_blocksize(s, HFS_SECTOR_SIZE); #ifdef CONFIG_MAC_PARTITION /* check to see if we're in a partition */ @@ -427,7 +425,7 @@ if (!mdb) { if (!silent) { hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n", - kdevname(dev)); + s->s_id); } goto bail2; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/hpfs/file.c linux-2.5/fs/hpfs/file.c --- linux-2.5.1/fs/hpfs/file.c Sun Dec 16 20:23:03 2001 +++ linux-2.5/fs/hpfs/file.c Thu Dec 27 22:10:28 2001 @@ -73,9 +73,7 @@ secno s; s = hpfs_bmap(inode, iblock); if (s) { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = s; - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh_result, inode->i_sb, s); return 0; } if (!create) return 0; @@ -89,9 +87,8 @@ } inode->i_blocks++; inode->u.hpfs_i.mmu_private += 512; - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = s; - bh_result->b_state |= (1UL << BH_Mapped) | (1UL << BH_New); + bh_result->b_state |= 1UL << BH_New; + map_bh(bh_result, inode->i_sb, s); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/hpfs/hpfs_fn.h linux-2.5/fs/hpfs/hpfs_fn.h --- linux-2.5.1/fs/hpfs/hpfs_fn.h Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/hpfs/hpfs_fn.h Sun Dec 30 21:17:30 2001 @@ -19,7 +19,6 @@ #include <linux/stat.h> #include <linux/string.h> #include <asm/bitops.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/smp_lock.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/hpfs/super.c linux-2.5/fs/hpfs/super.c --- linux-2.5.1/fs/hpfs/super.c Thu Oct 25 07:02:26 2001 +++ linux-2.5/fs/hpfs/super.c Mon Jan 14 22:39:45 2002 @@ -3,7 +3,7 @@ * * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 * - * mouning, unmounting, error handling + * mounting, unmounting, error handling */ #include <linux/string.h> @@ -362,7 +362,6 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options, int silent) { - kdev_t dev; struct buffer_head *bh0, *bh1, *bh2; struct hpfs_boot_block *bootblock; struct hpfs_super_block *superblock; @@ -408,8 +407,7 @@ } /*s->s_hpfs_mounting = 1;*/ - dev = s->s_dev; - set_blocksize(dev, 512); + sb_set_blocksize(s, 512); s->s_hpfs_fs_size = -1; if (!(bootblock = hpfs_map_sector(s, 0, &bh0, 0))) goto bail1; if (!(superblock = hpfs_map_sector(s, 16, &bh1, 1))) goto bail2; @@ -436,8 +434,6 @@ /* Fill superblock stuff */ s->s_magic = HPFS_SUPER_MAGIC; - s->s_blocksize = 512; - s->s_blocksize_bits = 9; s->s_op = &hpfs_sops; s->s_hpfs_root = superblock->root; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/inflate_fs/inflate_syms.c linux-2.5/fs/inflate_fs/inflate_syms.c --- linux-2.5.1/fs/inflate_fs/inflate_syms.c Thu Oct 25 20:53:53 2001 +++ linux-2.5/fs/inflate_fs/inflate_syms.c Thu Dec 13 16:32:36 2001 @@ -19,3 +19,4 @@ EXPORT_SYMBOL(zlib_fs_inflateReset); EXPORT_SYMBOL(zlib_fs_adler32); EXPORT_SYMBOL(zlib_fs_inflateSyncPoint); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/inode.c linux-2.5/fs/inode.c --- linux-2.5.1/fs/inode.c Mon Dec 10 22:13:25 2001 +++ linux-2.5/fs/inode.c Thu Jan 3 03:36:28 2002 @@ -17,6 +17,7 @@ #include <linux/swapctl.h> #include <linux/prefetch.h> #include <linux/locks.h> +#include <linux/compiler.h> /* * New inode.c implementation. @@ -296,6 +297,12 @@ * so we have to start looking from the list head. */ tmp = head; + + if (unlikely(current->need_resched)) { + spin_unlock(&inode_lock); + schedule(); + spin_lock(&inode_lock); + } } } @@ -382,7 +389,7 @@ /* * Search the super_blocks array for the device(s) to sync. */ - if (dev) { + if (!kdev_none(dev)) { if ((s = get_super(dev)) != NULL) { sync_inodes_sb(s); drop_super(s); @@ -826,7 +833,7 @@ inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); inode->i_sb = NULL; - inode->i_dev = 0; + inode->i_dev = NODEV; inode->i_blkbits = 0; inode->i_ino = ++last_ino; inode->i_flags = 0; @@ -1082,7 +1089,7 @@ } inodes_stat.nr_unused++; spin_unlock(&inode_lock); - if (!sb || sb->s_flags & MS_ACTIVE) + if (!sb || (sb->s_flags & MS_ACTIVE)) return; write_inode_now(inode, 1); spin_lock(&inode_lock); @@ -1207,6 +1214,8 @@ void update_atime (struct inode *inode) { + if (inode->i_atime == CURRENT_TIME) + return; if ( IS_NOATIME (inode) ) return; if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return; if ( IS_RDONLY (inode) ) return; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/dcache.c linux-2.5/fs/intermezzo/dcache.c --- linux-2.5.1/fs/intermezzo/dcache.c Tue Nov 13 17:20:56 2001 +++ linux-2.5/fs/intermezzo/dcache.c Tue Jan 8 01:17:10 2002 @@ -15,15 +15,13 @@ #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> -#include <linux/slab.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/string.h> #include <linux/intermezzo_fs.h> static int presto_dentry_revalidate(struct dentry *de, int ); -static kmem_cache_t * presto_dentry_slab; + /* called when a cache lookup succeeds */ static int presto_dentry_revalidate(struct dentry *de, int flag) @@ -49,91 +47,15 @@ } } -static void presto_d_release(struct dentry *dentry) +static void presto_dentry_iput(struct dentry *dentry, struct inode *inode) { - if (!presto_d2d(dentry)) { - /* This should really only happen in the case of a dentry - * with no inode. */ - return; - } - - presto_d2d(dentry)->dd_count--; - - if (! presto_d2d(dentry)->dd_count) { - kmem_cache_free(presto_dentry_slab, presto_d2d(dentry)); - dentry->d_fsdata = NULL; - } + dentry->d_time = 0; + iput(inode); } struct dentry_operations presto_dentry_ops = { d_revalidate: presto_dentry_revalidate, - d_release: presto_d_release + d_iput: presto_dentry_iput }; - -// XXX THIS DEPENDS ON THE KERNEL LOCK! - -void presto_set_dd(struct dentry * dentry) -{ - ENTRY; - if (dentry == NULL) - BUG(); - - if (dentry->d_fsdata) { - printk("VERY BAD: dentry: %p\n", dentry); - if (dentry->d_inode) - printk(" inode: %ld\n", dentry->d_inode->i_ino); - EXIT; - return; - } - - if (dentry->d_inode == NULL) { - dentry->d_fsdata = kmem_cache_alloc(presto_dentry_slab, - SLAB_KERNEL); - memset(dentry->d_fsdata, 0, sizeof(struct presto_dentry_data)); - presto_d2d(dentry)->dd_count = 1; - EXIT; - return; - } - - /* If there's already a dentry for this inode, share the data */ - if (dentry->d_alias.next != &dentry->d_inode->i_dentry || - dentry->d_alias.prev != &dentry->d_inode->i_dentry) { - struct dentry *de; - - if (dentry->d_alias.next != &dentry->d_inode->i_dentry) - de = list_entry(dentry->d_alias.next, struct dentry, - d_alias); - else - de = list_entry(dentry->d_alias.prev, struct dentry, - d_alias); - - dentry->d_fsdata = de->d_fsdata; - presto_d2d(dentry)->dd_count++; - EXIT; - return; - } - - dentry->d_fsdata = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL); - memset(dentry->d_fsdata, 0, sizeof(struct presto_dentry_data)); - presto_d2d(dentry)->dd_count = 1; - EXIT; - return; -} - -void presto_init_ddata_cache(void) -{ - ENTRY; - presto_dentry_slab = - kmem_cache_create("presto_cache", - sizeof(struct presto_dentry_data), 0, - SLAB_HWCACHE_ALIGN, NULL, - NULL); - EXIT; -} - -void presto_cleanup_ddata_cache(void) -{ - kmem_cache_destroy(presto_dentry_slab); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/dir.c linux-2.5/fs/intermezzo/dir.c --- linux-2.5.1/fs/intermezzo/dir.c Tue Nov 13 17:20:56 2001 +++ linux-2.5/fs/intermezzo/dir.c Tue Jan 8 01:17:10 2002 @@ -163,20 +163,13 @@ return ERR_PTR(-EPERM); } inode = iget(dir->i_sb, ino); - if (!inode || is_bad_inode(inode)) { + if (!inode || !inode->i_nlink || is_bad_inode(inode)) { CDEBUG(D_PIOCTL, "fatal: invalid inode %ld (%s).\n", ino, inode ? inode->i_nlink ? "bad inode" : "no links" : "NULL"); error = -ENOENT; EXIT; goto cleanup_iput; - } else if (inode->i_nlink == 0) { - /* This is quite evil, but we have little choice. If we were - * to iput() again with i_nlink == 0, delete_inode would get - * called again, which ext3 really Does Not Like. */ - atomic_dec(&inode->i_count); - EXIT; - return ERR_PTR(-ENOENT); } /* We need to make sure we have the right inode (by checking the @@ -216,7 +209,6 @@ unsigned int generation; ENTRY; - CDEBUG(D_CACHE, "calling presto_prep on dentry %p\n", dentry); error = presto_prep(dentry->d_parent, &cache, &fset); if ( error ) { EXIT; @@ -245,7 +237,7 @@ if (iops && iops->lookup) de = iops->lookup(dir, dentry); else { - printk("filesystem has no lookup\n"); + printk("filesystem has no lookup\n"); EXIT; goto exit; } @@ -261,8 +253,6 @@ goto exit; } - presto_set_dd(dentry); - /* some file systems set the methods in lookup, not in read_inode, as a result we should set the methods here as well as in read_inode @@ -704,7 +694,6 @@ double_down(&old_dir->i_zombie, &new_dir->i_zombie); } - // XXX this can be optimized: renamtes across filesets only require // multiple KML records, but can locally be executed normally. int presto_rename(struct inode *old_dir, struct dentry *old_dentry, @@ -724,6 +713,7 @@ EXIT; return error; } + error = presto_prep(new_parent, &new_cache, &new_fset); if ( error ) { EXIT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/ext_attr.c linux-2.5/fs/intermezzo/ext_attr.c --- linux-2.5.1/fs/intermezzo/ext_attr.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/ext_attr.c Sun Dec 30 21:17:30 2001 @@ -28,7 +28,6 @@ #include <asm/uaccess.h> #include <linux/slab.h> #include <linux/vmalloc.h> -#include <asm/segment.h> #include <linux/smp_lock.h> #include <linux/intermezzo_fs.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/file.c linux-2.5/fs/intermezzo/file.c --- linux-2.5.1/fs/intermezzo/file.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/file.c Thu Dec 13 16:32:37 2001 @@ -344,7 +344,7 @@ << file->f_dentry->d_inode->i_sb->s_blocksize_bits); error = presto_reserve_space(fset->fset_cache, res_size); - CDEBUG(D_INODE, "Reserved %Ld for %d\n", res_size, size); + CDEBUG(D_INODE, "Reserved %Ld for %Zd\n", res_size, size); if ( error ) { EXIT; return -ENOSPC; @@ -397,7 +397,7 @@ fops = filter_c2cffops(cache->cache_filter); res = fops->write(file, buf, size, off); if ( res != size ) { - CDEBUG(D_FILE, "file write returns short write: size %d, res %d\n", size, res); + CDEBUG(D_FILE, "file write returns short write: size %Zd, res %Zd\n", size, res); } if ( (res > 0) && fdata ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/inode.c linux-2.5/fs/intermezzo/inode.c --- linux-2.5.1/fs/intermezzo/inode.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/inode.c Tue Jan 8 01:17:10 2002 @@ -29,7 +29,6 @@ #include <asm/uaccess.h> #include <linux/slab.h> #include <linux/vmalloc.h> -#include <asm/segment.h> #include <linux/intermezzo_fs.h> #include <linux/intermezzo_upcall.h> @@ -47,6 +46,8 @@ void presto_set_ops(struct inode *inode, struct filter_fs *filter) { ENTRY; + if (!inode || is_bad_inode(inode)) + return; if (inode->i_gid == presto_excluded_gid ) { EXIT; CDEBUG(D_INODE, "excluded methods for %ld at %p, %p\n", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/journal.c linux-2.5/fs/intermezzo/journal.c --- linux-2.5.1/fs/intermezzo/journal.c Tue Nov 13 17:20:56 2001 +++ linux-2.5/fs/intermezzo/journal.c Tue Jan 8 01:17:10 2002 @@ -14,7 +14,6 @@ #include <linux/time.h> #include <linux/errno.h> #include <linux/locks.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/string.h> #include <linux/smp_lock.h> @@ -301,9 +300,8 @@ /* XXX needs to be done after reservation, disable ths until version 1.2 */ if ( dentry ) { - s.prevrec = cpu_to_le32(rec->offset - - presto_d2d(dentry)->dd_kml_offset); - presto_d2d(dentry)->dd_kml_offset = rec->offset; + s.prevrec = cpu_to_le32(rec->offset - dentry->d_time); + dentry->d_time = (unsigned long) rec->offset; } else { s.prevrec = -1; } @@ -1077,7 +1075,7 @@ return 0; } - CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %d\n", + CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %Zd\n", (long)lml_offset, sizeof(record)); rc = presto_fread(fset->fset_lml.fd_file, (char *)&record, sizeof(record), &offset); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/journal_ext2.c linux-2.5/fs/intermezzo/journal_ext2.c --- linux-2.5.1/fs/intermezzo/journal_ext2.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/journal_ext2.c Sun Dec 30 21:17:30 2001 @@ -12,7 +12,6 @@ #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/string.h> #include <linux/ext2_fs.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/journal_ext3.c linux-2.5/fs/intermezzo/journal_ext3.c --- linux-2.5.1/fs/intermezzo/journal_ext3.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/journal_ext3.c Sun Dec 30 21:17:30 2001 @@ -17,7 +17,6 @@ #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/string.h> #include <linux/smp_lock.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/journal_obdfs.c linux-2.5/fs/intermezzo/journal_obdfs.c --- linux-2.5.1/fs/intermezzo/journal_obdfs.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/journal_obdfs.c Sun Dec 30 21:17:30 2001 @@ -17,7 +17,6 @@ #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/string.h> #ifdef CONFIG_OBDFS_FS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/journal_reiserfs.c linux-2.5/fs/intermezzo/journal_reiserfs.c --- linux-2.5.1/fs/intermezzo/journal_reiserfs.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/journal_reiserfs.c Sun Dec 30 21:17:30 2001 @@ -17,7 +17,6 @@ #include <linux/errno.h> #include <linux/smp_lock.h> #include <linux/locks.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/string.h> #if 0 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/journal_xfs.c linux-2.5/fs/intermezzo/journal_xfs.c --- linux-2.5.1/fs/intermezzo/journal_xfs.c Tue Nov 13 17:20:56 2001 +++ linux-2.5/fs/intermezzo/journal_xfs.c Sun Dec 30 21:17:30 2001 @@ -12,7 +12,6 @@ #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/string.h> #ifdef CONFIG_FS_XFS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/kml_reint.c linux-2.5/fs/intermezzo/kml_reint.c --- linux-2.5.1/fs/intermezzo/kml_reint.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/kml_reint.c Sun Jan 13 18:08:45 2002 @@ -17,7 +17,6 @@ #include <linux/mm.h> #include <asm/uaccess.h> #include <asm/pgtable.h> -#include <asm/mmu_context.h> #include <linux/intermezzo_fs.h> #include <linux/intermezzo_kml.h> #include <linux/intermezzo_psdev.h> @@ -281,7 +280,7 @@ old_fs = get_fs(); set_fs (get_ds()); error = lento_mknod (mknod->path, mknod->mode, - MKDEV(mknod->major, mknod->minor), &info); + mk_kdev(mknod->major, mknod->minor), &info); set_fs (old_fs); kmlreint_post_secure (rec); EXIT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/presto.c linux-2.5/fs/intermezzo/presto.c --- linux-2.5.1/fs/intermezzo/presto.c Tue Nov 13 17:20:56 2001 +++ linux-2.5/fs/intermezzo/presto.c Tue Jan 8 01:17:10 2002 @@ -17,7 +17,6 @@ #include <linux/vmalloc.h> #include <linux/slab.h> #include <linux/locks.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/string.h> #include <linux/smp_lock.h> @@ -50,18 +49,16 @@ return err; } -inline struct presto_dentry_data *presto_d2d(struct dentry *dentry) + +static inline int presto_dentry_is_fsetroot(struct dentry *dentry) { - return (struct presto_dentry_data *)dentry->d_fsdata; + return ((long) dentry->d_fsdata) & PRESTO_FSETROOT; } static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry) { - if (dentry->d_fsdata == NULL) { - printk("fucked dentry: %p\n", dentry); - BUG(); - } - return presto_d2d(dentry)->dd_fset; + return (struct presto_file_set *) + (((long) dentry->d_fsdata) - PRESTO_FSETROOT); } /* find the presto minor device for this inode */ @@ -114,7 +111,7 @@ ENTRY; fsde = de; for ( ; ; ) { - if ( presto_dentry2fset(fsde) ) { + if ( presto_dentry_is_fsetroot(fsde) ) { EXIT; return presto_dentry2fset(fsde); } @@ -185,21 +182,36 @@ return 1; } + /* if it is a fsetroot, it's stored in the fset_flags */ + if ( fset && presto_dentry_is_fsetroot(dentry) ) { + EXIT; + return fset->fset_data & flag; + } + EXIT; - return (presto_d2d(dentry)->dd_flags & flag); + return ((int)dentry->d_fsdata & flag); } /* set a bit in the dentry flags */ void presto_set(struct dentry *dentry, int flag) { - ENTRY; if ( dentry->d_inode ) { CDEBUG(D_INODE, "SET ino %ld, flag %x\n", dentry->d_inode->i_ino, flag); } - presto_d2d(dentry)->dd_flags |= flag; - EXIT; + + if ( presto_dentry_is_fsetroot(dentry)) { + struct presto_file_set *fset = presto_dentry2fset(dentry); + if (fset) { + fset->fset_data |= flag; + CDEBUG(D_INODE, "Setting fset->fset_data: now %x\n", + fset->fset_data); + } + } else { + CDEBUG(D_INODE, "Setting dentry->d_fsdata\n"); + ((int)dentry->d_fsdata) |= flag; + } } /* given a path: complete the closes on the fset */ @@ -451,27 +463,39 @@ struct dentry *dentry; int error; + CDEBUG(D_INODE, "name: %s, and flag %x, or flag %x\n", + name, and_flag, or_flag); + error = presto_walk(name, &nd); if (error) return error; dentry = nd.dentry; - - CDEBUG(D_INODE, "name: %s, and flag %x, or flag %x, dd_flags %x\n", - name, and_flag, or_flag, presto_d2d(dentry)->dd_flags); - + CDEBUG(D_INODE, "dentry at %p, d_fsdata %p\n", dentry, dentry->d_fsdata); error = -ENXIO; if ( !presto_ispresto(dentry->d_inode) ) goto out; error = 0; + if ( presto_dentry_is_fsetroot(dentry) ) { + struct presto_file_set *fset = presto_dentry2fset(dentry); + CDEBUG(D_INODE, "Setting fset fset_data: fset %p\n", fset); + if ( fset ) { + fset->fset_data &= and_flag; + fset->fset_data |= or_flag; + if (res) { + *res = fset->fset_data; + } + } + CDEBUG(D_INODE, "fset %p, flags %x data %x\n", + fset, fset->fset_flags, fset->fset_data); + } else { + ((int)dentry->d_fsdata) &= and_flag; + ((int)dentry->d_fsdata) |= or_flag; + if (res) + *res = (int)dentry->d_fsdata; + } - presto_d2d(dentry)->dd_flags &= and_flag; - presto_d2d(dentry)->dd_flags |= or_flag; - if (res) - *res = presto_d2d(dentry)->dd_flags; - - // XXX this check makes no sense as d_count can change anytime. /* indicate if we were the only users while changing the flag */ if ( atomic_read(&dentry->d_count) > 1 ) error = -EBUSY; @@ -810,7 +834,6 @@ error = -EEXIST; CDEBUG(D_INODE, "\n"); - fset2 = presto_fset(dentry); if (fset2 && (fset2->fset_mtpt == dentry) ) { printk(KERN_ERR "Fsetroot already set (path %s)\n", path); @@ -825,7 +848,7 @@ fset->fset_flags = flags; fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO; - presto_d2d(dentry)->dd_fset = fset; + dentry->d_fsdata = (void *) ( ((long)fset) + PRESTO_FSETROOT ); list_add(&fset->fset_list, &cache->cache_fset_list); error = presto_init_kml_file(fset); @@ -869,15 +892,15 @@ cache->cache_flags |= CACHE_FSETROOT_SET; } - CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p, fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n", - fset, dentry, fset->fset_mtpt, fset->fset_name, cache, presto_d2d(dentry)->dd_fset); + CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p, fset %s, cache %p, d_fsdata %p\n", + fset, dentry, fset->fset_mtpt, fset->fset_name, cache, dentry->d_fsdata); EXIT; return 0; out_list_del: list_del(&fset->fset_list); - presto_d2d(dentry)->dd_fset = NULL; + dentry->d_fsdata = 0; out_dput: path_release(&fset->fset_nd); out_free: @@ -907,7 +930,7 @@ } error = -EINVAL; - if ( ! presto_dentry2fset(dentry)) { + if ( ! presto_dentry_is_fsetroot(dentry)) { EXIT; goto kml_out; } @@ -925,44 +948,12 @@ return error; } -static void presto_cleanup_fset(struct presto_file_set *fset) -{ - int error; - struct presto_cache *cache; - - ENTRY; -#ifdef CONFIG_KREINT - error = kml_cleanup (fset); - if ( error ) { - printk("InterMezzo: Closing kml for fset %s: %d\n", - fset->fset_name, error); - } -#endif - - error = presto_close_journal_file(fset); - if ( error ) { - printk("InterMezzo: Closing journal for fset %s: %d\n", - fset->fset_name, error); - } - cache = fset->fset_cache; - cache->cache_flags &= ~CACHE_FSETROOT_SET; - - list_del(&fset->fset_list); - - presto_d2d(fset->fset_mtpt)->dd_fset = NULL; - path_release(&fset->fset_nd); - - fset->fset_mtpt = NULL; - PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1); - PRESTO_FREE(fset, sizeof(*fset)); - EXIT; -} - int presto_clear_fsetroot(char *path) { struct nameidata nd; struct presto_file_set *fset; struct dentry *dentry; + struct presto_cache *cache; int error; ENTRY; @@ -980,7 +971,7 @@ } error = -EINVAL; - if ( ! presto_dentry2fset(dentry)) { + if ( ! presto_dentry_is_fsetroot(dentry)) { EXIT; goto put_out; } @@ -991,7 +982,28 @@ goto put_out; } - presto_cleanup_fset(fset); +#ifdef CONFIG_KREINT + error = kml_cleanup (fset); + if ( error ) { + printk("InterMezzo: Closing kml for fset %s: %d\n", + fset->fset_name, error); + } +#endif + + error = presto_close_journal_file(fset); + if ( error ) { + printk("InterMezzo: Closing journal for fset %s: %d\n", + fset->fset_name, error); + } + cache = fset->fset_cache; + cache->cache_flags &= ~CACHE_FSETROOT_SET; + + list_del(&fset->fset_list); + dentry->d_fsdata = 0; + path_release(&fset->fset_nd); + fset->fset_mtpt = NULL; + PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1); + PRESTO_FREE(fset, sizeof(*fset)); EXIT; put_out: @@ -1024,7 +1036,7 @@ } error = -EINVAL; - if ( ! presto_dentry2fset(dentry)) { + if ( ! presto_dentry_is_fsetroot(dentry)) { EXIT; goto put_out; } @@ -1035,18 +1047,29 @@ goto put_out; } - error = 0; + cache = fset->fset_cache; cache = fset->fset_cache; cache->cache_flags &= ~CACHE_FSETROOT_SET; tmp = &cache->cache_fset_list; tmpnext = tmp->next; while ( tmpnext != &cache->cache_fset_list) { - tmp = tmpnext; - tmpnext = tmp->next; + tmp=tmpnext; + tmpnext=tmp->next; fset = list_entry(tmp, struct presto_file_set, fset_list); - presto_cleanup_fset(fset); + + error = presto_close_journal_file(fset); + if ( error ) { + printk("InterMezzo: Closing journal for fset %s: %d\n", + fset->fset_name, error); + } + list_del(&fset->fset_list); + fset->fset_mtpt->d_fsdata = 0; + path_release(&fset->fset_nd); + fset->fset_mtpt = NULL; + PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) +1); + PRESTO_FREE(fset, sizeof(*fset)); } EXIT; @@ -1079,7 +1102,7 @@ } error = -EINVAL; - if ( ! presto_dentry2fset(dentry)) { + if ( ! presto_dentry_is_fsetroot(dentry)) { EXIT; goto kml_out; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/psdev.c linux-2.5/fs/intermezzo/psdev.c --- linux-2.5.1/fs/intermezzo/psdev.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/psdev.c Mon Jan 14 14:28:04 2002 @@ -35,6 +35,7 @@ #include <linux/sched.h> #include <linux/lp.h> #include <linux/slab.h> +#include <asm/ioctls.h> #include <linux/ioport.h> #include <linux/fcntl.h> #include <linux/delay.h> @@ -45,8 +46,8 @@ #include <linux/poll.h> #include <linux/init.h> #include <linux/list.h> +#include <linux/termios.h> #include <asm/io.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/poll.h> #include <asm/uaccess.h> @@ -77,12 +78,12 @@ { int minor; - if ( MAJOR(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) { + if ( major(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) { EXIT; return NULL; } - minor = MINOR(file->f_dentry->d_inode->i_rdev); + minor = minor(file->f_dentry->d_inode->i_rdev); if ( minor < 0 || minor >= MAX_PRESTODEV ) { EXIT; return NULL; @@ -176,7 +177,7 @@ /* move data into response buffer. */ if (req->rq_bufsize < count) { - printk("psdev_write: too much cnt: %d, cnt: %d, " + printk("psdev_write: too much cnt: %d, cnt: %Zd, " "opc: %d, uniq: %d.\n", req->rq_bufsize, count, hdr.opcode, hdr.unique); count = req->rq_bufsize; /* don't have more space! */ @@ -209,7 +210,7 @@ __FUNCTION__, kdevname(dev)); } - CDEBUG(D_PSDEV, "count %d\n", count); + CDEBUG(D_PSDEV, "count %Zd\n", count); if (list_empty(&(upccom->uc_pending))) { CDEBUG(D_UPCALL, "Empty pending list in read, not good\n"); return -EINVAL; @@ -228,7 +229,7 @@ } if (count < req->rq_bufsize) { - printk ("psdev_read: buffer too small, read %d of %d bytes\n", + printk ("psdev_read: buffer too small, read %Zd of %d bytes\n", count, req->rq_bufsize); } @@ -281,7 +282,7 @@ error = copy_from_user(&readmount, (void *)arg, sizeof(readmount)); if ( error ) { - printk("psdev: can't copy %d bytes from %p to %p\n", + printk("psdev: can't copy %Zd bytes from %p to %p\n", sizeof(readmount), (struct readmount *) arg, &readmount); EXIT; @@ -289,7 +290,7 @@ } len = readmount.io_len; - minor = MINOR(dev); + minor = minor(dev); PRESTO_ALLOC(tmp, char *, len); if (!tmp) { EXIT; @@ -469,7 +470,7 @@ input.size = size; upccom->uc_pid = saved_pid; - CDEBUG(D_PSDEV, "get_kmlsize: size = %d\n", size); + CDEBUG(D_PSDEV, "get_kmlsize: size = %Zd\n", size); EXIT; return copy_to_user((char *)arg, &input, sizeof(input)); @@ -621,12 +622,12 @@ error = copy_from_user(&kopt, (void *)arg, sizeof(kopt)); if ( error ) { - printk("psdev: can't copyin %d bytes from %p to %p\n", + printk("psdev: can't copyin %Zd bytes from %p to %p\n", sizeof(kopt), (struct kopt *) arg, &kopt); EXIT; return error; } - minor = MINOR(dev); + minor = minor(dev); if (cmd == PRESTO_SETOPT) error = dosetopt(minor, &kopt); @@ -787,7 +788,7 @@ } error = lento_mknod(input.name, input.mode, - MKDEV(input.major,input.minor),&input.info); + mk_kdev(input.major,input.minor),&input.info); EXIT; return error; } @@ -1244,7 +1245,7 @@ default: CDEBUG(D_PSDEV, "bad ioctl 0x%x, \n", cmd); - CDEBUG(D_PSDEV, "valid are 0x%x - 0x%x, 0x%x - 0x%x \n", + CDEBUG(D_PSDEV, "valid are 0x%Zx - 0x%Zx, 0x%Zx - 0x%Zx \n", PRESTO_GETMOUNT, PRESTO_GET_KMLSIZE, PRESTO_VFS_SETATTR, PRESTO_VFS_IOPEN); EXIT; @@ -1465,8 +1466,8 @@ break; /* signal is present: after timeout always return really smart idea, probably useless ... */ - if ( jiffies > req->rq_posttime + - upc_comms[minor].uc_timeout * HZ ) + if ( time_after(jiffies, req->rq_posttime + + upc_comms[minor].uc_timeout * HZ) ) break; } schedule(); @@ -1571,8 +1572,8 @@ req->rq_opcode, jiffies - req->rq_posttime, req->rq_unique, req->rq_rep_size); CDEBUG(D_UPCALL, - "..process %d woken up by Lento for req at 0x%x, data at %x\n", - current->pid, (int)req, (int)req->rq_data); + "..process %d woken up by Lento for req at 0x%p, data at %p\n", + current->pid, req, req->rq_data); if (upc_commp->uc_pid) { /* i.e. Lento is still alive */ /* Op went through, interrupt or not we go on */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/super.c linux-2.5/fs/intermezzo/super.c --- linux-2.5.1/fs/intermezzo/super.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/super.c Tue Jan 8 01:17:10 2002 @@ -159,7 +159,7 @@ { struct nameidata nd; struct dentry *dentry; - kdev_t devno = 0; + kdev_t devno = NODEV; int error; ENTRY; @@ -188,19 +188,19 @@ } devno = dentry->d_inode->i_rdev; - if ( MAJOR(devno) != PRESTO_PSDEV_MAJOR ) { + if ( major(devno) != PRESTO_PSDEV_MAJOR ) { EXIT; goto out; } - if ( MINOR(devno) >= MAX_PRESTODEV ) { + if ( minor(devno) >= MAX_PRESTODEV ) { EXIT; goto out; } EXIT; out: - *minor = MINOR(devno); + *minor = minor(devno); path_release(&nd); return 0; } @@ -319,6 +319,7 @@ goto out_err; } + cache->cache_sb = mysb; ops = filter_get_filter_fs(cache_type); @@ -347,7 +348,6 @@ &presto_dentry_ops); presto_sb->s_root->d_op = filter_c2udops(cache->cache_filter); cache->cache_mtde = mysb->s_root; - presto_set_dd(mysb->s_root); } CDEBUG(D_MALLOC, "after mounting: kmem %ld, vmem %ld\n", @@ -481,7 +481,6 @@ } presto_init_cache_hash(); - presto_init_ddata_cache(); status = register_filesystem(&presto_fs_type); if (status) { @@ -513,7 +512,7 @@ presto_psdev_cleanup(); cleanup_intermezzo_sysctl(); - presto_cleanup_ddata_cache(); + #ifdef PRESTO_DEVEL unregister_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev_devel"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/sysctl.c linux-2.5/fs/intermezzo/sysctl.c --- linux-2.5.1/fs/intermezzo/sysctl.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/sysctl.c Sun Dec 30 21:17:30 2001 @@ -16,7 +16,6 @@ #include <linux/ctype.h> #include <linux/init.h> #include <asm/bitops.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <linux/utsname.h> #include <linux/blk.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/upcall.c linux-2.5/fs/intermezzo/upcall.c --- linux-2.5.1/fs/intermezzo/upcall.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/fs/intermezzo/upcall.c Sun Dec 30 21:17:30 2001 @@ -20,7 +20,6 @@ */ #include <asm/system.h> -#include <asm/segment.h> #include <asm/signal.h> #include <linux/signal.h> @@ -37,7 +36,6 @@ #include <linux/string.h> #include <asm/uaccess.h> #include <linux/vmalloc.h> -#include <asm/segment.h> #include <linux/intermezzo_fs.h> #include <linux/intermezzo_upcall.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/intermezzo/vfs.c linux-2.5/fs/intermezzo/vfs.c --- linux-2.5.1/fs/intermezzo/vfs.c Tue Nov 13 17:20:56 2001 +++ linux-2.5/fs/intermezzo/vfs.c Tue Jan 8 01:17:10 2002 @@ -197,7 +197,7 @@ error = -EPERM; iops = filter_c2cdiops(fset->fset_cache->cache_filter); - if (!iops) { + if (!iops) { EXIT; return error; } @@ -449,8 +449,17 @@ dentry->d_inode->i_gid != presto_excluded_gid) { struct presto_cache *cache = fset->fset_cache; /* was this already done? */ - presto_set_ops(dentry->d_inode, cache->cache_filter); - + if ( !filter_c2cfiops(cache->cache_filter) ) + filter_setup_file_ops(cache->cache_filter, + dentry->d_inode, + &presto_file_iops, + &presto_file_fops); + + /* make the new inode ours */ + dentry->d_inode->i_op = + filter_c2ufiops(cache->cache_filter); + dentry->d_inode->i_fop = + filter_c2uffops(cache->cache_filter); filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, &presto_dentry_ops); @@ -480,8 +489,8 @@ presto_getversion(&new_file_ver, dentry->d_inode); if ( presto_do_kml(info, dentry->d_inode) ) error = presto_journal_create(&rec, fset, dentry, &tgt_dir_ver, - &new_file_ver, - dentry->d_inode->i_mode); + &new_file_ver, + dentry->d_inode->i_mode); presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x20); if ( presto_do_expect(info, dentry->d_inode) ) @@ -936,8 +945,15 @@ dentry->d_inode->i_gid != presto_excluded_gid) { struct presto_cache *cache = fset->fset_cache; - presto_set_ops(dentry->d_inode, cache->cache_filter); + /* was this already done? */ + if ( !filter_c2csiops(cache->cache_filter) ) + filter_setup_symlink_ops(cache->cache_filter, + dentry->d_inode, + &presto_sym_iops, + NULL); + /* make the new inode ours */ + dentry->d_inode->i_op = filter_c2usiops(cache->cache_filter); filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, &presto_dentry_ops); dentry->d_op = filter_c2udops(cache->cache_filter); @@ -1098,9 +1114,8 @@ if ( dentry->d_inode && !error && dentry->d_inode->i_gid != presto_excluded_gid) { struct presto_cache *cache = fset->fset_cache; - - presto_set_ops(dentry->d_inode, cache->cache_filter); - + /* make it ours */ + dentry->d_inode->i_op = filter_c2udiops(cache->cache_filter); filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, &presto_dentry_ops); @@ -1128,8 +1143,8 @@ presto_getversion(&new_dir_ver, dentry->d_inode); if ( presto_do_kml(info, dentry->d_inode) ) error = presto_journal_mkdir(&rec, fset, dentry, &tgt_dir_ver, - &new_dir_ver, - dentry->d_inode->i_mode); + &new_dir_ver, + dentry->d_inode->i_mode); presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x20); if ( presto_do_expect(info, dentry->d_inode) ) @@ -1398,12 +1413,15 @@ } error = iops->mknod(dir->d_inode, dentry, mode, dev); + if (error) { + EXIT; + goto exit_commit; + } if ( dentry->d_inode && dentry->d_inode->i_gid != presto_excluded_gid) { struct presto_cache *cache = fset->fset_cache; - - presto_set_ops(dentry->d_inode, cache->cache_filter); - + /* make it ours */ + dentry->d_inode->i_op = filter_c2udiops(cache->cache_filter); filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, &presto_dentry_ops); dentry->d_op = filter_c2udops(cache->cache_filter); @@ -1431,7 +1449,7 @@ error = presto_journal_mknod(&rec, fset, dentry, &tgt_dir_ver, &new_node_ver, dentry->d_inode->i_mode, - MAJOR(dev), MINOR(dev) ); + major(dev), minor(dev) ); presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x20); if ( presto_do_expect(info, dentry->d_inode) ) @@ -1439,6 +1457,7 @@ presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x30); EXIT; + exit_commit: presto_trans_commit(fset, handle); exit_lock2: unlock_kernel(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/isofs/inode.c linux-2.5/fs/isofs/inode.c --- linux-2.5.1/fs/isofs/inode.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/isofs/inode.c Sat Jan 5 16:38:08 2002 @@ -469,7 +469,6 @@ static struct super_block *isofs_read_super(struct super_block *s, void *data, int silent) { - kdev_t dev = s->s_dev; struct buffer_head * bh = NULL, *pri_bh = NULL; struct hs_primary_descriptor * h_pri = NULL; struct iso_primary_descriptor * pri = NULL; @@ -480,7 +479,6 @@ int iso_blknum, block; int orig_zonesize; int table; - unsigned int blocksize, blocksize_bits; unsigned int vol_desc_start; unsigned long first_data_zone; struct inode * inode; @@ -508,26 +506,10 @@ * larger than the blocksize the user specified, then use * that value. */ - blocksize = get_hardsect_size(dev); - if(blocksize > opt.blocksize) { - /* - * Force the blocksize we are going to use to be the - * hardware blocksize. - */ - opt.blocksize = blocksize; - } - - blocksize_bits = 0; - { - int i = opt.blocksize; - while (i != 1){ - blocksize_bits++; - i >>=1; - } - } - - set_blocksize(dev, opt.blocksize); - s->s_blocksize = opt.blocksize; + /* + * What if bugger tells us to go beyond page size? + */ + opt.blocksize = sb_min_blocksize(s, opt.blocksize); s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */ @@ -540,7 +522,7 @@ struct hs_volume_descriptor * hdp; struct iso_volume_descriptor * vdp; - block = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits); + block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits); if (!(bh = sb_bread(s, block))) goto out_no_read; @@ -651,7 +633,7 @@ * blocks that were 512 bytes (which should only very rarely * happen.) */ - if(blocksize != 0 && orig_zonesize < blocksize) + if(orig_zonesize < opt.blocksize) goto out_bad_size; /* RDE: convert log zone size to bit shift */ @@ -734,15 +716,7 @@ * entries. By forcing the blocksize in this way, we ensure * that we will never be required to do this. */ - if ( orig_zonesize != opt.blocksize ) { - set_blocksize(dev, orig_zonesize); -#ifndef BEQUIET - printk(KERN_DEBUG - "ISOFS: Forcing new log zone size:%d\n", orig_zonesize); -#endif - } - s->s_blocksize = orig_zonesize; - s->s_blocksize_bits = s -> u.isofs_sb.s_log_zone_size; + sb_set_blocksize(s, orig_zonesize); s->u.isofs_sb.s_nls_iocharset = NULL; @@ -845,7 +819,7 @@ out_no_read: printk(KERN_WARNING "isofs_read_super: " "bread failed, dev=%s, iso_blknum=%d, block=%d\n", - kdevname(dev), iso_blknum, block); + s->s_id, iso_blknum, block); goto out_unlock; out_bad_zone_size: printk(KERN_WARNING "Bad logical zone size %ld\n", @@ -853,7 +827,7 @@ goto out_freebh; out_bad_size: printk(KERN_WARNING "Logical zone size(%d) < hardware blocksize(%u)\n", - orig_zonesize, blocksize); + orig_zonesize, opt.blocksize); goto out_freebh; #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS out_no_support: @@ -890,7 +864,7 @@ * (0 == error.) */ int isofs_get_blocks(struct inode *inode, sector_t iblock, - struct buffer_head **bh_result, unsigned long nblocks) + struct buffer_head **bh, unsigned long nblocks) { unsigned long b_off; unsigned offset, sect_size; @@ -952,16 +926,14 @@ } } - if ( *bh_result ) { - (*bh_result)->b_dev = inode->i_dev; - (*bh_result)->b_blocknr = firstext + b_off - offset; - (*bh_result)->b_state |= (1UL << BH_Mapped); + if ( *bh ) { + map_bh(*bh, inode->i_sb, firstext + b_off - offset); } else { - *bh_result = sb_getblk(inode->i_sb, firstext+b_off-offset); - if ( !*bh_result ) + *bh = sb_getblk(inode->i_sb, firstext+b_off-offset); + if ( !*bh ) goto abort; } - bh_result++; /* Next buffer head */ + bh++; /* Next buffer head */ b_off++; /* Next buffer offset */ nblocks--; rv++; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/isofs/joliet.c linux-2.5/fs/isofs/joliet.c --- linux-2.5.1/fs/isofs/joliet.c Sun Aug 12 17:56:56 2001 +++ linux-2.5/fs/isofs/joliet.c Sun Dec 30 20:01:41 2001 @@ -8,7 +8,7 @@ #include <linux/string.h> #include <linux/nls.h> -#include <linux/slab.h> +#include <linux/mm.h> #include <linux/iso_fs.h> #include <asm/unaligned.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/isofs/namei.c linux-2.5/fs/isofs/namei.c --- linux-2.5.1/fs/isofs/namei.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/isofs/namei.c Sun Dec 30 20:01:41 2001 @@ -12,7 +12,7 @@ #include <linux/string.h> #include <linux/stat.h> #include <linux/fcntl.h> -#include <linux/slab.h> +#include <linux/mm.h> #include <linux/errno.h> #include <linux/config.h> /* Joliet? */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/isofs/rock.c linux-2.5/fs/isofs/rock.c --- linux-2.5.1/fs/isofs/rock.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/isofs/rock.c Tue Jan 1 23:42:42 2002 @@ -297,9 +297,9 @@ * stored in the low field, and use that. */ if((low & ~0xff) && high == 0) { - inode->i_rdev = MKDEV(low >> 8, low & 0xff); + inode->i_rdev = mk_kdev(low >> 8, low & 0xff); } else { - inode->i_rdev = MKDEV(high, low); + inode->i_rdev = mk_kdev(high, low); } } break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jbd/commit.c linux-2.5/fs/jbd/commit.c --- linux-2.5.1/fs/jbd/commit.c Fri Nov 9 22:25:04 2001 +++ linux-2.5/fs/jbd/commit.c Thu Dec 13 16:32:37 2001 @@ -47,7 +47,8 @@ struct buffer_head *wbuf[64]; int bufs; int flags; - int blocknr; + int err; + unsigned long blocknr; char *tagp = NULL; journal_header_t *header; journal_block_tag_t *tag = NULL; @@ -352,6 +353,11 @@ jbd_debug(4, "JBD: get descriptor\n"); descriptor = journal_get_descriptor_buffer(journal); + if (!descriptor) { + __journal_abort_hard(journal); + continue; + } + bh = jh2bh(descriptor); jbd_debug(4, "JBD: got buffer %ld (%p)\n", bh->b_blocknr, bh->b_data); @@ -375,7 +381,14 @@ /* Where is the buffer to be written? */ - blocknr = journal_next_log_block(journal); + err = journal_next_log_block(journal, &blocknr); + /* If the block mapping failed, just abandon the buffer + and repeat this loop: we'll fall into the + refile-on-abort condition above. */ + if (err) { + __journal_abort_hard(journal); + continue; + } /* Bump b_count to prevent truncate from stumbling over the shadowed buffer! @@@ This can go if we ever get @@ -554,16 +567,20 @@ jbd_debug(3, "JBD: commit phase 6\n"); + if (is_journal_aborted(journal)) + goto skip_commit; + /* Done it all: now write the commit record. We should have * cleaned up our previous buffers by now, so if we are in abort * mode we can now just skip the rest of the journal write * entirely. */ - if (is_journal_aborted(journal)) - goto skip_commit; - descriptor = journal_get_descriptor_buffer(journal); - + if (!descriptor) { + __journal_abort_hard(journal); + goto skip_commit; + } + /* AKPM: buglet - add `i' to tmp! */ for (i = 0; i < jh2bh(descriptor)->b_size; i += 512) { journal_header_t *tmp = diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jbd/journal.c linux-2.5/fs/jbd/journal.c --- linux-2.5.1/fs/jbd/journal.c Fri Nov 9 22:25:04 2001 +++ linux-2.5/fs/jbd/journal.c Tue Jan 8 00:44:24 2002 @@ -70,7 +70,6 @@ EXPORT_SYMBOL(journal_destroy); EXPORT_SYMBOL(journal_recover); EXPORT_SYMBOL(journal_update_superblock); -EXPORT_SYMBOL(__journal_abort); EXPORT_SYMBOL(journal_abort); EXPORT_SYMBOL(journal_errno); EXPORT_SYMBOL(journal_ack_err); @@ -461,8 +460,7 @@ printk (KERN_NOTICE __FUNCTION__ ": ENOMEM at get_unused_buffer_head, " "trying again.\n"); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } while (!new_bh); /* keep subsequent assertions sane */ @@ -477,7 +475,7 @@ new_jh->b_transaction = NULL; new_bh->b_size = jh2bh(jh_in)->b_size; - new_bh->b_dev = transaction->t_journal->j_dev; + new_bh->b_dev = to_kdev_t(transaction->t_journal->j_dev->bd_dev); new_bh->b_blocknr = blocknr; new_bh->b_state |= (1 << BH_Mapped) | (1 << BH_Dirty); @@ -606,7 +604,7 @@ * Log buffer allocation routines: */ -unsigned long journal_next_log_block(journal_t *journal) +int journal_next_log_block(journal_t *journal, unsigned long *retp) { unsigned long blocknr; @@ -617,7 +615,7 @@ journal->j_free--; if (journal->j_head == journal->j_last) journal->j_head = journal->j_first; - return journal_bmap(journal, blocknr); + return journal_bmap(journal, blocknr, retp); } /* @@ -627,17 +625,29 @@ * this is a no-op. If needed, we can use j_blk_offset - everything is * ready. */ -unsigned long journal_bmap(journal_t *journal, unsigned long blocknr) +int journal_bmap(journal_t *journal, unsigned long blocknr, + unsigned long *retp) { + int err = 0; unsigned long ret; if (journal->j_inode) { ret = bmap(journal->j_inode, blocknr); - J_ASSERT(ret != 0); + if (ret) + *retp = ret; + else { + printk (KERN_ALERT __FUNCTION__ + ": journal block not found " + "at offset %lu on %s\n", + blocknr, + bdevname(to_kdev_t(journal->j_dev->bd_dev))); + err = -EIO; + __journal_abort_soft(journal, err); + } } else { - ret = blocknr; /* +journal->j_blk_offset */ + *retp = blocknr; /* +journal->j_blk_offset */ } - return ret; + return err; } /* @@ -649,9 +659,15 @@ struct journal_head * journal_get_descriptor_buffer(journal_t *journal) { struct buffer_head *bh; - unsigned long blocknr = journal_next_log_block(journal); + unsigned long blocknr; + int err; + + err = journal_next_log_block(journal, &blocknr); - bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); + if (err) + return NULL; + + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); bh->b_state |= (1 << BH_Dirty); BUFFER_TRACE(bh, "return this buffer"); return journal_add_journal_head(bh); @@ -720,7 +736,8 @@ * must have all data blocks preallocated. */ -journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev, +journal_t * journal_init_dev(struct block_device *bdev, + struct block_device *fs_dev, int start, int len, int blocksize) { journal_t *journal = journal_init_common(); @@ -729,13 +746,13 @@ if (!journal) return NULL; - journal->j_dev = dev; + journal->j_dev = bdev; journal->j_fs_dev = fs_dev; journal->j_blk_offset = start; journal->j_maxlen = len; journal->j_blocksize = blocksize; - bh = getblk(journal->j_dev, start, journal->j_blocksize); + bh = __getblk(journal->j_dev, start, journal->j_blocksize); J_ASSERT(bh != NULL); journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; @@ -747,24 +764,33 @@ { struct buffer_head *bh; journal_t *journal = journal_init_common(); - int blocknr; + int err; + unsigned long blocknr; if (!journal) return NULL; - journal->j_dev = inode->i_dev; - journal->j_fs_dev = inode->i_dev; + journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev; journal->j_inode = inode; jbd_debug(1, "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n", - journal, bdevname(inode->i_dev), inode->i_ino, inode->i_size, + journal, inode->i_sb->s_id, inode->i_ino, + (long long) inode->i_size, inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize); journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits; journal->j_blocksize = inode->i_sb->s_blocksize; - blocknr = journal_bmap(journal, 0); - bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); + err = journal_bmap(journal, 0, &blocknr); + /* If that failed, give up */ + if (err) { + printk(KERN_ERR __FUNCTION__ ": Cannnot locate journal " + "superblock\n"); + kfree(journal); + return NULL; + } + + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); J_ASSERT(bh != NULL); journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; @@ -772,6 +798,18 @@ return journal; } +/* + * If the journal init or create aborts, we need to mark the journal + * superblock as being NULL to prevent the journal destroy from writing + * back a bogus superblock. + */ +static void journal_fail_superblock (journal_t *journal) +{ + struct buffer_head *bh = journal->j_sb_buffer; + brelse(bh); + journal->j_sb_buffer = NULL; +} + /* * Given a journal_t structure, initialise the various fields for * startup of a new journaling session. We use this both when creating @@ -817,14 +855,15 @@ int journal_create (journal_t *journal) { - int blocknr; + unsigned long blocknr; struct buffer_head *bh; journal_superblock_t *sb; - int i; + int i, err; if (journal->j_maxlen < JFS_MIN_JOURNAL_BLOCKS) { printk (KERN_ERR "Journal length (%d blocks) too short.\n", journal->j_maxlen); + journal_fail_superblock(journal); return -EINVAL; } @@ -841,17 +880,21 @@ have any blocks on disk beginning with JFS_MAGIC_NUMBER. */ jbd_debug(1, "JBD: Zeroing out journal blocks...\n"); for (i = 0; i < journal->j_maxlen; i++) { - blocknr = journal_bmap(journal, i); - bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); - wait_on_buffer(bh); + err = journal_bmap(journal, i, &blocknr); + if (err) + return err; + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); + lock_buffer(bh); memset (bh->b_data, 0, journal->j_blocksize); BUFFER_TRACE(bh, "marking dirty"); mark_buffer_dirty(bh); BUFFER_TRACE(bh, "marking uptodate"); mark_buffer_uptodate(bh, 1); + unlock_buffer(bh); __brelse(bh); } - sync_dev(journal->j_dev); + + fsync_dev(to_kdev_t(journal->j_dev->bd_dev)); jbd_debug(1, "JBD: journal cleared.\n"); /* OK, fill in the initial static fields in the new superblock */ @@ -915,7 +958,8 @@ { struct buffer_head *bh; journal_superblock_t *sb; - + int err = -EIO; + bh = journal->j_sb_buffer; J_ASSERT(bh != NULL); @@ -925,16 +969,18 @@ if (!buffer_uptodate(bh)) { printk (KERN_ERR "JBD: IO error reading journal superblock\n"); - return -EIO; + goto out; } } sb = journal->j_superblock; + err = -EINVAL; + if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) || sb->s_blocksize != htonl(journal->j_blocksize)) { printk(KERN_WARNING "JBD: no valid journal superblock found\n"); - return -EINVAL; + goto out; } switch(ntohl(sb->s_header.h_blocktype)) { @@ -946,17 +992,21 @@ break; default: printk(KERN_WARNING "JBD: unrecognised superblock format ID\n"); - return -EINVAL; + goto out; } if (ntohl(sb->s_maxlen) < journal->j_maxlen) journal->j_maxlen = ntohl(sb->s_maxlen); else if (ntohl(sb->s_maxlen) > journal->j_maxlen) { printk (KERN_WARNING "JBD: journal file too short\n"); - return -EINVAL; + goto out; } return 0; + +out: + journal_fail_superblock(journal); + return err; } /* @@ -1061,7 +1111,10 @@ /* We can now mark the journal as empty. */ journal->j_tail = 0; journal->j_tail_sequence = ++journal->j_transaction_sequence; - journal_update_superblock(journal, 1); + if (journal->j_sb_buffer) { + journal_update_superblock(journal, 1); + brelse(journal->j_sb_buffer); + } if (journal->j_inode) iput(journal->j_inode); @@ -1069,7 +1122,6 @@ journal_destroy_revoke(journal); unlock_journal(journal); - brelse(journal->j_sb_buffer); kfree(journal); MOD_DEC_USE_COUNT; } @@ -1306,14 +1358,14 @@ const char * journal_dev_name(journal_t *journal) { - kdev_t dev; + struct block_device *bdev; if (journal->j_inode) - dev = journal->j_inode->i_dev; + bdev = journal->j_inode->i_sb->s_bdev; else - dev = journal->j_dev; + bdev = journal->j_dev; - return bdevname(dev); + return bdevname(to_kdev_t(bdev->bd_dev)); } /* @@ -1356,11 +1408,16 @@ * progress). */ -/* Quick version for internal journal use (doesn't lock the journal) */ -void __journal_abort (journal_t *journal) +/* Quick version for internal journal use (doesn't lock the journal). + * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, + * and don't attempt to make any other journal updates. */ +void __journal_abort_hard (journal_t *journal) { transaction_t *transaction; + if (journal->j_flags & JFS_ABORT) + return; + printk (KERN_ERR "Aborting journal on device %s.\n", journal_dev_name(journal)); @@ -1370,23 +1427,27 @@ log_start_commit(journal, transaction); } -/* Full version for external use */ -void journal_abort (journal_t *journal, int errno) +/* Soft abort: record the abort error status in the journal superblock, + * but don't do any other IO. */ +void __journal_abort_soft (journal_t *journal, int errno) { - lock_journal(journal); - if (journal->j_flags & JFS_ABORT) - goto out; + return; if (!journal->j_errno) journal->j_errno = errno; - __journal_abort(journal); + __journal_abort_hard(journal); if (errno) journal_update_superblock(journal, 1); +} - out: +/* Full version for external use */ +void journal_abort (journal_t *journal, int errno) +{ + lock_journal(journal); + __journal_abort_soft(journal, errno); unlock_journal(journal); } @@ -1479,8 +1540,7 @@ last_warning = jiffies; } - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } @@ -1538,8 +1598,7 @@ last_warning = jiffies; } while (ret == 0) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jbd/recovery.c linux-2.5/fs/jbd/recovery.c --- linux-2.5.1/fs/jbd/recovery.c Fri Nov 9 22:25:04 2001 +++ linux-2.5/fs/jbd/recovery.c Tue Jan 8 00:44:25 2002 @@ -70,7 +70,8 @@ static int do_readahead(journal_t *journal, unsigned int start) { int err; - unsigned int max, nbufs, next, blocknr; + unsigned int max, nbufs, next; + unsigned long blocknr; struct buffer_head *bh; struct buffer_head * bufs[MAXBUF]; @@ -86,16 +87,15 @@ nbufs = 0; for (next = start; next < max; next++) { - blocknr = journal_bmap(journal, next); + err = journal_bmap(journal, next, &blocknr); - if (!blocknr) { + if (err) { printk (KERN_ERR "JBD: bad block at offset %u\n", next); - err = -EIO; goto failed; } - bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); if (!bh) { err = -ENOMEM; goto failed; @@ -132,22 +132,23 @@ static int jread(struct buffer_head **bhp, journal_t *journal, unsigned int offset) { - unsigned int blocknr; + int err; + unsigned long blocknr; struct buffer_head *bh; *bhp = NULL; J_ASSERT (offset < journal->j_maxlen); - blocknr = journal_bmap(journal, offset); + err = journal_bmap(journal, offset, &blocknr); - if (!blocknr) { + if (err) { printk (KERN_ERR "JBD: bad block at offset %u\n", offset); - return -EIO; + return err; } - bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); if (!bh) return -ENOMEM; @@ -459,8 +460,9 @@ /* Find a buffer for the new * data being restored */ - nbh = getblk(journal->j_fs_dev, blocknr, - journal->j_blocksize); + nbh = __getblk(journal->j_fs_dev, + blocknr, + journal->j_blocksize); if (nbh == NULL) { printk(KERN_ERR "JBD: Out of memory " @@ -471,6 +473,7 @@ goto failed; } + lock_buffer(nbh); memcpy(nbh->b_data, obh->b_data, journal->j_blocksize); if (flags & JFS_FLAG_ESCAPE) { @@ -484,6 +487,7 @@ mark_buffer_uptodate(nbh, 1); ++info->nr_replays; /* ll_rw_block(WRITE, 1, &nbh); */ + unlock_buffer(nbh); brelse(obh); brelse(nbh); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jbd/revoke.c linux-2.5/fs/jbd/revoke.c --- linux-2.5.1/fs/jbd/revoke.c Fri Nov 9 22:25:04 2001 +++ linux-2.5/fs/jbd/revoke.c Tue Jan 8 00:44:25 2002 @@ -137,8 +137,7 @@ if (!journal_oom_retry) return -ENOMEM; jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n"); - current->policy |= SCHED_YIELD; - schedule(); + yield(); goto repeat; } @@ -291,7 +290,7 @@ return -EINVAL; } - dev = journal->j_fs_dev; + dev = to_kdev_t(journal->j_fs_dev->bd_dev); bh = bh_in; if (!bh) { @@ -495,6 +494,8 @@ if (!descriptor) { descriptor = journal_get_descriptor_buffer(journal); + if (!descriptor) + return; header = (journal_header_t *) &jh2bh(descriptor)->b_data[0]; header->h_magic = htonl(JFS_MAGIC_NUMBER); header->h_blocktype = htonl(JFS_REVOKE_BLOCK); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jbd/transaction.c linux-2.5/fs/jbd/transaction.c --- linux-2.5.1/fs/jbd/transaction.c Fri Nov 9 22:25:04 2001 +++ linux-2.5/fs/jbd/transaction.c Tue Jan 8 00:44:25 2002 @@ -1058,21 +1058,6 @@ JBUFFER_TRACE(jh, "not on a transaction"); __journal_file_buffer(jh, handle->h_transaction, wanted_jlist); } - /* - * We need to mark the buffer dirty and refile it inside the lock to - * protect it from release by journal_try_to_free_buffer() - * - * We set ->b_flushtime to something small enough to typically keep - * kupdate away from the buffer. - * - * We don't need to do a balance_dirty() - __block_commit_write() - * does that. - */ - if (!async && !atomic_set_buffer_dirty(jh2bh(jh))) { - jh2bh(jh)->b_flushtime = - jiffies + journal->j_commit_interval + 1 * HZ; - refile_buffer(jh2bh(jh)); - } no_journal: spin_unlock(&journal_datalist_lock); if (need_brelse) { @@ -1391,9 +1376,7 @@ if (handle->h_sync) { do { old_handle_count = transaction->t_handle_count; - set_current_state(TASK_RUNNING); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } while (old_handle_count != transaction->t_handle_count); } @@ -1604,8 +1587,6 @@ assert_spin_locked(&journal_datalist_lock); - if (!buffer_jbd(bh)) - return 1; jh = bh2jh(bh); if (buffer_locked(bh) || buffer_dirty(bh)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jffs/inode-v23.c linux-2.5/fs/jffs/inode-v23.c --- linux-2.5.1/fs/jffs/inode-v23.c Thu Oct 4 22:14:35 2001 +++ linux-2.5/fs/jffs/inode-v23.c Sat Jan 5 16:38:08 2002 @@ -79,9 +79,9 @@ struct jffs_control *c; D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n", - kdevname(dev))); + sb->s_id)); - if (MAJOR(dev) != MTD_BLOCK_MAJOR) { + if (major(dev) != MTD_BLOCK_MAJOR) { printk(KERN_WARNING "JFFS: Trying to mount a " "non-mtd device.\n"); return 0; @@ -119,7 +119,7 @@ if (jffs_register_jffs_proc_dir(dev, c) < 0) { printk(KERN_WARNING "JFFS: Failed to initialize the JFFS " "proc file system for device %s.\n", - kdevname(dev)); + sb->s_id); } #endif @@ -144,7 +144,7 @@ D1(printk(KERN_NOTICE "JFFS: GC thread pid=%d.\n", (int) c->thread_pid)); D1(printk(KERN_NOTICE "JFFS: Successfully mounted device %s.\n", - kdevname(dev))); + sb->s_id)); return sb; jffs_sb_err3: @@ -153,7 +153,7 @@ jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp); jffs_sb_err1: printk(KERN_WARNING "JFFS: Failed to mount device %s.\n", - kdevname(dev)); + sb->s_id); return 0; } @@ -163,7 +163,6 @@ jffs_put_super(struct super_block *sb) { struct jffs_control *c = (struct jffs_control *) sb->u.generic_sbp; - D1(kdev_t dev = sb->s_dev); D2(printk("jffs_put_super()\n")); @@ -181,7 +180,7 @@ jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp); D1(printk(KERN_NOTICE "JFFS: Successfully unmounted device %s.\n", - kdevname(dev))); + sb->s_id)); } @@ -365,7 +364,6 @@ inode->i_ctime = raw_inode->ctime; inode->i_blksize = PAGE_SIZE; inode->i_blocks = (inode->i_size + 511) >> 9; - inode->i_version = 0; f = jffs_find_file(c, raw_inode->ino); @@ -1023,7 +1021,6 @@ from the in-memory file system structures. */ jffs_insert_node(c, del_f, &raw_inode, 0, del_node); - dir->i_version = ++event; dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); inode->i_nlink--; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jffs/jffs_fm.c linux-2.5/fs/jffs/jffs_fm.c --- linux-2.5.1/fs/jffs/jffs_fm.c Thu Oct 4 22:13:18 2001 +++ linux-2.5/fs/jffs/jffs_fm.c Wed Jan 2 12:18:05 2002 @@ -46,7 +46,7 @@ } DJM(no_jffs_fmcontrol++); - mtd = get_mtd_device(NULL, MINOR(dev)); + mtd = get_mtd_device(NULL, minor(dev)); if (!mtd) { kfree(fmc); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jffs2/background.c linux-2.5/fs/jffs2/background.c --- linux-2.5.1/fs/jffs2/background.c Thu Oct 25 07:07:09 2001 +++ linux-2.5/fs/jffs2/background.c Tue Jan 8 00:44:25 2002 @@ -106,8 +106,10 @@ sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* FIXME in the 2.2 backport */ current->nice = 10; +#endif for (;;) { spin_lock_irq(¤t->sigmask_lock); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jffs2/dir.c linux-2.5/fs/jffs2/dir.c --- linux-2.5.1/fs/jffs2/dir.c Fri Sep 14 21:04:07 2001 +++ linux-2.5/fs/jffs2/dir.c Thu Jan 3 23:04:40 2002 @@ -31,13 +31,14 @@ * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * - * $Id: dir.c,v 1.42 2001/05/24 22:24:39 dwmw2 Exp $ + * $Id: dir.c,v 1.45 2001/12/27 22:43:20 dwmw2 Exp $ * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/fs.h> +#include <linux/mtd/compatmac.h> /* For completion */ #include <linux/jffs2.h> #include <linux/jffs2_fs_i.h> #include <linux/jffs2_fs_sb.h> @@ -541,7 +542,7 @@ f = JFFS2_INODE_INFO(inode); - ri->dsize = ri->csize = strlen(target); + inode->i_size = ri->isize = ri->dsize = ri->csize = strlen(target); ri->totlen = sizeof(*ri) + ri->dsize; ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); @@ -795,7 +796,7 @@ if ((mode & S_IFMT) == S_IFBLK || (mode & S_IFMT) == S_IFCHR) { - dev = (MAJOR(to_kdev_t(rdev)) << 8) | MINOR(to_kdev_t(rdev)); + dev = (MAJOR(rdev) << 8) | MINOR(rdev); devlen = sizeof(dev); } @@ -931,20 +932,16 @@ ret = jffs2_do_unlink(old_dir_i, old_dentry, 1); if (ret) { - /* Try to delete the _new_ link to return a clean failure */ - int ret2 = jffs2_do_unlink(new_dir_i, new_dentry, 1); - if (ret2) { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); - down(&f->sem); - old_dentry->d_inode->i_nlink = f->inocache->nlink++; - up(&f->sem); + /* Oh shit. We really ought to make a single node which can do both atomically */ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); + down(&f->sem); + old_dentry->d_inode->i_nlink = f->inocache->nlink++; + up(&f->sem); - printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (old err %d, new err %d). You now have a hard link\n", ret, ret2); - /* Might as well let the VFS know */ - d_instantiate(new_dentry, old_dentry->d_inode); - atomic_inc(&old_dentry->d_inode->i_count); - } - + printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); + /* Might as well let the VFS know */ + d_instantiate(new_dentry, old_dentry->d_inode); + atomic_inc(&old_dentry->d_inode->i_count); } return ret; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jffs2/file.c linux-2.5/fs/jffs2/file.c --- linux-2.5.1/fs/jffs2/file.c Thu Oct 4 22:13:18 2001 +++ linux-2.5/fs/jffs2/file.c Thu Jan 3 23:04:40 2002 @@ -105,8 +105,8 @@ if ((inode->i_mode & S_IFMT) == S_IFBLK || (inode->i_mode & S_IFMT) == S_IFCHR) { /* For these, we don't actually need to read the old node */ - dev = (MAJOR(to_kdev_t(dentry->d_inode->i_rdev)) << 8) | - MINOR(to_kdev_t(dentry->d_inode->i_rdev)); + dev = (major(dentry->d_inode->i_rdev) << 8) | + minor(dentry->d_inode->i_rdev); mdata = (char *)&dev; mdatalen = sizeof(dev); D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jffs2/gc.c linux-2.5/fs/jffs2/gc.c --- linux-2.5.1/fs/jffs2/gc.c Thu Oct 4 22:13:18 2001 +++ linux-2.5/fs/jffs2/gc.c Thu Jan 3 23:04:40 2002 @@ -269,8 +269,8 @@ if ((inode->i_mode & S_IFMT) == S_IFBLK || (inode->i_mode & S_IFMT) == S_IFCHR) { /* For these, we don't actually need to read the old node */ - dev = (MAJOR(to_kdev_t(inode->i_rdev)) << 8) | - MINOR(to_kdev_t(inode->i_rdev)); + dev = (major(inode->i_rdev) << 8) | + minor(inode->i_rdev); mdata = (char *)&dev; mdatalen = sizeof(dev); D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jffs2/readinode.c linux-2.5/fs/jffs2/readinode.c --- linux-2.5.1/fs/jffs2/readinode.c Fri Sep 14 21:04:07 2001 +++ linux-2.5/fs/jffs2/readinode.c Wed Jan 2 12:19:28 2002 @@ -31,7 +31,7 @@ * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * - * $Id: readinode.c,v 1.56 2001/07/26 20:32:39 dwmw2 Exp $ + * $Id: readinode.c,v 1.57 2001/12/27 22:49:46 dwmw2 Exp $ * */ @@ -408,6 +408,12 @@ case S_IFLNK: inode->i_op = &jffs2_symlink_inode_operations; + /* Hack to work around broken isize in old symlink code. + Remove this when dwmw2 comes to his senses and stops + symlinks from being an entirely gratuitous special + case. */ + if (!inode->i_size) + inode->i_size = latest_node.dsize; break; case S_IFDIR: @@ -437,7 +443,7 @@ case S_IFSOCK: case S_IFIFO: inode->i_op = &jffs2_file_inode_operations; - init_special_inode(inode, inode->i_mode, kdev_t_to_nr(MKDEV(rdev>>8, rdev&0xff))); + init_special_inode(inode, inode->i_mode, kdev_t_to_nr(mk_kdev(rdev>>8, rdev&0xff))); break; default: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jffs2/super.c linux-2.5/fs/jffs2/super.c --- linux-2.5.1/fs/jffs2/super.c Thu Oct 4 22:14:35 2001 +++ linux-2.5/fs/jffs2/super.c Sat Jan 5 16:38:08 2002 @@ -197,9 +197,9 @@ struct inode *root_i; int i; - D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev))); + D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", sb->s_id)); - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) { + if (major(sb->s_dev) != MTD_BLOCK_MAJOR) { if (!silent) printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev)); return NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/jffs2/write.c linux-2.5/fs/jffs2/write.c --- linux-2.5.1/fs/jffs2/write.c Thu Oct 4 22:13:18 2001 +++ linux-2.5/fs/jffs2/write.c Sun Dec 30 20:01:41 2001 @@ -31,7 +31,7 @@ * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * - * $Id: write.c,v 1.28 2001/05/01 16:25:25 dwmw2 Exp $ + * $Id: write.c,v 1.30 2001/12/30 16:01:11 dwmw2 Exp $ * */ @@ -207,8 +207,6 @@ } raw->flash_offset = flash_ofs; raw->totlen = PAD(ri->totlen); - raw->next_in_ino = f->inocache->nodes; - f->inocache->nodes = raw; raw->next_phys = NULL; fn->ofs = ri->offset; @@ -222,6 +220,14 @@ sizeof(*ri)+datalen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ if (retlen) { + /* Doesn't belong to any inode */ + raw->next_in_ino = NULL; + + /* Don't change raw->size to match retlen. We may have + written the node header already, and only the data will + seem corrupted, in which case the scan would skip over + any node we write before the original intended end of + this node */ jffs2_add_physical_node_ref(c, raw, sizeof(*ri)+datalen, 1); jffs2_mark_node_obsolete(c, raw); } else { @@ -237,6 +243,11 @@ } /* Mark the space used */ jffs2_add_physical_node_ref(c, raw, retlen, 0); + + /* Link into per-inode list */ + raw->next_in_ino = f->inocache->nodes; + f->inocache->nodes = raw; + D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ri->dsize, ri->csize, ri->node_crc, ri->data_crc, ri->totlen)); if (writelen) *writelen = retlen; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/lockd/svclock.c linux-2.5/fs/lockd/svclock.c --- linux-2.5.1/fs/lockd/svclock.c Thu Oct 11 14:52:18 2001 +++ linux-2.5/fs/lockd/svclock.c Tue Jan 1 23:42:42 2002 @@ -306,8 +306,9 @@ struct nlm_block *block; int error; - dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", - file->f_file.f_dentry->d_inode->i_dev, + dprintk("lockd: nlmsvc_lock(%02x:%02x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", + major(file->f_file.f_dentry->d_inode->i_dev), + minor(file->f_file.f_dentry->d_inode->i_dev), file->f_file.f_dentry->d_inode->i_ino, lock->fl.fl_type, lock->fl.fl_pid, (long long)lock->fl.fl_start, @@ -385,8 +386,9 @@ { struct file_lock *fl; - dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n", - file->f_file.f_dentry->d_inode->i_dev, + dprintk("lockd: nlmsvc_testlock(%02x:%02x/%ld, ty=%d, %Ld-%Ld)\n", + major(file->f_file.f_dentry->d_inode->i_dev), + minor(file->f_file.f_dentry->d_inode->i_dev), file->f_file.f_dentry->d_inode->i_ino, lock->fl.fl_type, (long long)lock->fl.fl_start, @@ -417,8 +419,9 @@ { int error; - dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n", - file->f_file.f_dentry->d_inode->i_dev, + dprintk("lockd: nlmsvc_unlock(%02x:%02x/%ld, pi=%d, %Ld-%Ld)\n", + major(file->f_file.f_dentry->d_inode->i_dev), + minor(file->f_file.f_dentry->d_inode->i_dev), file->f_file.f_dentry->d_inode->i_ino, lock->fl.fl_pid, (long long)lock->fl.fl_start, @@ -445,8 +448,9 @@ { struct nlm_block *block; - dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n", - file->f_file.f_dentry->d_inode->i_dev, + dprintk("lockd: nlmsvc_cancel(%02x:%02x/%ld, pi=%d, %Ld-%Ld)\n", + major(file->f_file.f_dentry->d_inode->i_dev), + minor(file->f_file.f_dentry->d_inode->i_dev), file->f_file.f_dentry->d_inode->i_ino, lock->fl.fl_pid, (long long)lock->fl.fl_start, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/locks.c linux-2.5/fs/locks.c --- linux-2.5.1/fs/locks.c Thu Oct 11 14:52:18 2001 +++ linux-2.5/fs/locks.c Tue Jan 8 00:44:25 2002 @@ -445,8 +445,7 @@ /* Let the blocked process remove waiter from the * block list when it gets scheduled. */ - current->policy |= SCHED_YIELD; - schedule(); + yield(); } else { /* Remove waiter from the block list, because by the * time it wakes up blocker won't exist any more. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/minix/bitmap.c linux-2.5/fs/minix/bitmap.c --- linux-2.5.1/fs/minix/bitmap.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/minix/bitmap.c Sat Jan 5 16:38:08 2002 @@ -74,7 +74,7 @@ bh = sb->u.minix_sb.s_zmap[zone]; if (!minix_test_and_clear_bit(bit,bh->b_data)) printk("free_block (%s:%d): bit already cleared\n", - kdevname(sb->s_dev), block); + sb->s_id, block); mark_buffer_dirty(bh); return; } @@ -127,7 +127,7 @@ if (!ino || ino > sbi->s_ninodes) { printk("Bad inode number on dev %s: %ld is out of range\n", - bdevname(sb->s_dev), ino); + sb->s_id, ino); return NULL; } ino--; @@ -152,7 +152,7 @@ *bh = NULL; if (!ino || ino > sbi->s_ninodes) { printk("Bad inode number on dev %s: %ld is out of range\n", - bdevname(sb->s_dev), ino); + sb->s_id, ino); return NULL; } ino--; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/minix/inode.c linux-2.5/fs/minix/inode.c --- linux-2.5.1/fs/minix/inode.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/minix/inode.c Sat Jan 5 16:38:08 2002 @@ -126,9 +126,7 @@ struct buffer_head **map; struct minix_super_block *ms; int i, block; - kdev_t dev = s->s_dev; struct inode *root_inode; - unsigned int hblock; struct minix_sb_info *sbi = &s->u.minix_sb; /* N.B. These should be compile-time tests. @@ -138,13 +136,9 @@ if (64 != sizeof(struct minix2_inode)) panic("bad V2 i-node size"); - hblock = get_hardsect_size(dev); - if (hblock > BLOCK_SIZE) + if (!sb_set_blocksize(s, BLOCK_SIZE)) goto out_bad_hblock; - set_blocksize(dev, BLOCK_SIZE); - s->s_blocksize = BLOCK_SIZE; - s->s_blocksize_bits = BLOCK_SIZE_BITS; if (!(bh = sb_bread(s, 1))) goto out_bad_sb; @@ -214,7 +208,7 @@ /* set up enough so that it can read an inode */ s->s_op = &minix_sops; root_inode = iget(s, MINIX_ROOT_INO); - if (!root_inode) + if (!root_inode || is_bad_inode(root_inode)) goto out_no_root; s->s_root = d_alloc_root(root_inode); @@ -264,7 +258,7 @@ out_no_fs: if (!silent) printk("VFS: Can't find a Minix or Minix V2 filesystem on device " - "%s.\n", kdevname(dev)); + "%s.\n", s->s_id); out_release: brelse(bh); goto out; @@ -353,8 +347,10 @@ int i; raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh); - if (!raw_inode) + if (!raw_inode) { + make_bad_inode(inode); return; + } inode->i_mode = raw_inode->i_mode; inode->i_uid = (uid_t)raw_inode->i_uid; inode->i_gid = (gid_t)raw_inode->i_gid; @@ -378,8 +374,10 @@ int i; raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh); - if (!raw_inode) + if (!raw_inode) { + make_bad_inode(inode); return; + } inode->i_mode = raw_inode->i_mode; inode->i_uid = (uid_t)raw_inode->i_uid; inode->i_gid = (gid_t)raw_inode->i_gid; @@ -490,9 +488,8 @@ wait_on_buffer(bh); if (buffer_req(bh) && !buffer_uptodate(bh)) { - printk ("IO error syncing minix inode [" - "%s:%08lx]\n", - kdevname(inode->i_dev), inode->i_ino); + printk ("IO error syncing minix inode [%s:%08lx]\n", + inode->i_sb->s_id, inode->i_ino); err = -1; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/minix/itree_common.c linux-2.5/fs/minix/itree_common.c --- linux-2.5.1/fs/minix/itree_common.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/minix/itree_common.c Thu Dec 27 22:10:28 2001 @@ -141,7 +141,7 @@ } static inline int get_block(struct inode * inode, sector_t block, - struct buffer_head *bh_result, int create) + struct buffer_head *bh, int create) { int err = -EIO; int offsets[DEPTH]; @@ -160,9 +160,7 @@ /* Simplest case - block found, no allocation needed */ if (!partial) { got_it: - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = block_to_cpu(chain[depth-1].key); - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh, inode->i_sb, block_to_cpu(chain[depth-1].key)); /* Clean up and exit */ partial = chain+depth-1; /* the whole chain */ goto cleanup; @@ -196,7 +194,7 @@ if (splice_branch(inode, chain, partial, left) < 0) goto changed; - bh_result->b_state |= (1UL << BH_New); + bh->b_state |= (1UL << BH_New); goto got_it; changed: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/msdos/msdosfs_syms.c linux-2.5/fs/msdos/msdosfs_syms.c --- linux-2.5.1/fs/msdos/msdosfs_syms.c Mon Mar 13 20:35:39 2000 +++ linux-2.5/fs/msdos/msdosfs_syms.c Thu Dec 13 16:32:37 2001 @@ -40,3 +40,4 @@ module_init(init_msdos_fs) module_exit(exit_msdos_fs) +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/msdos/namei.c linux-2.5/fs/msdos/namei.c --- linux-2.5.1/fs/msdos/namei.c Fri Oct 12 20:48:42 2001 +++ linux-2.5/fs/msdos/namei.c Sun Dec 30 20:01:41 2001 @@ -476,7 +476,7 @@ if (error) goto out; } - new_dir->i_version = ++event; + new_dir->i_version++; /* There we go */ @@ -491,7 +491,7 @@ else MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN; mark_inode_dirty(old_inode); - old_dir->i_version = ++event; + old_dir->i_version++; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; mark_inode_dirty(old_dir); if (new_inode) { @@ -528,7 +528,7 @@ else MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN; mark_inode_dirty(old_inode); - old_dir->i_version = ++event; + old_dir->i_version++; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; mark_inode_dirty(old_dir); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/namei.c linux-2.5/fs/namei.c --- linux-2.5.1/fs/namei.c Fri Nov 30 16:41:52 2001 +++ linux-2.5/fs/namei.c Mon Jan 14 23:55:29 2002 @@ -99,16 +99,17 @@ * kernel data space before using them.. * * POSIX.1 2.4: an empty pathname is invalid (ENOENT). + * PATH_MAX includes the nul terminator --RR. */ static inline int do_getname(const char *filename, char *page) { int retval; - unsigned long len = PATH_MAX + 1; + unsigned long len = PATH_MAX; if ((unsigned long) filename >= TASK_SIZE) { if (!segment_eq(get_fs(), KERNEL_DS)) return -EFAULT; - } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX + 1) + } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX) len = TASK_SIZE - (unsigned long) filename; retval = strncpy_from_user((char *)page, filename, len); @@ -1589,7 +1590,7 @@ goto exit_lock; error = -EXDEV; - if (dir->i_dev != inode->i_dev) + if (dir->i_sb != inode->i_sb) goto exit_lock; /* @@ -1707,7 +1708,7 @@ if (error) return error; - if (new_dir->i_dev != old_dir->i_dev) + if (new_dir->i_sb != old_dir->i_sb) return -EXDEV; if (!new_dentry->d_inode) @@ -1787,7 +1788,7 @@ if (error) return error; - if (new_dir->i_dev != old_dir->i_dev) + if (new_dir->i_sb != old_dir->i_sb) return -EXDEV; if (!new_dentry->d_inode) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/namespace.c linux-2.5/fs/namespace.c --- linux-2.5.1/fs/namespace.c Thu Dec 13 08:11:09 2001 +++ linux-2.5/fs/namespace.c Sun Dec 30 20:01:41 2001 @@ -10,27 +10,26 @@ #include <linux/config.h> #include <linux/slab.h> +#include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/init.h> #include <linux/quotaops.h> #include <linux/acct.h> #include <linux/module.h> #include <linux/seq_file.h> +#include <linux/namespace.h> #include <asm/uaccess.h> -struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data); +struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data); int do_remount_sb(struct super_block *sb, int flags, void * data); void kill_super(struct super_block *sb); +int __init init_rootfs(void); static struct list_head *mount_hashtable; static int hash_mask, hash_bits; static kmem_cache_t *mnt_cache; -static LIST_HEAD(vfsmntlist); -static DECLARE_MUTEX(mount_sem); -static struct vfsmount *root_vfsmnt; - static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES); @@ -96,7 +95,7 @@ while (mnt->mnt_parent != mnt) mnt = mnt->mnt_parent; spin_unlock(&dcache_lock); - return mnt == root_vfsmnt; + return mnt == current->namespace->root; } static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) @@ -164,26 +163,29 @@ /* iterator */ static void *m_start(struct seq_file *m, loff_t *pos) { + struct namespace *n = m->private; struct list_head *p; - loff_t n = *pos; + loff_t l = *pos; - down(&mount_sem); - list_for_each(p, &vfsmntlist) - if (!n--) + down_read(&n->sem); + list_for_each(p, &n->list) + if (!l--) return list_entry(p, struct vfsmount, mnt_list); return NULL; } static void *m_next(struct seq_file *m, void *v, loff_t *pos) { + struct namespace *n = m->private; struct list_head *p = ((struct vfsmount *)v)->mnt_list.next; (*pos)++; - return p==&vfsmntlist ? NULL : list_entry(p, struct vfsmount, mnt_list); + return p==&n->list ? NULL : list_entry(p, struct vfsmount, mnt_list); } static void m_stop(struct seq_file *m, void *v) { - up(&mount_sem); + struct namespace *n = m->private; + up_read(&n->sem); } static inline void mangle(struct seq_file *m, const char *s) @@ -329,7 +331,7 @@ return retval; } - down(&mount_sem); + down_write(¤t->namespace->sem); spin_lock(&dcache_lock); if (atomic_read(&sb->s_active) == 1) { @@ -337,7 +339,7 @@ spin_unlock(&dcache_lock); lock_kernel(); DQUOT_OFF(sb); - acct_auto_close(sb->s_dev); + acct_auto_close(sb); unlock_kernel(); spin_lock(&dcache_lock); } @@ -348,7 +350,7 @@ retval = 0; } spin_unlock(&dcache_lock); - up(&mount_sem); + up_write(¤t->namespace->sem); return retval; } @@ -478,7 +480,7 @@ struct list_head head; attach_mnt(mnt, nd); list_add_tail(&head, &mnt->mnt_list); - list_splice(&head, vfsmntlist.prev); + list_splice(&head, current->namespace->list.prev); mntget(mnt); err = 0; } @@ -505,7 +507,7 @@ if (err) return err; - down(&mount_sem); + down_write(¤t->namespace->sem); err = -EINVAL; if (check_mnt(nd->mnt) && (!recurse || check_mnt(old_nd.mnt))) { err = -ENOMEM; @@ -525,7 +527,7 @@ mntput(mnt); } - up(&mount_sem); + up_write(¤t->namespace->sem); path_release(&old_nd); return err; } @@ -572,7 +574,7 @@ if (err) return err; - down(&mount_sem); + down_write(¤t->namespace->sem); while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) ; err = -EINVAL; @@ -612,7 +614,7 @@ out1: up(&nd->dentry->d_inode->i_zombie); out: - up(&mount_sem); + up_write(¤t->namespace->sem); if (!err) path_release(&parent_nd); path_release(&old_nd); @@ -622,13 +624,22 @@ static int do_add_mount(struct nameidata *nd, char *type, int flags, int mnt_flags, char *name, void *data) { - struct vfsmount *mnt = do_kern_mount(type, flags, name, data); - int err = PTR_ERR(mnt); + struct vfsmount *mnt; + int err; + + if (!type || !memchr(type, 0, PAGE_SIZE)) + return -EINVAL; + /* we need capabilities... */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + mnt = do_kern_mount(type, flags, name, data); + err = PTR_ERR(mnt); if (IS_ERR(mnt)) goto out; - down(&mount_sem); + down_write(¤t->namespace->sem); /* Something was mounted here while we slept */ while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) ; @@ -644,7 +655,7 @@ mnt->mnt_flags = mnt_flags; err = graft_tree(mnt, nd); unlock: - up(&mount_sem); + up_write(¤t->namespace->sem); mntput(mnt); out: return err; @@ -744,6 +755,86 @@ return retval; } +int copy_namespace(int flags, struct task_struct *tsk) +{ + struct namespace *namespace = tsk->namespace; + struct namespace *new_ns; + struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; + struct fs_struct *fs = tsk->fs; + + if (!namespace) + return 0; + + get_namespace(namespace); + + if (! (flags & CLONE_NEWNS)) + return 0; + + if (!capable(CAP_SYS_ADMIN)) { + put_namespace(namespace); + return -EPERM; + } + + new_ns = kmalloc(sizeof(struct namespace *), GFP_KERNEL); + if (!new_ns) + goto out; + + atomic_set(&new_ns->count, 1); + init_rwsem(&new_ns->sem); + new_ns->root = NULL; + INIT_LIST_HEAD(&new_ns->list); + + down_write(&tsk->namespace->sem); + /* First pass: copy the tree topology */ + new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root); + spin_lock(&dcache_lock); + list_add_tail(&new_ns->list, &new_ns->root->mnt_list); + spin_unlock(&dcache_lock); + + /* Second pass: switch the tsk->fs->* elements */ + if (fs) { + struct vfsmount *p, *q; + write_lock(&fs->lock); + + p = namespace->root; + q = new_ns->root; + while (p) { + if (p == fs->rootmnt) { + rootmnt = p; + fs->rootmnt = mntget(q); + } + if (p == fs->pwdmnt) { + pwdmnt = p; + fs->pwdmnt = mntget(q); + } + if (p == fs->altrootmnt) { + altrootmnt = p; + fs->altrootmnt = mntget(q); + } + p = next_mnt(p, namespace->root); + q = next_mnt(q, new_ns->root); + } + write_unlock(&fs->lock); + } + up_write(&tsk->namespace->sem); + + tsk->namespace = new_ns; + + if (rootmnt) + mntput(rootmnt); + if (pwdmnt) + mntput(pwdmnt); + if (altrootmnt) + mntput(altrootmnt); + + put_namespace(namespace); + return 0; + +out: + put_namespace(namespace); + return -ENOMEM; +} + asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, unsigned long flags, void * data) { @@ -862,7 +953,7 @@ user_nd.mnt = mntget(current->fs->rootmnt); user_nd.dentry = dget(current->fs->root); read_unlock(¤t->fs->lock); - down(&mount_sem); + down_write(¤t->namespace->sem); down(&old_nd.dentry->d_inode->i_zombie); error = -EINVAL; if (!check_mnt(user_nd.mnt)) @@ -907,7 +998,7 @@ path_release(&parent_nd); out2: up(&old_nd.dentry->d_inode->i_zombie); - up(&mount_sem); + up_write(¤t->namespace->sem); path_release(&user_nd); path_release(&old_nd); out1: @@ -920,95 +1011,34 @@ goto out2; } -/* - * Absolutely minimal fake fs - only empty root directory and nothing else. - * In 2.5 we'll use ramfs or tmpfs, but for now it's all we need - just - * something to go with root vfsmount. - */ -static struct inode_operations rootfs_dir_inode_operations; -static struct file_operations rootfs_dir_operations; -static int rootfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - struct inode * inode = new_inode(dir->i_sb); - int error = -ENOSPC; - if (inode) { - inode->i_mode = S_IFDIR|mode; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_op = &rootfs_dir_inode_operations; - inode->i_fop = &rootfs_dir_operations; - d_instantiate(dentry, inode); - dget(dentry); - error = 0; - } - return error; -} -static int rootfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) -{ - struct inode * inode = new_inode(dir->i_sb); - int error = -ENOSPC; - if (inode) { - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - init_special_inode(inode, mode, dev); - d_instantiate(dentry, inode); - dget(dentry); - error = 0; - } - return error; -} -static int rootfs_unlink(struct inode * dir, struct dentry *dentry) -{ - dentry->d_inode->i_nlink--; - dput(dentry); - return 0; -} -static struct dentry *rootfs_lookup(struct inode *dir, struct dentry *dentry) -{ - d_add(dentry, NULL); - return NULL; -} -static struct file_operations rootfs_dir_operations = { - read: generic_read_dir, - readdir: dcache_readdir, -}; -static struct inode_operations rootfs_dir_inode_operations = { - lookup: rootfs_lookup, - mkdir: rootfs_mkdir, - mknod: rootfs_mknod, - unlink: rootfs_unlink, -}; -static struct super_block *rootfs_read_super(struct super_block * sb, void * data, int silent) +static void __init init_mount_tree(void) { - struct inode * inode; - struct dentry * root; - static struct super_operations s_ops = {}; - sb->s_op = &s_ops; - inode = new_inode(sb); - if (!inode) - return NULL; - inode->i_mode = S_IFDIR|0555; - inode->i_uid = inode->i_gid = 0; - inode->i_op = &rootfs_dir_inode_operations; - inode->i_fop = &rootfs_dir_operations; - root = d_alloc_root(inode); - if (!root) { - iput(inode); - return NULL; + struct vfsmount *mnt; + struct namespace *namespace; + struct task_struct *p; + + mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); + if (IS_ERR(mnt)) + panic("Can't create rootfs"); + namespace = kmalloc(sizeof(*namespace), GFP_KERNEL); + if (!namespace) + panic("Can't allocate initial namespace"); + atomic_set(&namespace->count, 1); + INIT_LIST_HEAD(&namespace->list); + init_rwsem(&namespace->sem); + list_add(&mnt->mnt_list, &namespace->list); + namespace->root = mnt; + + init_task.namespace = namespace; + read_lock(&tasklist_lock); + for_each_task(p) { + get_namespace(namespace); + p->namespace = namespace; } - sb->s_root = root; - return sb; -} -static DECLARE_FSTYPE(root_fs_type, "rootfs", rootfs_read_super, FS_NOMOUNT); + read_unlock(&tasklist_lock); -static void __init init_mount_tree(void) -{ - register_filesystem(&root_fs_type); - root_vfsmnt = do_kern_mount("rootfs", 0, "rootfs", NULL); - if (IS_ERR(root_vfsmnt)) - panic("can't allocate root vfsmount"); - set_fs_pwd(current->fs, root_vfsmnt, root_vfsmnt->mnt_root); - set_fs_root(current->fs, root_vfsmnt, root_vfsmnt->mnt_root); + set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root); + set_fs_root(current->fs, namespace->root, namespace->root->mnt_root); } void __init mnt_init(unsigned long mempages) @@ -1066,5 +1096,6 @@ d++; i--; } while (i); + init_rootfs(); init_mount_tree(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ncpfs/inode.c linux-2.5/fs/ncpfs/inode.c --- linux-2.5.1/fs/ncpfs/inode.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/ncpfs/inode.c Wed Jan 2 17:23:52 2002 @@ -181,7 +181,7 @@ inode->i_nlink = 1; inode->i_uid = server->m.uid; inode->i_gid = server->m.gid; - inode->i_rdev = 0; + inode->i_rdev = NODEV; inode->i_blksize = NCP_BLOCK_SIZE; inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ncpfs/symlink.c linux-2.5/fs/ncpfs/symlink.c --- linux-2.5.1/fs/ncpfs/symlink.c Fri Dec 29 22:07:57 2000 +++ linux-2.5/fs/ncpfs/symlink.c Sun Dec 30 21:17:30 2001 @@ -21,7 +21,6 @@ #ifdef CONFIG_NCPFS_EXTRAS #include <asm/uaccess.h> -#include <asm/segment.h> #include <linux/errno.h> #include <linux/fs.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfs/dir.c linux-2.5/fs/nfs/dir.c --- linux-2.5.1/fs/nfs/dir.c Tue Jun 12 18:15:08 2001 +++ linux-2.5/fs/nfs/dir.c Sat Jan 5 16:38:08 2002 @@ -643,8 +643,8 @@ struct nfs_fh fhandle; int error; - dfprintk(VFS, "NFS: create(%x/%ld, %s\n", - dir->i_dev, dir->i_ino, dentry->d_name.name); + dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id, + dir->i_ino, dentry->d_name.name); attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; @@ -675,8 +675,8 @@ struct nfs_fh fhandle; int error; - dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n", - dir->i_dev, dir->i_ino, dentry->d_name.name); + dfprintk(VFS, "NFS: mknod(%s/%ld, %s\n", dir->i_sb->s_id, + dir->i_ino, dentry->d_name.name); attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; @@ -701,8 +701,8 @@ struct nfs_fh fhandle; int error; - dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n", - dir->i_dev, dir->i_ino, dentry->d_name.name); + dfprintk(VFS, "NFS: mkdir(%s/%ld, %s\n", dir->i_sb->s_id, + dir->i_ino, dentry->d_name.name); attr.ia_valid = ATTR_MODE; attr.ia_mode = mode | S_IFDIR; @@ -730,8 +730,8 @@ { int error; - dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n", - dir->i_dev, dir->i_ino, dentry->d_name.name); + dfprintk(VFS, "NFS: rmdir(%s/%ld, %s\n", dir->i_sb->s_id, + dir->i_ino, dentry->d_name.name); nfs_zap_caches(dir); error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); @@ -877,8 +877,8 @@ { int error; - dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n", - dir->i_dev, dir->i_ino, dentry->d_name.name); + dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id, + dir->i_ino, dentry->d_name.name); error = nfs_sillyrename(dir, dentry); if (error && error != -EBUSY) { @@ -900,8 +900,8 @@ unsigned int maxlen; int error; - dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n", - dir->i_dev, dir->i_ino, dentry->d_name.name, symname); + dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id, + dir->i_ino, dentry->d_name.name, symname); error = -ENAMETOOLONG; maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfs/file.c linux-2.5/fs/nfs/file.c --- linux-2.5.1/fs/nfs/file.c Sun Sep 23 16:48:01 2001 +++ linux-2.5/fs/nfs/file.c Sun Jan 13 22:25:59 2002 @@ -73,7 +73,7 @@ struct inode *inode = file->f_dentry->d_inode; int status; - dfprintk(VFS, "nfs: flush(%x/%ld)\n", inode->i_dev, inode->i_ino); + dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); /* Make sure all async reads have been sent off. We don't bother * waiting on them though... */ @@ -132,7 +132,7 @@ struct inode *inode = dentry->d_inode; int status; - dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino); + dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); lock_kernel(); status = nfs_wb_file(inode, file); @@ -161,15 +161,10 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) { long status; - loff_t pos = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + to; - struct inode *inode = page->mapping->host; lock_kernel(); status = nfs_updatepage(file, page, offset, to-offset); unlock_kernel(); - /* most likely it's already done. CHECKME */ - if (pos > inode->i_size) - inode->i_size = pos; return status; } @@ -249,9 +244,10 @@ { struct inode * inode = filp->f_dentry->d_inode; int status = 0; + int status2; - dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n", - inode->i_dev, inode->i_ino, + dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n", + inode->i_sb->s_id, inode->i_ino, fl->fl_type, fl->fl_flags, (long long)fl->fl_start, (long long)fl->fl_end); @@ -283,11 +279,15 @@ * Flush all pending writes before doing anything * with locks.. */ - filemap_fdatasync(inode->i_mapping); + status = filemap_fdatasync(inode->i_mapping); down(&inode->i_sem); - status = nfs_wb_all(inode); + status2 = nfs_wb_all(inode); + if (status2 && !status) + status = status2; up(&inode->i_sem); - filemap_fdatawait(inode->i_mapping); + status2 = filemap_fdatawait(inode->i_mapping); + if (status2 && !status) + status = status2; if (status < 0) return status; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfs/inode.c linux-2.5/fs/nfs/inode.c --- linux-2.5.1/fs/nfs/inode.c Sat Nov 24 21:17:18 2001 +++ linux-2.5/fs/nfs/inode.c Tue Jan 8 00:44:25 2002 @@ -104,20 +104,13 @@ { inode->i_blksize = inode->i_sb->s_blocksize; inode->i_mode = 0; - inode->i_rdev = 0; + inode->i_rdev = NODEV; /* We can't support UPDATE_ATIME(), since the server will reset it */ inode->i_flags |= S_NOATIME; - NFS_FILEID(inode) = 0; - NFS_FSID(inode) = 0; - NFS_FLAGS(inode) = 0; INIT_LIST_HEAD(&inode->u.nfs_i.read); INIT_LIST_HEAD(&inode->u.nfs_i.dirty); INIT_LIST_HEAD(&inode->u.nfs_i.commit); INIT_LIST_HEAD(&inode->u.nfs_i.writeback); - inode->u.nfs_i.nread = 0; - inode->u.nfs_i.ndirty = 0; - inode->u.nfs_i.ncommit = 0; - inode->u.nfs_i.npages = 0; NFS_CACHEINV(inode); NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; @@ -134,7 +127,7 @@ static void nfs_delete_inode(struct inode * inode) { - dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino); + dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); /* * The following can never actually happen... @@ -278,6 +271,9 @@ struct nfs_fsinfo fsinfo; int tcp, version, maxlen; + /* We probably want something more informative here */ + snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", major(sb->s_dev), minor(sb->s_dev)); + memset(&sb->u.nfs_sb, 0, sizeof(sb->u.nfs_sb)); if (!data) goto out_miss_args; @@ -655,19 +651,6 @@ inode->i_op = &nfs_symlink_inode_operations; else init_special_inode(inode, inode->i_mode, fattr->rdev); - /* - * Preset the size and mtime, as there's no need - * to invalidate the caches. - */ - inode->i_size = nfs_size_to_loff_t(fattr->size); - inode->i_mtime = nfs_time_to_secs(fattr->mtime); - inode->i_atime = nfs_time_to_secs(fattr->atime); - inode->i_ctime = nfs_time_to_secs(fattr->ctime); - NFS_CACHE_CTIME(inode) = fattr->ctime; - NFS_CACHE_MTIME(inode) = fattr->mtime; - NFS_CACHE_ISIZE(inode) = fattr->size; - NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); - NFS_ATTRTIMEO_UPDATE(inode) = jiffies; memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)); } nfs_refresh_inode(inode, fattr); @@ -697,6 +680,9 @@ return 0; if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0) return 0; + /* Force an attribute cache update if inode->i_count == 0 */ + if (!atomic_read(&inode->i_count)) + NFS_CACHEINV(inode); return 1; } @@ -764,8 +750,9 @@ goto out_no_inode; nfs_fill_inode(inode, fh, fattr); - dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n", - inode->i_dev, (long long)NFS_FILEID(inode), + dprintk("NFS: __nfs_fhget(%s/%Ld ct=%d)\n", + inode->i_sb->s_id, + (long long)NFS_FILEID(inode), atomic_read(&inode->i_count)); out: @@ -797,7 +784,9 @@ if (!S_ISREG(inode->i_mode)) attr->ia_valid &= ~ATTR_SIZE; + filemap_fdatasync(inode->i_mapping); error = nfs_wb_all(inode); + filemap_fdatawait(inode->i_mapping); if (error) goto out; @@ -825,6 +814,8 @@ fattr.pre_ctime = NFS_CACHE_CTIME(inode); fattr.valid |= NFS_ATTR_WCC; } + /* Force an attribute cache update */ + NFS_CACHEINV(inode); error = nfs_refresh_inode(inode, &fattr); out: return error; @@ -915,8 +906,8 @@ int status = -ESTALE; struct nfs_fattr fattr; - dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n", - inode->i_dev, (long long)NFS_FILEID(inode)); + dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", + inode->i_sb->s_id, (long long)NFS_FILEID(inode)); lock_kernel(); if (!inode || is_bad_inode(inode)) @@ -937,8 +928,9 @@ status = NFS_PROTO(inode)->getattr(inode, &fattr); if (status) { - dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n", - inode->i_dev, (long long)NFS_FILEID(inode), status); + dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", + inode->i_sb->s_id, + (long long)NFS_FILEID(inode), status); if (status == -ESTALE) { NFS_FLAGS(inode) |= NFS_INO_STALE; if (inode != inode->i_sb->s_root->d_inode) @@ -949,12 +941,14 @@ status = nfs_refresh_inode(inode, &fattr); if (status) { - dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n", - inode->i_dev, (long long)NFS_FILEID(inode), status); + dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", + inode->i_sb->s_id, + (long long)NFS_FILEID(inode), status); goto out; } - dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n", - inode->i_dev, (long long)NFS_FILEID(inode)); + dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", + inode->i_sb->s_id, + (long long)NFS_FILEID(inode)); NFS_FLAGS(inode) &= ~NFS_INO_STALE; out: @@ -966,6 +960,34 @@ } /* + * nfs_fattr_obsolete - Test if attribute data is newer than cached data + * @inode: inode + * @fattr: attributes to test + * + * Avoid stuffing the attribute cache with obsolete information. + * We always accept updates if the attribute cache timed out, or if + * fattr->ctime is newer than our cached value. + * If fattr->ctime matches the cached value, we still accept the update + * if it increases the file size. + */ +static inline +int nfs_fattr_obsolete(struct inode *inode, struct nfs_fattr *fattr) +{ + s64 cdif; + + if (time_after(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) + goto out_valid; + if ((cdif = (s64)fattr->ctime - (s64)NFS_CACHE_CTIME(inode)) > 0) + goto out_valid; + /* Ugh... */ + if (cdif == 0 && fattr->size > NFS_CACHE_ISIZE(inode)) + goto out_valid; + return -1; + out_valid: + return 0; +} + +/* * Many nfs protocol calls return the new file attributes after * an operation. Here we update the inode to reflect the state * of the server's inode. @@ -982,10 +1004,11 @@ { __u64 new_size, new_mtime; loff_t new_isize; + time_t new_atime; int invalid = 0; - dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d info=0x%x)\n", - inode->i_dev, inode->i_ino, + dfprintk(VFS, "NFS: refresh_inode(%s/%ld ct=%d info=0x%x)\n", + inode->i_sb->s_id, inode->i_ino, atomic_read(&inode->i_count), fattr->valid); if (NFS_FSID(inode) != fattr->fsid || @@ -1012,13 +1035,18 @@ */ NFS_READTIME(inode) = jiffies; + new_atime = nfs_time_to_secs(fattr->atime); + /* Avoid races */ + if (nfs_fattr_obsolete(inode, fattr)) + goto out_nochange; + /* * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache. * NOT inode->i_size!!! */ if (NFS_CACHE_ISIZE(inode) != new_size) { #ifdef NFS_DEBUG_VERBOSE - printk(KERN_DEBUG "NFS: isize change on %x/%ld\n", inode->i_dev, inode->i_ino); + printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); #endif invalid = 1; } @@ -1030,7 +1058,7 @@ */ if (NFS_CACHE_MTIME(inode) != new_mtime) { #ifdef NFS_DEBUG_VERBOSE - printk(KERN_DEBUG "NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino); + printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); #endif invalid = 1; } @@ -1056,7 +1084,7 @@ NFS_CACHE_CTIME(inode) = fattr->ctime; inode->i_ctime = nfs_time_to_secs(fattr->ctime); - inode->i_atime = nfs_time_to_secs(fattr->atime); + inode->i_atime = new_atime; NFS_CACHE_MTIME(inode) = new_mtime; inode->i_mtime = nfs_time_to_secs(new_mtime); @@ -1079,9 +1107,6 @@ inode->i_blocks = fattr->du.nfs2.blocks; inode->i_blksize = fattr->du.nfs2.blocksize; } - inode->i_rdev = 0; - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) - inode->i_rdev = to_kdev_t(fattr->rdev); /* Update attrtimeo value */ if (!invalid && time_after(jiffies, NFS_ATTRTIMEO_UPDATE(inode)+NFS_ATTRTIMEO(inode))) { @@ -1093,7 +1118,10 @@ if (invalid) nfs_zap_caches(inode); return 0; - + out_nochange: + if (new_atime - inode->i_atime > 0) + inode->i_atime = new_atime; + return 0; out_changed: /* * Big trouble! The inode has become a different object. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfs/nfs2xdr.c linux-2.5/fs/nfs/nfs2xdr.c --- linux-2.5.1/fs/nfs/nfs2xdr.c Sat Nov 3 01:40:09 2001 +++ linux-2.5/fs/nfs/nfs2xdr.c Mon Dec 17 14:29:55 2001 @@ -270,14 +270,12 @@ count = ntohl(*p++); hdrlen = (u8 *) p - (u8 *) iov->iov_base; - recvd = req->rq_rlen - hdrlen; - if (p != iov[req->rq_rnr-1].iov_base) { - /* Unexpected reply header size. Punt. - * XXX: Move iovec contents to align data on page - * boundary and adjust RPC header size guess */ - printk(KERN_WARNING "NFS: Odd RPC header size in read reply: %d\n", hdrlen); - return -errno_NFSERR_IO; + if (iov->iov_len > hdrlen) { + dprintk("NFS: READ header is short. iovec will be shifted.\n"); + xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen); } + + recvd = req->rq_rlen - hdrlen; if (count > recvd) { printk(KERN_WARNING "NFS: server cheating in read reply: " "count %d > recvd %d\n", count, recvd); @@ -448,27 +446,23 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res) { struct iovec *iov = req->rq_rvec; + int hdrlen; int status, nr; u32 *end, *entry, len; if ((status = ntohl(*p++))) return -nfs_stat_to_errno(status); - if ((void *) p != ((u8 *) iov->iov_base+iov->iov_len)) { - /* Unexpected reply header size. Punt. */ - printk(KERN_WARNING "NFS: Odd RPC header size in readdirres reply\n"); - return -errno_NFSERR_IO; + + hdrlen = (u8 *) p - (u8 *) iov->iov_base; + if (iov->iov_len > hdrlen) { + dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); + xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen); } + /* Get start and end address of XDR data */ p = (u32 *) iov[1].iov_base; end = (u32 *) ((u8 *) p + iov[1].iov_len); - - /* Get start and end of dirent buffer */ - if (res->buffer != p) { - printk(KERN_ERR "NFS: Bad result buffer in readdir\n"); - return -errno_NFSERR_IO; - } - for (nr = 0; *p++; nr++) { entry = p - 1; if (p + 2 > end) @@ -598,13 +592,21 @@ static int nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res) { + struct iovec *iov = req->rq_rvec; u32 *strlen; char *string; + int hdrlen; int status; unsigned int len; if ((status = ntohl(*p++))) return -nfs_stat_to_errno(status); + hdrlen = (u8 *) p - (u8 *) iov->iov_base; + if (iov->iov_len > hdrlen) { + dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); + xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen); + } + strlen = (u32*)res->buffer; /* Convert length of symlink */ len = ntohl(*strlen); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfs/nfs3proc.c linux-2.5/fs/nfs/nfs3proc.c --- linux-2.5.1/fs/nfs/nfs3proc.c Mon Oct 1 20:45:37 2001 +++ linux-2.5/fs/nfs/nfs3proc.c Thu Dec 13 16:32:37 2001 @@ -17,6 +17,37 @@ #define NFSDBG_FACILITY NFSDBG_PROC +/* A wrapper to handle the EJUKEBOX error message */ +static int +nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) +{ + sigset_t oldset; + int res; + rpc_clnt_sigmask(clnt, &oldset); + do { + res = rpc_call_sync(clnt, msg, flags); + if (res != -EJUKEBOX) + break; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(NFS_JUKEBOX_RETRY_TIME); + res = -ERESTARTSYS; + } while (!signalled()); + rpc_clnt_sigunmask(clnt, &oldset); + return res; +} + +static inline int +nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) +{ + struct rpc_message msg = { proc, argp, resp, NULL }; + return nfs3_rpc_wrapper(clnt, &msg, flags); +} + +#define rpc_call(clnt, proc, argp, resp, flags) \ + nfs3_rpc_call_wrapper(clnt, proc, argp, resp, flags) +#define rpc_call_sync(clnt, msg, flags) \ + nfs3_rpc_wrapper(clnt, msg, flags) + /* * Bare-bones access to getattr: this is for nfs_read_super. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfs/nfsroot.c linux-2.5/fs/nfs/nfsroot.c --- linux-2.5.1/fs/nfs/nfsroot.c Thu Oct 25 07:02:26 2001 +++ linux-2.5/fs/nfs/nfsroot.c Wed Jan 2 12:18:51 2002 @@ -334,7 +334,7 @@ */ int __init nfs_root_setup(char *line) { - ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255); + ROOT_DEV = mk_kdev(UNNAMED_MAJOR, 255); if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) { strncpy(nfs_root_name, line, sizeof(nfs_root_name)); nfs_root_name[sizeof(nfs_root_name)-1] = '\0'; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfs/pagelist.c linux-2.5/fs/nfs/pagelist.c --- linux-2.5.1/fs/nfs/pagelist.c Fri Nov 9 22:28:15 2001 +++ linux-2.5/fs/nfs/pagelist.c Tue Jan 8 00:44:25 2002 @@ -96,8 +96,7 @@ continue; if (signalled() && (server->flags & NFS_MOUNT_INTR)) return ERR_PTR(-ERESTARTSYS); - current->policy = SCHED_YIELD; - schedule(); + yield(); } /* Initialize the request struct. Initially, we assume a @@ -187,7 +186,7 @@ BUG(); } #endif - for (pos = head->prev; pos != head; pos = pos->prev) { + list_for_each_prev(pos, head) { struct nfs_page *p = nfs_list_entry(pos); if (page_index(p->wb_page) < pg_idx) break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfs/read.c linux-2.5/fs/nfs/read.c --- linux-2.5.1/fs/nfs/read.c Fri Nov 9 22:28:15 2001 +++ linux-2.5/fs/nfs/read.c Sat Jan 5 16:38:09 2002 @@ -108,9 +108,10 @@ if (count < rsize) rsize = count; - dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %Ld, %d, %p)\n", + dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Ld, %d, %p)\n", NFS_SERVER(inode)->hostname, - inode->i_dev, (long long)NFS_FILEID(inode), + inode->i_sb->s_id, + (long long)NFS_FILEID(inode), (long long)offset, rsize, buffer); lock_kernel(); @@ -265,9 +266,10 @@ msg.rpc_cred = data->cred; /* Start the async call */ - dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n", + dprintk("NFS: %4d initiated read call (req %s/%Ld count %d nriov %d.\n", task->tk_pid, - inode->i_dev, (long long)NFS_FILEID(inode), + inode->i_sb->s_id, + (long long)NFS_FILEID(inode), data->args.count, data->args.nriov); rpc_clnt_sigmask(clnt, &oldset); @@ -397,28 +399,37 @@ { struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; struct inode *inode = data->inode; - int count = data->res.count; + unsigned int count = data->res.count; dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", task->tk_pid, task->tk_status); + if (nfs_async_handle_jukebox(task)) + return; + nfs_refresh_inode(inode, &data->fattr); while (!list_empty(&data->pages)) { struct nfs_page *req = nfs_list_entry(data->pages.next); struct page *page = req->wb_page; nfs_list_remove_request(req); - if (task->tk_status >= 0 && count >= 0) { + if (task->tk_status >= 0) { + if (count < PAGE_CACHE_SIZE) { + char *p = kmap(page); + memset(p + count, 0, PAGE_CACHE_SIZE - count); + kunmap(page); + count = 0; + } else + count -= PAGE_CACHE_SIZE; SetPageUptodate(page); - count -= PAGE_CACHE_SIZE; } else SetPageError(page); flush_dcache_page(page); kunmap(page); UnlockPage(page); - dprintk("NFS: read (%x/%Ld %d@%Ld)\n", - req->wb_inode->i_dev, + dprintk("NFS: read (%s/%Ld %d@%Ld)\n", + req->wb_inode->i_sb->s_id, (long long)NFS_FILEID(req->wb_inode), req->wb_bytes, (long long)(page_offset(page) + req->wb_offset)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfs/unlink.c linux-2.5/fs/nfs/unlink.c --- linux-2.5.1/fs/nfs/unlink.c Thu Aug 16 16:39:37 2001 +++ linux-2.5/fs/nfs/unlink.c Thu Dec 13 16:32:37 2001 @@ -123,6 +123,8 @@ struct dentry *dir = data->dir; struct inode *dir_i; + if (nfs_async_handle_jukebox(task)) + return; if (!dir) return; dir_i = dir->d_inode; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfs/write.c linux-2.5/fs/nfs/write.c --- linux-2.5.1/fs/nfs/write.c Tue Nov 20 22:18:50 2001 +++ linux-2.5/fs/nfs/write.c Sat Jan 5 16:38:09 2002 @@ -49,7 +49,7 @@ #include <linux/config.h> #include <linux/types.h> #include <linux/slab.h> -#include <linux/swap.h> +#include <linux/mm.h> #include <linux/pagemap.h> #include <linux/file.h> @@ -159,8 +159,9 @@ if (!cred) cred = get_rpccred(NFS_I(inode)->mm_cred); - dprintk("NFS: nfs_writepage_sync(%x/%Ld %d@%Ld)\n", - inode->i_dev, (long long)NFS_FILEID(inode), + dprintk("NFS: nfs_writepage_sync(%s/%Ld %d@%Ld)\n", + inode->i_sb->s_id, + (long long)NFS_FILEID(inode), count, (long long)(page_offset(page) + offset)); buffer = kmap(page) + offset; @@ -213,6 +214,7 @@ unsigned int offset, unsigned int count) { struct nfs_page *req; + loff_t end; int status; req = nfs_update_request(file, inode, page, offset, count); @@ -223,6 +225,10 @@ req->wb_cred = get_rpccred(NFS_I(inode)->mm_cred); nfs_unlock_request(req); nfs_strategy(inode); + end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count); + if (inode->i_size < end) + inode->i_size = end; + out: return status; } @@ -305,18 +311,30 @@ /* * Insert a write request into an inode + * Note: we sort the list in order to be able to optimize nfs_find_request() + * & co. for the 'write append' case. For 2.5 we may want to consider + * some form of hashing so as to perform well on random writes. */ static inline void nfs_inode_add_request(struct inode *inode, struct nfs_page *req) { + struct list_head *pos, *head; + unsigned long pg_idx = page_index(req->wb_page); + if (!list_empty(&req->wb_hash)) return; if (!NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: unlocked request attempted hashed!\n"); - if (list_empty(&inode->u.nfs_i.writeback)) + head = &inode->u.nfs_i.writeback; + if (list_empty(head)) igrab(inode); + list_for_each_prev(pos, head) { + struct nfs_page *entry = nfs_inode_wb_entry(pos); + if (page_index(entry->wb_page) < pg_idx) + break; + } inode->u.nfs_i.npages++; - list_add(&req->wb_hash, &inode->u.nfs_i.writeback); + list_add(&req->wb_hash, pos); req->wb_count++; } @@ -354,15 +372,18 @@ static inline struct nfs_page * _nfs_find_request(struct inode *inode, struct page *page) { - struct list_head *head, *next; + struct list_head *head, *pos; + unsigned long pg_idx = page_index(page); head = &inode->u.nfs_i.writeback; - next = head->next; - while (next != head) { - struct nfs_page *req = nfs_inode_wb_entry(next); - next = next->next; - if (page_index(req->wb_page) != page_index(page)) + list_for_each_prev(pos, head) { + struct nfs_page *req = nfs_inode_wb_entry(pos); + unsigned long found_idx = page_index(req->wb_page); + + if (pg_idx < found_idx) continue; + if (pg_idx != found_idx) + break; req->wb_count++; return req; } @@ -444,20 +465,20 @@ else idx_end = idx_start + npages - 1; - spin_lock(&nfs_wreq_lock); head = &inode->u.nfs_i.writeback; - p = head->next; - while (p != head) { + restart: + spin_lock(&nfs_wreq_lock); + list_for_each_prev(p, head) { unsigned long pg_idx; struct nfs_page *req = nfs_inode_wb_entry(p); - p = p->next; - if (file && req->wb_file != file) continue; pg_idx = page_index(req->wb_page); - if (pg_idx < idx_start || pg_idx > idx_end) + if (pg_idx < idx_start) + break; + if (pg_idx > idx_end) continue; if (!NFS_WBACK_BUSY(req)) @@ -468,9 +489,8 @@ nfs_release_request(req); if (error < 0) return error; - spin_lock(&nfs_wreq_lock); - p = head->next; res++; + goto restart; } spin_unlock(&nfs_wreq_lock); return res; @@ -781,6 +801,7 @@ struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; struct nfs_page *req; + loff_t end; int status = 0; dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n", @@ -812,6 +833,10 @@ goto done; status = 0; + end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count); + if (inode->i_size < end) + inode->i_size = end; + /* If we wrote past the end of the page. * Call the strategy routine so it can send out a bunch * of requests. @@ -924,9 +949,9 @@ msg.rpc_resp = &data->res; msg.rpc_cred = data->cred; - dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n", + dprintk("NFS: %4d initiated write call (req %s/%Ld count %d nriov %d)\n", task->tk_pid, - inode->i_dev, + inode->i_sb->s_id, (long long)NFS_FILEID(inode), data->args.count, data->args.nriov); @@ -991,6 +1016,9 @@ dprintk("NFS: %4d nfs_writeback_done (status %d)\n", task->tk_pid, task->tk_status); + if (nfs_async_handle_jukebox(task)) + return; + /* We can't handle that yet but we check for it nevertheless */ if (resp->count < argp->count && task->tk_status >= 0) { static unsigned long complain; @@ -1039,8 +1067,8 @@ kunmap(page); - dprintk("NFS: write (%x/%Ld %d@%Ld)", - req->wb_inode->i_dev, + dprintk("NFS: write (%s/%Ld %d@%Ld)", + req->wb_inode->i_sb->s_id, (long long)NFS_FILEID(req->wb_inode), req->wb_bytes, (long long)(page_offset(page) + req->wb_offset)); @@ -1184,13 +1212,16 @@ dprintk("NFS: %4d nfs_commit_done (status %d)\n", task->tk_pid, task->tk_status); + if (nfs_async_handle_jukebox(task)) + return; + nfs_write_attributes(inode, resp->fattr); while (!list_empty(&data->pages)) { req = nfs_list_entry(data->pages.next); nfs_list_remove_request(req); - dprintk("NFS: commit (%x/%Ld %d@%Ld)", - req->wb_inode->i_dev, + dprintk("NFS: commit (%s/%Ld %d@%Ld)", + req->wb_inode->i_sb->s_id, (long long)NFS_FILEID(req->wb_inode), req->wb_bytes, (long long)(page_offset(req->wb_page) + req->wb_offset)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfsd/export.c linux-2.5/fs/nfsd/export.c --- linux-2.5.1/fs/nfsd/export.c Thu Oct 4 05:57:36 2001 +++ linux-2.5/fs/nfsd/export.c Tue Jan 1 23:42:42 2002 @@ -16,6 +16,7 @@ #include <linux/unistd.h> #include <linux/slab.h> +#include <linux/sched.h> #include <linux/stat.h> #include <linux/in.h> @@ -49,7 +50,7 @@ #define CLIENT_HASH(a) \ ((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK) /* XXX: is this adequate for 32bit kdev_t ? */ -#define EXPORT_HASH(dev) ((dev) & (NFSCLNT_EXPMAX - 1)) +#define EXPORT_HASH(dev) (minor(dev) & (NFSCLNT_EXPMAX - 1)) struct svc_clnthash { struct svc_clnthash * h_next; @@ -75,7 +76,7 @@ svc_export * exp; exp = clp->cl_export[EXPORT_HASH(dev)]; - while (exp && exp->ex_dev != dev) + while (exp && !kdev_same(exp->ex_dev, dev)) exp = exp->ex_next; return exp; } @@ -94,7 +95,7 @@ exp = clp->cl_export[EXPORT_HASH(dev)]; if (exp) do { - if (exp->ex_ino == ino && exp->ex_dev == dev) + if (exp->ex_ino == ino && kdev_same(exp->ex_dev, dev)) goto out; } while (NULL != (exp = exp->ex_next)); exp = NULL; @@ -197,9 +198,10 @@ inode = nd.dentry->d_inode; err = -EINVAL; - if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) { - printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n", - inode->i_dev, dev); + if (!kdev_same(inode->i_dev, dev) || inode->i_ino != nxp->ex_ino) { + printk(KERN_DEBUG "exp_export: i_dev = %02x:%02x, dev = %02x:%02x\n", + major(inode->i_dev), minor(inode->i_dev), + major(dev), minor(dev)); /* I'm just being paranoid... */ goto finish; } @@ -301,7 +303,7 @@ dentry = unexp->ex_dentry; mnt = unexp->ex_mnt; inode = dentry->d_inode; - if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino) + if (!kdev_same(unexp->ex_dev, inode->i_dev) || unexp->ex_ino != inode->i_ino) printk(KERN_WARNING "nfsd: bad dentry in unexport!\n"); dput(dentry); mntput(mnt); @@ -352,9 +354,10 @@ err = -EINVAL; clp = exp_getclientbyname(nxp->ex_client); if (clp) { - expp = clp->cl_export + EXPORT_HASH(nxp->ex_dev); + kdev_t ex_dev = to_kdev_t(nxp->ex_dev); + expp = clp->cl_export + EXPORT_HASH(ex_dev); while ((exp = *expp) != NULL) { - if (exp->ex_dev == nxp->ex_dev) { + if (kdev_same(exp->ex_dev, ex_dev)) { if (exp->ex_ino == nxp->ex_ino) { *expp = exp->ex_next; exp_do_unexport(exp); @@ -396,12 +399,13 @@ dev = nd.dentry->d_inode->i_dev; ino = nd.dentry->d_inode->i_ino; - dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n", - path, nd.dentry, clp->cl_ident, dev, (long) ino); + dprintk("nfsd: exp_rootfh(%s [%p] %s:%02x:%02x/%ld)\n", + path, nd.dentry, clp->cl_ident, + major(dev), minor(dev), (long) ino); exp = exp_parent(clp, dev, nd.dentry); } else { - dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n", - clp->cl_ident, dev, (long) ino); + dprintk("nfsd: exp_rootfh(%s:%02x:%02x/%ld)\n", + clp->cl_ident, major(dev), minor(dev), (long) ino); if ((exp = exp_get(clp, dev, ino))) { nd.mnt = mntget(exp->ex_mnt); nd.dentry = dget(exp->ex_dentry); @@ -417,11 +421,12 @@ printk("exp_rootfh: Aieee, NULL d_inode\n"); goto out; } - if (inode->i_dev != dev || inode->i_ino != ino) { + if (!kdev_same(inode->i_dev, dev) || inode->i_ino != ino) { printk("exp_rootfh: Aieee, ino/dev mismatch\n"); - printk("exp_rootfh: arg[dev(%x):ino(%ld)]" - " inode[dev(%x):ino(%ld)]\n", - dev, (long) ino, inode->i_dev, (long) inode->i_ino); + printk("exp_rootfh: arg[dev(%02x:%02x):ino(%ld)]" + " inode[dev(%02x:%02x):ino(%ld)]\n", + major(dev), minor(dev), (long) ino, + major(inode->i_dev), minor(inode->i_dev), (long) inode->i_ino); } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfsd/nfs3xdr.c linux-2.5/fs/nfsd/nfs3xdr.c --- linux-2.5.1/fs/nfsd/nfs3xdr.c Thu Oct 4 05:27:48 2001 +++ linux-2.5/fs/nfsd/nfs3xdr.c Thu Jan 3 00:45:28 2002 @@ -173,9 +173,9 @@ p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511); else p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9); - *p++ = htonl((u32) MAJOR(inode->i_rdev)); - *p++ = htonl((u32) MINOR(inode->i_rdev)); - p = xdr_encode_hyper(p, (u64) inode->i_dev); + *p++ = htonl((u32) major(inode->i_rdev)); + *p++ = htonl((u32) minor(inode->i_rdev)); + p = xdr_encode_hyper(p, (u64) kdev_t_to_nr(inode->i_dev)); p = xdr_encode_hyper(p, (u64) inode->i_ino); p = encode_time3(p, inode->i_atime); p = encode_time3(p, lease_get_mtime(inode)); @@ -203,9 +203,9 @@ p = xdr_encode_hyper(p, (u64) fhp->fh_post_size); } p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); - *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev)); - *p++ = htonl((u32) MINOR(fhp->fh_post_rdev)); - p = xdr_encode_hyper(p, (u64) inode->i_dev); + *p++ = htonl((u32) major(fhp->fh_post_rdev)); + *p++ = htonl((u32) minor(fhp->fh_post_rdev)); + p = xdr_encode_hyper(p, (u64) kdev_t_to_nr(inode->i_dev)); p = xdr_encode_hyper(p, (u64) inode->i_ino); p = encode_time3(p, fhp->fh_post_atime); p = encode_time3(p, fhp->fh_post_mtime); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfsd/nfsctl.c linux-2.5/fs/nfsd/nfsctl.c --- linux-2.5.1/fs/nfsd/nfsctl.c Sun Oct 21 17:32:33 2001 +++ linux-2.5/fs/nfsd/nfsctl.c Tue Jan 1 23:42:42 2002 @@ -125,7 +125,7 @@ if (!(clp = exp_getclient(sin))) err = -EPERM; else - err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen); + err = exp_rootfh(clp, NODEV, 0, data->gd_path, res, data->gd_maxlen); exp_unlock(); return err; } @@ -148,7 +148,7 @@ if (!(clp = exp_getclient(sin))) err = -EPERM; else - err = exp_rootfh(clp, 0, 0, data->gd_path, &fh, NFS_FHSIZE); + err = exp_rootfh(clp, NODEV, 0, data->gd_path, &fh, NFS_FHSIZE); exp_unlock(); if (err == 0) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfsd/nfsfh.c linux-2.5/fs/nfsd/nfsfh.c --- linux-2.5.1/fs/nfsd/nfsfh.c Thu Oct 4 05:59:22 2001 +++ linux-2.5/fs/nfsd/nfsfh.c Tue Jan 1 23:42:42 2002 @@ -424,7 +424,8 @@ /* It's a directory, or we are required to confirm the file's * location in the tree. */ - dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,datap[0]); + dprintk("nfs_fh: need to look harder for %02x:%02x/%d\n", + major(sb->s_dev), minor(sb->s_dev), datap[0]); if (!S_ISDIR(result->d_inode->i_mode)) { nfsdstats.fh_nocache_nondir++; @@ -556,7 +557,7 @@ case 0: if ((data_left-=2)<0) goto out; nfsdev = ntohl(*datap++); - xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF); + xdev = mk_kdev(nfsdev>>16, nfsdev&0xFFFF); xino = *datap++; break; default: @@ -788,8 +789,8 @@ struct dentry *parent = dentry->d_parent; __u32 *datap; - dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n", - exp->ex_dev, (long) exp->ex_ino, + dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", + major(exp->ex_dev), minor(exp->ex_dev), (long) exp->ex_ino, parent->d_name.name, dentry->d_name.name, (inode ? inode->i_ino : 0)); @@ -811,7 +812,7 @@ memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); fhp->fh_handle.fh_size = NFS_FHSIZE; fhp->fh_handle.ofh_dcookie = 0xfeebbaca; - fhp->fh_handle.ofh_dev = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev)); + fhp->fh_handle.ofh_dev = htonl((major(exp->ex_dev)<<16)| minor(exp->ex_dev)); fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev; fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino); fhp->fh_handle.ofh_dirino = ino_t_to_u32(dentry->d_parent->d_inode->i_ino); @@ -823,7 +824,7 @@ fhp->fh_handle.fh_fsid_type = 0; datap = fhp->fh_handle.fh_auth+0; /* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */ - *datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev)); + *datap++ = htonl((major(exp->ex_dev)<<16)| minor(exp->ex_dev)); *datap++ = ino_t_to_u32(exp->ex_ino); fhp->fh_handle.fh_size = 3*4; if (inode) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfsd/nfsproc.c linux-2.5/fs/nfsd/nfsproc.c --- linux-2.5.1/fs/nfsd/nfsproc.c Sun Oct 21 17:40:36 2001 +++ linux-2.5/fs/nfsd/nfsproc.c Tue Jan 1 23:42:42 2002 @@ -197,7 +197,7 @@ struct inode *inode; struct dentry *dchild; int nfserr, type, mode; - dev_t rdev = NODEV; + dev_t rdev = 0; dprintk("nfsd: CREATE %s %.*s\n", SVCFH_fmt(dirfhp), argp->len, argp->name); @@ -255,7 +255,7 @@ case S_IFCHR: case S_IFBLK: /* reserve rdev for later checking */ - attr->ia_size = inode->i_rdev; + attr->ia_size = kdev_t_to_nr(inode->i_rdev); attr->ia_valid |= ATTR_SIZE; /* FALLTHROUGH */ @@ -313,7 +313,7 @@ /* Make sure the type and device matches */ nfserr = nfserr_exist; if (inode && (type != (inode->i_mode & S_IFMT) || - (is_borc && inode->i_rdev != rdev))) + (is_borc && kdev_t_to_nr(inode->i_rdev) != rdev))) goto out_unlock; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfsd/nfsxdr.c linux-2.5/fs/nfsd/nfsxdr.c --- linux-2.5.1/fs/nfsd/nfsxdr.c Wed Oct 17 21:16:34 2001 +++ linux-2.5/fs/nfsd/nfsxdr.c Tue Jan 1 23:42:42 2002 @@ -149,11 +149,11 @@ } *p++ = htonl((u32) inode->i_blksize); if (S_ISCHR(type) || S_ISBLK(type)) - *p++ = htonl((u32) inode->i_rdev); + *p++ = htonl((u32) kdev_t_to_nr(inode->i_rdev)); else *p++ = htonl(0xffffffff); *p++ = htonl((u32) inode->i_blocks); - *p++ = htonl((u32) inode->i_dev); + *p++ = htonl((u32) kdev_t_to_nr(inode->i_dev)); *p++ = htonl((u32) inode->i_ino); *p++ = htonl((u32) inode->i_atime); *p++ = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nfsd/vfs.c linux-2.5/fs/nfsd/vfs.c --- linux-2.5.1/fs/nfsd/vfs.c Fri Oct 5 19:23:53 2001 +++ linux-2.5/fs/nfsd/vfs.c Sat Jan 5 16:38:09 2002 @@ -66,7 +66,7 @@ struct raparms *p_next; unsigned int p_count; ino_t p_ino; - dev_t p_dev; + kdev_t p_dev; unsigned long p_reada, p_ramax, p_raend, @@ -543,13 +543,13 @@ * specified by (dev, ino). */ static inline struct raparms * -nfsd_get_raparms(dev_t dev, ino_t ino) +nfsd_get_raparms(kdev_t dev, ino_t ino) { struct raparms *ra, **rap, **frap = NULL; int depth = 0; for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) { - if (ra->p_ino == ino && ra->p_dev == dev) + if (ra->p_ino == ino && kdev_same(ra->p_dev, dev)) goto found; depth++; if (ra->p_count == 0) @@ -560,9 +560,13 @@ return NULL; rap = frap; ra = *frap; - memset(ra, 0, sizeof(*ra)); ra->p_dev = dev; ra->p_ino = ino; + ra->p_reada = 0; + ra->p_ramax = 0; + ra->p_raend = 0; + ra->p_ralen = 0; + ra->p_rawin = 0; found: if (rap != &raparm_cache) { *rap = ra->p_next; @@ -730,7 +734,7 @@ */ if (EX_WGATHER(exp)) { if (atomic_read(&inode->i_writecount) > 1 - || (last_ino == inode->i_ino && last_dev == inode->i_dev)) { + || (last_ino == inode->i_ino && kdev_same(last_dev, inode->i_dev))) { dprintk("nfsd: write defer %d\n", current->pid); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((HZ+99)/100); @@ -1245,7 +1249,7 @@ tdir = tdentry->d_inode; err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev; - if (fdir->i_dev != tdir->i_dev) + if (fdir->i_sb != tdir->i_sb) goto out; err = nfserr_perm; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/Config.in linux-2.5/fs/nls/Config.in --- linux-2.5.1/fs/nls/Config.in Thu Jun 28 00:10:55 2001 +++ linux-2.5/fs/nls/Config.in Mon Jan 14 22:39:45 2002 @@ -43,6 +43,7 @@ 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 CP1250 (Slavic/Central European Languages)' CONFIG_NLS_CODEPAGE_1250 tristate 'Windows CP1251 (Bulgarian, Belarusian)' 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 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_base.c linux-2.5/fs/nls/nls_base.c --- linux-2.5.1/fs/nls/nls_base.c Fri Feb 9 19:29:44 2001 +++ linux-2.5/fs/nls/nls_base.c Sun Dec 30 20:01:41 2001 @@ -13,7 +13,7 @@ #include <linux/string.h> #include <linux/config.h> #include <linux/nls.h> -#include <linux/slab.h> +#include <linux/kernel.h> #include <linux/errno.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_big5.c linux-2.5/fs/nls/nls_big5.c --- linux-2.5.1/fs/nls/nls_big5.c Mon Oct 16 19:58:51 2000 +++ linux-2.5/fs/nls/nls_big5.c Thu Dec 13 22:09:29 2001 @@ -42,6 +42,7 @@ module_init(init_nls_big5) module_exit(exit_nls_big5) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp1251.c linux-2.5/fs/nls/nls_cp1251.c --- linux-2.5.1/fs/nls/nls_cp1251.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp1251.c Thu Dec 13 16:32:37 2001 @@ -315,4 +315,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp1255.c linux-2.5/fs/nls/nls_cp1255.c --- linux-2.5.1/fs/nls/nls_cp1255.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp1255.c Thu Dec 13 16:32:37 2001 @@ -396,4 +396,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp437.c linux-2.5/fs/nls/nls_cp437.c --- linux-2.5.1/fs/nls/nls_cp437.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp437.c Thu Dec 13 16:32:37 2001 @@ -401,4 +401,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp737.c linux-2.5/fs/nls/nls_cp737.c --- linux-2.5.1/fs/nls/nls_cp737.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp737.c Thu Dec 13 16:32:37 2001 @@ -364,4 +364,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp775.c linux-2.5/fs/nls/nls_cp775.c --- linux-2.5.1/fs/nls/nls_cp775.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp775.c Thu Dec 13 16:32:37 2001 @@ -333,4 +333,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp850.c linux-2.5/fs/nls/nls_cp850.c --- linux-2.5.1/fs/nls/nls_cp850.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp850.c Thu Dec 13 16:32:37 2001 @@ -329,4 +329,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp852.c linux-2.5/fs/nls/nls_cp852.c --- linux-2.5.1/fs/nls/nls_cp852.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp852.c Thu Dec 13 16:32:37 2001 @@ -351,4 +351,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp855.c linux-2.5/fs/nls/nls_cp855.c --- linux-2.5.1/fs/nls/nls_cp855.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp855.c Thu Dec 13 16:32:37 2001 @@ -313,4 +313,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp857.c linux-2.5/fs/nls/nls_cp857.c --- linux-2.5.1/fs/nls/nls_cp857.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp857.c Thu Dec 13 16:32:37 2001 @@ -315,4 +315,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp860.c linux-2.5/fs/nls/nls_cp860.c --- linux-2.5.1/fs/nls/nls_cp860.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp860.c Thu Dec 13 16:32:37 2001 @@ -378,4 +378,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp861.c linux-2.5/fs/nls/nls_cp861.c --- linux-2.5.1/fs/nls/nls_cp861.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp861.c Thu Dec 13 16:32:37 2001 @@ -401,4 +401,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp862.c linux-2.5/fs/nls/nls_cp862.c --- linux-2.5.1/fs/nls/nls_cp862.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp862.c Thu Dec 13 16:32:37 2001 @@ -435,4 +435,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp863.c linux-2.5/fs/nls/nls_cp863.c --- linux-2.5.1/fs/nls/nls_cp863.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp863.c Thu Dec 13 16:32:37 2001 @@ -395,4 +395,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp864.c linux-2.5/fs/nls/nls_cp864.c --- linux-2.5.1/fs/nls/nls_cp864.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp864.c Thu Dec 13 16:32:37 2001 @@ -421,4 +421,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp865.c linux-2.5/fs/nls/nls_cp865.c --- linux-2.5.1/fs/nls/nls_cp865.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp865.c Thu Dec 13 16:32:37 2001 @@ -401,4 +401,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp866.c linux-2.5/fs/nls/nls_cp866.c --- linux-2.5.1/fs/nls/nls_cp866.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp866.c Thu Dec 13 16:32:37 2001 @@ -319,4 +319,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp869.c linux-2.5/fs/nls/nls_cp869.c --- linux-2.5.1/fs/nls/nls_cp869.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp869.c Thu Dec 13 16:32:37 2001 @@ -329,4 +329,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp874.c linux-2.5/fs/nls/nls_cp874.c --- linux-2.5.1/fs/nls/nls_cp874.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/nls/nls_cp874.c Thu Dec 13 16:32:37 2001 @@ -287,4 +287,4 @@ * c-continued-brace-offset: 0 * End: */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp932.c linux-2.5/fs/nls/nls_cp932.c --- linux-2.5.1/fs/nls/nls_cp932.c Fri Apr 6 17:51:19 2001 +++ linux-2.5/fs/nls/nls_cp932.c Thu Dec 13 22:09:29 2001 @@ -7904,6 +7904,7 @@ module_init(init_nls_cp932) module_exit(exit_nls_cp932) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp936.c linux-2.5/fs/nls/nls_cp936.c --- linux-2.5.1/fs/nls/nls_cp936.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_cp936.c Thu Dec 13 22:09:29 2001 @@ -11024,6 +11024,7 @@ module_init(init_nls_cp936) module_exit(exit_nls_cp936) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp949.c linux-2.5/fs/nls/nls_cp949.c --- linux-2.5.1/fs/nls/nls_cp949.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_cp949.c Thu Dec 13 22:09:29 2001 @@ -13941,6 +13941,7 @@ module_init(init_nls_cp949) module_exit(exit_nls_cp949) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_cp950.c linux-2.5/fs/nls/nls_cp950.c --- linux-2.5.1/fs/nls/nls_cp950.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_cp950.c Thu Dec 13 22:09:30 2001 @@ -9480,6 +9480,7 @@ module_init(init_nls_cp950) module_exit(exit_nls_cp950) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_euc-jp.c linux-2.5/fs/nls/nls_euc-jp.c --- linux-2.5.1/fs/nls/nls_euc-jp.c Fri Apr 6 17:51:19 2001 +++ linux-2.5/fs/nls/nls_euc-jp.c Thu Dec 13 22:09:30 2001 @@ -581,6 +581,7 @@ module_init(init_nls_euc_jp) module_exit(exit_nls_euc_jp) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_euc-kr.c linux-2.5/fs/nls/nls_euc-kr.c --- linux-2.5.1/fs/nls/nls_euc-kr.c Mon Oct 16 19:58:51 2000 +++ linux-2.5/fs/nls/nls_euc-kr.c Thu Dec 13 22:09:30 2001 @@ -42,6 +42,7 @@ module_init(init_nls_euc_kr) module_exit(exit_nls_euc_kr) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_gb2312.c linux-2.5/fs/nls/nls_gb2312.c --- linux-2.5.1/fs/nls/nls_gb2312.c Mon Oct 16 19:58:51 2000 +++ linux-2.5/fs/nls/nls_gb2312.c Thu Dec 13 22:09:30 2001 @@ -42,6 +42,7 @@ module_init(init_nls_gb2312) module_exit(exit_nls_gb2312) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-1.c linux-2.5/fs/nls/nls_iso8859-1.c --- linux-2.5.1/fs/nls/nls_iso8859-1.c Wed Jul 19 05:48:33 2000 +++ linux-2.5/fs/nls/nls_iso8859-1.c Thu Dec 13 22:09:30 2001 @@ -254,6 +254,7 @@ module_init(init_nls_iso8859_1) module_exit(exit_nls_iso8859_1) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-13.c linux-2.5/fs/nls/nls_iso8859-13.c --- linux-2.5.1/fs/nls/nls_iso8859-13.c Sun May 20 00:47:55 2001 +++ linux-2.5/fs/nls/nls_iso8859-13.c Thu Dec 13 22:09:30 2001 @@ -282,6 +282,7 @@ module_init(init_nls_iso8859_13) module_exit(exit_nls_iso8859_13) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-14.c linux-2.5/fs/nls/nls_iso8859-14.c --- linux-2.5.1/fs/nls/nls_iso8859-14.c Wed Jul 19 05:48:33 2000 +++ linux-2.5/fs/nls/nls_iso8859-14.c Thu Dec 13 22:09:30 2001 @@ -338,6 +338,7 @@ module_init(init_nls_iso8859_14) module_exit(exit_nls_iso8859_14) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-15.c linux-2.5/fs/nls/nls_iso8859-15.c --- linux-2.5.1/fs/nls/nls_iso8859-15.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_iso8859-15.c Thu Dec 13 22:09:30 2001 @@ -304,6 +304,7 @@ module_init(init_nls_iso8859_15) module_exit(exit_nls_iso8859_15) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-2.c linux-2.5/fs/nls/nls_iso8859-2.c --- linux-2.5.1/fs/nls/nls_iso8859-2.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_iso8859-2.c Thu Dec 13 22:09:30 2001 @@ -305,6 +305,7 @@ module_init(init_nls_iso8859_2) module_exit(exit_nls_iso8859_2) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-3.c linux-2.5/fs/nls/nls_iso8859-3.c --- linux-2.5.1/fs/nls/nls_iso8859-3.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_iso8859-3.c Thu Dec 13 22:09:30 2001 @@ -305,6 +305,7 @@ module_init(init_nls_iso8859_3) module_exit(exit_nls_iso8859_3) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-4.c linux-2.5/fs/nls/nls_iso8859-4.c --- linux-2.5.1/fs/nls/nls_iso8859-4.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_iso8859-4.c Thu Dec 13 22:09:30 2001 @@ -305,6 +305,7 @@ module_init(init_nls_iso8859_4) module_exit(exit_nls_iso8859_4) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-5.c linux-2.5/fs/nls/nls_iso8859-5.c --- linux-2.5.1/fs/nls/nls_iso8859-5.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_iso8859-5.c Thu Dec 13 22:09:30 2001 @@ -269,6 +269,7 @@ module_init(init_nls_iso8859_5) module_exit(exit_nls_iso8859_5) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-6.c linux-2.5/fs/nls/nls_iso8859-6.c --- linux-2.5.1/fs/nls/nls_iso8859-6.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_iso8859-6.c Thu Dec 13 22:09:30 2001 @@ -260,6 +260,7 @@ module_init(init_nls_iso8859_6) module_exit(exit_nls_iso8859_6) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-7.c linux-2.5/fs/nls/nls_iso8859-7.c --- linux-2.5.1/fs/nls/nls_iso8859-7.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_iso8859-7.c Thu Dec 13 22:09:30 2001 @@ -314,6 +314,7 @@ module_init(init_nls_iso8859_7) module_exit(exit_nls_iso8859_7) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-8.c linux-2.5/fs/nls/nls_iso8859-8.c --- linux-2.5.1/fs/nls/nls_iso8859-8.c Fri Apr 6 17:51:19 2001 +++ linux-2.5/fs/nls/nls_iso8859-8.c Thu Dec 13 22:09:30 2001 @@ -42,6 +42,7 @@ module_init(init_nls_iso8859_8) module_exit(exit_nls_iso8859_8) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_iso8859-9.c linux-2.5/fs/nls/nls_iso8859-9.c --- linux-2.5.1/fs/nls/nls_iso8859-9.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_iso8859-9.c Thu Dec 13 22:09:30 2001 @@ -269,6 +269,7 @@ module_init(init_nls_iso8859_9) module_exit(exit_nls_iso8859_9) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_koi8-r.c linux-2.5/fs/nls/nls_koi8-r.c --- linux-2.5.1/fs/nls/nls_koi8-r.c Fri Jul 21 22:19:51 2000 +++ linux-2.5/fs/nls/nls_koi8-r.c Thu Dec 13 22:09:30 2001 @@ -320,6 +320,7 @@ module_init(init_nls_koi8_r) module_exit(exit_nls_koi8_r) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_koi8-ru.c linux-2.5/fs/nls/nls_koi8-ru.c --- linux-2.5.1/fs/nls/nls_koi8-ru.c Sun May 20 00:47:55 2001 +++ linux-2.5/fs/nls/nls_koi8-ru.c Thu Dec 13 22:09:30 2001 @@ -80,6 +80,7 @@ module_init(init_nls_koi8_ru) module_exit(exit_nls_koi8_ru) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_koi8-u.c linux-2.5/fs/nls/nls_koi8-u.c --- linux-2.5.1/fs/nls/nls_koi8-u.c Sun May 20 00:47:55 2001 +++ linux-2.5/fs/nls/nls_koi8-u.c Thu Dec 13 22:09:30 2001 @@ -327,6 +327,7 @@ module_init(init_nls_koi8_u) module_exit(exit_nls_koi8_u) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_sjis.c linux-2.5/fs/nls/nls_sjis.c --- linux-2.5.1/fs/nls/nls_sjis.c Mon Oct 16 19:58:51 2000 +++ linux-2.5/fs/nls/nls_sjis.c Thu Dec 13 22:09:30 2001 @@ -42,6 +42,7 @@ module_init(init_nls_sjis) module_exit(exit_nls_sjis) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_tis-620.c linux-2.5/fs/nls/nls_tis-620.c --- linux-2.5.1/fs/nls/nls_tis-620.c Fri Apr 6 17:51:19 2001 +++ linux-2.5/fs/nls/nls_tis-620.c Thu Dec 13 22:09:30 2001 @@ -42,6 +42,7 @@ module_init(init_nls_tis_620) module_exit(exit_nls_tis_620) +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/nls/nls_utf8.c linux-2.5/fs/nls/nls_utf8.c --- linux-2.5.1/fs/nls/nls_utf8.c Wed Jul 19 05:48:33 2000 +++ linux-2.5/fs/nls/nls_utf8.c Thu Dec 13 22:09:30 2001 @@ -58,3 +58,4 @@ module_init(init_nls_utf8) module_exit(exit_nls_utf8) +MODULE_LICENSE("Dual BSD/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ntfs/fs.c linux-2.5/fs/ntfs/fs.c --- linux-2.5.1/fs/ntfs/fs.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/ntfs/fs.c Thu Dec 27 15:56:12 2001 @@ -1016,14 +1016,11 @@ init_ntfs_super_block(vol); if (!parse_options(vol, (char*)options)) goto ntfs_read_super_vol; - blocksize = get_hardsect_size(sb->s_dev); - if (blocksize < 512) - blocksize = 512; - if (set_blocksize(sb->s_dev, blocksize) < 0) { - ntfs_error("Unable to set blocksize %d.\n", blocksize); + blocksize = sb_min_blocksize(sb, 512); + if (!blocksize) { + ntfs_error("Unable to set blocksize.\n"); goto ntfs_read_super_vol; } - sb->s_blocksize = blocksize; /* Read the super block (boot block). */ if (!(bh = sb_bread(sb, 0))) { ntfs_error("Reading super block failed\n"); @@ -1052,10 +1049,7 @@ } ntfs_debug(DEBUG_OTHER, "Done to init volume\n"); /* Inform the kernel that a device block is a NTFS cluster. */ - sb->s_blocksize = vol->cluster_size; - sb->s_blocksize_bits = vol->cluster_size_bits; - if (blocksize != vol->cluster_size && - set_blocksize(sb->s_dev, sb->s_blocksize) < 0) { + if (!sb_set_blocksize(sb, vol->cluster_size)) { ntfs_error("Cluster size too small for device.\n"); goto ntfs_read_super_unl; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ntfs/support.c linux-2.5/fs/ntfs/support.c --- linux-2.5.1/fs/ntfs/support.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/ntfs/support.c Sat Jan 5 16:38:09 2002 @@ -200,7 +200,7 @@ if (buffer_req(bh) && !buffer_uptodate(bh)) { printk(KERN_ERR "IO error syncing NTFS " "cluster [%s:%i]\n", - bdevname(sb->s_dev), cluster); + sb->s_id, cluster); brelse(bh); error = -EIO; goto error_ret; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/openpromfs/inode.c linux-2.5/fs/openpromfs/inode.c --- linux-2.5.1/fs/openpromfs/inode.c Sun Nov 11 18:13:25 2001 +++ linux-2.5/fs/openpromfs/inode.c Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: inode.c,v 1.14 2001/02/13 01:17:17 davem Exp $ +/* $Id: inode.c,v 1.15 2001/11/12 09:43:39 davem Exp $ * openpromfs.c: /proc/openprom handling routines * * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/partitions/acorn.c linux-2.5/fs/partitions/acorn.c --- linux-2.5.1/fs/partitions/acorn.c Tue Dec 11 17:44:13 2001 +++ linux-2.5/fs/partitions/acorn.c Wed Jan 2 12:18:11 2002 @@ -28,8 +28,8 @@ extern void xd_set_geometry(kdev_t dev, unsigned char, unsigned char, unsigned long, unsigned int); - if (MAJOR(dev) == MFM_ACORN_MAJOR) { - unsigned long totalblocks = hd->part[MINOR(dev)].nr_sects; + if (major(dev) == MFM_ACORN_MAJOR) { + unsigned long totalblocks = hd->part[minor(dev)].nr_sects; xd_set_geometry(dev, secspertrack, heads, totalblocks, 1); } #endif @@ -261,7 +261,7 @@ /* * Work out start of non-adfs partition. */ - nr_sects = hd->part[MINOR(to_kdev_t(bdev->bd_dev))].nr_sects - start_sect; + nr_sects = hd->part[minor(to_kdev_t(bdev->bd_dev))].nr_sects - start_sect; if (start_sect) { first_sector += start_sect; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/partitions/atari.c linux-2.5/fs/partitions/atari.c --- linux-2.5.1/fs/partitions/atari.c Tue Oct 2 03:03:26 2001 +++ linux-2.5/fs/partitions/atari.c Tue Jan 1 23:42:42 2002 @@ -43,7 +43,7 @@ int atari_partition (struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int minor) { - int m_lim = minor + hd->max_p; + int m_lim = minor + (1 << hd->minor_shift); Sector sect; struct rootsector *rs; struct partition_info *pi; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/partitions/check.c linux-2.5/fs/partitions/check.c --- linux-2.5.1/fs/partitions/check.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/fs/partitions/check.c Sun Jan 13 22:17:23 2002 @@ -38,7 +38,8 @@ int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ -static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = { +static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sect, int first_minor) = { #ifdef CONFIG_ACORN_PARTITION acorn_partition, #endif @@ -227,26 +228,26 @@ if (first_time) printk(KERN_INFO "Partition check:\n"); first_time = 0; - first_sector = hd->part[MINOR(dev)].start_sect; + first_sector = hd->part[minor(dev)].start_sect; /* * This is a kludge to allow the partition check to be * skipped for specific drives (e.g. IDE CD-ROM drives) */ if ((int)first_sector == -1) { - hd->part[MINOR(dev)].start_sect = 0; + hd->part[minor(dev)].start_sect = 0; return; } if (hd->de_arr) - de = hd->de_arr[MINOR(dev) >> hd->minor_shift]; + de = hd->de_arr[minor(dev) >> hd->minor_shift]; i = devfs_generate_path (de, buf, sizeof buf); if (i >= 0) printk(KERN_INFO " /dev/%s:", buf + i); else - printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf)); + printk(KERN_INFO " %s:", disk_name(hd, minor(dev), buf)); bdev = bdget(kdev_t_to_nr(dev)); - bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9; + bdev->bd_inode->i_size = (loff_t)hd->part[minor(dev)].nr_sects << 9; bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev)); for (i = 0; check_part[i]; i++) { int res; @@ -333,11 +334,12 @@ void devfs_register_partitions (struct gendisk *dev, int minor, int unregister) { #ifdef CONFIG_DEVFS_FS - int part; + int part, max_p; if (!unregister) devfs_register_disc (dev, minor); - for (part = 1; part < dev->max_p; part++) { + max_p = (1 << dev->minor_shift); + for (part = 1; part < max_p; part++) { if ( unregister || (dev->part[part + minor].nr_sects < 1) ) { devfs_unregister (dev->part[part + minor].de); dev->part[part + minor].de = NULL; @@ -381,10 +383,10 @@ return; minors = 1 << g->minor_shift; - first_minor = MINOR(dev); + first_minor = minor(dev); if (first_minor & (minors-1)) { printk("grok_partitions: bad device 0x%02x:%02x\n", - MAJOR(dev), first_minor); + major(dev), first_minor); first_minor &= ~(minors-1); } end_minor = first_minor + minors; @@ -404,7 +406,7 @@ g->sizes[i] = 0; } blk_size[g->major] = g->sizes; - check_partition(g, MKDEV(g->major, first_minor), 1 + first_minor); + check_partition(g, mk_kdev(g->major, first_minor), 1 + first_minor); /* * We need to set the sizes array before we will be able to access @@ -450,8 +452,8 @@ return -EINVAL; max_p = 1 << g->minor_shift; - major = MAJOR(dev); - minor = MINOR(dev); + major = major(dev); + minor = minor(dev); minor0 = minor & ~(max_p - 1); if (minor0 != minor) /* for now only whole-disk reread */ return -EINVAL; /* %%% later.. */ @@ -459,7 +461,7 @@ /* invalidate stuff */ for (p = max_p - 1; p >= 0; p--) { minor = minor0 + p; - devp = MKDEV(major,minor); + devp = mk_kdev(major,minor); #if 0 /* %%% superfluous? */ if (g->part[minor].nr_sects == 0) continue; @@ -476,5 +478,30 @@ /* sd.c used to set blksize_size to 2048 in case rscsi_disks[target].device->sector_size == 2048 */ + return 0; +} + +/* + * Make sure that a proposed subpartition is strictly contained inside + * the parent partition. If all is well, call add_gd_partition(). + */ +int +check_and_add_subpartition(struct gendisk *hd, int super_minor, int minor, + int sub_start, int sub_size) +{ + int start = hd->part[super_minor].start_sect; + int size = hd->part[super_minor].nr_sects; + + if (start == sub_start && size == sub_size) { + /* full parent partition, we have it already */ + return 0; + } + + if (start <= sub_start && start+size >= sub_start+sub_size) { + add_gd_partition(hd, minor, sub_start, sub_size); + return 1; + } + + printk("bad subpartition - ignored\n"); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/partitions/check.h linux-2.5/fs/partitions/check.h --- linux-2.5.1/fs/partitions/check.h Sun Dec 16 23:45:06 2001 +++ linux-2.5/fs/partitions/check.h Mon Jan 14 14:35:05 2002 @@ -1,4 +1,5 @@ #include <linux/pagemap.h> +#include <linux/blkdev.h> /* * add_gd_partition adds a partitions details to the devices partition @@ -6,13 +7,10 @@ */ void add_gd_partition(struct gendisk *hd, int minor, int start, int size); -typedef struct {struct page *v;} Sector; - -unsigned char *read_dev_sector(struct block_device *, unsigned long, Sector *); - -static inline void put_dev_sector(Sector p) -{ - page_cache_release(p.v); -} +/* + * check_and_add_subpartition does the same for subpartitions + */ +int check_and_add_subpartition(struct gendisk *hd, int super_minor, + int minor, int sub_start, int sub_size); extern int warn_no_part; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/partitions/ibm.c linux-2.5/fs/partitions/ibm.c --- linux-2.5.1/fs/partitions/ibm.c Tue Oct 2 03:03:26 2001 +++ linux-2.5/fs/partitions/ibm.c Wed Jan 2 12:18:16 2002 @@ -125,7 +125,7 @@ return 0; if (ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo); return 0; - blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; + blocksize = hardsect_size[major(dev)][minor(dev)]; if ( blocksize <= 0 ) { return 0; } @@ -159,19 +159,19 @@ printk ("(MDSK)"); } else { offset = (info->label_block + 1); - size = hd -> sizes[MINOR(dev)]<<1; + size = hd -> sizes[minor(dev)]<<1; } - two_partitions( hd, MINOR(dev), blocksize, offset, size); + two_partitions( hd, minor(dev), blocksize, offset, size); break; case ibm_partition_lnx1: case ibm_partition_none: offset = (info->label_block + 1); - size = hd -> sizes[MINOR(dev)]<<1; - two_partitions( hd, MINOR(dev), blocksize, offset, size); + size = hd -> sizes[minor(dev)]<<1; + two_partitions( hd, minor(dev), blocksize, offset, size); break; case ibm_partition_vol1: - size = hd -> sizes[MINOR(dev)]<<1; - add_gd_partition(hd, MINOR(dev), 0, size); + size = hd -> sizes[minor(dev)]<<1; + add_gd_partition(hd, minor(dev), 0, size); /* get block number and read then first format1 label */ blk = cchhb2blk(&vlabel.vtoc, geo) + 1; @@ -187,7 +187,7 @@ offset + geo->sectors; counter++; - add_gd_partition(hd, MINOR(dev) + counter, + add_gd_partition(hd, minor(dev) + counter, offset * blocksize, psize * blocksize); @@ -200,8 +200,8 @@ } break; default: - add_gd_partition( hd, MINOR(dev), 0, 0); - add_gd_partition( hd, MINOR(dev) + 1, 0, 0); + add_gd_partition( hd, minor(dev), 0, 0); + add_gd_partition( hd, minor(dev) + 1, 0, 0); } printk ( "\n" ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/partitions/msdos.c linux-2.5/fs/partitions/msdos.c --- linux-2.5.1/fs/partitions/msdos.c Thu Oct 11 15:07:07 2001 +++ linux-2.5/fs/partitions/msdos.c Sun Jan 13 22:17:23 2002 @@ -166,7 +166,7 @@ add_gd_partition(hd, *current_minor, next, size); #if CONFIG_BLK_DEV_MD if (SYS_IND(p) == LINUX_RAID_PARTITION) { - md_autodetect_dev(MKDEV(hd->major,*current_minor)); + md_autodetect_dev(mk_kdev(hd->major,*current_minor)); } #endif @@ -255,50 +255,6 @@ } #ifdef CONFIG_BSD_DISKLABEL -static void -check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p, - int minor, int *current_minor) -{ - struct hd_struct *lin_p; - /* check relative position of partitions. */ - for (lin_p = hd->part + 1 + minor; - lin_p - hd->part - minor < *current_minor; lin_p++) { - /* no relationship -> try again */ - if (lin_p->start_sect + lin_p->nr_sects <= le32_to_cpu(bsd_p->p_offset) || - lin_p->start_sect >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) - continue; - /* equal -> no need to add */ - if (lin_p->start_sect == le32_to_cpu(bsd_p->p_offset) && - lin_p->nr_sects == le32_to_cpu(bsd_p->p_size)) - return; - /* bsd living within dos partition */ - if (lin_p->start_sect <= le32_to_cpu(bsd_p->p_offset) && lin_p->start_sect - + lin_p->nr_sects >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) { -#ifdef DEBUG_BSD_DISKLABEL - printk("w: %d %ld+%ld,%d+%d", - lin_p - hd->part, - lin_p->start_sect, lin_p->nr_sects, - le32_to_cpu(bsd_p->p_offset), - le32_to_cpu(bsd_p->p_size)); -#endif - break; - } - /* ouch: bsd and linux overlap. Don't even try for that partition */ -#ifdef DEBUG_BSD_DISKLABEL - printk("???: %d %ld+%ld,%d+%d", - lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects, - le32_to_cpu(bsd_p->p_offset), le32_to_cpu(bsd_p->p_size)); -#endif - printk("???"); - return; - } /* if the bsd partition is not currently known to linux, we end - * up here - */ - add_gd_partition(hd, *current_minor, le32_to_cpu(bsd_p->p_offset), - le32_to_cpu(bsd_p->p_size)); - (*current_minor)++; -} - /* * Create devices for BSD partitions listed in a disklabel, under a * dos-like partition. See extended_partition() for more information. @@ -320,16 +276,22 @@ put_dev_sector(sect); return; } - printk(" %s: <%s", partition_name(hd, minor, buf), name); + printk(" %s: <%s:", partition_name(hd, minor, buf), name); if (le16_to_cpu(l->d_npartitions) < max_partitions) max_partitions = le16_to_cpu(l->d_npartitions); - for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { + for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { + int bsd_start, bsd_size; + if ((*current_minor & mask) == 0) break; if (p->p_fstype == BSD_FS_UNUSED) continue; - check_and_add_bsd_partition(hd, p, minor, current_minor); + bsd_start = le32_to_cpu(p->p_offset); + bsd_size = le32_to_cpu(p->p_size); + if (check_and_add_subpartition(hd, minor, *current_minor, + bsd_start, bsd_size)) + (*current_minor)++; } put_dev_sector(sect); printk(" >\n"); @@ -580,7 +542,7 @@ NR_SECTS(p)*sector_size); #if CONFIG_BLK_DEV_MD if (SYS_IND(p) == LINUX_RAID_PARTITION) { - md_autodetect_dev(MKDEV(hd->major,minor)); + md_autodetect_dev(mk_kdev(hd->major,minor)); } #endif if (is_extended_partition(p)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/proc/array.c linux-2.5/fs/proc/array.c --- linux-2.5.1/fs/proc/array.c Thu Oct 11 16:00:01 2001 +++ linux-2.5/fs/proc/array.c Tue Jan 8 00:44:25 2002 @@ -335,9 +335,12 @@ /* scale priority and nice values from timeslices to -20..20 */ /* to make it look like a "normal" Unix priority/nice value */ - priority = task->counter; - priority = 20 - (priority * 10 + DEF_COUNTER / 2) / DEF_COUNTER; - nice = task->nice; + priority = task->prio; + if (priority >= MAX_RT_PRIO) + priority -= MAX_RT_PRIO; + else + priority = priority-100; + nice = task->__nice; read_lock(&tasklist_lock); ppid = task->pid ? task->p_opptr->pid : 0; @@ -387,7 +390,7 @@ task->nswap, task->cnswap, task->exit_signal, - task->processor); + task->cpu); if(mm) mmput(mm); return res; @@ -556,7 +559,7 @@ str[3] = flags & VM_MAYSHARE ? 's' : 'p'; str[4] = 0; - dev = 0; + dev = NODEV; ino = 0; if (map->vm_file != NULL) { dev = map->vm_file->f_dentry->d_inode->i_dev; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/proc/base.c linux-2.5/fs/proc/base.c --- linux-2.5.1/fs/proc/base.c Thu Oct 11 06:42:47 2001 +++ linux-2.5/fs/proc/base.c Mon Jan 14 22:39:45 2002 @@ -23,6 +23,9 @@ #include <linux/init.h> #include <linux/file.h> #include <linux/string.h> +#include <linux/seq_file.h> +#include <linux/namespace.h> +#include <linux/mm.h> /* * For hysterical raisins we keep the same inumbers as in the old procfs. @@ -246,6 +249,46 @@ read: pid_maps_read, }; +extern struct seq_operations mounts_op; +static int mounts_open(struct inode *inode, struct file *file) +{ + struct task_struct *task = inode->u.proc_i.task; + int ret = seq_open(file, &mounts_op); + + if (!ret) { + struct seq_file *m = file->private_data; + struct namespace *namespace; + task_lock(task); + namespace = task->namespace; + if (namespace) + get_namespace(namespace); + task_unlock(task); + + if (namespace) + m->private = namespace; + else { + seq_release(inode, file); + ret = -EINVAL; + } + } + return ret; +} + +static int mounts_release(struct inode *inode, struct file *file) +{ + struct seq_file *m = file->private_data; + struct namespace *namespace = m->private; + put_namespace(namespace); + return seq_release(inode, file); +} + +static struct file_operations proc_mounts_operations = { + open: mounts_open, + read: seq_read, + llseek: seq_lseek, + release: mounts_release, +}; + #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ static ssize_t proc_info_read(struct file * file, char * buf, @@ -497,6 +540,7 @@ PROC_PID_STATM, PROC_PID_MAPS, PROC_PID_CPU, + PROC_PID_MOUNTS, PROC_PID_FD_DIR = 0x8000, /* 0x8000-0xffff */ }; @@ -516,6 +560,7 @@ E(PROC_PID_CWD, "cwd", S_IFLNK|S_IRWXUGO), E(PROC_PID_ROOT, "root", S_IFLNK|S_IRWXUGO), E(PROC_PID_EXE, "exe", S_IFLNK|S_IRWXUGO), + E(PROC_PID_MOUNTS, "mounts", S_IFREG|S_IRUGO), {0,0,NULL,0} }; #undef E @@ -553,6 +598,7 @@ task_unlock(p); if (!files) goto out; + read_lock(&files->file_lock); for (fd = filp->f_pos-2; fd < files->max_fds; fd++, filp->f_pos++) { @@ -573,6 +619,7 @@ if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) break; } + read_unlock(&files->file_lock); put_files_struct(files); } out: @@ -874,6 +921,9 @@ case PROC_PID_MEM: inode->i_op = &proc_mem_inode_operations; inode->i_fop = &proc_mem_operations; + break; + case PROC_PID_MOUNTS: + inode->i_fop = &proc_mounts_operations; break; default: printk("procfs: impossible type (%d)",p->type); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/proc/proc_misc.c linux-2.5/fs/proc/proc_misc.c --- linux-2.5.1/fs/proc/proc_misc.c Thu Nov 29 15:49:55 2001 +++ linux-2.5/fs/proc/proc_misc.c Tue Jan 8 00:44:25 2002 @@ -84,11 +84,11 @@ a = avenrun[0] + (FIXED_1/200); b = avenrun[1] + (FIXED_1/200); c = avenrun[2] + (FIXED_1/200); - len = sprintf(page,"%d.%02d %d.%02d %d.%02d %d/%d %d\n", + len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), - nr_running, nr_threads, last_pid); + nr_running(), nr_threads, last_pid); return proc_calc_metrics(page, start, off, count, eof, len); } @@ -100,7 +100,7 @@ int len; uptime = jiffies; - idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime; + idle = init_task.times.tms_utime + init_task.times.tms_stime; /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but that would overflow about every five days at HZ == 100. @@ -291,10 +291,10 @@ } len += sprintf(page + len, - "\nctxt %u\n" + "\nctxt %lu\n" "btime %lu\n" "processes %lu\n", - kstat.context_swtch, + nr_context_switches(), xtime.tv_sec - jif / HZ, total_forks); @@ -500,18 +500,6 @@ write: write_profile, }; -extern struct seq_operations mounts_op; -static int mounts_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &mounts_op); -} -static struct file_operations proc_mounts_operations = { - open: mounts_open, - read: seq_read, - llseek: seq_lseek, - release: seq_release, -}; - struct proc_dir_entry *proc_root_kcore; static void create_seq_entry(char *name, mode_t mode, struct file_operations *f) @@ -555,11 +543,12 @@ for (p = simple_ones; p->name; p++) create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL); + proc_symlink("mounts", NULL, "self/mounts"); + /* And now for trickier ones */ entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); if (entry) entry->proc_fops = &proc_kmsg_operations; - create_seq_entry("mounts", 0, &proc_mounts_operations); create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); create_seq_entry("interrupts", 0, &proc_interrupts_operations); #ifdef CONFIG_MODULES diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/qnx4/dir.c linux-2.5/fs/qnx4/dir.c --- linux-2.5.1/fs/qnx4/dir.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/qnx4/dir.c Sun Dec 30 21:17:30 2001 @@ -18,7 +18,6 @@ #include <linux/qnx4_fs.h> #include <linux/stat.h> -#include <asm/segment.h> static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/qnx4/fsync.c linux-2.5/fs/qnx4/fsync.c --- linux-2.5.1/fs/qnx4/fsync.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/qnx4/fsync.c Sun Dec 30 21:17:30 2001 @@ -21,7 +21,6 @@ #include <linux/fs.h> #include <linux/qnx4_fs.h> -#include <asm/segment.h> #include <asm/system.h> /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/qnx4/inode.c linux-2.5/fs/qnx4/inode.c --- linux-2.5.1/fs/qnx4/inode.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/qnx4/inode.c Mon Jan 14 22:39:49 2002 @@ -18,8 +18,8 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/slab.h> -#include <linux/qnx4_fs.h> #include <linux/fs.h> +#include <linux/qnx4_fs.h> #include <linux/locks.h> #include <linux/init.h> #include <linux/highuid.h> @@ -48,7 +48,7 @@ if (buffer_req(bh) && !buffer_uptodate(bh)) { printk ("IO error syncing qnx4 inode [%s:%08lx]\n", - kdevname(inode->i_dev), inode->i_ino); + inode->i_sb->s_id, inode->i_ino); err = -1; } brelse (bh); @@ -89,7 +89,7 @@ } if (!ino) { printk("qnx4: bad inode number on dev %s: %d is out of range\n", - kdevname(inode->i_dev), ino); + inode->i_sb->s_id, ino); return; } QNX4DEBUG(("qnx4: write inode 2.\n")); @@ -97,7 +97,7 @@ lock_kernel(); if (!(bh = sb_bread(inode->i_sb, block))) { printk("qnx4: major problem: unable to read inode from dev " - "%s\n", kdevname(inode->i_dev)); + "%s\n", inode->i_sb->s_id); unlock_kernel(); return; } @@ -213,9 +213,7 @@ phys = qnx4_block_map( inode, iblock ); if ( phys ) { // logical block is before EOF - bh->b_dev = inode->i_dev; - bh->b_blocknr = phys; - bh->b_state |= (1UL << BH_Mapped); + map_bh(bh, inode->i_sb, phys); } else if ( create ) { // to be done. } @@ -303,7 +301,7 @@ if (*(sb->u.qnx4_sb.sb->RootDir.di_fname) != '/') { return "no qnx4 filesystem (no root dir)."; } else { - QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", kdevname(sb->s_dev))); + QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", sb->s_id)); rd = le32_to_cpu(sb->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_blk) - 1; rl = le32_to_cpu(sb->u.qnx4_sb.sb->RootDir.di_first_xtnt.xtnt_size); for (j = 0; j < rl; j++) { @@ -318,6 +316,10 @@ if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) { found = 1; sb->u.qnx4_sb.BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL ); + if (!sb->u.qnx4_sb.BitMap) { + brelse (bh); + return "not enough memory for bitmap inode"; + } memcpy( sb->u.qnx4_sb.BitMap, rootdir, sizeof( struct qnx4_inode_entry ) ); /* keep bitmap inode known */ break; } @@ -339,13 +341,10 @@ void *data, int silent) { struct buffer_head *bh; - kdev_t dev = s->s_dev; struct inode *root; const char *errmsg; - set_blocksize(dev, QNX4_BLOCK_SIZE); - s->s_blocksize = QNX4_BLOCK_SIZE; - s->s_blocksize_bits = QNX4_BLOCK_SIZE_BITS; + sb_set_blocksize(s, QNX4_BLOCK_SIZE); /* Check the boot signature. Since the qnx4 code is dangerous, we should leave as quickly as possible @@ -445,6 +444,7 @@ struct buffer_head *bh; struct qnx4_inode_entry *raw_inode; int block, ino; + struct super_block *sb = inode->i_sb; ino = inode->i_ino; inode->i_mode = 0; @@ -452,14 +452,14 @@ QNX4DEBUG(("Reading inode : [%d]\n", ino)); if (!ino) { printk("qnx4: bad inode number on dev %s: %d is out of range\n", - kdevname(inode->i_dev), ino); + sb->s_id, ino); return; } block = ino / QNX4_INODES_PER_BLOCK; - if (!(bh = sb_bread(inode->i_sb, block))) { + if (!(bh = sb_bread(sb, block))) { printk("qnx4: major problem: unable to read inode from dev " - "%s\n", kdevname(inode->i_dev)); + "%s\n", sb->s_id); return; } raw_inode = ((struct qnx4_inode_entry *) bh->b_data) + @@ -490,7 +490,7 @@ inode->i_mapping->a_ops = &qnx4_aops; inode->u.qnx4_i.mmu_private = inode->i_size; } else - printk("qnx4: bad inode %d on dev %s\n",ino,kdevname(inode->i_dev)); + printk("qnx4: bad inode %d on dev %s\n",ino,sb->s_id); brelse(bh); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/qnx4/namei.c linux-2.5/fs/qnx4/namei.c --- linux-2.5.1/fs/qnx4/namei.c Tue Sep 5 21:07:30 2000 +++ linux-2.5/fs/qnx4/namei.c Sat Jan 5 16:38:09 2002 @@ -21,7 +21,6 @@ #include <linux/fcntl.h> #include <linux/errno.h> -#include <asm/segment.h> /* * check if the filename is correct. For some obscure reason, qnx writes a @@ -214,7 +213,7 @@ retval = -EPERM; if (!inode->i_nlink) { QNX4DEBUG(("Deleting nonexistent file (%s:%lu), %d\n", - kdevname(inode->i_dev), + inode->i_sb->s_id, inode->i_ino, inode->i_nlink)); inode->i_nlink = 1; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/qnx4/truncate.c linux-2.5/fs/qnx4/truncate.c --- linux-2.5.1/fs/qnx4/truncate.c Fri Feb 9 19:29:44 2001 +++ linux-2.5/fs/qnx4/truncate.c Sun Dec 30 20:01:41 2001 @@ -13,9 +13,8 @@ #include <linux/config.h> #include <linux/types.h> #include <linux/errno.h> -#include <linux/slab.h> -#include <linux/qnx4_fs.h> #include <linux/fs.h> +#include <linux/qnx4_fs.h> #include <linux/locks.h> #include <asm/uaccess.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ramfs/inode.c linux-2.5/fs/ramfs/inode.c --- linux-2.5.1/fs/ramfs/inode.c Wed Oct 24 22:19:18 2001 +++ linux-2.5/fs/ramfs/inode.c Thu Dec 27 15:56:12 2001 @@ -325,6 +325,7 @@ } static DECLARE_FSTYPE(ramfs_fs_type, "ramfs", ramfs_read_super, FS_LITTER); +static DECLARE_FSTYPE(rootfs_fs_type, "rootfs", ramfs_read_super, FS_NOMOUNT|FS_LITTER); static int __init init_ramfs_fs(void) { @@ -338,5 +339,11 @@ module_init(init_ramfs_fs) module_exit(exit_ramfs_fs) + +int __init init_rootfs(void) +{ + return register_filesystem(&rootfs_fs_type); +} + MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/bitmap.c linux-2.5/fs/reiserfs/bitmap.c --- linux-2.5.1/fs/reiserfs/bitmap.c Fri Nov 9 22:18:25 2001 +++ linux-2.5/fs/reiserfs/bitmap.c Sat Jan 12 12:32:41 2002 @@ -84,7 +84,7 @@ to free a list of blocks at once. -Hans */ /* I wonder if it would be less modest now that we use journaling. -Hans */ -void reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long block) +static void _reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long block) { struct super_block * s = th->t_super; struct reiserfs_super_block * rs; @@ -92,9 +92,6 @@ struct buffer_head ** apbh; int nr, offset; - RFALSE(!s, "vs-4060: trying to free block on nonexistent device"); - RFALSE(is_reusable (s, block, 1) == 0, "vs-4070: can not free such block"); - PROC_INFO_INC( s, free_block ); rs = SB_DISK_SUPER_BLOCK (s); @@ -103,16 +100,20 @@ get_bit_address (s, block, &nr, &offset); - /* mark it before we clear it, just in case */ - journal_mark_freed(th, s, block) ; + if (nr >= sb_bmap_nr (rs)) { + reiserfs_warning ("vs-4075: reiserfs_free_block: " + "block %lu is out of range on %s\n", + block, bdevname(s->s_dev)); + return; + } reiserfs_prepare_for_journal(s, apbh[nr], 1 ) ; /* clear bit for the given block in bit map */ if (!reiserfs_test_and_clear_le_bit (offset, apbh[nr]->b_data)) { reiserfs_warning ("vs-4080: reiserfs_free_block: " - "free_block (%04x:%lu)[dev:blocknr]: bit already cleared\n", - s->s_dev, block); + "free_block (%s:%lu)[dev:blocknr]: bit already cleared\n", + s->s_id, block); } journal_mark_dirty (th, s, apbh[nr]); @@ -124,7 +125,24 @@ s->s_dirt = 1; } +void reiserfs_free_block (struct reiserfs_transaction_handle *th, + unsigned long block) { + struct super_block * s = th->t_super; + + RFALSE(!s, "vs-4061: trying to free block on nonexistent device"); + RFALSE(is_reusable (s, block, 1) == 0, "vs-4071: can not free such block"); + /* mark it before we clear it, just in case */ + journal_mark_freed(th, s, block) ; + _reiserfs_free_block(th, block) ; +} +/* preallocated blocks don't need to be run through journal_mark_freed */ +void reiserfs_free_prealloc_block (struct reiserfs_transaction_handle *th, + unsigned long block) { + RFALSE(!s, "vs-4060: trying to free block on nonexistent device"); + RFALSE(is_reusable (s, block, 1) == 0, "vs-4070: can not free such block"); + _reiserfs_free_block(th, block) ; +} /* beginning from offset-th bit in bmap_nr-th bitmap block, find_forward finds the closest zero bit. It returns 1 and zero @@ -402,7 +420,6 @@ ** has allocated it. loop around and try again */ if (reiserfs_test_and_set_le_bit (j, SB_AP_BITMAP (s)[i]->b_data)) { - reiserfs_warning("vs-4150: reiserfs_new_blocknrs, block not free"); reiserfs_restore_prepared_buffer(s, SB_AP_BITMAP(s)[i]) ; amount_needed++ ; continue ; @@ -488,12 +505,7 @@ ** to be grouped towards the start of the border */ border = le32_to_cpu(INODE_PKEY(p_s_inode)->k_dir_id) % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ; - } else { - /* why would we want to delcare a local variable to this if statement - ** name border????? -chris - ** unsigned long border = 0; - */ - if (!reiserfs_hashed_relocation(th->t_super)) { + } else if (!reiserfs_hashed_relocation(th->t_super)) { hash_in = le32_to_cpu((INODE_PKEY(p_s_inode))->k_dir_id); /* I wonder if the CPU cost of the hash will obscure the layout @@ -503,7 +515,6 @@ hash_out = keyed_hash(((char *) (&hash_in)), 4); border = hash_out % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ; - } } border += bstart ; allocated[0] = 0 ; /* important. Allows a check later on to see if at @@ -659,11 +670,13 @@ static void __discard_prealloc (struct reiserfs_transaction_handle * th, struct inode * inode) { + unsigned long save = inode->u.reiserfs_i.i_prealloc_block ; while (inode->u.reiserfs_i.i_prealloc_count > 0) { - reiserfs_free_block(th,inode->u.reiserfs_i.i_prealloc_block); + reiserfs_free_prealloc_block(th,inode->u.reiserfs_i.i_prealloc_block); inode->u.reiserfs_i.i_prealloc_block++; inode->u.reiserfs_i.i_prealloc_count --; } + inode->u.reiserfs_i.i_prealloc_block = save ; list_del (&(inode->u.reiserfs_i.i_prealloc_list)); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/buffer2.c linux-2.5/fs/reiserfs/buffer2.c --- linux-2.5.1/fs/reiserfs/buffer2.c Fri Nov 9 22:18:25 2001 +++ linux-2.5/fs/reiserfs/buffer2.c Tue Jan 8 01:42:18 2002 @@ -2,15 +2,6 @@ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ - -/* - * Contains code from - * - * linux/include/linux/lock.h and linux/fs/buffer.c /linux/fs/minix/fsync.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - #include <linux/config.h> #include <linux/sched.h> #include <linux/locks.h> @@ -21,12 +12,8 @@ /* * wait_buffer_until_released * reiserfs_bread - * reiserfs_getblk - * get_new_buffer */ - - /* when we allocate a new block (get_new_buffer, get_empty_nodes) and get buffer for it, it is possible that it is held by someone else or even by this process. In this function we wait until all other @@ -46,9 +33,7 @@ buffer_journal_dirty(bh) ? ' ' : '!'); } run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - /*current->counter = 0;*/ - schedule(); + yield(); } if (repeat_counter > 30000000) { reiserfs_warning("vs-3051: done waiting, ignore vs-3050 messages for (%b)\n", bh) ; @@ -63,289 +48,15 @@ then it creates a new buffer and schedules I/O to read the block. */ /* The function is NOT SCHEDULE-SAFE! */ - -struct buffer_head * reiserfs_bread (struct super_block *super, int n_block, int n_size) +struct buffer_head * reiserfs_bread (struct super_block *super, int n_block) { struct buffer_head *result; - PROC_EXP( unsigned int ctx_switches = kstat.context_swtch ); + PROC_EXP( unsigned int ctx_switches = nr_context_switches() ); - result = bread (super -> s_dev, n_block, n_size); + result = sb_bread(super, n_block); PROC_INFO_INC( super, breads ); - PROC_EXP( if( kstat.context_swtch != ctx_switches ) + PROC_EXP( if( nr_context_switches() != ctx_switches ) PROC_INFO_INC( super, bread_miss ) ); return result; } - -/* This function looks for a buffer which contains a given block. If - the block is in cache it returns it, otherwise it returns a new - buffer which is not uptodate. This is called by reiserfs_bread and - other functions. Note that get_new_buffer ought to be called this - and this ought to be called get_new_buffer, since this doesn't - actually get the block off of the disk. */ -/* The function is NOT SCHEDULE-SAFE! */ - -struct buffer_head * reiserfs_getblk (kdev_t n_dev, int n_block, int n_size) -{ - return getblk (n_dev, n_block, n_size); -} - -#ifdef NEW_GET_NEW_BUFFER - -/* returns one buffer with a blocknr near blocknr. */ -static int get_new_buffer_near_blocknr( - struct super_block * p_s_sb, - int blocknr, - struct buffer_head ** pp_s_new_bh, - struct path * p_s_path - ) { - unsigned long n_new_blocknumber = 0; - int n_ret_value, - n_repeat = CARRY_ON; - -#ifdef CONFIG_REISERFS_CHECK - int repeat_counter = 0; - - if (!blocknr) - printk ("blocknr passed to get_new_buffer_near_blocknr was 0"); -#endif - - - if ( (n_ret_value = reiserfs_new_blocknrs (p_s_sb, &n_new_blocknumber, - blocknr, 1)) == NO_DISK_SPACE ) - return NO_DISK_SPACE; - - *pp_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, n_new_blocknumber, p_s_sb->s_blocksize); - if ( buffer_uptodate(*pp_s_new_bh) ) { - - RFALSE( buffer_dirty(*pp_s_new_bh) || (*pp_s_new_bh)->b_dev == NODEV, - "PAP-14080: invalid uptodate buffer %b for the new block", - *pp_s_new_bh); - - /* Free path buffers to prevent deadlock. */ - /* It is possible that this process has the buffer, which this function is getting, already in - its path, and is responsible for double incrementing the value of b_count. If we recalculate - the path after schedule we can avoid risking an endless loop. This problematic situation is - possible in a multiple processing environment. Suppose process 1 has acquired a path P; then - process 2 balanced and remove block A from the tree. Process 1 continues and runs - get_new_buffer, that returns buffer with block A. If node A was on the path P, then it will - have b_count == 2. If we now will simply wait in while ( (*pp_s_new_bh)->b_count > 1 ) we get - into an endless loop, as nobody will release this buffer and the current process holds buffer - twice. That is why we do decrement_counters_in_path(p_s_path) before waiting until b_count - becomes 1. (it there were other processes holding node A, then eventually we will get a - moment, when all of them released a buffer). */ - if ( atomic_read (&((*pp_s_new_bh)->b_count)) > 1 ) { - decrement_counters_in_path(p_s_path); - n_ret_value |= SCHEDULE_OCCURRED; - } - - while ( atomic_read (&((*pp_s_new_bh)->b_count)) > 1 ) { - -#ifdef REISERFS_INFO - printk("get_new_buffer() calls schedule to decrement b_count\n"); -#endif - -#ifdef CONFIG_REISERFS_CHECK - if ( ! (++repeat_counter % 10000) ) - printk("get_new_buffer(%u): counter(%d) too big", current->pid, repeat_counter); -#endif - - current->counter = 0; - schedule(); - } - -#ifdef CONFIG_REISERFS_CHECK - if ( buffer_dirty(*pp_s_new_bh) || (*pp_s_new_bh)->b_dev == NODEV ) { - print_buffer_head(*pp_s_new_bh,"get_new_buffer"); - reiserfs_panic(p_s_sb, "PAP-14090: get_new_buffer: invalid uptodate buffer %b for the new block(case 2)", *pp_s_new_bh); - } -#endif - - } - else { - ; - - RFALSE( atomic_read (&((*pp_s_new_bh)->b_count)) != 1, - "PAP-14100: not uptodate buffer %b for the new block has b_count more than one", - *pp_s_new_bh); - - } - return (n_ret_value | n_repeat); -} - - -/* returns the block number of the last unformatted node, assumes p_s_key_to_search.k_offset is a byte in the tail of - the file, Useful for when you want to append to a file, and convert a direct item into an unformatted node near the - last unformatted node of the file. Putting the unformatted node near the direct item is potentially very bad to do. - If there is no unformatted node in the file, then we return the block number of the direct item. */ -/* The function is NOT SCHEDULE-SAFE! */ -inline int get_last_unformatted_node_blocknr_of_file( struct key * p_s_key_to_search, struct super_block * p_s_sb, - struct buffer_head * p_s_bh - struct path * p_unf_search_path, struct inode * p_s_inode) - -{ - struct key unf_key_to_search; - struct item_head * p_s_ih; - int n_pos_in_item; - struct buffer_head * p_indirect_item_bh; - - copy_key(&unf_key_to_search,p_s_key_to_search); - unf_key_to_search.k_uniqueness = TYPE_INDIRECT; - unf_key_to_search.k_offset = p_s_inode->u.reiserfs_i.i_first_direct_byte - 1; - - /* p_s_key_to_search->k_offset - MAX_ITEM_LEN(p_s_sb->s_blocksize); */ - if (search_for_position_by_key (p_s_sb, &unf_key_to_search, p_unf_search_path, &n_pos_in_item) == POSITION_FOUND) - { - p_s_ih = B_N_PITEM_HEAD(p_indirect_item_bh = PATH_PLAST_BUFFER(p_unf_search_path), PATH_LAST_POSITION(p_unf_search_path)); - return (B_I_POS_UNFM_POINTER(p_indirect_item_bh, p_s_ih, n_pos_in_item)); - } - /* else */ - printk("reiser-1800: search for unformatted node failed, p_s_key_to_search->k_offset = %u, unf_key_to_search.k_offset = %u, MAX_ITEM_LEN(p_s_sb->s_blocksize) = %ld, debug this\n", p_s_key_to_search->k_offset, unf_key_to_search.k_offset, MAX_ITEM_LEN(p_s_sb->s_blocksize) ); - print_buffer_head(PATH_PLAST_BUFFER(p_unf_search_path), "the buffer holding the item before the key we failed to find"); - print_block_head(PATH_PLAST_BUFFER(p_unf_search_path), "the block head"); - return 0; /* keeps the compiler quiet */ -} - - - /* hasn't been out of disk space tested */ -/* The function is NOT SCHEDULE-SAFE! */ -static int get_buffer_near_last_unf ( struct super_block * p_s_sb, struct key * p_s_key_to_search, - struct inode * p_s_inode, struct buffer_head * p_s_bh, - struct buffer_head ** pp_s_un_bh, struct path * p_s_search_path) -{ - int unf_blocknr = 0, /* blocknr from which we start search for a free block for an unformatted node, if 0 - then we didn't find an unformatted node though we might have found a file hole */ - n_repeat = CARRY_ON; - struct key unf_key_to_search; - struct path unf_search_path; - - copy_key(&unf_key_to_search,p_s_key_to_search); - unf_key_to_search.k_uniqueness = TYPE_INDIRECT; - - if ( - (p_s_inode->u.reiserfs_i.i_first_direct_byte > 4095) /* i_first_direct_byte gets used for all sorts of - crap other than what the name indicates, thus - testing to see if it is 0 is not enough */ - && (p_s_inode->u.reiserfs_i.i_first_direct_byte < MAX_KEY_OFFSET) /* if there is no direct item then - i_first_direct_byte = MAX_KEY_OFFSET */ - ) - { - /* actually, we don't want the last unformatted node, we want the last unformatted node - which is before the current file offset */ - unf_key_to_search.k_offset = ((p_s_inode->u.reiserfs_i.i_first_direct_byte -1) < unf_key_to_search.k_offset) ? p_s_inode->u.reiserfs_i.i_first_direct_byte -1 : unf_key_to_search.k_offset; - - while (unf_key_to_search.k_offset > -1) - { - /* This is our poorly documented way of initializing paths. -Hans */ - init_path (&unf_search_path); - /* get the blocknr from which we start the search for a free block. */ - unf_blocknr = get_last_unformatted_node_blocknr_of_file( p_s_key_to_search, /* assumes this points to the file tail */ - p_s_sb, /* lets us figure out the block size */ - p_s_bh, /* if there is no unformatted node in the file, - then it returns p_s_bh->b_blocknr */ - &unf_search_path, - p_s_inode - ); -/* printk("in while loop: unf_blocknr = %d, *pp_s_un_bh = %p\n", unf_blocknr, *pp_s_un_bh); */ - if (unf_blocknr) - break; - else /* release the path and search again, this could be really slow for huge - holes.....better to spend the coding time adding compression though.... -Hans */ - { - /* Vladimir, is it a problem that I don't brelse these buffers ?-Hans */ - decrement_counters_in_path(&unf_search_path); - unf_key_to_search.k_offset -= 4096; - } - } - if (unf_blocknr) { - n_repeat |= get_new_buffer_near_blocknr(p_s_sb, unf_blocknr, pp_s_un_bh, p_s_search_path); - } - else { /* all unformatted nodes are holes */ - n_repeat |= get_new_buffer_near_blocknr(p_s_sb, p_s_bh->b_blocknr, pp_s_un_bh, p_s_search_path); - } - } - else { /* file has no unformatted nodes */ - n_repeat |= get_new_buffer_near_blocknr(p_s_sb, p_s_bh->b_blocknr, pp_s_un_bh, p_s_search_path); -/* printk("in else: unf_blocknr = %d, *pp_s_un_bh = %p\n", unf_blocknr, *pp_s_un_bh); */ -/* print_path (0, p_s_search_path); */ - } - - return n_repeat; -} - -#endif /* NEW_GET_NEW_BUFFER */ - - -#ifdef OLD_GET_NEW_BUFFER - -/* The function is NOT SCHEDULE-SAFE! */ -int get_new_buffer( - struct reiserfs_transaction_handle *th, - struct buffer_head * p_s_bh, - struct buffer_head ** pp_s_new_bh, - struct path * p_s_path - ) { - unsigned long n_new_blocknumber = 0; - int n_repeat; - struct super_block * p_s_sb = th->t_super; - - if ( (n_repeat = reiserfs_new_unf_blocknrs (th, &n_new_blocknumber, p_s_bh->b_blocknr)) == NO_DISK_SPACE ) - return NO_DISK_SPACE; - - *pp_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, n_new_blocknumber, p_s_sb->s_blocksize); - if (atomic_read (&(*pp_s_new_bh)->b_count) > 1) { - /* Free path buffers to prevent deadlock which can occur in the - situation like : this process holds p_s_path; Block - (*pp_s_new_bh)->b_blocknr is on the path p_s_path, but it is - not necessary, that *pp_s_new_bh is in the tree; process 2 - could remove it from the tree and freed block - (*pp_s_new_bh)->b_blocknr. Reiserfs_new_blocknrs in above - returns block (*pp_s_new_bh)->b_blocknr. Reiserfs_getblk gets - buffer for it, and it has b_count > 1. If we now will simply - wait in while ( (*pp_s_new_bh)->b_count > 1 ) we get into an - endless loop, as nobody will release this buffer and the - current process holds buffer twice. That is why we do - decrement_counters_in_path(p_s_path) before waiting until - b_count becomes 1. (it there were other processes holding node - pp_s_new_bh, then eventually we will get a moment, when all of - them released a buffer). */ - decrement_counters_in_path(p_s_path); - wait_buffer_until_released (*pp_s_new_bh); - n_repeat |= SCHEDULE_OCCURRED; - } - - RFALSE( atomic_read (&((*pp_s_new_bh)->b_count)) != 1 || - buffer_dirty (*pp_s_new_bh), - "PAP-14100: not free or dirty buffer %b for the new block", - *pp_s_new_bh); - - return n_repeat; -} - -#endif /* OLD_GET_NEW_BUFFER */ - - -#ifdef GET_MANY_BLOCKNRS - /* code not yet functional */ -get_next_blocknr ( - unsigned long * p_blocknr_array, /* we get a whole bunch of blocknrs all at once for - the write. This is better than getting them one at - a time. */ - unsigned long ** p_blocknr_index, /* pointer to current offset into the array. */ - unsigned long blocknr_array_length -) -{ - unsigned long return_value; - - if (*p_blocknr_index < p_blocknr_array + blocknr_array_length) { - return_value = **p_blocknr_index; - **p_blocknr_index = 0; - *p_blocknr_index++; - return (return_value); - } - else - { - kfree (p_blocknr_array); - } -} -#endif /* GET_MANY_BLOCKNRS */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/dir.c linux-2.5/fs/reiserfs/dir.c --- linux-2.5.1/fs/reiserfs/dir.c Tue Oct 30 23:11:34 2001 +++ linux-2.5/fs/reiserfs/dir.c Thu Jan 10 13:58:14 2002 @@ -22,22 +22,6 @@ fsync: reiserfs_dir_fsync, }; -/* - * directories can handle most operations... - */ -struct inode_operations reiserfs_dir_inode_operations = { - //&reiserfs_dir_operations, /* default_file_ops */ - create: reiserfs_create, - lookup: reiserfs_lookup, - link: reiserfs_link, - unlink: reiserfs_unlink, - symlink: reiserfs_symlink, - mkdir: reiserfs_mkdir, - rmdir: reiserfs_rmdir, - mknod: reiserfs_mknod, - rename: reiserfs_rename, -}; - int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) { lock_kernel(); reiserfs_commit_for_inode(dentry->d_inode) ; @@ -131,13 +115,13 @@ if (d_reclen <= 32) { local_buf = small_buf ; } else { - local_buf = kmalloc(d_reclen, GFP_NOFS) ; + local_buf = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ; if (!local_buf) { pathrelse (&path_to_entry); return -ENOMEM ; } if (item_moved (&tmp_ih, &path_to_entry)) { - kfree(local_buf) ; + reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ; goto research; } } @@ -149,12 +133,12 @@ if (filldir (dirent, local_buf, d_reclen, d_off, d_ino, DT_UNKNOWN) < 0) { if (local_buf != small_buf) { - kfree(local_buf) ; + reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ; } goto end; } if (local_buf != small_buf) { - kfree(local_buf) ; + reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ; } // next entry should be looked for with such offset @@ -186,7 +170,7 @@ } /* directory continues in the right neighboring block */ - set_cpu_key_k_offset (&pos_key, le_key_k_offset (ITEM_VERSION_1, rkey)); + set_cpu_key_k_offset (&pos_key, le_key_k_offset (KEY_FORMAT_3_5, rkey)); } /* while */ @@ -197,4 +181,72 @@ pathrelse (&path_to_entry); reiserfs_check_path(&path_to_entry) ; return 0; +} + +/* compose directory item containing "." and ".." entries (entries are + not aligned to 4 byte boundary) */ +/* the last four params are LE */ +void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid, + __u32 par_dirid, __u32 par_objid) +{ + struct reiserfs_de_head * deh; + + memset (body, 0, EMPTY_DIR_SIZE_V1); + deh = (struct reiserfs_de_head *)body; + + /* direntry header of "." */ + put_deh_offset( &(deh[0]), DOT_OFFSET ); + /* these two are from make_le_item_head, and are are LE */ + deh[0].deh_dir_id = dirid; + deh[0].deh_objectid = objid; + deh[0].deh_state = 0; /* Endian safe if 0 */ + put_deh_location( &(deh[0]), EMPTY_DIR_SIZE_V1 - strlen( "." )); + mark_de_visible(&(deh[0])); + + /* direntry header of ".." */ + put_deh_offset( &(deh[1]), DOT_DOT_OFFSET); + /* key of ".." for the root directory */ + /* these two are from the inode, and are are LE */ + deh[1].deh_dir_id = par_dirid; + deh[1].deh_objectid = par_objid; + deh[1].deh_state = 0; /* Endian safe if 0 */ + put_deh_location( &(deh[1]), deh_location( &(deh[0]) ) - strlen( ".." ) ); + mark_de_visible(&(deh[1])); + + /* copy ".." and "." */ + memcpy (body + deh_location( &(deh[0]) ), ".", 1); + memcpy (body + deh_location( &(deh[1]) ), "..", 2); +} + +/* compose directory item containing "." and ".." entries */ +void make_empty_dir_item (char * body, __u32 dirid, __u32 objid, + __u32 par_dirid, __u32 par_objid) +{ + struct reiserfs_de_head * deh; + + memset (body, 0, EMPTY_DIR_SIZE); + deh = (struct reiserfs_de_head *)body; + + /* direntry header of "." */ + put_deh_offset( &(deh[0]), DOT_OFFSET ); + /* these two are from make_le_item_head, and are are LE */ + deh[0].deh_dir_id = dirid; + deh[0].deh_objectid = objid; + deh[0].deh_state = 0; /* Endian safe if 0 */ + put_deh_location( &(deh[0]), EMPTY_DIR_SIZE - ROUND_UP( strlen( "." ) ) ); + mark_de_visible(&(deh[0])); + + /* direntry header of ".." */ + put_deh_offset( &(deh[1]), DOT_DOT_OFFSET ); + /* key of ".." for the root directory */ + /* these two are from the inode, and are are LE */ + deh[1].deh_dir_id = par_dirid; + deh[1].deh_objectid = par_objid; + deh[1].deh_state = 0; /* Endian safe if 0 */ + put_deh_location( &(deh[1]), deh_location( &(deh[0])) - ROUND_UP( strlen( ".." ) ) ); + mark_de_visible(&(deh[1])); + + /* copy ".." and "." */ + memcpy (body + deh_location( &(deh[0]) ), ".", 1); + memcpy (body + deh_location( &(deh[1]) ), "..", 2); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/do_balan.c linux-2.5/fs/reiserfs/do_balan.c --- linux-2.5.1/fs/reiserfs/do_balan.c Fri Nov 9 22:18:25 2001 +++ linux-2.5/fs/reiserfs/do_balan.c Thu Dec 13 16:32:37 2001 @@ -274,13 +274,6 @@ int pos_in_item; int zeros_num; -#if 0 - if (tb->insert_size [0] % 4) { - reiserfs_panic (tb->tb_sb, "balance_leaf: wrong insert_size %d", - tb->insert_size [0]); - } -#endif - PROC_INFO_INC( tb -> tb_sb, balance_at[ 0 ] ); /* Make balance in case insert_size[0] < 0 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/file.c linux-2.5/fs/reiserfs/file.c --- linux-2.5.1/fs/reiserfs/file.c Fri Oct 12 21:20:42 2001 +++ linux-2.5/fs/reiserfs/file.c Thu Dec 13 16:32:37 2001 @@ -33,7 +33,7 @@ /* fast out for when nothing needs to be done */ if ((atomic_read(&inode->i_count) > 1 || - !inode->u.reiserfs_i.i_pack_on_close || + !(inode->u.reiserfs_i.i_flags & i_pack_on_close_mask) || !tail_has_to_be_packed(inode)) && inode->u.reiserfs_i.i_prealloc_count <= 0) { return 0; @@ -50,7 +50,7 @@ journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ; if (atomic_read(&inode->i_count) <= 1 && - inode->u.reiserfs_i.i_pack_on_close && + (inode->u.reiserfs_i.i_flags & i_pack_on_close_mask) && tail_has_to_be_packed (inode)) { /* if regular file is released by last holder and it has been appended (we append by unformatted node only) or its direct @@ -97,10 +97,16 @@ /* version 2 items will be caught by the s_maxbytes check ** done for us in vmtruncate */ - if (inode_items_version(inode) == ITEM_VERSION_1 && + if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 && attr->ia_size > MAX_NON_LFS) return -EFBIG ; } + + if ((((attr->ia_valid & ATTR_UID) && (attr->ia_uid & ~0xffff)) || + ((attr->ia_valid & ATTR_GID) && (attr->ia_gid & ~0xffff))) && + (get_inode_sd_version (inode) == STAT_DATA_V1)) + /* stat data of format v3.5 has 16 bit uid and gid */ + return -EINVAL; error = inode_change_ok(inode, attr) ; if (!error) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/fix_node.c linux-2.5/fs/reiserfs/fix_node.c --- linux-2.5.1/fs/reiserfs/fix_node.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/reiserfs/fix_node.c Thu Jan 10 13:58:14 2002 @@ -806,7 +806,7 @@ RFALSE( ! *p_n_blocknr, "PAP-8135: reiserfs_new_blocknrs failed when got new blocks"); - p_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, *p_n_blocknr, p_s_sb->s_blocksize); + p_s_new_bh = sb_getblk(p_s_sb, *p_n_blocknr); if (atomic_read (&(p_s_new_bh->b_count)) > 1) { /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ /* @@ -1926,7 +1926,7 @@ n_child_position = ( p_s_bh == p_s_tb->FL[n_h] ) ? p_s_tb->lkey[n_h] : B_NR_ITEMS (p_s_tb->FL[n_h]); n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position); - p_s_bh = reiserfs_bread(p_s_sb, n_son_number, p_s_sb->s_blocksize); + p_s_bh = reiserfs_bread(p_s_sb, n_son_number); if (!p_s_bh) return IO_ERROR; if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) { @@ -1959,7 +1959,7 @@ n_child_position = ( p_s_bh == p_s_tb->FR[n_h] ) ? p_s_tb->rkey[n_h] + 1 : 0; n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position); - p_s_bh = reiserfs_bread(p_s_sb, n_son_number, p_s_sb->s_blocksize); + p_s_bh = reiserfs_bread(p_s_sb, n_son_number); if (!p_s_bh) return IO_ERROR; if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) { @@ -1979,7 +1979,7 @@ return CARRY_ON; } - +#ifdef CONFIG_REISERFS_CHECK void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s) { void * vp; @@ -2007,6 +2007,7 @@ reiserfs_warning ("vs-8302: reiserfs_kfree: allocated memory %d\n", s->u.reiserfs_sb.s_kmallocs); } +#endif static int get_virtual_node_size (struct super_block * sb, struct buffer_head * bh) @@ -2021,23 +2022,6 @@ // entry would eat 2 byte of virtual node space return sb->s_blocksize; -#if 0 - size = sizeof (struct virtual_node) + sizeof (struct virtual_item); - ih = B_N_PITEM_HEAD (bh, 0); - nr_items = B_NR_ITEMS (bh); - for (i = 0; i < nr_items; i ++, ih ++) { - /* each item occupies some space in virtual node */ - size += sizeof (struct virtual_item); - if (is_direntry_le_ih (ih)) - /* each entry and new one occupeis 2 byte in the virtual node */ - size += (ih_entry_count(ih) + 1) * sizeof( __u16 ); - } - - /* 1 bit for each bitmap block to note whether bitmap block was - dirtied in the operation */ - /* size += (SB_BMAP_NR (sb) * 2 / 8 + 4);*/ - return size; -#endif } @@ -2115,7 +2099,7 @@ reiserfs_panic (p_s_sb, "tb_buffer_sanity_check(): buffer is not in tree %s[%d] (%b)\n", descr, level, p_s_bh); } - if (p_s_bh->b_dev != p_s_sb->s_dev || + if (!kdev_same(p_s_bh->b_dev, p_s_sb->s_dev) || p_s_bh->b_size != p_s_sb->s_blocksize || p_s_bh->b_blocknr > SB_BLOCK_COUNT(p_s_sb)) { reiserfs_panic (p_s_sb, "tb_buffer_sanity_check(): check failed for buffer %s[%d] (%b)\n", descr, level, p_s_bh); @@ -2342,15 +2326,6 @@ reiserfs_panic (p_s_tb->tb_sb, "PAP-8320: fix_nodes: S[0] (%b %z) is not uptodate " "at the beginning of fix_nodes or not in tree (mode %c)", p_s_tbS0, p_s_tbS0, n_op_mode); } - - // FIXME: new items have to be of 8 byte multiples. Including new - // directory items those look like old ones - /* - if (p_s_tb->insert_size[0] % 8) - reiserfs_panic (p_s_tb->tb_sb, "vs-: fix_nodes: incorrect insert_size %d, " - "mode %c", - p_s_tb->insert_size[0], n_op_mode); - */ /* Check parameters. */ switch (n_op_mode) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/inode.c linux-2.5/fs/reiserfs/inode.c --- linux-2.5.1/fs/reiserfs/inode.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/reiserfs/inode.c Sat Jan 5 16:38:09 2002 @@ -17,6 +17,8 @@ #define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */ #define GET_BLOCK_NO_ISEM 8 /* i_sem is not held, don't preallocate */ +static int reiserfs_get_block (struct inode * inode, sector_t block, + struct buffer_head * bh_result, int create); // // initially this function was derived from minix or ext2's analog and // evolved as the prototype did @@ -40,11 +42,13 @@ reiserfs_delete_object (&th, inode); pop_journal_writer(windex) ; - reiserfs_release_objectid (&th, inode->i_ino); journal_end(&th, inode->i_sb, jbegin_count) ; - up (&inode->i_sem); + up (&inode->i_sem); + + /* all items of file are deleted, so we can remove "save" link */ + remove_save_link (inode, 0/* not truncate */); } else { /* no object items are in the tree */ ; @@ -72,9 +76,9 @@ void make_cpu_key (struct cpu_key * key, const struct inode * inode, loff_t offset, int type, int length ) { - _make_cpu_key (key, inode_items_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id), - le32_to_cpu (INODE_PKEY (inode)->k_objectid), - offset, type, length); + _make_cpu_key (key, get_inode_item_key_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id), + le32_to_cpu (INODE_PKEY (inode)->k_objectid), + offset, type, length); } @@ -205,9 +209,7 @@ static inline void set_block_dev_mapped (struct buffer_head * bh, b_blocknr_t block, struct inode * inode) { - bh->b_dev = inode->i_dev; - bh->b_blocknr = block; - bh->b_state |= (1UL << BH_Mapped); + map_bh(bh, inode->i_sb, block); } @@ -215,9 +217,9 @@ // files which were created in the earlier version can not be longer, // than 2 gb // -int file_capable (struct inode * inode, long block) +static int file_capable (struct inode * inode, long block) { - if (inode_items_version (inode) != ITEM_VERSION_1 || // it is new file. + if (get_inode_item_key_version (inode) != KEY_FORMAT_3_5 || // it is new file. block < (1 << (31 - inode->i_sb->s_blocksize_bits))) // old file, but 'block' is inside of 2gb return 1; @@ -269,7 +271,9 @@ pathrelse (&path); if (p) kunmap(bh_result->b_page) ; - if ((args & GET_BLOCK_NO_HOLE)) { + // We do not return -ENOENT if there is a hole but page is uptodate, because it means + // That there is some MMAPED data associated with it that is yet to be written to disk. + if ((args & GET_BLOCK_NO_HOLE) && !Page_Uptodate(bh_result->b_page) ) { return -ENOENT ; } return 0 ; @@ -287,12 +291,14 @@ blocknr = get_block_num(ind_item, path.pos_in_item) ; ret = 0 ; if (blocknr) { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = blocknr; - bh_result->b_state |= (1UL << BH_Mapped); - } else if ((args & GET_BLOCK_NO_HOLE)) { - ret = -ENOENT ; - } + map_bh(bh_result, inode->i_sb, blocknr); + } else + // We do not return -ENOENT if there is a hole but page is uptodate, because it means + // That there is some MMAPED data associated with it that is yet to be written to disk. + if ((args & GET_BLOCK_NO_HOLE) && !Page_Uptodate(bh_result->b_page) ) { + ret = -ENOENT; + } + pathrelse (&path); if (p) kunmap(bh_result->b_page) ; @@ -315,6 +321,16 @@ */ if (buffer_uptodate(bh_result)) { goto finished ; + } else + /* + ** grab_tail_page can trigger calls to reiserfs_get_block on up to date + ** pages without any buffers. If the page is up to date, we don't want + ** read old data off disk. Set the up to date bit on the buffer instead + ** and jump to the end + */ + if (Page_Uptodate(bh_result->b_page)) { + mark_buffer_uptodate(bh_result, 1); + goto finished ; } // read file tail into part of page @@ -380,10 +396,9 @@ finished: pathrelse (&path); - bh_result->b_blocknr = 0 ; - bh_result->b_dev = inode->i_dev; + /* I _really_ doubt that you want it. Chris? */ + map_bh(bh_result, inode->i_sb, 0); mark_buffer_uptodate (bh_result, 1); - bh_result->b_state |= (1UL << BH_Mapped); return 0; } @@ -540,7 +555,7 @@ /* bad.... */ lock_kernel() ; th.t_trans_id = 0 ; - version = inode_items_version (inode); + version = get_inode_item_key_version (inode); if (block < 0) { unlock_kernel(); @@ -564,7 +579,7 @@ return ret; } - inode->u.reiserfs_i.i_pack_on_close = 1 ; + inode->u.reiserfs_i.i_flags |= i_pack_on_close_mask; windex = push_journal_writer("reiserfs_get_block") ; @@ -823,7 +838,7 @@ } if (retval == POSITION_FOUND) { reiserfs_warning ("vs-825: reiserfs_get_block: " - "%k should not be found\n", &key); + "%K should not be found\n", &key); retval = -EEXIST; if (allocated_block_nr) reiserfs_free_block (&th, allocated_block_nr); @@ -880,7 +895,8 @@ struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih); unsigned long blocks; - inode_items_version (inode) = ITEM_VERSION_1; + set_inode_item_key_version (inode, KEY_FORMAT_3_5); + set_inode_sd_version (inode, STAT_DATA_V1); inode->i_mode = sd_v1_mode(sd); inode->i_nlink = sd_v1_nlink(sd); inode->i_uid = sd_v1_uid(sd); @@ -929,13 +945,13 @@ inode->i_generation = sd_v2_generation(sd); if (S_ISDIR (inode->i_mode) || S_ISLNK (inode->i_mode)) - inode_items_version (inode) = ITEM_VERSION_1; + set_inode_item_key_version (inode, KEY_FORMAT_3_5); else - inode_items_version (inode) = ITEM_VERSION_2; + set_inode_item_key_version (inode, KEY_FORMAT_3_6); } /* nopack = 0, by default */ - inode->u.reiserfs_i.nopack = 0; + inode->u.reiserfs_i.i_flags &= ~i_nopack_mask; pathrelse (path); if (S_ISREG (inode->i_mode)) { @@ -970,8 +986,8 @@ set_sd_v2_ctime(sd_v2, inode->i_ctime ); set_sd_v2_blocks(sd_v2, inode->i_blocks ); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - set_sd_v2_rdev(sd_v2, inode->i_rdev ); -} + set_sd_v2_rdev(sd_v2, kdev_t_to_nr(inode->i_rdev) ); + } else { set_sd_v2_generation(sd_v2, inode->i_generation); @@ -994,7 +1010,7 @@ set_sd_v1_mtime(sd_v1, inode->i_mtime ); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) - set_sd_v1_rdev(sd_v1, inode->i_rdev ); + set_sd_v1_rdev(sd_v1, kdev_t_to_nr(inode->i_rdev) ); else set_sd_v1_blocks(sd_v1, inode->i_blocks ); @@ -1115,7 +1131,7 @@ /* set version 1, version 2 could be used too, because stat data key is the same in both versions */ - key.version = ITEM_VERSION_1; + key.version = KEY_FORMAT_3_5; key.on_disk_key.k_dir_id = dirino; key.on_disk_key.k_objectid = inode->i_ino; key.on_disk_key.u.k_offset_v1.k_offset = SD_OFFSET; @@ -1138,6 +1154,30 @@ } init_inode (inode, &path_to_sd); + + /* It is possible that knfsd is trying to access inode of a file + that is being removed from the disk by some other thread. As we + update sd on unlink all that is required is to check for nlink + here. This bug was first found by Sizif when debugging + SquidNG/Butterfly, forgotten, and found again after Philippe + Gramoulle <philippe.gramoulle@mmania.com> reproduced it. + + More logical fix would require changes in fs/inode.c:iput() to + remove inode from hash-table _after_ fs cleaned disk stuff up and + in iget() to return NULL if I_FREEING inode is found in + hash-table. */ + /* Currently there is one place where it's ok to meet inode with + nlink==0: processing of open-unlinked and half-truncated files + during mount (fs/reiserfs/super.c:finish_unfinished()). */ + if( ( inode -> i_nlink == 0 ) && + ! inode -> i_sb -> u.reiserfs_sb.s_is_unlinked_ok ) { + reiserfs_warning( "vs-13075: reiserfs_read_inode2: " + "dead inode read from disk %K. " + "This is likely to be race with knfsd. Ignore\n", + &key ); + make_bad_inode( inode ); + } + reiserfs_check_path(&path_to_sd) ; /* init inode should be relsing */ } @@ -1162,7 +1202,7 @@ } struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *data, - int len, int fhtype, int parent) { + int len, int fhtype, int parent) { struct cpu_key key ; struct inode *inode = NULL ; struct list_head *lp; @@ -1303,26 +1343,6 @@ } } -void reiserfs_dirty_inode (struct inode * inode) { - struct reiserfs_transaction_handle th ; - - if (inode->i_sb->s_flags & MS_RDONLY) { - reiserfs_warning("clm-6006: writing inode %lu on readonly FS\n", - inode->i_ino) ; - return ; - } - lock_kernel() ; - - /* this is really only used for atime updates, so they don't have - ** to be included in O_SYNC or fsync - */ - journal_begin(&th, inode->i_sb, 1) ; - reiserfs_update_sd (&th, inode); - journal_end(&th, inode->i_sb, 1) ; - unlock_kernel() ; -} - - /* FIXME: no need any more. right? */ int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode) { @@ -1345,20 +1365,20 @@ struct cpu_key key; int retval; - _make_cpu_key (&key, ITEM_VERSION_1, le32_to_cpu (ih->ih_key.k_dir_id), + _make_cpu_key (&key, KEY_FORMAT_3_5, le32_to_cpu (ih->ih_key.k_dir_id), le32_to_cpu (ih->ih_key.k_objectid), DOT_OFFSET, TYPE_DIRENTRY, 3/*key length*/); /* compose item head for new item. Directories consist of items of old type (ITEM_VERSION_1). Do not set key (second arg is 0), it is done by reiserfs_new_inode */ if (old_format_only (sb)) { - make_le_item_head (ih, 0, ITEM_VERSION_1, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2); + make_le_item_head (ih, 0, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2); make_empty_dir_item_v1 (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid, INODE_PKEY (dir)->k_dir_id, INODE_PKEY (dir)->k_objectid ); } else { - make_le_item_head (ih, 0, ITEM_VERSION_1, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2); + make_le_item_head (ih, 0, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2); make_empty_dir_item (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid, INODE_PKEY (dir)->k_dir_id, @@ -1394,12 +1414,12 @@ struct cpu_key key; int retval; - _make_cpu_key (&key, ITEM_VERSION_1, + _make_cpu_key (&key, KEY_FORMAT_3_5, le32_to_cpu (ih->ih_key.k_dir_id), le32_to_cpu (ih->ih_key.k_objectid), 1, TYPE_DIRECT, 3/*key length*/); - make_le_item_head (ih, 0, ITEM_VERSION_1, 1, TYPE_DIRECT, item_len, 0/*free_space*/); + make_le_item_head (ih, 0, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len, 0/*free_space*/); /* look for place in the tree for new item */ retval = search_item (sb, &key, path); @@ -1470,13 +1490,13 @@ inode->i_generation = ++event; #endif if (old_format_only (sb)) - make_le_item_head (&ih, 0, ITEM_VERSION_1, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT); + make_le_item_head (&ih, 0, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT); else - make_le_item_head (&ih, 0, ITEM_VERSION_2, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT); + make_le_item_head (&ih, 0, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT); /* key to search for correct place for new stat data */ - _make_cpu_key (&key, ITEM_VERSION_2, le32_to_cpu (ih.ih_key.k_dir_id), + _make_cpu_key (&key, KEY_FORMAT_3_6, le32_to_cpu (ih.ih_key.k_dir_id), le32_to_cpu (ih.ih_key.k_objectid), SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/); /* find proper place for inserting of stat data */ @@ -1512,25 +1532,35 @@ INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ; - if (old_format_only (sb)) + if (old_format_only (sb)) { + if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) { + pathrelse (&path_to_key); + /* i_uid or i_gid is too big to be stored in stat data v3.5 */ + iput (inode); + *err = -EINVAL; + return NULL; + } inode2sd_v1 (&sd, inode); - else + } else inode2sd (&sd, inode); // these do not go to on-disk stat data inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid); inode->i_blksize = PAGE_SIZE; - inode->i_dev = sb->s_dev; // store in in-core inode the key of stat data and version all // object items will have (directory items will have old offset // format, other new objects will consist of new items) memcpy (INODE_PKEY (inode), &(ih.ih_key), KEY_SIZE); if (old_format_only (sb) || S_ISDIR(mode) || S_ISLNK(mode)) - inode_items_version (inode) = ITEM_VERSION_1; + set_inode_item_key_version (inode, KEY_FORMAT_3_5); else - inode_items_version (inode) = ITEM_VERSION_2; - + set_inode_item_key_version (inode, KEY_FORMAT_3_6); + if (old_format_only (sb)) + set_inode_sd_version (inode, STAT_DATA_V1); + else + set_inode_sd_version (inode, STAT_DATA_V2); + /* insert the stat data into the tree */ retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd)); if (retval) { @@ -1690,12 +1720,23 @@ ** because the truncate might pack the item anyway ** (it will unmap bh if it packs). */ - journal_begin(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ; + /* it is enough to reserve space in transaction for 2 balancings: + one for "save" link adding and another for the first + cut_from_item. 1 is for update_sd */ + journal_begin(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ; reiserfs_update_inode_transaction(p_s_inode) ; windex = push_journal_writer("reiserfs_vfs_truncate_file") ; + if (update_timestamps) + /* we are doing real truncate: if the system crashes before the last + transaction of truncating gets committed - on reboot the file + either appears truncated properly or not truncated at all */ + add_save_link (&th, p_s_inode, 1); reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ; pop_journal_writer(windex) ; - journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ; + journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ; + + if (update_timestamps) + remove_save_link (p_s_inode, 1/* truncate */); if (page) { length = offset & (blocksize - 1) ; @@ -1735,6 +1776,7 @@ int bytes_copied = 0 ; int copy_size ; + kmap(bh_result->b_page) ; start_over: lock_kernel() ; journal_begin(&th, inode->i_sb, jbegin_count) ; @@ -1794,7 +1836,7 @@ goto research ; } } else { - reiserfs_warning("clm-6003: bad item inode %lu, device %s\n", inode->i_ino, kdevname(inode->i_sb->s_dev)) ; + reiserfs_warning("clm-6003: bad item inode %lu, device %s\n", inode->i_ino, inode->i_sb->s_id) ; retval = -EIO ; goto out ; } @@ -1807,10 +1849,8 @@ /* this is where we fill in holes in the file. */ if (use_get_block) { - kmap(bh_result->b_page) ; retval = reiserfs_get_block(inode, block, bh_result, GET_BLOCK_CREATE | GET_BLOCK_NO_ISEM) ; - kunmap(bh_result->b_page) ; if (!retval) { if (!buffer_mapped(bh_result) || bh_result->b_blocknr == 0) { /* get_block failed to find a mapped unformatted node. */ @@ -1819,6 +1859,7 @@ } } } + kunmap(bh_result->b_page) ; return retval ; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/ioctl.c linux-2.5/fs/reiserfs/ioctl.c --- linux-2.5.1/fs/reiserfs/ioctl.c Sat Sep 8 19:05:32 2001 +++ linux-2.5/fs/reiserfs/ioctl.c Thu Dec 13 16:32:37 2001 @@ -46,7 +46,7 @@ return -EINVAL ; } /* ioctl already done */ - if (inode->u.reiserfs_i.nopack) { + if (inode->u.reiserfs_i.i_flags & i_nopack_mask) { return 0 ; } lock_kernel(); @@ -59,7 +59,7 @@ write_from = inode->i_size & (blocksize - 1) ; /* if we are on a block boundary, we are already unpacked. */ if ( write_from == 0) { - inode->u.reiserfs_i.nopack = 1; + inode->u.reiserfs_i.i_flags |= i_nopack_mask; goto out ; } @@ -79,7 +79,7 @@ /* conversion can change page contents, must flush */ flush_dcache_page(page) ; - inode->u.reiserfs_i.nopack = 1; + inode->u.reiserfs_i.i_flags |= i_nopack_mask; kunmap(page) ; /* mapped by prepare_write */ out_unlock: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/item_ops.c linux-2.5/fs/reiserfs/item_ops.c --- linux-2.5.1/fs/reiserfs/item_ops.c Fri Oct 12 21:19:28 2001 +++ linux-2.5/fs/reiserfs/item_ops.c Thu Jan 10 13:58:14 2002 @@ -685,17 +685,110 @@ ////////////////////////////////////////////////////////////////////////////// +// Error catching functions to catch errors caused by incorrect item types. +// +static int errcatch_bytes_number (struct item_head * ih, int block_size) +{ + reiserfs_warning ("green-16001: Invalid item type observed, run fsck ASAP\n"); + return 0; +} + +static void errcatch_decrement_key (struct cpu_key * key) +{ + reiserfs_warning ("green-16002: Invalid item type observed, run fsck ASAP\n"); +} + + +static int errcatch_is_left_mergeable (struct key * key, unsigned long bsize) +{ + reiserfs_warning ("green-16003: Invalid item type observed, run fsck ASAP\n"); + return 0; +} + + +static void errcatch_print_item (struct item_head * ih, char * item) +{ + reiserfs_warning ("green-16004: Invalid item type observed, run fsck ASAP\n"); +} + + +static void errcatch_check_item (struct item_head * ih, char * item) +{ + reiserfs_warning ("green-16005: Invalid item type observed, run fsck ASAP\n"); +} + +static int errcatch_create_vi (struct virtual_node * vn, + struct virtual_item * vi, + int is_affected, + int insert_size) +{ + reiserfs_warning ("green-16006: Invalid item type observed, run fsck ASAP\n"); + return 0; // We might return -1 here as well, but it won't help as create_virtual_node() from where + // this operation is called from is of return type void. +} + +static int errcatch_check_left (struct virtual_item * vi, int free, + int start_skip, int end_skip) +{ + reiserfs_warning ("green-16007: Invalid item type observed, run fsck ASAP\n"); + return -1; +} + + +static int errcatch_check_right (struct virtual_item * vi, int free) +{ + reiserfs_warning ("green-16008: Invalid item type observed, run fsck ASAP\n"); + return -1; +} + +static int errcatch_part_size (struct virtual_item * vi, int first, int count) +{ + reiserfs_warning ("green-16009: Invalid item type observed, run fsck ASAP\n"); + return 0; +} + +static int errcatch_unit_num (struct virtual_item * vi) +{ + reiserfs_warning ("green-16010: Invalid item type observed, run fsck ASAP\n"); + return 0; +} + +static void errcatch_print_vi (struct virtual_item * vi) +{ + reiserfs_warning ("green-16011: Invalid item type observed, run fsck ASAP\n"); +} + +struct item_operations errcatch_ops = { + errcatch_bytes_number, + errcatch_decrement_key, + errcatch_is_left_mergeable, + errcatch_print_item, + errcatch_check_item, + + errcatch_create_vi, + errcatch_check_left, + errcatch_check_right, + errcatch_part_size, + errcatch_unit_num, + errcatch_print_vi +}; + + + +////////////////////////////////////////////////////////////////////////////// // // #if ! (TYPE_STAT_DATA == 0 && TYPE_INDIRECT == 1 && TYPE_DIRECT == 2 && TYPE_DIRENTRY == 3) do not compile #endif -struct item_operations * item_ops [4] = { +struct item_operations * item_ops [TYPE_ANY + 1] = { &stat_data_ops, &indirect_ops, &direct_ops, - &direntry_ops + &direntry_ops, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &errcatch_ops /* This is to catch errors with invalid type (15th entry for TYPE_ANY) */ }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/journal.c linux-2.5/fs/reiserfs/journal.c --- linux-2.5.1/fs/reiserfs/journal.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/reiserfs/journal.c Thu Jan 10 13:58:14 2002 @@ -92,6 +92,8 @@ static int flush_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) ; static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) ; static int can_dirty(struct reiserfs_journal_cnode *cn) ; +static int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed); +static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks); static void init_journal_hash(struct super_block *p_s_sb) { memset(SB_JOURNAL(p_s_sb)->j_hash_table, 0, JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)) ; @@ -115,13 +117,13 @@ struct reiserfs_bitmap_node *bn ; static int id = 0 ; - bn = kmalloc(sizeof(struct reiserfs_bitmap_node), GFP_NOFS) ; + bn = reiserfs_kmalloc(sizeof(struct reiserfs_bitmap_node), GFP_NOFS, p_s_sb) ; if (!bn) { return NULL ; } - bn->data = kmalloc(p_s_sb->s_blocksize, GFP_NOFS) ; + bn->data = reiserfs_kmalloc(p_s_sb->s_blocksize, GFP_NOFS, p_s_sb) ; if (!bn->data) { - kfree(bn) ; + reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ; return NULL ; } bn->id = id++ ; @@ -147,8 +149,7 @@ } bn = allocate_bitmap_node(p_s_sb) ; if (!bn) { - current->policy |= SCHED_YIELD ; - schedule() ; + yield(); goto repeat ; } return bn ; @@ -157,8 +158,8 @@ struct reiserfs_bitmap_node *bn) { SB_JOURNAL(p_s_sb)->j_used_bitmap_nodes-- ; if (SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes > REISERFS_MAX_BITMAP_NODES) { - kfree(bn->data) ; - kfree(bn) ; + reiserfs_kfree(bn->data, p_s_sb->s_blocksize, p_s_sb) ; + reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ; } else { list_add(&bn->list, &SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ; SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes++ ; @@ -226,8 +227,8 @@ while(next != &SB_JOURNAL(p_s_sb)->j_bitmap_nodes) { bn = list_entry(next, struct reiserfs_bitmap_node, list) ; list_del(next) ; - kfree(bn->data) ; - kfree(bn) ; + reiserfs_kfree(bn->data, p_s_sb->s_blocksize, p_s_sb) ; + reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ; next = SB_JOURNAL(p_s_sb)->j_bitmap_nodes.next ; SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes-- ; } @@ -420,7 +421,7 @@ struct reiserfs_journal_cnode *cn ; cn = journal_hash(table, dev, bl) ; while(cn) { - if ((cn->blocknr == bl) && (cn->dev == dev)) + if ((cn->blocknr == bl) && (kdev_same(cn->dev, dev))) return cn ; cn = cn->hnext ; } @@ -766,7 +767,7 @@ cn = cn->hprev ; while(cn) { - if (cn->dev == dev && cn->blocknr == blocknr && cn->jlist) { + if (kdev_same(cn->dev,dev) && cn->blocknr == blocknr && cn->jlist) { return cn->jlist ; } cn = cn->hprev ; @@ -1179,7 +1180,7 @@ mark_buffer_notjournal_dirty(cn->bh) ; while(walk_cn) { if (walk_cn->bh && walk_cn->blocknr == blocknr && - walk_cn->dev == cn->dev) { + kdev_same(walk_cn->dev,cn->dev)) { if (walk_cn->jlist) { atomic_dec(&(walk_cn->jlist->j_nonzerolen)) ; } @@ -1282,7 +1283,7 @@ } cur = *head ; while(cur) { - if (cur->blocknr == bh->b_blocknr && cur->dev == bh->b_dev && (jl == NULL || jl == cur->jlist) && + if (cur->blocknr == bh->b_blocknr && kdev_same(cur->dev,bh->b_dev) && (jl == NULL || jl == cur->jlist) && (!test_bit(BLOCK_FREED, &cur->state) || remove_freed)) { if (cur->hnext) { cur->hnext->hprev = cur->hprev ; @@ -1293,7 +1294,7 @@ *head = cur->hnext ; } cur->blocknr = 0 ; - cur->dev = 0 ; + cur->dev = NODEV ; cur->state = 0 ; if (cur->bh && cur->jlist) /* anybody who clears the cur->bh will also dec the nonzerolen */ atomic_dec(&(cur->jlist->j_nonzerolen)) ; @@ -1498,13 +1499,13 @@ } trans_id = le32_to_cpu(desc->j_trans_id) ; /* now we know we've got a good transaction, and it was inside the valid time ranges */ - log_blocks = kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS) ; - real_blocks = kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS) ; + log_blocks = reiserfs_kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; + real_blocks = reiserfs_kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; if (!log_blocks || !real_blocks) { brelse(c_bh) ; brelse(d_bh) ; - kfree(log_blocks) ; - kfree(real_blocks) ; + reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; reiserfs_warning("journal-1169: kmalloc failed, unable to mount FS\n") ; return -1 ; } @@ -1523,8 +1524,8 @@ brelse_array(real_blocks, i) ; brelse(c_bh) ; brelse(d_bh) ; - kfree(log_blocks) ; - kfree(real_blocks) ; + reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } } @@ -1538,8 +1539,8 @@ brelse_array(real_blocks, le32_to_cpu(desc->j_len)) ; brelse(c_bh) ; brelse(d_bh) ; - kfree(log_blocks) ; - kfree(real_blocks) ; + reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } memcpy(real_blocks[i]->b_data, log_blocks[i]->b_data, real_blocks[i]->b_size) ; @@ -1558,8 +1559,8 @@ brelse_array(real_blocks + i, le32_to_cpu(desc->j_len) - i) ; brelse(c_bh) ; brelse(d_bh) ; - kfree(log_blocks) ; - kfree(real_blocks) ; + reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } brelse(real_blocks[i]) ; @@ -1575,8 +1576,8 @@ SB_JOURNAL(p_s_sb)->j_trans_id = trans_id + 1; brelse(c_bh) ; brelse(d_bh) ; - kfree(log_blocks) ; - kfree(real_blocks) ; + reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; return 0 ; } @@ -1694,7 +1695,7 @@ /* step three, starting at the oldest transaction, replay */ if (last_flush_start > 0) { oldest_start = last_flush_start ; - oldest_trans_id = last_flush_trans_id ; + oldest_trans_id = last_flush_trans_id + 1 ; } cur_dblock = oldest_start ; if (oldest_trans_id) { @@ -1714,6 +1715,8 @@ } cur_dblock = reiserfs_get_journal_block(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start ; replay_count++ ; + if (cur_dblock == oldest_start) + break; } if (oldest_trans_id == 0) { @@ -1773,7 +1776,7 @@ atomic_read(&(jl->j_commit_left)) == 0) { kupdate_one_transaction(ct->p_s_sb, jl) ; } - kfree(ct->self) ; + reiserfs_kfree(ct->self, sizeof(struct reiserfs_journal_commit_task), ct->p_s_sb) ; } static void setup_commit_task_arg(struct reiserfs_journal_commit_task *ct, @@ -1797,7 +1800,7 @@ /* using GFP_NOFS, GFP_KERNEL could try to flush inodes, which will try ** to start/join a transaction, which will deadlock */ - ct = kmalloc(sizeof(struct reiserfs_journal_commit_task), GFP_NOFS) ; + ct = reiserfs_kmalloc(sizeof(struct reiserfs_journal_commit_task), GFP_NOFS, p_s_sb) ; if (ct) { setup_commit_task_arg(ct, p_s_sb, jindex) ; queue_task(&(ct->task), &reiserfs_commit_thread_tq); @@ -1844,7 +1847,7 @@ break ; } wake_up(&reiserfs_commit_thread_done) ; - interruptible_sleep_on_timeout(&reiserfs_commit_thread_wait, 5) ; + interruptible_sleep_on_timeout(&reiserfs_commit_thread_wait, 5 * HZ) ; } unlock_kernel() ; wake_up(&reiserfs_commit_thread_done) ; @@ -2080,7 +2083,7 @@ } -int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) { +static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) { return do_journal_begin_r(th, p_s_sb, nblocks, 1) ; } @@ -2235,7 +2238,7 @@ ** ** returns 1 if it cleaned and relsed the buffer. 0 otherwise */ -int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) { +static int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) { struct buffer_head *bh ; struct reiserfs_journal_cnode *cn ; int ret = 0; @@ -2276,7 +2279,7 @@ } /* removes from a specific journal list hash */ -int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) { +static int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) { remove_journal_hash(SB_JOURNAL(s)->j_list_hash_table, jl, bh, remove_freed) ; return 0 ; } @@ -2302,7 +2305,7 @@ ** to disk right now. */ while(cur && can_dirty) { - if (cur->jlist && cur->bh && cur->blocknr && cur->dev == dev && + if (cur->jlist && cur->bh && cur->blocknr && kdev_same(cur->dev,dev) && cur->blocknr == blocknr) { can_dirty = 0 ; } @@ -2315,7 +2318,7 @@ while(cur && can_dirty) { if (cur->jlist && cur->jlist->j_len > 0 && atomic_read(&(cur->jlist->j_commit_left)) > 0 && cur->bh && - cur->blocknr && cur->dev == dev && cur->blocknr == blocknr) { + cur->blocknr && kdev_same(cur->dev,dev) && cur->blocknr == blocknr) { can_dirty = 0 ; } cur = cur->hnext ; @@ -2338,20 +2341,6 @@ int show_reiserfs_locks(void) { dump_journal_writers() ; -#if 0 /* debugging code for when we are compiled static don't delete */ - p_s_sb = sb_entry(super_blocks.next); - while (p_s_sb != sb_entry(&super_blocks)) { - if (reiserfs_is_super(p_s_sb)) { -printk("journal lock is %d, join lock is %d, writers %d must wait is %d\n", - atomic_read(&(SB_JOURNAL(p_s_sb)->j_wlock)), - atomic_read(&(SB_JOURNAL(p_s_sb)->j_jlock)), - atomic_read(&(SB_JOURNAL(p_s_sb)->j_wcount)), - SB_JOURNAL(p_s_sb)->j_must_wait) ; - printk("used cnodes %d, free cnodes %d\n", SB_JOURNAL(p_s_sb)->j_cnode_used, SB_JOURNAL(p_s_sb)->j_cnode_free) ; - } - p_s_sb = sb_entry(p_s_sb->s_list.next); - } -#endif return 0 ; } @@ -2582,7 +2571,7 @@ /* find all older transactions with this block, make sure they don't try to write it out */ cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ; while (cn) { - if (p_s_sb->s_dev == cn->dev && blocknr == cn->blocknr) { + if (kdev_same(p_s_sb->s_dev,cn->dev) && blocknr == cn->blocknr) { set_bit(BLOCK_FREED, &cn->state) ; if (cn->bh) { if (!cleaned) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/lbalance.c linux-2.5/fs/reiserfs/lbalance.c --- linux-2.5.1/fs/reiserfs/lbalance.c Tue Oct 30 23:11:34 2001 +++ linux-2.5/fs/reiserfs/lbalance.c Thu Dec 13 16:32:37 2001 @@ -63,7 +63,7 @@ /* form item header */ memcpy (&new_ih.ih_key, &ih->ih_key, KEY_SIZE); - put_ih_version( &new_ih, ITEM_VERSION_1 ); + put_ih_version( &new_ih, KEY_FORMAT_3_5 ); /* calculate item len */ put_ih_item_len( &new_ih, DEH_SIZE * copy_count + copy_records_len ); put_ih_entry_count( &new_ih, 0 ); @@ -78,7 +78,7 @@ set_le_ih_k_offset (&new_ih, U32_MAX); /* this item is not yet valid, but we want I_IS_DIRECTORY_ITEM to return 1 for it, so we -1 */ } - set_le_key_k_type (ITEM_VERSION_1, &(new_ih.ih_key), TYPE_DIRENTRY); + set_le_key_k_type (KEY_FORMAT_3_5, &(new_ih.ih_key), TYPE_DIRENTRY); } /* insert item into dest buffer */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/namei.c linux-2.5/fs/reiserfs/namei.c --- linux-2.5.1/fs/reiserfs/namei.c Fri Nov 9 22:18:25 2001 +++ linux-2.5/fs/reiserfs/namei.c Thu Jan 10 22:41:07 2002 @@ -17,17 +17,6 @@ #include <linux/reiserfs_fs.h> #include <linux/smp_lock.h> - /* there should be an overview right - here, as there should be in every - conceptual grouping of code. This - should be combined with dir.c and - called dir.c (naming will become - too large to be called one file in - a few years), stop senselessly - imitating the incoherent - structuring of code used by other - filesystems. */ - #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; } #define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--; @@ -105,7 +94,7 @@ BUG (); /* store key of the found entry */ - de->de_entry_key.version = ITEM_VERSION_1; + de->de_entry_key.version = KEY_FORMAT_3_5; de->de_entry_key.on_disk_key.k_dir_id = le32_to_cpu (de->de_ih->ih_key.k_dir_id); de->de_entry_key.on_disk_key.k_objectid = le32_to_cpu (de->de_ih->ih_key.k_objectid); set_cpu_key_k_offset (&(de->de_entry_key), deh_offset (deh)); @@ -320,9 +309,10 @@ while (1) { retval = search_by_entry_key (dir->i_sb, &key_to_search, path_to_entry, de); - if (retval == IO_ERROR) - // FIXME: still has to be dealt with - reiserfs_panic (dir->i_sb, "zam-7001: io error in " __FUNCTION__ "\n"); + if (retval == IO_ERROR) { + reiserfs_warning ("zam-7001: io error in " __FUNCTION__ "\n"); + return IO_ERROR; + } /* compare names for all entries having given hash value */ retval = linear_search_in_dir_item (&key_to_search, de, name, namelen); @@ -347,7 +337,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dentry) +static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dentry) { int retval; struct inode * inode = 0; @@ -373,7 +363,6 @@ return NULL; } - // // a portion of this function, particularly the VFS interface portion, // was derived from minix or ext2's analog and evolved as the @@ -518,7 +507,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode) +static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode) { int retval; struct inode * inode; @@ -574,7 +563,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev) +static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev) { int retval; struct inode * inode; @@ -629,7 +618,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode) +static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode) { int retval; struct inode * inode; @@ -708,17 +697,20 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -int reiserfs_rmdir (struct inode * dir, struct dentry *dentry) +static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry) { int retval; struct inode * inode; int windex ; struct reiserfs_transaction_handle th ; - int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; + int jbegin_count; INITIALIZE_PATH (path); struct reiserfs_dir_entry de; + /* we will be doing 2 balancings and update 2 stat data */ + jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2; + journal_begin(&th, dir->i_sb, jbegin_count) ; windex = push_journal_writer("reiserfs_rmdir") ; @@ -762,6 +754,9 @@ dir->i_blocks = ((dir->i_size + 511) >> 9); reiserfs_update_sd (&th, dir); + /* prevent empty directory from getting lost */ + add_save_link (&th, inode, 0/* not truncate */); + pop_journal_writer(windex) ; journal_end(&th, dir->i_sb, jbegin_count) ; reiserfs_check_path(&path) ; @@ -785,7 +780,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -int reiserfs_unlink (struct inode * dir, struct dentry *dentry) +static int reiserfs_unlink (struct inode * dir, struct dentry *dentry) { int retval; struct inode * inode; @@ -793,7 +788,13 @@ INITIALIZE_PATH (path); int windex ; struct reiserfs_transaction_handle th ; - int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; + int jbegin_count; + + inode = dentry->d_inode; + + /* in this transaction we can be doing at max two balancings and update + two stat datas */ + jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2; journal_begin(&th, dir->i_sb, jbegin_count) ; windex = push_journal_writer("reiserfs_unlink") ; @@ -803,7 +804,6 @@ retval = -ENOENT; goto end_unlink; } - inode = dentry->d_inode; reiserfs_update_inode_transaction(inode) ; reiserfs_update_inode_transaction(dir) ; @@ -817,7 +817,7 @@ if (!inode->i_nlink) { printk("reiserfs_unlink: deleting nonexistent file (%s:%lu), %d\n", - kdevname(inode->i_dev), inode->i_ino, inode->i_nlink); + inode->i_sb->s_id, inode->i_ino, inode->i_nlink); inode->i_nlink = 1; } @@ -834,6 +834,10 @@ dir->i_ctime = dir->i_mtime = CURRENT_TIME; reiserfs_update_sd (&th, dir); + if (!inode->i_nlink) + /* prevent file from getting lost */ + add_save_link (&th, inode, 0/* not truncate */); + pop_journal_writer(windex) ; journal_end(&th, dir->i_sb, jbegin_count) ; reiserfs_check_path(&path) ; @@ -855,7 +859,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -int reiserfs_symlink (struct inode * dir, struct dentry * dentry, const char * symname) +static int reiserfs_symlink (struct inode * dir, struct dentry * dentry, const char * symname) { int retval; struct inode * inode; @@ -872,12 +876,12 @@ } item_len = ROUND_UP (strlen (symname)); - if (item_len > MAX_ITEM_LEN (dir->i_sb->s_blocksize)) { + if (item_len > MAX_DIRECT_ITEM_LEN (dir->i_sb->s_blocksize)) { iput(inode) ; return -ENAMETOOLONG; } - name = kmalloc (item_len, GFP_NOFS); + name = reiserfs_kmalloc (item_len, GFP_NOFS, dir->i_sb); if (!name) { iput(inode) ; return -ENOMEM; @@ -890,7 +894,7 @@ inode = reiserfs_new_inode (&th, dir, S_IFLNK | S_IRWXUGO, name, strlen (symname), dentry, inode, &retval); - kfree (name); + reiserfs_kfree (name, item_len, dir->i_sb); if (inode == 0) { /* reiserfs_new_inode iputs for us */ pop_journal_writer(windex) ; journal_end(&th, dir->i_sb, jbegin_count) ; @@ -932,7 +936,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct dentry * dentry) +static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct dentry * dentry) { int retval; struct inode *inode = old_dentry->d_inode; @@ -1032,8 +1036,8 @@ * one path. If it holds 2 or more, it can get into endless waiting in * get_empty_nodes or its clones */ -int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry, - struct inode * new_dir, struct dentry *new_dentry) +static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry, + struct inode * new_dir, struct dentry *new_dentry) { int retval; INITIALIZE_PATH (old_entry_path); @@ -1044,8 +1048,13 @@ struct inode * old_inode, * new_inode; int windex ; struct reiserfs_transaction_handle th ; - int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; + int jbegin_count ; + + /* two balancings: old name removal, new name insertion or "save" link, + stat data updates: old directory and new directory and maybe block + containing ".." of renamed directory */ + jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 3; old_inode = old_dentry->d_inode; new_inode = new_dentry->d_inode; @@ -1096,8 +1105,8 @@ // FIXME: is it possible, that new_inode == 0 here? If yes, it // is not clear how does ext2 handle that if (!new_inode) { - printk ("reiserfs_rename: new entry is found, new inode == 0\n"); - BUG (); + reiserfs_panic (old_dir->i_sb, + "vs-7050: new entry is found, new inode == 0\n"); } } else if (retval) { pop_journal_writer(windex) ; @@ -1164,13 +1173,6 @@ reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh); if (S_ISDIR(old_inode->i_mode)) reiserfs_restore_prepared_buffer (old_inode->i_sb, dot_dot_de.de_bh); -#if 0 - // FIXME: do we need this? shouldn't we simply continue? - run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - /*current->counter = 0;*/ - schedule(); -#endif continue; } @@ -1195,29 +1197,25 @@ if (new_inode) { // adjust link number of the victim if (S_ISDIR(new_inode->i_mode)) { - DEC_DIR_INODE_NLINK(new_inode) + new_inode->i_nlink = 0; } else { - new_inode->i_nlink--; + new_inode->i_nlink--; } new_inode->i_ctime = CURRENT_TIME; } if (S_ISDIR(old_inode->i_mode)) { - //if (dot_dot_de.de_bh) { - // adjust ".." of renamed directory + // adjust ".." of renamed directory set_ino_in_dir_entry (&dot_dot_de, INODE_PKEY (new_dir)); journal_mark_dirty (&th, new_dir->i_sb, dot_dot_de.de_bh); - - DEC_DIR_INODE_NLINK(old_dir) - if (new_inode) { - if (S_ISDIR(new_inode->i_mode)) { - DEC_DIR_INODE_NLINK(new_inode) - } else { - new_inode->i_nlink--; - } - } else { - INC_DIR_INODE_NLINK(new_dir) - } + + if (!new_inode) + /* there (in new_dir) was no directory, so it got new link + (".." of renamed directory) */ + INC_DIR_INODE_NLINK(new_dir); + + /* old directory lost one link - ".. " of renamed directory */ + DEC_DIR_INODE_NLINK(old_dir); } // looks like in 2.3.99pre3 brelse is atomic. so we can use pathrelse @@ -1228,18 +1226,40 @@ // anybody, but it will panic if will not be able to find the // entry. This needs one more clean up if (reiserfs_cut_from_item (&th, &old_entry_path, &(old_de.de_entry_key), old_dir, NULL, 0) < 0) - reiserfs_warning ("vs-: reiserfs_rename: coudl not cut old name. Fsck later?\n"); + reiserfs_warning ("vs-7060: reiserfs_rename: couldn't not cut old name. Fsck later?\n"); old_dir->i_size -= DEH_SIZE + old_de.de_entrylen; old_dir->i_blocks = ((old_dir->i_size + 511) >> 9); reiserfs_update_sd (&th, old_dir); reiserfs_update_sd (&th, new_dir); - if (new_inode) + + if (new_inode) { + if (new_inode->i_nlink == 0) + add_save_link (&th, new_inode, 0/* not truncate */); reiserfs_update_sd (&th, new_inode); + } pop_journal_writer(windex) ; journal_end(&th, old_dir->i_sb, jbegin_count) ; return 0; } + + + +/* + * directories can handle most operations... + */ +struct inode_operations reiserfs_dir_inode_operations = { + //&reiserfs_dir_operations, /* default_file_ops */ + create: reiserfs_create, + lookup: reiserfs_lookup, + link: reiserfs_link, + unlink: reiserfs_unlink, + symlink: reiserfs_symlink, + mkdir: reiserfs_mkdir, + rmdir: reiserfs_rmdir, + mknod: reiserfs_mknod, + rename: reiserfs_rename, +}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/objectid.c linux-2.5/fs/reiserfs/objectid.c --- linux-2.5.1/fs/reiserfs/objectid.c Fri Nov 9 22:18:25 2001 +++ linux-2.5/fs/reiserfs/objectid.c Thu Dec 13 16:32:37 2001 @@ -162,7 +162,7 @@ i += 2; } - reiserfs_warning ("vs-15010: reiserfs_release_objectid: tried to free free object id (%lu)", + reiserfs_warning ("vs-15011: reiserfs_release_objectid: tried to free free object id (%lu)\n", ( long unsigned ) objectid_to_release); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/prints.c linux-2.5/fs/reiserfs/prints.c --- linux-2.5.1/fs/reiserfs/prints.c Fri Nov 9 22:18:25 2001 +++ linux-2.5/fs/reiserfs/prints.c Sat Jan 5 16:38:09 2002 @@ -109,7 +109,7 @@ static void sprintf_item_head (char * buf, struct item_head * ih) { if (ih) { - sprintf (buf, "%s", (ih_version (ih) == ITEM_VERSION_2) ? "*NEW* " : "*OLD*"); + sprintf (buf, "%s", (ih_version (ih) == KEY_FORMAT_3_6) ? "*3.6* " : "*3.5*"); sprintf_le_key (buf + strlen (buf), &(ih->ih_key)); sprintf (buf + strlen (buf), ", item_len %d, item_location %d, " "free_space(entry_count) %d", @@ -335,7 +335,7 @@ /* this is not actually called, but makes reiserfs_panic() "noreturn" */ panic ("REISERFS: panic (device %s): %s\n", - sb ? kdevname(sb->s_dev) : "sb == 0", error_buf); + sb ? sb->s_id : "sb == 0", error_buf); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/procfs.c linux-2.5/fs/reiserfs/procfs.c --- linux-2.5.1/fs/reiserfs/procfs.c Fri Nov 9 22:18:25 2001 +++ linux-2.5/fs/reiserfs/procfs.c Fri Jan 11 17:53:57 2002 @@ -15,6 +15,7 @@ #include <linux/sched.h> #include <asm/uaccess.h> #include <linux/reiserfs_fs.h> +#include <linux/reiserfs_fs_sb.h> #include <linux/smp_lock.h> #include <linux/locks.h> #include <linux/init.h> @@ -76,12 +77,20 @@ { int len = 0; struct super_block *sb; + char *format; - sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + sb = procinfo_prologue( to_kdev_t (( long ) data )); if( sb == NULL ) return -ENOENT; + if ( sb->u.reiserfs_sb.s_properties & (1 << REISERFS_3_6) ) { + format = "3.6"; + } else if ( sb->u.reiserfs_sb.s_properties & (1 << REISERFS_3_5) ) { + format = "3.5"; + } else { + format = "unknown"; + } len += sprintf( &buffer[ len ], "%s format\twith checks %s\n", - old_format_only( sb ) ? "old" : "new", + format, #if defined( CONFIG_REISERFS_CHECK ) "on" #else @@ -134,7 +143,7 @@ struct reiserfs_sb_info *r; int len = 0; - sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + sb = procinfo_prologue( to_kdev_t (( long ) data) ); if( sb == NULL ) return -ENOENT; r = &sb->u.reiserfs_sb; @@ -179,7 +188,7 @@ dont_have_tails( sb ) ? "NO_TAILS " : "TAILS ", replay_only( sb ) ? "REPLAY_ONLY " : "", reiserfs_dont_log( sb ) ? "DONT_LOG " : "LOG ", - old_format_only( sb ) ? "CONV " : "", + convert_reiserfs( sb ) ? "CONV " : "", atomic_read( &r -> s_generation_counter ), SF( s_kmallocs ), @@ -214,7 +223,7 @@ int len = 0; int level; - sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + sb = procinfo_prologue( to_kdev_t (( long ) data) ); if( sb == NULL ) return -ENOENT; r = &sb->u.reiserfs_sb; @@ -293,7 +302,7 @@ struct reiserfs_sb_info *r = &sb->u.reiserfs_sb; int len = 0; - sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + sb = procinfo_prologue( to_kdev_t ( ( long ) data) ); if( sb == NULL ) return -ENOENT; r = &sb->u.reiserfs_sb; @@ -334,7 +343,7 @@ int hash_code; int len = 0; - sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + sb = procinfo_prologue( to_kdev_t ( ( long ) data) ); if( sb == NULL ) return -ENOENT; sb_info = &sb->u.reiserfs_sb; @@ -387,7 +396,7 @@ int len = 0; int exact; - sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + sb = procinfo_prologue( to_kdev_t ( ( long ) data) ); if( sb == NULL ) return -ENOENT; sb_info = &sb->u.reiserfs_sb; @@ -438,7 +447,7 @@ struct reiserfs_super_block *rs; int len = 0; - sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + sb = procinfo_prologue( to_kdev_t ( ( long ) data) ); if( sb == NULL ) return -ENOENT; r = &sb->u.reiserfs_sb; @@ -491,7 +500,8 @@ "prepare_retry: \t%12lu\n", DJF( s_journal_block ), - DJF( s_journal_dev ) == 0 ? "none" : bdevname( DJF( s_journal_dev ) ), +// kdev_none(DJF( s_journal_dev )) ? "none" : bdevname( DJF( s_journal_dev ) ), + "FIXME -- davej", DJF( s_journal_dev ), DJF( s_orig_journal_size ), DJF( s_journal_trans_max ), @@ -546,14 +556,13 @@ int reiserfs_proc_info_init( struct super_block *sb ) { spin_lock_init( & __PINFO( sb ).lock ); - sb->u.reiserfs_sb.procdir = proc_mkdir( bdevname( sb -> s_dev ), - proc_info_root ); + sb->u.reiserfs_sb.procdir = proc_mkdir(sb->s_id, proc_info_root); if( sb->u.reiserfs_sb.procdir ) { sb->u.reiserfs_sb.procdir -> owner = THIS_MODULE; return 0; } reiserfs_warning( "reiserfs: cannot create /proc/%s/%s\n", - proc_info_root_name, bdevname( sb -> s_dev ) ); + proc_info_root_name, sb->s_id ); return 1; } @@ -564,7 +573,7 @@ __PINFO( sb ).exiting = 1; spin_unlock( & __PINFO( sb ).lock ); if ( proc_info_root ) { - remove_proc_entry( bdevname( sb -> s_dev ), proc_info_root ); + remove_proc_entry( sb->s_id, proc_info_root ); sb->u.reiserfs_sb.procdir = NULL; } return 0; @@ -579,7 +588,7 @@ { return ( sb->u.reiserfs_sb.procdir ) ? create_proc_read_entry ( name, 0, sb->u.reiserfs_sb.procdir, func, - ( void * ) ( int ) sb -> s_dev ) : NULL; + ( void * ) ( long ) kdev_t_to_nr (sb -> s_dev) ) : NULL; } void reiserfs_proc_unregister( struct super_block *sb, const char *name ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/resize.c linux-2.5/fs/reiserfs/resize.c --- linux-2.5.1/fs/reiserfs/resize.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/reiserfs/resize.c Wed Jan 2 23:16:43 2002 @@ -111,7 +111,7 @@ for (i = 0; i < bmap_nr; i++) bitmap[i] = SB_AP_BITMAP(s)[i]; for (i = bmap_nr; i < bmap_nr_new; i++) { - bitmap[i] = reiserfs_getblk(s->s_dev, i * s->s_blocksize * 8, s->s_blocksize); + bitmap[i] = sb_getblk(s, i * s->s_blocksize * 8); memset(bitmap[i]->b_data, 0, sb->s_blocksize); reiserfs_test_and_set_le_bit(0, bitmap[i]->b_data); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/stree.c linux-2.5/fs/reiserfs/stree.c --- linux-2.5.1/fs/reiserfs/stree.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/reiserfs/stree.c Thu Jan 10 13:58:14 2002 @@ -225,7 +225,7 @@ // find out version of the key to->version = le_key_version (from); - if (to->version == ITEM_VERSION_1) { + if (to->version == KEY_FORMAT_3_5) { to->on_disk_key.u.k_offset_v1.k_offset = le32_to_cpu (from->u.k_offset_v1.k_offset); to->on_disk_key.u.k_offset_v1.k_uniqueness = le32_to_cpu (from->u.k_offset_v1.k_uniqueness); } else { @@ -395,7 +395,7 @@ p_s_chk_path->path_length > MAX_HEIGHT, "PAP-5050: pointer to the key(%p) is NULL or illegal path length(%d)", p_s_key, p_s_chk_path->path_length); - RFALSE( PATH_PLAST_BUFFER(p_s_chk_path)->b_dev == NODEV, + RFALSE( kdev_same(PATH_PLAST_BUFFER(p_s_chk_path)->b_dev, NODEV), "PAP-5060: device must not be NODEV"); if ( COMP_KEYS(get_lkey(p_s_chk_path, p_s_sb), p_s_key) == 1 ) @@ -524,6 +524,10 @@ ih = (struct item_head *)(buf + BLKH_SIZE); prev_location = blocksize; for (i = 0; i < nr; i ++, ih ++) { + if ( le_ih_k_type(ih) == TYPE_ANY) { + reiserfs_warning ("is_leaf: wrong item type for item %h\n",ih); + return 0; + } if (ih_location (ih) >= blocksize || ih_location (ih) < IH_SIZE * nr) { reiserfs_warning ("is_leaf: item location seems wrong: %h\n", ih); return 0; @@ -604,7 +608,7 @@ if (blocknr == 0) return; - bh = reiserfs_getblk (s->s_dev, blocknr, s->s_blocksize); + bh = sb_getblk (s, blocknr); if (!buffer_uptodate (bh)) { ll_rw_block (READA, 1, &bh); @@ -649,8 +653,7 @@ DISK_LEAF_NODE_LEVEL */ ) { int n_block_number = SB_ROOT_BLOCK (p_s_sb), - expected_level = SB_TREE_HEIGHT (p_s_sb), - n_block_size = p_s_sb->s_blocksize; + expected_level = SB_TREE_HEIGHT (p_s_sb); struct buffer_head * p_s_bh; struct path_element * p_s_last_element; int n_node_level, n_retval; @@ -697,7 +700,7 @@ /* Read the next tree node, and set the last element in the path to have a pointer to it. */ if ( ! (p_s_bh = p_s_last_element->pe_buffer = - reiserfs_bread(p_s_sb, n_block_number, n_block_size)) ) { + reiserfs_bread(p_s_sb, n_block_number)) ) { p_s_search_path->path_length --; pathrelse(p_s_search_path); return IO_ERROR; @@ -727,7 +730,11 @@ continue; } - RFALSE( ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb), + /* only check that the key is in the buffer if p_s_key is not + equal to the MAX_KEY. Latter case is only possible in + "finish_unfinished()" processing during mount. */ + RFALSE( COMP_KEYS( &MAX_KEY, p_s_key ) && + ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb), "PAP-5130: key is not in the buffer"); #ifdef CONFIG_REISERFS_CHECK if ( cur_tb ) { @@ -917,7 +924,7 @@ } // new file gets truncated - if (inode_items_version (inode) == ITEM_VERSION_2) { + if (get_inode_item_key_version (inode) == KEY_FORMAT_3_6) { // round_len = ROUND_UP (new_file_length); /* this was n_new_file_length < le_ih ... */ @@ -992,10 +999,6 @@ struct item_head * p_le_ih = PATH_PITEM_HEAD(p_s_path); struct buffer_head * p_s_bh = PATH_PLAST_BUFFER(p_s_path); -#ifdef CONFIG_REISERFS_CHECK - int n_repeat_counter = 0; -#endif - /* Stat_data item. */ if ( is_statdata_le_ih (p_le_ih) ) { @@ -1020,13 +1023,11 @@ { int n_unfm_number, /* Number of the item unformatted nodes. */ n_counter, - n_retry, /* Set to one if there is unformatted node buffer in use. */ n_blk_size; __u32 * p_n_unfm_pointer; /* Pointer to the unformatted node number. */ __u32 tmp; struct item_head s_ih; /* Item header. */ char c_mode; /* Returned mode of the balance. */ - struct buffer_head * p_s_un_bh; int need_research; @@ -1099,8 +1100,8 @@ // note: path could be changed, first line in for loop takes care // of it - for ( n_retry = 0, n_counter = *p_n_removed; - n_counter < n_unfm_number; n_counter++, p_n_unfm_pointer-- ) { + for (n_counter = *p_n_removed; + n_counter < n_unfm_number; n_counter++, p_n_unfm_pointer-- ) { if (item_moved (&s_ih, p_s_path)) { need_research = 1 ; @@ -1110,69 +1111,23 @@ p_n_unfm_pointer > (__u32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1, "vs-5265: pointer out of range"); - if ( ! get_block_num(p_n_unfm_pointer,0) ) { /* Hole, nothing to remove. */ - if ( ! n_retry ) + /* Hole, nothing to remove. */ + if ( ! get_block_num(p_n_unfm_pointer,0) ) { (*p_n_removed)++; - continue; + continue; } - /* Search for the buffer in cache. */ - p_s_un_bh = sb_get_hash_table(p_s_sb, get_block_num(p_n_unfm_pointer,0)); - if (p_s_un_bh) { - mark_buffer_clean(p_s_un_bh) ; - if (buffer_locked(p_s_un_bh)) { - __wait_on_buffer(p_s_un_bh) ; - } - /* even if the item moves, the block number of the - ** unformatted node we want to cut won't. So, it was - ** safe to clean the buffer here, this block _will_ - ** get freed during this call to prepare_for_delete_or_cut - */ - if ( item_moved (&s_ih, p_s_path) ) { - need_research = 1; - brelse(p_s_un_bh) ; - break ; - } - } - if ( p_s_un_bh && block_in_use (p_s_un_bh)) { - /* Block is locked or held more than by one holder and by - journal. */ - -#ifdef CONFIG_REISERFS_CHECK - if (n_repeat_counter && (n_repeat_counter % 100000) == 0) { - printk("prepare_for_delete, waiting on buffer %lu, b_count %d, %s%cJDIRTY %cJDIRTY_WAIT\n", - p_s_un_bh->b_blocknr, atomic_read (&p_s_un_bh->b_count), - buffer_locked (p_s_un_bh) ? "locked, " : "", - buffer_journaled(p_s_un_bh) ? ' ' : '!', - buffer_journal_dirty(p_s_un_bh) ? ' ' : '!') ; - - } -#endif - n_retry = 1; - brelse (p_s_un_bh); - continue; - } - - if ( ! n_retry ) - (*p_n_removed)++; - - RFALSE( p_s_un_bh && - get_block_num(p_n_unfm_pointer, 0) != p_s_un_bh->b_blocknr, - // note: minix_truncate allows that. As truncate is - // protected by down (inode->i_sem), two truncates can not - // co-exist - "PAP-5280: blocks numbers are different"); + (*p_n_removed)++; tmp = get_block_num(p_n_unfm_pointer,0); put_block_num(p_n_unfm_pointer, 0, 0); journal_mark_dirty (th, p_s_sb, p_s_bh); - bforget (p_s_un_bh); inode->i_blocks -= p_s_sb->s_blocksize / 512; reiserfs_free_block(th, tmp); if ( item_moved (&s_ih, p_s_path) ) { - need_research = 1; - break ; - } + need_research = 1; + break ; + } } /* a trick. If the buffer has been logged, this @@ -1182,28 +1137,6 @@ */ reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh); - if ( n_retry ) { - /* There is block in use. Wait, they should release it soon */ - - RFALSE( *p_n_removed >= n_unfm_number, "PAP-5290: illegal case"); -#ifdef CONFIG_REISERFS_CHECK - if ( !(++n_repeat_counter % 500000) ) { - reiserfs_warning("PAP-5300: prepare_for_delete_or_cut: (pid %u): " - "could not delete item %k in (%d) iterations. New file length %Lu. (inode %Ld), Still trying\n", - current->pid, p_s_item_key, n_repeat_counter, n_new_file_length, inode->i_size); - if (n_repeat_counter == 5000000) { - print_block (PATH_PLAST_BUFFER(p_s_path), 3, - PATH_LAST_POSITION (p_s_path) - 2, PATH_LAST_POSITION (p_s_path) + 2); - reiserfs_panic(p_s_sb, "PAP-5305: prepare_for_delete_or_cut: key %k, new_file_length %Ld", - p_s_item_key, n_new_file_length); - } - } -#endif - - run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - schedule(); - } /* This loop can be optimized. */ } while ( (*p_n_removed < n_unfm_number || need_research) && search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_FOUND ); @@ -1388,8 +1321,8 @@ /* this deletes item which never gets split */ -static void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, - struct key * key) +void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, + struct key * key) { struct tree_balance tb; INITIALIZE_PATH (path); @@ -1403,13 +1336,13 @@ while (1) { retval = search_item (th->t_super, &cpu_key, &path); if (retval == IO_ERROR) { - reiserfs_warning ("vs-: reiserfs_delete_solid_item: " + reiserfs_warning ("vs-5350: reiserfs_delete_solid_item: " "i/o failure occurred trying to delete %K\n", &cpu_key); break; } if (retval != ITEM_FOUND) { pathrelse (&path); - reiserfs_warning ("vs-: reiserfs_delete_solid_item: %k not found", + reiserfs_warning ("vs-5355: reiserfs_delete_solid_item: %k not found", key); break; } @@ -1429,7 +1362,7 @@ } // IO_ERROR, NO_DISK_SPACE, etc - reiserfs_warning ("vs-: reiserfs_delete_solid_item: " + reiserfs_warning ("vs-5360: reiserfs_delete_solid_item: " "could not delete %K due to fix_nodes failure\n", &cpu_key); unfix_nodes (&tb); break; @@ -1446,15 +1379,6 @@ /* for directory this deletes item containing "." and ".." */ reiserfs_do_truncate (th, inode, NULL, 0/*no timestamp updates*/); - /* delete stat data */ - /* this debug code needs to go away. Trying to find a truncate race - ** -- clm -- 4/1/2000 - */ -#if 0 - if (inode->i_nlink != 0) { - reiserfs_warning("clm-4001: deleting inode with link count==%d\n", inode->i_nlink) ; - } -#endif #if defined( USE_INODE_GENERATION_COUNTER ) if( !old_format_only ( th -> t_super ) ) { @@ -1491,7 +1415,7 @@ */ if (atomic_read(&p_s_inode->i_count) > 1 || !tail_has_to_be_packed (p_s_inode) || - !page || p_s_inode->u.reiserfs_i.nopack) { + !page || (p_s_inode->u.reiserfs_i.i_flags & i_nopack_mask)) { // leave tail in an unformatted node *p_c_mode = M_SKIP_BALANCING; cut_bytes = n_block_size - (n_new_file_size & (n_block_size - 1)); @@ -1693,7 +1617,7 @@ ** be flushed before the transaction commits, so we don't need to ** deal with it here. */ - p_s_inode->u.reiserfs_i.i_pack_on_close = 0 ; + p_s_inode->u.reiserfs_i.i_flags &= ~i_pack_on_close_mask; } return n_ret_value; } @@ -1702,14 +1626,14 @@ static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode) { if (inode->i_nlink) - reiserfs_warning ("vs-5655: truncate_directory: link count != 0"); + reiserfs_warning ("vs-5655: truncate_directory: link count != 0\n"); - set_le_key_k_offset (ITEM_VERSION_1, INODE_PKEY (inode), DOT_OFFSET); - set_le_key_k_type (ITEM_VERSION_1, INODE_PKEY (inode), TYPE_DIRENTRY); + set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), DOT_OFFSET); + set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_DIRENTRY); reiserfs_delete_solid_item (th, INODE_PKEY (inode)); - set_le_key_k_offset (ITEM_VERSION_1, INODE_PKEY (inode), SD_OFFSET); - set_le_key_k_type (ITEM_VERSION_1, INODE_PKEY (inode), TYPE_STAT_DATA); + set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), SD_OFFSET); + set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_STAT_DATA); } @@ -1782,6 +1706,7 @@ pathrelse(&s_search_path); return; } + /* Update key to search for the last file item. */ set_cpu_key_k_offset (&s_item_key, n_file_size); @@ -1818,7 +1743,6 @@ if (update_timestamps) { p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME; - // FIXME: sd gets wrong size here } reiserfs_update_sd(th, p_s_inode) ; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/super.c linux-2.5/fs/reiserfs/super.c --- linux-2.5.1/fs/reiserfs/super.c Fri Nov 9 22:18:25 2001 +++ linux-2.5/fs/reiserfs/super.c Mon Jan 14 14:03:45 2002 @@ -19,6 +19,7 @@ #include <linux/smp_lock.h> #include <linux/locks.h> #include <linux/init.h> +#include <linux/blkdev.h> #define REISERFS_OLD_BLOCKSIZE 4096 #define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20 @@ -26,6 +27,9 @@ char reiserfs_super_magic_string[] = REISERFS_SUPER_MAGIC_STRING; char reiser2fs_super_magic_string[] = REISER2FS_SUPER_MAGIC_STRING; +static int reiserfs_remount (struct super_block * s, int * flags, char * data); +static int reiserfs_statfs (struct super_block * s, struct statfs * buf); + // // a portion of this function, particularly the VFS interface portion, // was derived from minix or ext2's analog and evolved as the @@ -33,7 +37,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -void reiserfs_write_super (struct super_block * s) +static void reiserfs_write_super (struct super_block * s) { int dirty = 0 ; @@ -52,7 +56,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -void reiserfs_write_super_lockfs (struct super_block * s) +static void reiserfs_write_super_lockfs (struct super_block * s) { int dirty = 0 ; @@ -73,6 +77,247 @@ reiserfs_allow_writes(s) ; } +extern const struct key MAX_KEY; + + +/* this is used to delete "save link" when there are no items of a + file it points to. It can either happen if unlink is completed but + "save unlink" removal, or if file has both unlink and truncate + pending and as unlink completes first (because key of "save link" + protecting unlink is bigger that a key lf "save link" which + protects truncate), so there left no items to make truncate + completion on */ +static void remove_save_link_only (struct super_block * s, struct key * key) +{ + struct reiserfs_transaction_handle th; + + /* we are going to do one balancing */ + journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT); + + reiserfs_delete_solid_item (&th, key); + if (is_direct_le_key (KEY_FORMAT_3_5, key)) + /* removals are protected by direct items */ + reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid)); + + journal_end (&th, s, JOURNAL_PER_BALANCE_CNT); +} + + +/* look for uncompleted unlinks and truncates and complete them */ +static void finish_unfinished (struct super_block * s) +{ + INITIALIZE_PATH (path); + struct cpu_key max_cpu_key, obj_key; + struct key save_link_key; + int retval; + struct item_head * ih; + struct buffer_head * bh; + int item_pos; + char * item; + int done; + struct inode * inode; + int truncate; + + + /* compose key to look for "save" links */ + max_cpu_key.version = KEY_FORMAT_3_5; + max_cpu_key.on_disk_key = MAX_KEY; + max_cpu_key.key_length = 3; + + done = 0; + s -> u.reiserfs_sb.s_is_unlinked_ok = 1; + while (1) { + retval = search_item (s, &max_cpu_key, &path); + if (retval != ITEM_NOT_FOUND) { + reiserfs_warning ("vs-2140: finish_unfinished: search_by_key returned %d\n", + retval); + break; + } + + bh = get_last_bh (&path); + item_pos = get_item_pos (&path); + if (item_pos != B_NR_ITEMS (bh)) { + reiserfs_warning ("vs-2060: finish_unfinished: wrong position found\n"); + break; + } + item_pos --; + ih = B_N_PITEM_HEAD (bh, item_pos); + + if (le32_to_cpu (ih->ih_key.k_dir_id) != MAX_KEY_OBJECTID) + /* there are no "save" links anymore */ + break; + + save_link_key = ih->ih_key; + if (is_indirect_le_ih (ih)) + truncate = 1; + else + truncate = 0; + + /* reiserfs_iget needs k_dirid and k_objectid only */ + item = B_I_PITEM (bh, ih); + obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__u32 *)item); + obj_key.on_disk_key.k_objectid = le32_to_cpu (ih->ih_key.k_objectid); + obj_key.on_disk_key.u.k_offset_v1.k_offset = 0; + obj_key.on_disk_key.u.k_offset_v1.k_uniqueness = 0; + + pathrelse (&path); + + inode = reiserfs_iget (s, &obj_key); + if (!inode) { + /* the unlink almost completed, it just did not manage to remove + "save" link and release objectid */ + reiserfs_warning ("vs-2180: finish_unfinished: iget failed for %K\n", + &obj_key); + remove_save_link_only (s, &save_link_key); + continue; + } + + if (!truncate && inode->i_nlink) { + /* file is not unlinked */ + reiserfs_warning ("vs-2185: finish_unfinished: file %K is not unlinked\n", + &obj_key); + remove_save_link_only (s, &save_link_key); + continue; + } + + if (truncate) { + inode -> u.reiserfs_i.i_flags |= i_link_saved_truncate_mask; + /* not completed truncate found. New size was committed together + with "save" link */ + reiserfs_warning ("Truncating %k to %Ld ..", + INODE_PKEY (inode), inode->i_size); + reiserfs_truncate_file (inode, 0/*don't update modification time*/); + remove_save_link (inode, truncate); + } else { + inode -> u.reiserfs_i.i_flags |= i_link_saved_unlink_mask; + /* not completed unlink (rmdir) found */ + reiserfs_warning ("Removing %k..", INODE_PKEY (inode)); + /* removal gets completed in iput */ + } + + iput (inode); + reiserfs_warning ("done\n"); + done ++; + } + s -> u.reiserfs_sb.s_is_unlinked_ok = 0; + + pathrelse (&path); + if (done) + reiserfs_warning ("There were %d uncompleted unlinks/truncates. " + "Completed\n", done); +} + +/* to protect file being unlinked from getting lost we "safe" link files + being unlinked. This link will be deleted in the same transaction with last + item of file. mounting the filesytem we scan all these links and remove + files which almost got lost */ +void add_save_link (struct reiserfs_transaction_handle * th, + struct inode * inode, int truncate) +{ + INITIALIZE_PATH (path); + int retval; + struct cpu_key key; + struct item_head ih; + __u32 link; + + /* file can only get one "save link" of each kind */ + RFALSE( truncate && + ( inode -> u.reiserfs_i.i_flags & i_link_saved_truncate_mask ), + "saved link already exists for truncated inode %lx", + ( long ) inode -> i_ino ); + RFALSE( !truncate && + ( inode -> u.reiserfs_i.i_flags & i_link_saved_unlink_mask ), + "saved link already exists for unlinked inode %lx", + ( long ) inode -> i_ino ); + + /* setup key of "save" link */ + key.version = KEY_FORMAT_3_5; + key.on_disk_key.k_dir_id = MAX_KEY_OBJECTID; + key.on_disk_key.k_objectid = inode->i_ino; + if (!truncate) { + /* unlink, rmdir, rename */ + set_cpu_key_k_offset (&key, 1 + inode->i_sb->s_blocksize); + set_cpu_key_k_type (&key, TYPE_DIRECT); + + /* item head of "safe" link */ + make_le_item_head (&ih, &key, key.version, 1 + inode->i_sb->s_blocksize, TYPE_DIRECT, + 4/*length*/, 0xffff/*free space*/); + } else { + /* truncate */ + set_cpu_key_k_offset (&key, 1); + set_cpu_key_k_type (&key, TYPE_INDIRECT); + + /* item head of "safe" link */ + make_le_item_head (&ih, &key, key.version, 1, TYPE_INDIRECT, + 4/*length*/, 0/*free space*/); + } + key.key_length = 3; + + /* look for its place in the tree */ + retval = search_item (inode->i_sb, &key, &path); + if (retval != ITEM_NOT_FOUND) { + reiserfs_warning ("vs-2100: add_save_link:" + "search_by_key (%K) returned %d\n", &key, retval); + pathrelse (&path); + return; + } + + /* body of "save" link */ + link = cpu_to_le32 (INODE_PKEY (inode)->k_dir_id); + + /* put "save" link inot tree */ + retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link); + if (retval) + reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n", + retval); + else { + if( truncate ) + inode -> u.reiserfs_i.i_flags |= i_link_saved_truncate_mask; + else + inode -> u.reiserfs_i.i_flags |= i_link_saved_unlink_mask; + } +} + + +/* this opens transaction unlike add_save_link */ +void remove_save_link (struct inode * inode, int truncate) +{ + struct reiserfs_transaction_handle th; + struct key key; + + + /* we are going to do one balancing only */ + journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT); + + /* setup key of "save" link */ + key.k_dir_id = cpu_to_le32 (MAX_KEY_OBJECTID); + key.k_objectid = INODE_PKEY (inode)->k_objectid; + if (!truncate) { + /* unlink, rmdir, rename */ + set_le_key_k_offset (KEY_FORMAT_3_5, &key, + 1 + inode->i_sb->s_blocksize); + set_le_key_k_type (KEY_FORMAT_3_5, &key, TYPE_DIRECT); + } else { + /* truncate */ + set_le_key_k_offset (KEY_FORMAT_3_5, &key, 1); + set_le_key_k_type (KEY_FORMAT_3_5, &key, TYPE_INDIRECT); + } + + if( ( truncate && + ( inode -> u.reiserfs_i.i_flags & i_link_saved_truncate_mask ) ) || + ( !truncate && + ( inode -> u.reiserfs_i.i_flags & i_link_saved_unlink_mask ) ) ) + reiserfs_delete_solid_item (&th, &key); + if (!truncate) { + reiserfs_release_objectid (&th, inode->i_ino); + inode -> u.reiserfs_i.i_flags &= ~i_link_saved_unlink_mask; + } else + inode -> u.reiserfs_i.i_flags &= ~i_link_saved_truncate_mask; + + journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT); +} + + // // a portion of this function, particularly the VFS interface portion, // was derived from minix or ext2's analog and evolved as the @@ -80,7 +325,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -void reiserfs_put_super (struct super_block * s) +static void reiserfs_put_super (struct super_block * s) { int i; struct reiserfs_transaction_handle th ; @@ -123,6 +368,26 @@ return; } +/* we don't mark inodes dirty, we just log them */ +static void reiserfs_dirty_inode (struct inode * inode) { + struct reiserfs_transaction_handle th ; + + if (inode->i_sb->s_flags & MS_RDONLY) { + reiserfs_warning("clm-6006: writing inode %lu on readonly FS\n", + inode->i_ino) ; + return ; + } + lock_kernel() ; + + /* this is really only used for atime updates, so they don't have + ** to be included in O_SYNC or fsync + */ + journal_begin(&th, inode->i_sb, 1) ; + reiserfs_update_sd (&th, inode); + journal_end(&th, inode->i_sb, 1) ; + unlock_kernel() ; +} + struct super_operations reiserfs_sops = { read_inode: reiserfs_read_inode, @@ -220,7 +485,7 @@ int reiserfs_is_super(struct super_block *s) { - return (s->s_dev != 0 && s->s_op == &reiserfs_sops) ; + return (!kdev_none(s->s_dev) && s->s_op == &reiserfs_sops) ; } @@ -231,7 +496,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -int reiserfs_remount (struct super_block * s, int * flags, char * data) +static int reiserfs_remount (struct super_block * s, int * flags, char * data) { struct reiserfs_super_block * rs; struct reiserfs_transaction_handle th ; @@ -284,6 +549,10 @@ /* this will force a full flush of all journal lists */ SB_JOURNAL(s)->j_must_wait = 1 ; journal_end(&th, s, 10) ; + + if (!( *flags & MS_RDONLY ) ) + finish_unfinished( s ); + return 0; } @@ -302,11 +571,11 @@ labeling scheme currently used will have enough space. Then we need one block for the super. -Hans */ bmp = (REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1; /* first of bitmap blocks */ - SB_AP_BITMAP (s)[0] = reiserfs_bread (s, bmp, s->s_blocksize); + SB_AP_BITMAP (s)[0] = reiserfs_bread (s, bmp); if(!SB_AP_BITMAP(s)[0]) return 1; for (i = 1, bmp = dl = s->s_blocksize * 8; i < sb_bmap_nr(rs); i ++) { - SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp, s->s_blocksize); + SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp); if (!SB_AP_BITMAP (s)[i]) return 1; bmp += dl; @@ -329,7 +598,7 @@ memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * sb_bmap_nr(rs)); for (i = 0; i < sb_bmap_nr(rs); i ++) { - SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp1 + i, s->s_blocksize); + SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp1 + i); if (!SB_AP_BITMAP (s)[i]) return 1; } @@ -355,17 +624,17 @@ free, SB_FREE_BLOCKS (s)); } -static int read_super_block (struct super_block * s, int size, int offset) +static int read_super_block (struct super_block * s, int offset) { struct buffer_head * bh; struct reiserfs_super_block * rs; - bh = bread (s->s_dev, offset / size, size); + bh = sb_bread (s, offset / s->s_blocksize); if (!bh) { printk ("read_super_block: " - "bread failed (dev %s, block %d, size %d)\n", - kdevname (s->s_dev), offset / size, size); + "bread failed (dev %s, block %ld, size %ld)\n", + kdevname (s->s_dev), offset / s->s_blocksize, s->s_blocksize); return 1; } @@ -373,7 +642,7 @@ if (!is_reiserfs_magic_string (rs)) { printk ("read_super_block: " "can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n", - kdevname(s->s_dev), bh->b_blocknr, size); + kdevname(s->s_dev), bh->b_blocknr, s->s_blocksize); brelse (bh); return 1; } @@ -381,30 +650,23 @@ // // ok, reiserfs signature (old or new) found in at the given offset // - s->s_blocksize = sb_blocksize(rs); - s->s_blocksize_bits = 0; - while ((1 << s->s_blocksize_bits) != s->s_blocksize) - s->s_blocksize_bits ++; - brelse (bh); - if (s->s_blocksize != size) - set_blocksize (s->s_dev, s->s_blocksize); + sb_set_blocksize (s, sb_blocksize(rs)); - bh = reiserfs_bread (s, offset / s->s_blocksize, s->s_blocksize); + bh = reiserfs_bread (s, offset / s->s_blocksize); if (!bh) { printk("read_super_block: " - "bread failed (dev %s, block %d, size %d)\n", - kdevname (s->s_dev), offset / size, size); + "bread failed (dev %s, block %ld, size %ld)\n", + kdevname (s->s_dev), offset / s->s_blocksize, s->s_blocksize); return 1; } rs = (struct reiserfs_super_block *)bh->b_data; - if (!is_reiserfs_magic_string (rs) || - sb_blocksize(rs) != s->s_blocksize) { + if (!is_reiserfs_magic_string (rs) || sb_blocksize(rs) != s->s_blocksize) { printk ("read_super_block: " - "can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n", - kdevname(s->s_dev), bh->b_blocknr, size); + "can't find a reiserfs filesystem on (dev %s, block %lu, size %ld)\n", + kdevname(s->s_dev), bh->b_blocknr, s->s_blocksize); brelse (bh); printk ("read_super_block: can't find a reiserfs filesystem on dev %s.\n", kdevname(s->s_dev)); return 1; @@ -608,18 +870,18 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent) +static struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent) { int size; struct inode *root_inode; - kdev_t dev = s->s_dev; int j; - extern int *blksize_size[]; struct reiserfs_transaction_handle th ; int old_format = 0; unsigned long blocks; int jinit_done = 0 ; struct reiserfs_iget4_args args ; + int old_magic; + struct reiserfs_super_block * rs; memset (&s->u.reiserfs_sb, 0, sizeof (struct reiserfs_sb_info)); @@ -633,18 +895,14 @@ return NULL; } - if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)] != 0) { - /* as blocksize is set for partition we use it */ - size = blksize_size[MAJOR(dev)][MINOR(dev)]; - } else { - size = BLOCK_SIZE; - set_blocksize (s->s_dev, BLOCK_SIZE); - } + size = block_size(s->s_dev); + sb_set_blocksize(s, size); /* read block (64-th 1k block), which can contain reiserfs super block */ - if (read_super_block (s, size, REISERFS_DISK_OFFSET_IN_BYTES)) { + if (read_super_block (s, REISERFS_DISK_OFFSET_IN_BYTES)) { // try old format (undistributed bitmap, super block in 8-th 1k block of a device) - if (read_super_block (s, size, REISERFS_OLD_DISK_OFFSET_IN_BYTES)) + sb_set_blocksize(s, size); + if (read_super_block (s, REISERFS_OLD_DISK_OFFSET_IN_BYTES)) goto error; else old_format = 1; @@ -704,18 +962,15 @@ goto error ; } - if (!(s->s_flags & MS_RDONLY)) { - struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s); - int old_magic; - - old_magic = strncmp (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, + rs = SB_DISK_SUPER_BLOCK (s); + old_magic = strncmp (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, strlen ( REISER2FS_SUPER_MAGIC_STRING)); - if( old_magic && le16_to_cpu(rs->s_version) != 0 ) { - dput(s->s_root) ; - s->s_root = NULL ; - reiserfs_warning("reiserfs: wrong version/magic combination in the super-block\n") ; - goto error ; - } + if (!old_magic) + set_bit(REISERFS_3_6, &(s->u.reiserfs_sb.s_properties)); + else + set_bit(REISERFS_3_5, &(s->u.reiserfs_sb.s_properties)); + + if (!(s->s_flags & MS_RDONLY)) { journal_begin(&th, s, 1) ; reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; @@ -724,34 +979,34 @@ if ( old_magic ) { // filesystem created under 3.5.x found - if (!old_format_only (s)) { + if (convert_reiserfs (s)) { reiserfs_warning("reiserfs: converting 3.5.x filesystem to the new format\n") ; // after this 3.5.x will not be able to mount this partition memcpy (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, sizeof (REISER2FS_SUPER_MAGIC_STRING)); reiserfs_convert_objectid_map_v1(s) ; + set_bit(REISERFS_3_6, &(s->u.reiserfs_sb.s_properties)); + clear_bit(REISERFS_3_5, &(s->u.reiserfs_sb.s_properties)); } else { reiserfs_warning("reiserfs: using 3.5.x disk format\n") ; } - } else { - // new format found - set_bit (REISERFS_CONVERT, &(s->u.reiserfs_sb.s_mount_opt)); } - // mark hash in super block: it could be unset. overwrite should be ok - set_sb_hash_function_code( rs, function2code(s->u.reiserfs_sb.s_hash_function ) ); - journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); journal_end(&th, s, 1) ; + + /* look for files which were to be removed in previous session */ + finish_unfinished (s); + s->s_dirt = 0; } else { - struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s); - if (strncmp (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, - strlen ( REISER2FS_SUPER_MAGIC_STRING))) { + if ( old_magic ) { reiserfs_warning("reiserfs: using 3.5.x disk format\n") ; } } + // mark hash in super block: it could be unset. overwrite should be ok + set_sb_hash_function_code( rs, function2code(s->u.reiserfs_sb.s_hash_function ) ); reiserfs_proc_info_init( s ); reiserfs_proc_register( s, "version", reiserfs_version_in_proc ); @@ -792,7 +1047,7 @@ // at the ext2 code and comparing. It's subfunctions contain no code // used as a template unless they are so labeled. // -int reiserfs_statfs (struct super_block * s, struct statfs * buf) +static int reiserfs_statfs (struct super_block * s, struct statfs * buf) { struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s); @@ -835,6 +1090,7 @@ reiserfs_proc_info_global_done(); unregister_filesystem(&reiserfs_fs_type); } + module_init(init_reiserfs_fs) ; module_exit(exit_reiserfs_fs) ; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/reiserfs/tail_conversion.c linux-2.5/fs/reiserfs/tail_conversion.c --- linux-2.5.1/fs/reiserfs/tail_conversion.c Tue Oct 30 23:11:34 2001 +++ linux-2.5/fs/reiserfs/tail_conversion.c Thu Dec 13 16:32:37 2001 @@ -240,7 +240,7 @@ /* Set direct item header to insert. */ - make_le_item_head (&s_ih, 0, inode_items_version (p_s_inode), pos1 + 1, + make_le_item_head (&s_ih, 0, get_inode_item_key_version (p_s_inode), pos1 + 1, TYPE_DIRECT, round_tail_len, 0xffff/*ih_free_space*/); /* we want a pointer to the first byte of the tail in the page. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/romfs/inode.c linux-2.5/fs/romfs/inode.c --- linux-2.5.1/fs/romfs/inode.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/romfs/inode.c Sat Jan 5 16:38:09 2002 @@ -96,15 +96,12 @@ romfs_read_super(struct super_block *s, void *data, int silent) { struct buffer_head *bh; - kdev_t dev = s->s_dev; struct romfs_super_block *rsb; int sz; /* I would parse the options here, but there are none.. :) */ - set_blocksize(dev, ROMBSIZE); - s->s_blocksize = ROMBSIZE; - s->s_blocksize_bits = ROMBSBITS; + sb_set_blocksize(s, ROMBSIZE); s->u.generic_sbp = (void *) 0; s->s_maxbytes = 0xFFFFFFFF; @@ -121,12 +118,12 @@ || sz < ROMFH_SIZE) { if (!silent) printk ("VFS: Can't find a romfs filesystem on dev " - "%s.\n", kdevname(dev)); + "%s.\n", s->s_id); goto out; } if (romfs_checksum(rsb, min_t(int, sz, 512))) { printk ("romfs: bad initial checksum on dev " - "%s.\n", kdevname(dev)); + "%s.\n", s->s_id); goto out; } @@ -520,7 +517,9 @@ default: /* depending on MBZ for sock/fifos */ nextfh = ntohl(ri.spec); - nextfh = kdev_t_to_nr(MKDEV(nextfh>>16,nextfh&0xffff)); + /* convert back and forth for typechecking and + * source tagging */ + nextfh = kdev_t_to_nr(mk_kdev(nextfh>>16,nextfh&0xffff)); init_special_inode(i, ino, nextfh); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/smbfs/ChangeLog linux-2.5/fs/smbfs/ChangeLog --- linux-2.5.1/fs/smbfs/ChangeLog Wed Oct 3 00:03:34 2001 +++ linux-2.5/fs/smbfs/ChangeLog Thu Jan 3 23:04:40 2002 @@ -1,5 +1,15 @@ ChangeLog for smbfs. +2001-12-31 René Scharfe <l.s.r@web.de> + + * inode.c: added smb_show_options to show mount options in /proc/mounts + * inode.c, getopt.c, getopt.h: merged flag and has_arg in struct option + * inode.c: use S_IRWXUGO where appropriate + +2001-12-22 Urban Widmark <urban@teststation.com> + + * file.c, proc.c: Fix problems triggered by the "fsx test" + 2001-09-17 Urban Widmark <urban@teststation.com> * proc.c: Use 4096 (was 512) as the blocksize for better write diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/smbfs/file.c linux-2.5/fs/smbfs/file.c --- linux-2.5.1/fs/smbfs/file.c Wed Oct 3 00:03:34 2001 +++ linux-2.5/fs/smbfs/file.c Thu Jan 3 23:04:40 2002 @@ -270,7 +270,6 @@ static int smb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { - kmap(page); return 0; } @@ -283,7 +282,6 @@ lock_kernel(); status = smb_updatepage(file, page, offset, to-offset); unlock_kernel(); - kunmap(page); return status; } @@ -349,8 +347,14 @@ smb_file_release(struct inode *inode, struct file * file) { lock_kernel(); - if (!--inode->u.smbfs_i.openers) + if (!--inode->u.smbfs_i.openers) { + /* We must flush any dirty pages now as we won't be able to + write anything after close. mmap can trigger this. + "openers" should perhaps include mmap'ers ... */ + filemap_fdatasync(inode->i_mapping); + filemap_fdatawait(inode->i_mapping); smb_close(inode); + } unlock_kernel(); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/smbfs/getopt.c linux-2.5/fs/smbfs/getopt.c --- linux-2.5.1/fs/smbfs/getopt.c Fri Apr 27 21:10:32 2001 +++ linux-2.5/fs/smbfs/getopt.c Thu Jan 3 23:04:40 2002 @@ -46,7 +46,7 @@ for (i = 0; opts[i].name != NULL; i++) { if (!strcmp(opts[i].name, token)) { - if (opts[i].has_arg && (!val || !*val)) { + if (!opts[i].flag && (!val || !*val)) { printk("%s: the %s option requires an argument\n", caller, token); return -1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/smbfs/getopt.h linux-2.5/fs/smbfs/getopt.h --- linux-2.5.1/fs/smbfs/getopt.h Mon Aug 14 20:31:10 2000 +++ linux-2.5/fs/smbfs/getopt.h Thu Jan 3 23:04:40 2002 @@ -3,7 +3,6 @@ struct option { const char *name; - int has_arg; unsigned long flag; int val; }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/smbfs/inode.c linux-2.5/fs/smbfs/inode.c --- linux-2.5.1/fs/smbfs/inode.c Wed Oct 3 00:03:34 2001 +++ linux-2.5/fs/smbfs/inode.c Thu Jan 3 23:04:40 2002 @@ -22,6 +22,7 @@ #include <linux/dcache.h> #include <linux/smp_lock.h> #include <linux/nls.h> +#include <linux/seq_file.h> #include <linux/smb_fs.h> #include <linux/smbno.h> @@ -41,9 +42,12 @@ #define SMB_NLS_REMOTE "" #endif +#define SMB_TTL_DEFAULT 1000 + static void smb_delete_inode(struct inode *); static void smb_put_super(struct super_block *); static int smb_statfs(struct super_block *, struct statfs *); +static int smb_show_options(struct seq_file *, struct vfsmount *); static struct super_operations smb_sops = { @@ -51,6 +55,7 @@ delete_inode: smb_delete_inode, put_super: smb_put_super, statfs: smb_statfs, + show_options: smb_show_options, }; @@ -259,21 +264,20 @@ clear_inode(ino); } -/* FIXME: flags and has_arg could probably be merged. */ static struct option opts[] = { - { "version", 1, 0, 'v' }, - { "win95", 0, SMB_MOUNT_WIN95, 1 }, - { "oldattr", 0, SMB_MOUNT_OLDATTR, 1 }, - { "dirattr", 0, SMB_MOUNT_DIRATTR, 1 }, - { "case", 0, SMB_MOUNT_CASE, 1 }, - { "uid", 1, 0, 'u' }, - { "gid", 1, 0, 'g' }, - { "file_mode", 1, 0, 'f' }, - { "dir_mode", 1, 0, 'd' }, - { "iocharset", 1, 0, 'i' }, - { "codepage", 1, 0, 'c' }, - { "ttl", 1, 0, 't' }, - { NULL, 0, 0, 0} + { "version", 0, 'v' }, + { "win95", SMB_MOUNT_WIN95, 1 }, + { "oldattr", SMB_MOUNT_OLDATTR, 1 }, + { "dirattr", SMB_MOUNT_DIRATTR, 1 }, + { "case", SMB_MOUNT_CASE, 1 }, + { "uid", 0, 'u' }, + { "gid", 0, 'g' }, + { "file_mode", 0, 'f' }, + { "dir_mode", 0, 'd' }, + { "iocharset", 0, 'i' }, + { "codepage", 0, 'c' }, + { "ttl", 0, 't' }, + { NULL, 0, 0} }; static int @@ -310,12 +314,10 @@ mnt->gid = value; break; case 'f': - mnt->file_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO); - mnt->file_mode |= S_IFREG; + mnt->file_mode = (value & S_IRWXUGO) | S_IFREG; break; case 'd': - mnt->dir_mode = value & (S_IRWXU | S_IRWXG | S_IRWXO); - mnt->dir_mode |= S_IFDIR; + mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR; break; case 'i': strncpy(mnt->codepage.local_name, optarg, @@ -338,6 +340,45 @@ return c; } +/* + * smb_show_options() is for displaying mount options in /proc/mounts. + * It tries to avoid showing settings that were not changed from their + * defaults. + */ +static int +smb_show_options(struct seq_file *s, struct vfsmount *m) +{ + struct smb_mount_data_kernel *mnt = m->mnt_sb->u.smbfs_sb.mnt; + int i; + + for (i = 0; opts[i].name != NULL; i++) + if (mnt->flags & opts[i].flag) + seq_printf(s, ",%s", opts[i].name); + + if (mnt->uid != 0) + seq_printf(s, ",uid=%d", mnt->uid); + if (mnt->gid != 0) + seq_printf(s, ",gid=%d", mnt->gid); + if (mnt->mounted_uid != 0) + seq_printf(s, ",mounted_uid=%d", mnt->mounted_uid); + + /* + * Defaults for file_mode and dir_mode are unknown to us; they + * depend on the current umask of the user doing the mount. + */ + seq_printf(s, ",file_mode=%04o", mnt->file_mode & S_IRWXUGO); + seq_printf(s, ",dir_mode=%04o", mnt->dir_mode & S_IRWXUGO); + + if (strcmp(mnt->codepage.local_name, CONFIG_NLS_DEFAULT)) + seq_printf(s, ",iocharset=%s", mnt->codepage.local_name); + if (strcmp(mnt->codepage.remote_name, SMB_NLS_REMOTE)) + seq_printf(s, ",codepage=%s", mnt->codepage.remote_name); + + if (mnt->ttl != SMB_TTL_DEFAULT) + seq_printf(s, ",ttl=%d", mnt->ttl); + + return 0; +} static void smb_put_super(struct super_block *sb) @@ -425,7 +466,7 @@ strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE, SMB_NLS_MAXNAMELEN); - mnt->ttl = 1000; + mnt->ttl = SMB_TTL_DEFAULT; if (ver == SMB_MOUNT_OLDVERSION) { mnt->version = oldmnt->version; @@ -434,12 +475,8 @@ mnt->uid = oldmnt->uid; mnt->gid = oldmnt->gid; - mnt->file_mode = - oldmnt->file_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - mnt->dir_mode = - oldmnt->dir_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - mnt->file_mode |= S_IFREG; - mnt->dir_mode |= S_IFDIR; + mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG; + mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR; mnt->flags = (oldmnt->file_mode >> 9); } else { @@ -510,7 +547,7 @@ { struct inode *inode = dentry->d_inode; struct smb_sb_info *server = server_from_dentry(dentry); - unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); + unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXUGO); int error, changed, refresh = 0; struct smb_fattr fattr; @@ -535,6 +572,10 @@ VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n", DENTRY_PATH(dentry), (long) inode->i_size, (long) attr->ia_size); + + filemap_fdatasync(inode->i_mapping); + filemap_fdatawait(inode->i_mapping); + error = smb_open(dentry, O_WRONLY); if (error) goto out; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/super.c linux-2.5/fs/super.c --- linux-2.5.1/fs/super.c Sat Dec 8 00:24:52 2001 +++ linux-2.5/fs/super.c Sun Jan 6 19:17:51 2002 @@ -34,8 +34,6 @@ #define __NO_VERSION__ #include <linux/module.h> -int do_remount_sb(struct super_block *sb, int flags, void * data); - LIST_HEAD(super_blocks); spinlock_t sb_lock = SPIN_LOCK_UNLOCKED; @@ -377,7 +375,7 @@ get_filesystem(type); } -void put_unnamed_dev(kdev_t dev); /* should become static */ +static void put_anon_dev(kdev_t dev); /** * remove_super - makes superblock unreachable @@ -407,7 +405,7 @@ if (bdev) blkdev_put(bdev, BDEV_FS); else - put_unnamed_dev(dev); + put_anon_dev(dev); } struct vfsmount *alloc_vfsmnt(void); @@ -420,7 +418,7 @@ list_for_each(p, &super_blocks) { struct super_block * s = sb_entry(p); - if (s->s_dev == dev) { + if (kdev_same(s->s_dev, dev)) { s->s_count++; return s; } @@ -452,7 +450,7 @@ { struct super_block * sb; - if (dev) { + if (!kdev_none(dev)) { sb = get_super(dev); if (sb) { if (sb->s_dirt) @@ -489,7 +487,7 @@ { struct super_block * s; - if (!dev) + if (kdev_none(dev)) return NULL; while (1) { @@ -530,40 +528,127 @@ return err; } +/** + * do_remount_sb - asks filesystem to change mount options. + * @sb: superblock in question + * @flags: numeric part of options + * @data: the rest of options + * + * Alters the mount options of a mounted file system. + */ +int do_remount_sb(struct super_block *sb, int flags, void *data) +{ + int retval; + + if (!(flags & MS_RDONLY) && !kdev_none(sb->s_dev) && is_read_only(sb->s_dev)) + return -EACCES; + /*flags |= MS_RDONLY;*/ + if (flags & MS_RDONLY) + acct_auto_close(sb); + shrink_dcache_sb(sb); + fsync_super(sb); + /* If we are remounting RDONLY, make sure there are no rw files open */ + if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) + if (!fs_may_remount_ro(sb)) + return -EBUSY; + if (sb->s_op && sb->s_op->remount_fs) { + lock_super(sb); + retval = sb->s_op->remount_fs(sb, &flags, data); + unlock_super(sb); + if (retval) + return retval; + } + sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); + return 0; +} + /* * Unnamed block devices are dummy devices used by virtual * filesystems which don't use real block-devices. -- jrs */ -static unsigned long unnamed_dev_in_use[256/(8*sizeof(unsigned long))]; +enum {Max_anon = 256}; +static unsigned long unnamed_dev_in_use[Max_anon/(8*sizeof(unsigned long))]; +static spinlock_t unnamed_dev_lock = SPIN_LOCK_UNLOCKED;/* protects the above */ -kdev_t get_unnamed_dev(void) +/** + * put_anon_dev - release anonymous device number. + * @dev: device in question + */ +static void put_anon_dev(kdev_t dev) { - int i; - - for (i = 1; i < 256; i++) { - if (!test_and_set_bit(i,unnamed_dev_in_use)) - return MKDEV(UNNAMED_MAJOR, i); - } - return 0; + spin_lock(&unnamed_dev_lock); + clear_bit(minor(dev), unnamed_dev_in_use); + spin_unlock(&unnamed_dev_lock); } -void put_unnamed_dev(kdev_t dev) +/** + * get_anon_super - allocate a superblock for non-device fs + * @type: filesystem type + * @compare: check if existing superblock is what we want + * @data: argument for @compare. + * + * get_anon_super is a helper for non-blockdevice filesystems. + * It either finds and returns one of the superblocks of given type + * (if it can find one that would satisfy caller) or creates a new + * one. In the either case we return an active reference to superblock + * with ->s_umount locked. If superblock is new it gets a new + * anonymous device allocated for it and is inserted into lists - + * other initialization is left to caller. + * + * Rather than duplicating all that logics every time when + * we want something that doesn't fit "nodev" and "single" we pull + * the relevant code into common helper and let get_sb_...() call + * it. + * + * NB: get_sb_...() is going to become an fs type method, with + * current ->read_super() becoming a callback used by common instances. + */ +struct super_block *get_anon_super(struct file_system_type *type, + int (*compare)(struct super_block *,void *), void *data) { - if (!dev || MAJOR(dev) != UNNAMED_MAJOR) - return; - if (test_and_clear_bit(MINOR(dev), unnamed_dev_in_use)) - return; - printk("VFS: put_unnamed_dev: freeing unused device %s\n", - kdevname(dev)); + struct super_block *s = alloc_super(); + int dev; + struct list_head *p; + + if (!s) + return ERR_PTR(-ENOMEM); + + spin_lock(&unnamed_dev_lock); + dev = find_first_zero_bit(unnamed_dev_in_use, Max_anon); + if (dev == Max_anon) { + spin_unlock(&unnamed_dev_lock); + destroy_super(s); + return ERR_PTR(-EMFILE); + } + set_bit(dev, unnamed_dev_in_use); + spin_unlock(&unnamed_dev_lock); + +retry: + spin_lock(&sb_lock); + if (compare) list_for_each(p, &type->fs_supers) { + struct super_block *old; + old = list_entry(p, struct super_block, s_instances); + if (!compare(old, data)) + continue; + if (!grab_super(old)) + goto retry; + destroy_super(s); + return old; + } + + s->s_dev = mk_kdev(0, dev); + insert_super(s, type); + return s; } static struct super_block *get_sb_bdev(struct file_system_type *fs_type, - char *dev_name, int flags, void * data) + int flags, char *dev_name, void * data) { struct inode *inode; struct block_device *bdev; struct block_device_operations *bdops; + devfs_handle_t de; struct super_block * s; struct nameidata nd; struct list_head *p; @@ -587,28 +672,26 @@ goto out; bd_acquire(inode); bdev = inode->i_bdev; - bdops = devfs_get_ops ( devfs_get_handle_from_inode (inode) ); + de = devfs_get_handle_from_inode (inode); + bdops = devfs_get_ops (de); /* Increments module use count */ if (bdops) bdev->bd_op = bdops; /* Done with lookups, semaphore down */ dev = to_kdev_t(bdev->bd_dev); if (!(flags & MS_RDONLY)) mode |= FMODE_WRITE; error = blkdev_get(bdev, mode, 0, BDEV_FS); + devfs_put_ops (de); /* Decrement module use count now we're safe */ if (error) goto out; check_disk_change(dev); error = -EACCES; - if (!(flags & MS_RDONLY) && is_read_only(dev)) { - blkdev_put(bdev, BDEV_FS); - goto out; - } + if (!(flags & MS_RDONLY) && is_read_only(dev)) + goto out1; error = -ENOMEM; s = alloc_super(); - if (!s) { - blkdev_put(bdev, BDEV_FS); - goto out; - } + if (!s) + goto out1; error = -EBUSY; restart: @@ -616,14 +699,13 @@ list_for_each(p, &super_blocks) { struct super_block *old = sb_entry(p); - if (old->s_dev != dev) + if (!kdev_same(old->s_dev, dev)) continue; if (old->s_type != fs_type || ((flags ^ old->s_flags) & MS_RDONLY)) { spin_unlock(&sb_lock); destroy_super(s); - blkdev_put(bdev, BDEV_FS); - goto out; + goto out1; } if (!grab_super(old)) goto restart; @@ -636,97 +718,104 @@ s->s_bdev = bdev; s->s_flags = flags; insert_super(s, fs_type); - + strncpy(s->s_id, bdevname(dev), sizeof(s->s_id)); error = -EINVAL; - lock_super(s); if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) - goto out_fail; + goto failed; s->s_flags |= MS_ACTIVE; - unlock_super(s); path_release(&nd); return s; -out_fail: - unlock_super(s); +failed: deactivate_super(s); remove_super(s); + goto out; +out1: + blkdev_put(bdev, BDEV_FS); out: path_release(&nd); return ERR_PTR(error); } static struct super_block *get_sb_nodev(struct file_system_type *fs_type, - int flags, void * data) + int flags, char *dev_name, void *data) { - struct super_block *s = alloc_super(); + struct super_block *s = get_anon_super(fs_type, NULL, NULL); + + if (IS_ERR(s)) + return s; - if (!s) - return ERR_PTR(-ENOMEM); - s->s_dev = get_unnamed_dev(); - if (!s->s_dev) { - destroy_super(s); - return ERR_PTR(-EMFILE); - } s->s_flags = flags; - spin_lock(&sb_lock); - insert_super(s, fs_type); - lock_super(s); - if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) - goto out_fail; + if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) { + deactivate_super(s); + remove_super(s); + return ERR_PTR(-EINVAL); + } s->s_flags |= MS_ACTIVE; - unlock_super(s); return s; +} -out_fail: - unlock_super(s); - deactivate_super(s); - remove_super(s); - return ERR_PTR(-EINVAL); +static int compare_single(struct super_block *s, void *p) +{ + return 1; } static struct super_block *get_sb_single(struct file_system_type *fs_type, - int flags, void *data) + int flags, char *dev_name, void *data) { - struct super_block * s = alloc_super(); - if (!s) - return ERR_PTR(-ENOMEM); - /* - * Get the superblock of kernel-wide instance, but - * keep the reference to fs_type. - */ -retry: - spin_lock(&sb_lock); - if (!list_empty(&fs_type->fs_supers)) { - struct super_block *old; - old = list_entry(fs_type->fs_supers.next, struct super_block, - s_instances); - if (!grab_super(old)) - goto retry; - destroy_super(s); - do_remount_sb(old, flags, data); - return old; - } else { - s->s_dev = get_unnamed_dev(); - if (!s->s_dev) { - spin_unlock(&sb_lock); - destroy_super(s); - return ERR_PTR(-EMFILE); - } + struct super_block *s = get_anon_super(fs_type, compare_single, NULL); + + if (IS_ERR(s)) + return s; + if (!s->s_root) { s->s_flags = flags; - insert_super(s, fs_type); - lock_super(s); - if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) - goto out_fail; + if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) { + deactivate_super(s); + remove_super(s); + return ERR_PTR(-EINVAL); + } s->s_flags |= MS_ACTIVE; - unlock_super(s); - return s; - - out_fail: - unlock_super(s); - deactivate_super(s); - remove_super(s); - return ERR_PTR(-EINVAL); } + do_remount_sb(s, flags, data); + return s; +} + +struct vfsmount * +do_kern_mount(const char *fstype, int flags, char *name, void *data) +{ + struct file_system_type *type = get_fs_type(fstype); + struct super_block *sb = ERR_PTR(-ENOMEM); + struct vfsmount *mnt; + + if (!type) + return ERR_PTR(-ENODEV); + + mnt = alloc_vfsmnt(); + if (!mnt) + goto out; + set_devname(mnt, name); + if (type->fs_flags & FS_REQUIRES_DEV) + sb = get_sb_bdev(type, flags, name, data); + else if (type->fs_flags & FS_SINGLE) + sb = get_sb_single(type, flags, name, data); + else + sb = get_sb_nodev(type, flags, name, data); + if (IS_ERR(sb)) + goto out_mnt; + if (type->fs_flags & FS_NOMOUNT) + sb->s_flags |= MS_NOUSER; + mnt->mnt_sb = sb; + mnt->mnt_root = dget(sb->s_root); + mnt->mnt_mountpoint = sb->s_root; + mnt->mnt_parent = mnt; + up_write(&sb->s_umount); + put_filesystem(type); + return mnt; +out_mnt: + free_vfsmnt(mnt); +out: + put_filesystem(type); + return (struct vfsmount *)sb; } void kill_super(struct super_block *sb) @@ -739,7 +828,6 @@ return; down_write(&sb->s_umount); - lock_kernel(); sb->s_root = NULL; /* Need to clean after the sucker */ if (fs->fs_flags & FS_LITTER) @@ -748,6 +836,7 @@ dput(root); fsync_super(sb); lock_super(sb); + lock_kernel(); sb->s_flags &= ~MS_ACTIVE; invalidate_inodes(sb); /* bad name - it should be evict_inodes() */ if (sop) { @@ -768,96 +857,7 @@ remove_super(sb); } -/* - * Alters the mount flags of a mounted file system. Only the mount point - * is used as a reference - file system type and the device are ignored. - */ - -int do_remount_sb(struct super_block *sb, int flags, void *data) -{ - int retval; - - if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev)) - return -EACCES; - /*flags |= MS_RDONLY;*/ - if (flags & MS_RDONLY) - acct_auto_close(sb->s_dev); - shrink_dcache_sb(sb); - fsync_super(sb); - /* If we are remounting RDONLY, make sure there are no rw files open */ - if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) - if (!fs_may_remount_ro(sb)) - return -EBUSY; - if (sb->s_op && sb->s_op->remount_fs) { - lock_super(sb); - retval = sb->s_op->remount_fs(sb, &flags, data); - unlock_super(sb); - if (retval) - return retval; - } - sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); - - /* - * We can't invalidate inodes as we can loose data when remounting - * (someone might manage to alter data while we are waiting in lock_super() - * or in foo_remount_fs())) - */ - - return 0; -} - -struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data) -{ - struct file_system_type * fstype; - struct vfsmount *mnt = NULL; - struct super_block *sb; - - if (!type || !memchr(type, 0, PAGE_SIZE)) - return ERR_PTR(-EINVAL); - - /* we need capabilities... */ - if (!capable(CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); - - /* ... filesystem driver... */ - fstype = get_fs_type(type); - if (!fstype) - return ERR_PTR(-ENODEV); - - /* ... allocated vfsmount... */ - mnt = alloc_vfsmnt(); - if (!mnt) { - mnt = ERR_PTR(-ENOMEM); - goto fs_out; - } - set_devname(mnt, name); - /* get locked superblock */ - if (fstype->fs_flags & FS_REQUIRES_DEV) - sb = get_sb_bdev(fstype, name, flags, data); - else if (fstype->fs_flags & FS_SINGLE) - sb = get_sb_single(fstype, flags, data); - else - sb = get_sb_nodev(fstype, flags, data); - - if (IS_ERR(sb)) { - free_vfsmnt(mnt); - mnt = (struct vfsmount *)sb; - goto fs_out; - } - if (fstype->fs_flags & FS_NOMOUNT) - sb->s_flags |= MS_NOUSER; - - mnt->mnt_sb = sb; - mnt->mnt_root = dget(sb->s_root); - mnt->mnt_mountpoint = mnt->mnt_root; - mnt->mnt_parent = mnt; - up_write(&sb->s_umount); -fs_out: - put_filesystem(fstype); - return mnt; -} - struct vfsmount *kern_mount(struct file_system_type *type) { - return do_kern_mount((char *)type->name, 0, (char *)type->name, NULL); + return do_kern_mount(type->name, 0, (char *)type->name, NULL); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/sysv/ChangeLog linux-2.5/fs/sysv/ChangeLog --- linux-2.5.1/fs/sysv/ChangeLog Fri Nov 9 21:45:35 2001 +++ linux-2.5/fs/sysv/ChangeLog Sun Jan 6 01:38:27 2002 @@ -1,3 +1,50 @@ +Fri Jan 4 2001 Alexander Viro <viro@math.psu.edu> + + * ialloc.c (sysv_free_inode): Use sb->s_id instead of bdevname(). + * inode.c (sysv_read_inode): Likewise. + (sysv_update_inode): Likewise. + (sysv_sync_inode): Likewise. + * super.c (detect_sysv): Likewise. + (complete_read_super): Likewise. + (sysv_read_super): Likewise. + (v7_read_super): Likewise. + +Sun Dec 30 2001 Manfred Spraul <manfreds@colorfullife.com> + + * dir.c (dir_commit_chunk): Do not set dir->i_version. + (sysv_readdir): Likewise. + +Thu Dec 27 2001 Alexander Viro <viro@math.psu.edu> + + * itree.c (get_block): Use map_bh() to fill out bh_result. + +Tue Dec 25 2001 Alexander Viro <viro@math.psu.edu> + + * super.c (sysv_read_super): Use sb_set_blocksize() to set blocksize. + (v7_read_super): Likewise. + +Tue Nov 27 2001 Alexander Viro <viro@math.psu.edu> + + * itree.c (get_block): Change type for iblock argument to sector_t. + * super.c (sysv_read_super): Set s_blocksize early. + (v7_read_super): Likewise. + * balloc.c (sysv_new_block): Use sb_bread(). instead of bread(). + (sysv_count_free_blocks): Likewise. + * ialloc.c (sysv_raw_inode): Likewise. + * itree.c (get_branch): Likewise. + (free_branches): Likewise. + * super.c (sysv_read_super): Likewise. + (v7_read_super): Likewise. + +Sat Dec 15 2001 Christoph Hellwig <hch@caldera.de> + + * inode.c (sysv_read_inode): Mark inode as bad in case of failure. + * super.c (complete_read_super): Check for bad root inode. + +Wed Nov 21 2001 Andrew Morton <andrewm@uow.edu.au> + + * file.c (sysv_sync_file): Call fsync_inode_data_buffers. + Fri Oct 26 2001 Christoph Hellwig <hch@caldera.de> * dir.c, ialloc.c, namei.c, include/linux/sysv_fs_i.h: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/sysv/dir.c linux-2.5/fs/sysv/dir.c --- linux-2.5.1/fs/sysv/dir.c Fri Nov 9 21:45:35 2001 +++ linux-2.5/fs/sysv/dir.c Sun Dec 30 20:01:41 2001 @@ -41,7 +41,6 @@ struct inode *dir = (struct inode *)page->mapping->host; int err = 0; - dir->i_version = ++event; page->mapping->a_ops->commit_write(NULL, page, from, to); if (IS_SYNC(dir)) err = waitfor_one_page(page); @@ -111,7 +110,6 @@ done: filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; - filp->f_version = inode->i_version; UPDATE_ATIME(inode); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/sysv/ialloc.c linux-2.5/fs/sysv/ialloc.c --- linux-2.5.1/fs/sysv/ialloc.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/sysv/ialloc.c Sat Jan 5 16:38:09 2002 @@ -109,7 +109,7 @@ clear_inode(inode); if (!raw_inode) { printk("sysv_free_inode: unable to read inode block on device " - "%s\n", bdevname(inode->i_dev)); + "%s\n", inode->i_sb->s_id); return; } lock_super(sb); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/sysv/inode.c linux-2.5/fs/sysv/inode.c --- linux-2.5.1/fs/sysv/inode.c Fri Nov 9 21:45:35 2001 +++ linux-2.5/fs/sysv/inode.c Sat Jan 5 16:38:09 2002 @@ -149,16 +149,15 @@ ino = inode->i_ino; if (!ino || ino > sb->sv_ninodes) { - printk("Bad inode number on dev %s" - ": %d is out of range\n", - kdevname(inode->i_dev), ino); - return; + printk("Bad inode number on dev %s: %d is out of range\n", + inode->i_sb->s_id, ino); + goto bad_inode; } raw_inode = sysv_raw_inode(sb, ino, &bh); if (!raw_inode) { printk("Major problem: unable to read inode from dev %s\n", - bdevname(inode->i_dev)); - return; + inode->i_sb->s_id); + goto bad_inode; } /* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */ inode->i_mode = fs16_to_cpu(sb, raw_inode->i_mode); @@ -178,6 +177,11 @@ rdev = (u16)fs32_to_cpu(sb, inode->u.sysv_i.i_data[0]); inode->u.sysv_i.i_dir_start_lookup = 0; sysv_set_inode(inode, rdev); + return; + +bad_inode: + make_bad_inode(inode); + return; } static struct buffer_head * sysv_update_inode(struct inode * inode) @@ -190,7 +194,7 @@ ino = inode->i_ino; if (!ino || ino > sb->sv_ninodes) { printk("Bad inode number on dev %s: %d is out of range\n", - bdevname(inode->i_dev), ino); + inode->i_sb->s_id, ino); return 0; } raw_inode = sysv_raw_inode(sb, ino, &bh); @@ -237,7 +241,7 @@ wait_on_buffer(bh); if (buffer_req(bh) && !buffer_uptodate(bh)) { printk ("IO error syncing sysv inode [%s:%08lx]\n", - bdevname(inode->i_dev), inode->i_ino); + inode->i_sb->s_id, inode->i_ino); err = -1; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/sysv/itree.c linux-2.5/fs/sysv/itree.c --- linux-2.5.1/fs/sysv/itree.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/sysv/itree.c Thu Dec 27 22:10:28 2001 @@ -211,9 +211,7 @@ /* Simplest case - block found, no allocation needed */ if (!partial) { got_it: - bh_result->b_dev = sb->s_dev; - bh_result->b_blocknr = block_to_cpu(sb, chain[depth-1].key); - bh_result->b_state |= (1UL << BH_Mapped); + map_bh(bh_result, sb, block_to_cpu(sb, chain[depth-1].key)); /* Clean up and exit */ partial = chain+depth-1; /* the whole chain */ goto cleanup; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/sysv/super.c linux-2.5/fs/sysv/super.c --- linux-2.5.1/fs/sysv/super.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/sysv/super.c Sat Jan 5 16:38:09 2002 @@ -208,7 +208,7 @@ if (!(sb->s_flags & MS_RDONLY)) { printk("SysV FS: SCO EAFS on %s detected, " "forcing read-only mode.\n", - bdevname(sb->s_dev)); + sb->s_id); sb->s_flags |= MS_RDONLY; } return sbd->s_type; @@ -232,7 +232,7 @@ if (sbd->s_type >= 0x10) { printk("SysV FS: can't handle long file names on %s, " - "forcing read-only mode.\n", kdevname(sb->s_dev)); + "forcing read-only mode.\n", sb->s_id); sb->s_flags |= MS_RDONLY; } @@ -315,17 +315,15 @@ sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits; - sb->s_blocksize = bsize; - sb->s_blocksize_bits = n_bits; if (!silent) printk("VFS: Found a %s FS (block size = %ld) on device %s\n", - found, sb->s_blocksize, bdevname(sb->s_dev)); + found, sb->s_blocksize, sb->s_id); sb->s_magic = SYSV_MAGIC_BASE + sb->sv_type; /* set up enough so that it can read an inode */ sb->s_op = &sysv_sops; root_inode = iget(sb,SYSV_ROOT_INO); - if (!root_inode) { + if (!root_inode || is_bad_inode(root_inode)) { printk("SysV FS: get root inode failed\n"); return 0; } @@ -347,7 +345,6 @@ { struct buffer_head *bh1; struct buffer_head *bh = NULL; - kdev_t dev = sb->s_dev; unsigned long blocknr; int size = 0; int i; @@ -361,8 +358,7 @@ panic("Coherent FS: bad super-block size"); if (64 != sizeof (struct sysv_inode)) panic("sysv fs: bad i-node size"); - set_blocksize(dev,BLOCK_SIZE); - sb->s_blocksize = BLOCK_SIZE; + sb_set_blocksize(sb, BLOCK_SIZE); sb->sv_block_base = 0; for (i = 0; i < sizeof(flavours)/sizeof(flavours[0]) && !size; i++) { @@ -380,8 +376,7 @@ case 1: blocknr = bh->b_blocknr << 1; brelse(bh); - set_blocksize(dev, 512); - sb->s_blocksize = 512; + sb_set_blocksize(sb, 512); bh1 = sb_bread(sb, blocknr); bh = sb_bread(sb, blocknr + 1); break; @@ -391,8 +386,7 @@ case 3: blocknr = bh->b_blocknr >> 1; brelse(bh); - set_blocksize(dev, 2048); - sb->s_blocksize = 2048; + sb_set_blocksize(sb, 2048); bh1 = bh = sb_bread(sb, blocknr); break; default: @@ -408,7 +402,7 @@ brelse(bh1); brelse(bh); - set_blocksize(sb->s_dev,BLOCK_SIZE); + sb_set_blocksize(sb, BLOCK_SIZE); printk("oldfs: cannot read superblock\n"); failed: return NULL; @@ -417,7 +411,7 @@ brelse(bh); if (!silent) printk("VFS: unable to find oldfs superblock on device %s\n", - bdevname(dev)); + sb->s_id); goto failed; Ebadsize: brelse(bh); @@ -431,7 +425,6 @@ int silent) { struct buffer_head *bh, *bh2 = NULL; - kdev_t dev = sb->s_dev; struct v7_super_block *v7sb; struct sysv_inode *v7i; @@ -443,13 +436,12 @@ sb->sv_type = FSTYPE_V7; sb->sv_bytesex = BYTESEX_PDP; - set_blocksize(dev, 512); - sb->s_blocksize = 512; + sb_set_blocksize(sb, 512); if ((bh = sb_bread(sb, 1)) == NULL) { if (!silent) printk("VFS: unable to read V7 FS superblock on " - "device %s.\n", bdevname(dev)); + "device %s.\n", sb->s_id); goto failed; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/udf/inode.c linux-2.5/fs/udf/inode.c --- linux-2.5.1/fs/udf/inode.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/udf/inode.c Sat Jan 5 16:38:09 2002 @@ -215,7 +215,6 @@ page_cache_release(page); mark_inode_dirty(inode); - inode->i_version ++; } struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err) @@ -310,7 +309,6 @@ mark_buffer_dirty(sbh); udf_release_data(sbh); mark_inode_dirty(inode); - inode->i_version ++; return dbh; } @@ -324,11 +322,7 @@ { phys = udf_block_map(inode, block); if (phys) - { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); - } + map_bh(bh_result, inode->i_sb, phys); return 0; } @@ -357,11 +351,9 @@ if (!phys) BUG(); - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); if (new) bh_result->b_state |= (1UL << BH_New); + map_bh(bh_result, inode->i_sb, phys); abort: unlock_kernel(); return err; @@ -1039,7 +1031,6 @@ long convtime_usec; int offset, alen; - inode->i_version = ++event; UDF_I_NEW_INODE(inode) = 0; fe = (struct FileEntry *)bh->b_data; @@ -1540,7 +1531,7 @@ if (buffer_req(bh) && !buffer_uptodate(bh)) { printk("IO error syncing udf inode [%s:%08lx]\n", - bdevname(inode->i_dev), inode->i_ino); + inode->i_sb->s_id, inode->i_ino); err = -EIO; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/udf/namei.c linux-2.5/fs/udf/namei.c --- linux-2.5.1/fs/udf/namei.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/udf/namei.c Sun Dec 30 20:01:41 2001 @@ -595,7 +595,6 @@ dir->i_size += nfidlen; if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) UDF_I_LENALLOC(dir) += nfidlen; - dir->i_version = ++event; mark_inode_dirty(dir); return fi; } @@ -654,7 +653,6 @@ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) { mark_inode_dirty(dir); - dir->i_version = ++event; } if (fibh.sbh != fibh.ebh) udf_release_data(fibh.ebh); @@ -692,7 +690,6 @@ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) { mark_inode_dirty(dir); - dir->i_version = ++event; } mark_inode_dirty(inode); @@ -756,7 +753,6 @@ cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL); cfi.fileCharacteristics |= FILE_DIRECTORY; udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); - dir->i_version = ++event; dir->i_nlink++; mark_inode_dirty(dir); d_instantiate(dentry, inode); @@ -851,14 +847,12 @@ if (!empty_dir(inode)) goto end_rmdir; retval = udf_delete_entry(dir, fi, &fibh, &cfi); - dir->i_version = ++event; if (retval) goto end_rmdir; if (inode->i_nlink != 2) udf_warning(inode->i_sb, "udf_rmdir", "empty directory has nlink != 2 (%d)", inode->i_nlink); - inode->i_version = ++event; inode->i_nlink = 0; inode->i_size = 0; mark_inode_dirty(inode); @@ -1070,7 +1064,6 @@ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) { mark_inode_dirty(dir); - dir->i_version = ++event; } if (fibh.sbh != fibh.ebh) udf_release_data(fibh.ebh); @@ -1123,7 +1116,6 @@ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB) { mark_inode_dirty(dir); - dir->i_version = ++event; } if (fibh.sbh != fibh.ebh) udf_release_data(fibh.ebh); @@ -1205,7 +1197,6 @@ if (!nfi) goto end_rename; } - new_dir->i_version = ++event; /* * Like most other Unix systems, set the ctime for inodes on a @@ -1227,7 +1218,6 @@ ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi); udf_delete_entry(old_dir, ofi, &ofibh, &ocfi); - old_dir->i_version = ++event; if (new_inode) { new_inode->i_nlink--; @@ -1247,7 +1237,6 @@ if (UDF_I_ALLOCTYPE(old_inode) == ICB_FLAG_AD_IN_ICB) { mark_inode_dirty(old_inode); - old_inode->i_version = ++event; } else mark_buffer_dirty_inode(dir_bh, old_inode); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/udf/super.c linux-2.5/fs/udf/super.c --- linux-2.5.1/fs/udf/super.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/udf/super.c Sat Jan 5 16:38:09 2002 @@ -357,30 +357,11 @@ static int udf_set_blocksize(struct super_block *sb, int bsize) { - /* Use specified block size if specified */ - if (bsize) - sb->s_blocksize = bsize; - if (get_hardsect_size(sb->s_dev) > sb->s_blocksize) - sb->s_blocksize = get_hardsect_size(sb->s_dev); - - /* Block size must be an even multiple of 512 */ - switch (sb->s_blocksize) - { - case 512: sb->s_blocksize_bits = 9; break; - case 1024: sb->s_blocksize_bits = 10; break; - case 2048: sb->s_blocksize_bits = 11; break; - case 4096: sb->s_blocksize_bits = 12; break; - case 8192: sb->s_blocksize_bits = 13; break; - default: - { - udf_debug("Bad block size (%ld)\n", sb->s_blocksize); - printk(KERN_ERR "udf: bad block size (%ld)\n", sb->s_blocksize); - return 0; - } + if (!sb_min_blocksize(sb, bsize)) { + udf_debug("Bad block size (%d)\n", bsize); + printk(KERN_ERR "udf: bad block size (%d)\n", bsize); + return 0; } - - /* Set the block size */ - set_blocksize(sb->s_dev, sb->s_blocksize); return sb->s_blocksize; } @@ -1568,7 +1549,7 @@ vsprintf(error_buf, fmt, args); va_end(args); printk (KERN_CRIT "UDF-fs error (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); } void udf_warning(struct super_block *sb, const char *function, @@ -1580,7 +1561,7 @@ vsprintf(error_buf, fmt, args); va_end(args); printk(KERN_WARNING "UDF-fs warning (device %s): %s: %s\n", - bdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ufs/inode.c linux-2.5/fs/ufs/inode.c --- linux-2.5.1/fs/ufs/inode.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/ufs/inode.c Thu Dec 27 22:10:28 2001 @@ -310,22 +310,16 @@ static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) { - struct super_block * sb; - struct ufs_sb_private_info * uspi; + struct super_block * sb = inode->i_sb; + struct ufs_sb_private_info * uspi = sb->u.ufs_sb.s_uspi; struct buffer_head * bh; int ret, err, new; unsigned long ptr, phys; - sb = inode->i_sb; - uspi = sb->u.ufs_sb.s_uspi; - if (!create) { phys = ufs_frag_map(inode, fragment); - if (phys) { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); - } + if (phys) + map_bh(bh_result, sb, phys); return 0; } @@ -392,11 +386,9 @@ out: if (err) goto abort; - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); if (new) bh_result->b_state |= (1UL << BH_New); + map_bh(bh_result, sb, phys); abort: unlock_kernel(); return err; @@ -494,13 +486,13 @@ if (inode->i_ino < UFS_ROOTINO || inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino); - return; + goto bad_inode; } bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino)); if (!bh) { ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); - return; + goto bad_inode; } ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino)); @@ -565,6 +557,11 @@ brelse (bh); UFSD(("EXIT\n")) + return; + +bad_inode: + make_bad_inode(inode); + return; } static int ufs_update_inode(struct inode * inode, int do_sync) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ufs/super.c linux-2.5/fs/ufs/super.c --- linux-2.5.1/fs/ufs/super.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/ufs/super.c Thu Jan 10 22:41:07 2002 @@ -203,13 +203,13 @@ switch (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_ONERROR) { case UFS_MOUNT_ONERROR_PANIC: panic ("UFS-fs panic (device %s): %s: %s\n", - kdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); case UFS_MOUNT_ONERROR_LOCK: case UFS_MOUNT_ONERROR_UMOUNT: case UFS_MOUNT_ONERROR_REPAIR: printk (KERN_CRIT "UFS-fs error (device %s): %s: %s\n", - kdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); } } @@ -233,7 +233,7 @@ va_end (args); sb->s_flags |= MS_RDONLY; printk (KERN_CRIT "UFS-fs panic (device %s): %s: %s\n", - kdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); } void ufs_warning (struct super_block * sb, const char * function, @@ -245,7 +245,7 @@ vsprintf (error_buf, fmt, args); va_end (args); printk (KERN_WARNING "UFS-fs warning (device %s): %s: %s\n", - kdevname(sb->s_dev), function, error_buf); + sb->s_id, function, error_buf); } static int ufs_parse_options (char * options, unsigned * mount_options) @@ -442,6 +442,7 @@ struct ufs_super_block_second * usb2; struct ufs_super_block_third * usb3; struct ufs_buffer_head * ubh; + struct inode *inode; unsigned block_size, super_block_size; unsigned flags; @@ -596,8 +597,7 @@ } again: - set_blocksize (sb->s_dev, block_size); - sb->s_blocksize = block_size; + sb_set_blocksize(sb, block_size); /* * read ufs super block from device @@ -716,8 +716,6 @@ /* * Read ufs_super_block into internal data structures */ - sb->s_blocksize = fs32_to_cpu(sb, usb1->fs_fsize); - sb->s_blocksize_bits = fs32_to_cpu(sb, usb1->fs_fshift); sb->s_op = &ufs_super_ops; sb->dq_op = NULL; /***/ sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic); @@ -790,7 +788,13 @@ fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_maxsymlinklen); sb->u.ufs_sb.s_flags = flags; - sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO)); + + inode = iget(sb, UFS_ROOTINO); + if (!inode || is_bad_inode(inode)) + goto failed; + sb->s_root = d_alloc_root(inode); + if (!sb->s_root) + goto dalloc_failed; /* @@ -803,6 +807,8 @@ UFSD(("EXIT\n")) return(sb); +dalloc_failed: + iput(inode); failed: if (ubh) ubh_brelse_uspi (uspi); if (uspi) kfree (uspi); @@ -973,3 +979,4 @@ module_init(init_ufs_fs) module_exit(exit_ufs_fs) +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/ufs/truncate.c linux-2.5/fs/ufs/truncate.c --- linux-2.5.1/fs/ufs/truncate.c Sun Dec 16 20:23:05 2001 +++ linux-2.5/fs/ufs/truncate.c Tue Jan 8 00:44:25 2002 @@ -448,10 +448,7 @@ if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) ufs_sync_inode (inode); run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - schedule (); - - + yield(); } offset = inode->i_size & uspi->s_fshift; if (offset) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/umsdos/inode.c linux-2.5/fs/umsdos/inode.c --- linux-2.5.1/fs/umsdos/inode.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/fs/umsdos/inode.c Wed Jan 2 01:30:12 2002 @@ -49,7 +49,7 @@ void UMSDOS_put_super (struct super_block *sb) { Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n")); - if (saved_root && pseudo_root && sb->s_dev == ROOT_DEV) { + if (saved_root && pseudo_root && kdev_same(sb->s_dev, ROOT_DEV)) { shrink_dcache_parent(saved_root); dput(saved_root); saved_root = NULL; @@ -414,7 +414,7 @@ * must check like this, because we can be used with initrd */ - if (sb->s_dev != ROOT_DEV) + if (!kdev_same(sb->s_dev, ROOT_DEV)) goto out_noroot; /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/vfat/namei.c linux-2.5/fs/vfat/namei.c --- linux-2.5.1/fs/vfat/namei.c Thu Oct 25 07:02:26 2001 +++ linux-2.5/fs/vfat/namei.c Sun Dec 30 20:01:41 2001 @@ -1040,8 +1040,8 @@ return res; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); - inode->i_version = ++event; - dir->i_version = event; + inode->i_version++; + dir->i_version++; dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,inode); return 0; @@ -1057,7 +1057,7 @@ /* remove the shortname */ dir->i_mtime = CURRENT_TIME; dir->i_atime = CURRENT_TIME; - dir->i_version = ++event; + dir->i_version++; mark_inode_dirty(dir); de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, bh); @@ -1138,8 +1138,8 @@ goto out; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); - inode->i_version = ++event; - dir->i_version = event; + inode->i_version++; + dir->i_version++; dir->i_nlink++; inode->i_nlink = 2; /* no need to mark them dirty */ res = fat_new_dir(inode, dir, 1); @@ -1209,7 +1209,7 @@ if (res < 0) goto rename_done; } - new_dir->i_version = ++event; + new_dir->i_version++; /* releases old_bh */ vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de); @@ -1218,7 +1218,7 @@ fat_attach(old_inode, sinfo.ino); mark_inode_dirty(old_inode); - old_dir->i_version = ++event; + old_dir->i_version++; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; mark_inode_dirty(old_dir); if (new_inode) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/fs/vfat/vfatfs_syms.c linux-2.5/fs/vfat/vfatfs_syms.c --- linux-2.5.1/fs/vfat/vfatfs_syms.c Fri Oct 12 20:48:42 2001 +++ linux-2.5/fs/vfat/vfatfs_syms.c Thu Dec 13 16:32:37 2001 @@ -33,3 +33,4 @@ module_init(init_vfat_fs) module_exit(exit_vfat_fs) +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-alpha/pci.h linux-2.5/include/asm-alpha/pci.h --- linux-2.5.1/include/asm-alpha/pci.h Fri Oct 12 22:35:54 2001 +++ linux-2.5/include/asm-alpha/pci.h Thu Dec 27 16:32:31 2001 @@ -101,6 +101,20 @@ extern void pci_unmap_single(struct pci_dev *, dma_addr_t, size_t, int); extern void pci_unmap_page(struct pci_dev *, dma_addr_t, size_t, int); +/* pci_unmap_{single,page} is not a nop, thus... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) + /* Map a set of buffers described by scatterlist in streaming mode for PCI DMA. This is the scather-gather version of the above pci_map_single interface. Here the scatter gather list elements diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-alpha/processor.h linux-2.5/include/asm-alpha/processor.h --- linux-2.5.1/include/asm-alpha/processor.h Fri Oct 5 19:11:05 2001 +++ linux-2.5/include/asm-alpha/processor.h Thu Dec 27 15:14:59 2001 @@ -30,7 +30,6 @@ * Bus types */ #define EISA_bus 1 -#define EISA_bus__is_a_macro /* for versions in ksyms.c */ #define MCA_bus 0 #define MCA_bus__is_a_macro /* for versions in ksyms.c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/adi_evb.h linux-2.5/include/asm-arm/arch-adifcc/adi_evb.h --- linux-2.5.1/include/asm-arm/arch-adifcc/adi_evb.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/adi_evb.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,19 @@ +/* + * linux/include/asm/arch-80200fcc/adi_evb.h + * + * ADI 80200FCC evaluation board definitions + * + * Author: Deepak Saxena <dsaxena@mvista.com> + * + * Copyright (C) 2001 MontaVista Software 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. + */ + +#define ADI_EVB__RAMBASE 0xa0000000 +#define ADI_EVB__UART 0x00400000 /* UART */ +#define ADI_EVB_7SEG_1 0x00500000 /* 7-Segment */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/dma.h linux-2.5/include/asm-arm/arch-adifcc/dma.h --- linux-2.5.1/include/asm-arm/arch-adifcc/dma.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/dma.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,18 @@ +/* + * linux/include/asm-arm/arch-80200fcc/dma.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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. + */ +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_ADDRESS 0xffffffff + +/* No DMA */ +#define MAX_DMA_CHANNELS 0 + +#endif /* _ASM_ARCH_DMA_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/hardware.h linux-2.5/include/asm-arm/arch-adifcc/hardware.h --- linux-2.5.1/include/asm-arm/arch-adifcc/hardware.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/hardware.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,27 @@ +/* + * linux/include/asm-arm/arch-adifcc/hardware.h + * + * Hardware definitions for ADI based systems + * + * Author: Deepak Saxena <dsaxena@mvista.com> + * + * Copyright (C) 2000-2001 MontaVista Software 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. + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include <linux/config.h> + +#define PCIO_BASE 0 + +#if defined(CONFIG_ARCH_ADI_EVB) +#include "adi_evb.h" +#endif + +#endif /* _ASM_ARCH_HARDWARE_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/io.h linux-2.5/include/asm-arm/arch-adifcc/io.h --- linux-2.5.1/include/asm-arm/arch-adifcc/io.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/io.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,22 @@ +/* + * linux/include/asm-arm/arch-adifcc/io.h + * + * Author: Deepak Saxena <dsaxena@mvista.com> + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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. + */ + +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) (PCIO_BASE + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/irq.h linux-2.5/include/asm-arm/arch-adifcc/irq.h --- linux-2.5.1/include/asm-arm/arch-adifcc/irq.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/irq.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,13 @@ +/* + * linux/include/asm-arm/arch-adifcc/irq.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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. + */ + +#define fixup_irq(irq) (irq) + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/irqs.h linux-2.5/include/asm-arm/arch-adifcc/irqs.h --- linux-2.5.1/include/asm-arm/arch-adifcc/irqs.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/irqs.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,28 @@ +/* + * linux/include/asm-arm/arch-80200fcc/irqs.h + * + * Author: Deepak Saxena <dsaxena@mvista.com> + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + */ + +#define IRQ_XS80200_BCU 0 /* Bus Control Unit */ +#define IRQ_XS80200_PMU 1 /* Performance Monitoring Unit */ +#define IRQ_XS80200_EXTIRQ 2 /* external IRQ signal */ +#define IRQ_XS80200_EXTFIQ 3 /* external IRQ signal */ + +#define NR_XS80200_IRQS 4 +#define NR_IRQS NR_XS80200_IRQS + +#define IRQ_XSCALE_PMU IRQ_XS80200_PMU + +#ifdef CONFIG_XSCALE_ADI_EVB + +/* Interrupts available on the ADI Eval Board */ + +#endif + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/memory.h linux-2.5/include/asm-arm/arch-adifcc/memory.h --- linux-2.5.1/include/asm-arm/arch-adifcc/memory.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/memory.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,57 @@ +/* + * linux/include/asm-arm/arch-adifcc/memory.h + * + * Copyright (c) 2001 MontaVista Software, Inc. + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + + +/* + * Task size: 3GB + */ +#define TASK_SIZE (0xc0000000UL) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +/* + * Page offset: 3GB + */ +#define PAGE_OFFSET (0xc0000000UL) + +/* + * Physical DRAM offset. + */ +#define PHYS_OFFSET (0xC0000000UL) + +/* + * physical vs virtual ram conversion + */ +#define __virt_to_phys__is_a_macro +#define __phys_to_virt__is_a_macro +#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) +#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + * + * These are dummies for now. + */ +#define __virt_to_bus__is_a_macro +#define __bus_to_virt__is_a_macro +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt(x) __phys_to_virt(x) + +#define PHYS_TO_NID(x) 0 + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/param.h linux-2.5/include/asm-arm/arch-adifcc/param.h --- linux-2.5.1/include/asm-arm/arch-adifcc/param.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/param.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,3 @@ +/* + * linux/include/asm-arm/arch-adifcc/param.h + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/serial.h linux-2.5/include/asm-arm/arch-adifcc/serial.h --- linux-2.5.1/include/asm-arm/arch-adifcc/serial.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/serial.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,36 @@ +/* + * include/asm-arm/arch-adifcc/serial.h + * + * Author: Deepak Saxena <dsaxena@mvista.com> + * + * Copyright (c) 2001 MontaVista Software, Inc. + */ + + +/* + * This assumes you have a 1.8432 MHz clock for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ +#define BASE_BAUD ( 1852000 / 16 ) + +/* Standard COM flags */ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#ifdef CONFIG_ARCH_ADI_EVB + +#define RS_TABLE_SIZE 1 + +/* + * One serial port, int goes to FIQ, so we run in polled mode + */ +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0xff400000, 0, STD_COM_FLAGS } /* ttyS0 */ + +#define EXTRA_SERIAL_PORT_DEFNS + +#endif + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/system.h linux-2.5/include/asm-arm/arch-adifcc/system.h --- linux-2.5.1/include/asm-arm/arch-adifcc/system.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/system.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/arch-adifcc/system.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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. + */ + +static inline void arch_idle(void) +{ +#if 0 + if (!hlt_counter) + cpu_do_idle(0); +#endif +} + + +static inline void arch_reset(char mode) +{ + if ( 1 && mode == 's') { + /* Jump into ROM at address 0 */ + cpu_reset(0); + } else { + /* Use on-chip reset capability */ + } +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/time.h linux-2.5/include/asm-arm/arch-adifcc/time.h --- linux-2.5.1/include/asm-arm/arch-adifcc/time.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/time.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,9 @@ +/* + * linux/include/asm-arm/arch-adifcc/time.h + * + */ + +/* + * No on board timer, implemenation @ arch/arm/kernel/xscale-time.c + */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/timex.h linux-2.5/include/asm-arm/arch-adifcc/timex.h --- linux-2.5.1/include/asm-arm/arch-adifcc/timex.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/timex.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,10 @@ +/* + * linux/include/asm-arm/arch-adifcc/timex.h + * + * XScale architecture timex specifications + */ + +/* This is for a timer based on the XS80200's PMU counter */ + +#define CLOCK_TICK_RATE 600000000 /* Underlying HZ */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/uncompress.h linux-2.5/include/asm-arm/arch-adifcc/uncompress.h --- linux-2.5.1/include/asm-arm/arch-adifcc/uncompress.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/uncompress.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,35 @@ +/* + * linux/include/asm-arm/arch-adifcc/uncompress.h + * + * Author: Deepak Saxena <dsaxena@mvista.com> + * + * Copyright (c) 2001 MontaVista Software, Inc. + * + */ + +#define UART_BASE ((volatile unsigned char *)0x00400000) + +static __inline__ void putc(char c) +{ + while ((UART_BASE[5] & 0x60) != 0x60); + UART_BASE[0] = c; +} + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + while (*s) { + putc(*s); + if (*s == '\n') + putc('\r'); + s++; + } +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-adifcc/vmalloc.h linux-2.5/include/asm-arm/arch-adifcc/vmalloc.h --- linux-2.5.1/include/asm-arm/arch-adifcc/vmalloc.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-adifcc/vmalloc.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,16 @@ +/* + * linux/include/asm-arm/arch-adifcc/vmalloc.h + */ + +/* + * 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. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (0xe8000000) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-anakin/io.h linux-2.5/include/asm-arm/arch-anakin/io.h --- linux-2.5.1/include/asm-arm/arch-anakin/io.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-anakin/io.h Sun Jan 6 01:38:27 2002 @@ -17,12 +17,7 @@ #define IO_SPACE_LIMIT 0xffffffff -#define __io(a) a -#define __arch_getw(a) (*(volatile unsigned short *) (a)) -#define __arch_putw(b, a) (*(volatile unsigned short *) (a) = (b)) - -#define iomem_valid_addr(i, s) 1 -#define iomem_to_phys(i) i +#define __io(a) (a) /* * We don't support ins[lb]/outs[lb]. Make them fault. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-anakin/time.h linux-2.5/include/asm-arm/arch-anakin/time.h --- linux-2.5.1/include/asm-arm/arch-anakin/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-anakin/time.h Sun Jan 6 01:38:27 2002 @@ -20,8 +20,7 @@ do_timer(regs); } -static inline void -setup_timer(void) +void __init time_init(void) { timer_irq.handler = anakin_timer_interrupt; timer_irq.flags = SA_INTERRUPT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-arc/io.h linux-2.5/include/asm-arm/arch-arc/io.h --- linux-2.5.1/include/asm-arm/arch-arc/io.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-arc/io.h Sun Jan 6 01:38:27 2002 @@ -249,4 +249,10 @@ /* the following macro is depreciated */ #define ioaddr(port) __ioaddr((port)) +/* + * No ioremap support here. + */ +#define __arch_ioremap(c,s,f) ((void *)(c)) +#define __arch_iounmap(c) do { } while (0) + #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-arc/irq.h linux-2.5/include/asm-arm/arch-arc/irq.h --- linux-2.5.1/include/asm-arm/arch-arc/irq.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/arch-arc/irq.h Sun Jan 6 01:38:27 2002 @@ -6,143 +6,5 @@ * 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: - * 24-09-1996 RMK Created - * 10-10-1996 RMK Brought up to date with arch-sa110eval - * 22-10-1996 RMK Changed interrupt numbers & uses new inb/outb macros - * 11-01-1998 RMK Added mask_and_ack_irq - * 22-08-1998 RMK Restructured IRQ routines */ -#include <linux/config.h> -#include <asm/hardware/ioc.h> -#include <asm/io.h> - -#ifdef CONFIG_ARCH_ARC -#define a_clf() clf() -#define a_stf() stf() -#else -#define a_clf() do { } while (0) -#define a_stf() do { } while (0) -#endif - #define fixup_irq(x) (x) - -static void arc_mask_irq_ack_a(unsigned int irq) -{ - unsigned int val, mask; - - mask = 1 << irq; - a_clf(); - 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 val, mask; - - mask = 1 << irq; - a_clf(); - val = ioc_readb(IOC_IRQMASKA); - ioc_writeb(val & ~mask, IOC_IRQMASKA); - a_stf(); -} - -static void arc_unmask_irq_a(unsigned int irq) -{ - unsigned int val, mask; - - mask = 1 << irq; - a_clf(); - val = ioc_readb(IOC_IRQMASKA); - ioc_writeb(val | mask, IOC_IRQMASKA); - a_stf(); -} - -static void arc_mask_irq_b(unsigned int irq) -{ - unsigned int val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - mask = 1 << (irq & 7); - val = ioc_readb(IOC_FIQMASK); - ioc_writeb(val | mask, IOC_FIQMASK); -} - -static __inline__ void irq_init_irq(void) -{ - int irq; - - ioc_writeb(0, IOC_IRQMASKA); - ioc_writeb(0, IOC_IRQMASKB); - ioc_writeb(0, IOC_FIQMASK); - - for (irq = 0; irq < NR_IRQS; irq++) { - switch (irq) { - case 0 ... 6: - irq_desc[irq].probe_ok = 1; - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = arc_mask_irq_ack_a; - irq_desc[irq].mask = arc_mask_irq_a; - irq_desc[irq].unmask = arc_unmask_irq_a; - break; - - case 7: - irq_desc[irq].noautoenable = 1; - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = arc_mask_irq_ack_a; - irq_desc[irq].mask = arc_mask_irq_a; - irq_desc[irq].unmask = arc_unmask_irq_a; - break; - - case 9 ... 15: - irq_desc[irq].probe_ok = 1; - case 8: - irq_desc[irq].valid = 1; - 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 64 ... 72: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = arc_mask_irq_fiq; - irq_desc[irq].mask = arc_mask_irq_fiq; - irq_desc[irq].unmask = arc_unmask_irq_fiq; - break; - } - } - - irq_desc[IRQ_KEYBOARDTX].noautoenable = 1; - - init_FIQ(); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-arc/time.h linux-2.5/include/asm-arm/arch-arc/time.h --- linux-2.5.1/include/asm-arm/arch-arc/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-arc/time.h Sun Jan 6 01:38:27 2002 @@ -24,7 +24,7 @@ /* * Set up timer interrupt. */ -static inline void setup_timer(void) +void __init time_init(void) { ioctime_init(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-cl7500/irq.h linux-2.5/include/asm-arm/arch-cl7500/irq.h --- linux-2.5.1/include/asm-arm/arch-cl7500/irq.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/arch-cl7500/irq.h Sun Jan 6 01:38:27 2002 @@ -30,198 +30,3 @@ return irq; } - -static void cl7500_mask_irq_ack_a(unsigned int irq) -{ - unsigned int val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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) -{ -} - -static struct irqaction irq_isa = { no_action, 0, 0, "isa", NULL, NULL }; - -static __inline__ void irq_init_irq(void) -{ - int irq; - - 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) { - case 0 ... 6: - irq_desc[irq].probe_ok = 1; - case 7: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = cl7500_mask_irq_ack_a; - irq_desc[irq].mask = cl7500_mask_irq_a; - irq_desc[irq].unmask = cl7500_unmask_irq_a; - break; - - case 9 ... 15: - irq_desc[irq].probe_ok = 1; - case 8: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = cl7500_mask_irq_b; - irq_desc[irq].mask = cl7500_mask_irq_b; - irq_desc[irq].unmask = cl7500_unmask_irq_b; - break; - - case 16 ... 22: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = cl7500_mask_irq_dma; - irq_desc[irq].mask = cl7500_mask_irq_dma; - irq_desc[irq].unmask = cl7500_unmask_irq_dma; - break; - - case 24 ... 31: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = cl7500_mask_irq_c; - irq_desc[irq].mask = cl7500_mask_irq_c; - irq_desc[irq].unmask = cl7500_unmask_irq_c; - break; - - 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 48 ... 55: - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = no_action; - irq_desc[irq].mask = no_action; - irq_desc[irq].unmask = no_action; - break; - - case 64 ... 72: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = cl7500_mask_irq_fiq; - irq_desc[irq].mask = cl7500_mask_irq_fiq; - irq_desc[irq].unmask = cl7500_unmask_irq_fiq; - break; - } - } - - setup_arm_irq(IRQ_ISA, &irq_isa); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-cl7500/keyboard.h linux-2.5/include/asm-arm/arch-cl7500/keyboard.h --- linux-2.5.1/include/asm-arm/arch-cl7500/keyboard.h Thu Oct 25 20:53:53 2001 +++ linux-2.5/include/asm-arm/arch-cl7500/keyboard.h Sun Jan 6 01:38:27 2002 @@ -6,6 +6,7 @@ * * Copyright (C) 1998-2001 Russell King */ +#include <asm/irq.h> #define NR_SCANCODES 128 extern int ps2kbd_init_hw(void); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-cl7500/time.h linux-2.5/include/asm-arm/arch-cl7500/time.h --- linux-2.5.1/include/asm-arm/arch-cl7500/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-cl7500/time.h Sun Jan 6 01:38:27 2002 @@ -9,6 +9,8 @@ * 04-Dec-1997 RMK Updated for new arch/arm/time.c */ +extern void ioctime_init(void); + static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { do_timer(regs); @@ -29,9 +31,8 @@ /* * Set up timer interrupt. */ -static inline void setup_timer(void) +void __init time_init(void) { - extern void ioctime_init(void); ioctime_init(); timer_irq.handler = timer_interrupt; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/autcpu12.h linux-2.5/include/asm-arm/arch-clps711x/autcpu12.h --- linux-2.5.1/include/asm-arm/arch-clps711x/autcpu12.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/autcpu12.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,78 @@ +/* + * AUTCPU12 specific defines + * + * (c) 2001 Thomas Gleixner, autronix automation <gleixner@autronix.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_AUTCPU12_H +#define __ASM_ARCH_AUTCPU12_H + +/* + * The CS8900A ethernet chip has its I/O registers wired to chip select 2 + * (nCS2). This is the mapping for it. + */ +#define AUTCPU12_PHYS_CS8900A CS2_PHYS_BASE /* physical */ +#define AUTCPU12_VIRT_CS8900A (0xfe000000) /* virtual */ + +/* + * The flash bank is wired to chip select 0 + */ +#define AUTCPU12_PHYS_FLASH CS0_PHYS_BASE /* physical */ + +/* offset for device specific information structure */ +#define AUTCPU12_LCDINFO_OFFS (0x00010000) +/* +* Videomemory is the internal SRAM (CS 6) +*/ +#define AUTCPU12_PHYS_VIDEO CS6_PHYS_BASE +#define AUTCPU12_VIRT_VIDEO (0xfd000000) + +/* +* All special IO's are tied to CS1 +*/ +#define AUTCPU12_PHYS_CHAR_LCD CS1_PHYS_BASE +0x00000000 /* physical */ + +#define AUTCPU12_PHYS_NVRAM CS1_PHYS_BASE +0x02000000 /* physical */ + +#define AUTCPU12_PHYS_CSAUX1 CS1_PHYS_BASE +0x04000000 /* physical */ + +#define AUTCPU12_PHYS_SMC CS1_PHYS_BASE +0x06000000 /* physical */ + +#define AUTCPU12_PHYS_CAN CS1_PHYS_BASE +0x08000000 /* physical */ + +#define AUTCPU12_PHYS_TOUCH CS1_PHYS_BASE +0x0A000000 /* physical */ + +#define AUTCPU12_PHYS_IO CS1_PHYS_BASE +0x0C000000 /* physical */ + +#define AUTCPU12_PHYS_LPT CS1_PHYS_BASE +0x0E000000 /* physical */ + +/* +* defines for smartmedia card access +*/ +#define AUTCPU12_SMC_RDY (1<<2) +#define AUTCPU12_SMC_ALE (1<<3) +#define AUTCPU12_SMC_CLE (1<<4) +#define AUTCPU12_SMC_PORT_OFFSET PBDR +#define AUTCPU12_SMC_SELECT_OFFSET 0x10 +/* +* defines for lcd contrast +*/ +#define AUTCPU12_DPOT_PORT_OFFSET PEDR +#define AUTCPU12_DPOT_CS (1<<0) +#define AUTCPU12_DPOT_CLK (1<<1) +#define AUTCPU12_DPOT_UD (1<<2) + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/dma.h linux-2.5/include/asm-arm/arch-clps711x/dma.h --- linux-2.5.1/include/asm-arm/arch-clps711x/dma.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/dma.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,28 @@ +/* + * linux/include/asm-arm/arch-clps711x/dma.h + * + * Copyright (C) 1997,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 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_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_ADDRESS 0xffffffff + +#define MAX_DMA_CHANNELS 0 + +#endif /* _ASM_ARCH_DMA_H */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/hardware.h linux-2.5/include/asm-arm/arch-clps711x/hardware.h --- linux-2.5.1/include/asm-arm/arch-clps711x/hardware.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/hardware.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,179 @@ +/* + * linux/include/asm-arm/arch-clps711x/hardware.h + * + * This file contains the hardware definitions of the Prospector P720T. + * + * 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_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include <linux/config.h> + +#define CLPS7111_VIRT_BASE 0xff000000 +#define CLPS7111_BASE CLPS7111_VIRT_BASE + +/* + * The physical addresses that the external chip select signals map to is + * dependent on the setting of the nMEDCHG signal on EP7211 and EP7212 + * processors. CONFIG_EP72XX_BOOT_ROM is only available if these + * processors are in use. + */ +#ifndef CONFIG_EP72XX_ROM_BOOT +#define CS0_PHYS_BASE (0x00000000) +#define CS1_PHYS_BASE (0x10000000) +#define CS2_PHYS_BASE (0x20000000) +#define CS3_PHYS_BASE (0x30000000) +#define CS4_PHYS_BASE (0x40000000) +#define CS5_PHYS_BASE (0x50000000) +#define CS6_PHYS_BASE (0x60000000) +#define CS7_PHYS_BASE (0x70000000) +#else +#define CS0_PHYS_BASE (0x70000000) +#define CS1_PHYS_BASE (0x60000000) +#define CS2_PHYS_BASE (0x50000000) +#define CS3_PHYS_BASE (0x40000000) +#define CS4_PHYS_BASE (0x30000000) +#define CS5_PHYS_BASE (0x20000000) +#define CS6_PHYS_BASE (0x10000000) +#define CS7_PHYS_BASE (0x00000000) +#endif + +#if defined (CONFIG_ARCH_EP7211) + +#define EP7211_VIRT_BASE CLPS7111_VIRT_BASE +#define EP7211_BASE CLPS7111_VIRT_BASE +#include <asm/hardware/ep7211.h> + +#elif defined (CONFIG_ARCH_EP7212) + +#define EP7212_VIRT_BASE CLPS7111_VIRT_BASE +#define EP7212_BASE CLPS7111_VIRT_BASE +#include <asm/hardware/ep7212.h> + + +#endif + +#define SYSPLD_VIRT_BASE 0xfe000000 +#define SYSPLD_BASE SYSPLD_VIRT_BASE + +#ifndef __ASSEMBLER__ + +#define PCIO_BASE IO_BASE + +#endif + + +#if defined (CONFIG_ARCH_AUTCPU12) + +#define CS89712_VIRT_BASE CLPS7111_VIRT_BASE +#define CS89712_BASE CLPS7111_VIRT_BASE + +#include <asm/hardware/clps7111.h> +#include <asm/hardware/ep7212.h> +#include <asm/hardware/cs89712.h> + +#endif + + +#if defined (CONFIG_ARCH_CDB89712) + +#include <asm/hardware/clps7111.h> +#include <asm/hardware/ep7212.h> +#include <asm/hardware/cs89712.h> + +/* dynamic ioremap() areas */ +#define FLASH_START 0x00000000 +#define FLASH_SIZE 0x800000 +#define FLASH_WIDTH 4 + +#define SRAM_START 0x60000000 +#define SRAM_SIZE 0xc000 +#define SRAM_WIDTH 4 + +#define BOOTROM_START 0x70000000 +#define BOOTROM_SIZE 0x80 +#define BOOTROM_WIDTH 4 + + +/* static cdb89712_map_io() areas */ +#define REGISTER_START 0x80000000 +#define REGISTER_SIZE 0x4000 +#define REGISTER_BASE 0xff000000 + +#define ETHER_START 0x20000000 +#define ETHER_SIZE 0x1000 +#define ETHER_BASE 0xfe000000 + +#endif + + +#if defined (CONFIG_ARCH_EDB7211) + +/* + * The extra 8 lines of the keyboard matrix are wired to chip select 3 (nCS3) + * and repeat across it. This is the mapping for it. + * + * In jumpered boot mode, nCS3 is mapped to 0x4000000, not 0x3000000. This + * was cause for much consternation and headscratching. This should probably + * be made a compile/run time kernel option. + */ +#define EP7211_PHYS_EXTKBD CS3_PHYS_BASE /* physical */ + +#define EP7211_VIRT_EXTKBD (0xfd000000) /* virtual */ + + +/* + * The CS8900A ethernet chip has its I/O registers wired to chip select 2 + * (nCS2). This is the mapping for it. + * + * In jumpered boot mode, nCS2 is mapped to 0x5000000, not 0x2000000. This + * was cause for much consternation and headscratching. This should probably + * be made a compile/run time kernel option. + */ +#define EP7211_PHYS_CS8900A CS2_PHYS_BASE /* physical */ + +#define EP7211_VIRT_CS8900A (0xfc000000) /* virtual */ + + +/* + * The two flash banks are wired to chip selects 0 and 1. This is the mapping + * for them. + * + * nCS0 and nCS1 are at 0x70000000 and 0x60000000, respectively, when running + * in jumpered boot mode. + */ +#define EP7211_PHYS_FLASH1 CS0_PHYS_BASE /* physical */ +#define EP7211_PHYS_FLASH2 CS1_PHYS_BASE /* physical */ + +#define EP7211_VIRT_FLASH1 (0xfa000000) /* virtual */ +#define EP7211_VIRT_FLASH2 (0xfb000000) /* virtual */ + +#endif /* CONFIG_ARCH_EDB7211 */ + + +/* + * Relevant bits in port D, which controls power to the various parts of + * the LCD on the EDB7211. + */ +#define EDB_PD1_LCD_DC_DC_EN (1<<1) +#define EDB_PD2_LCDEN (1<<2) +#define EDB_PD3_LCDBL (1<<3) + + +#endif + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/io.h linux-2.5/include/asm-arm/arch-clps711x/io.h --- linux-2.5.1/include/asm-arm/arch-clps711x/io.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/io.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,37 @@ +/* + * linux/include/asm-arm/arch-clps711x/io.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) ((a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +/* + * We don't support ins[lb]/outs[lb]. Make them fault. + */ +#define __raw_readsb(p,d,l) do { *(int *)0 = 0; } while (0) +#define __raw_readsl(p,d,l) do { *(int *)0 = 0; } while (0) +#define __raw_writesb(p,d,l) do { *(int *)0 = 0; } while (0) +#define __raw_writesl(p,d,l) do { *(int *)0 = 0; } while (0) + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/irq.h linux-2.5/include/asm-arm/arch-clps711x/irq.h --- linux-2.5.1/include/asm-arm/arch-clps711x/irq.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/irq.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,20 @@ +/* + * linux/include/asm-arm/arch-clps711x/irq.h + * + * 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 + */ +#define fixup_irq(i) (i) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/irqs.h linux-2.5/include/asm-arm/arch-clps711x/irqs.h --- linux-2.5.1/include/asm-arm/arch-clps711x/irqs.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/irqs.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,53 @@ +/* + * linux/include/asm-arm/arch-clps711x/irqs.h + * + * 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 + */ + +/* + * Interrupts from INTSR1 + */ +#define IRQ_CSINT 4 +#define IRQ_EINT1 5 +#define IRQ_EINT2 6 +#define IRQ_EINT3 7 +#define IRQ_TC1OI 8 +#define IRQ_TC2OI 9 +#define IRQ_RTCMI 10 +#define IRQ_TINT 11 +#define IRQ_UTXINT1 12 +#define IRQ_URXINT1 13 +#define IRQ_UMSINT 14 +#define IRQ_SSEOTI 15 + +#define INT1_IRQS (0x0000fff0) +#define INT1_ACK_IRQS (0x00004f10) + +/* + * Interrupts from INTSR2 + */ +#define IRQ_KBDINT (16+0) /* bit 0 */ +#define IRQ_SS2RX (16+1) /* bit 1 */ +#define IRQ_SS2TX (16+2) /* bit 2 */ +#define IRQ_UTXINT2 (16+12) /* bit 12 */ +#define IRQ_URXINT2 (16+13) /* bit 13 */ + +#define INT2_IRQS (0x30070000) +#define INT2_ACK_IRQS (0x00010000) + +#define NR_IRQS 30 + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/keyboard.h linux-2.5/include/asm-arm/arch-clps711x/keyboard.h --- linux-2.5.1/include/asm-arm/arch-clps711x/keyboard.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/keyboard.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,26 @@ +/* + * linux/include/asm-arm/arch-clps711x/keyboard.h + * + * Copyright (C) 1998-2001 Russell King + */ +#include <asm/mach-types.h> + +#define NR_SCANCODES 128 + +#define kbd_disable_irq() do { } while (0) +#define kbd_enable_irq() do { } while (0) + +/* + * EDB7211 keyboard driver + */ +extern void edb7211_kbd_init_hw(void); +extern void clps711x_kbd_init_hw(void); + +static inline void kbd_init_hw(void) +{ + if (machine_is_edb7211()) + edb7211_kbd_init_hw(); + + if (machine_is_autcpu12()) + clps711x_kbd_init_hw(); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/memory.h linux-2.5/include/asm-arm/arch-clps711x/memory.h --- linux-2.5.1/include/asm-arm/arch-clps711x/memory.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/memory.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,204 @@ +/* + * linux/include/asm-arm/arch-clps711x/mmu.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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_ARCH_MMU_H +#define __ASM_ARCH_MMU_H + +/* + * Task size: 3GB + */ +#define TASK_SIZE (0xc0000000UL) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +/* + * Page offset: 3GB + */ +#define PAGE_OFFSET (0xc0000000UL) +#define PHYS_OFFSET (0xc0000000UL) + +/* + * On integrator, the dram is contiguous + */ +#define __virt_to_phys__is_a_macro +#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + PHYS_OFFSET) +#define __phys_to_virt__is_a_macro +#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - PHYS_OFFSET) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + */ + +#if defined(CONFIG_ARCH_CDB89712) + +#define __virt_to_bus__is_a_macro +#define __virt_to_bus(x) (x) +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(x) (x) + +#elif defined (CONFIG_ARCH_AUTCPU12) + +#define __virt_to_bus__is_a_macro +#define __virt_to_bus(x) (x) +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(x) (x) + +#else + +#define __virt_to_bus__is_a_macro +#define __virt_to_bus(x) ((x) - PAGE_OFFSET) +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(x) ((x) + PAGE_OFFSET) + +#endif + + +/* + * Like the SA1100, the EDB7211 has a large gap between physical RAM + * banks. In 2.2, the Psion (CL-PS7110) port added custom support for + * discontiguous physical memory. In 2.4, we can use the standard + * Linux NUMA support. + * + * This is not necessary for EP7211 implementations with only one used + * memory bank. For those systems, simply undefine CONFIG_DISCONTIGMEM. + */ + +#ifdef CONFIG_ARCH_EDB7211 + +#ifdef CONFIG_DISCONTIGMEM +/* + * Because of the wide memory address space between physical RAM banks on the + * SA1100, it's much more convenient to use Linux's NUMA support to implement + * our memory map representation. Assuming all memory nodes have equal access + * characteristics, we then have generic discontigous memory support. + * + * Of course, all this isn't mandatory for SA1100 implementations with only + * one used memory bank. For those, simply undefine CONFIG_DISCONTIGMEM. + * + * The nodes are matched with the physical memory bank addresses which are + * incidentally the same as virtual addresses. + * + * node 0: 0xc0000000 - 0xc7ffffff + * node 1: 0xc8000000 - 0xcfffffff + * node 2: 0xd0000000 - 0xd7ffffff + * node 3: 0xd8000000 - 0xdfffffff + */ + +#define NR_NODES 4 + +/* + * Given a kernel address, find the home node of the underlying memory. + */ +#define KVADDR_TO_NID(addr) \ + (((unsigned long)(addr) - PAGE_OFFSET) >> NODE_MAX_MEM_SHIFT) + +/* + * Given a physical address, convert it to a node id. + */ +#define PHYS_TO_NID(addr) KVADDR_TO_NID(__phys_to_virt(addr)) + +/* + * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory + * and returns the mem_map of that node. + */ +#define ADDR_TO_MAPBASE(kaddr) \ + NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr))) + +/* + * Given a kaddr, LOCAL_MAR_NR finds the owning node of the memory + * and returns the index corresponding to the appropriate page in the + * node's mem_map. + */ +#define LOCAL_MAP_NR(kaddr) \ + (((unsigned long)(kaddr)-LOCAL_BASE_ADDR((kaddr))) >> PAGE_SHIFT) + +/* + * Given a kaddr, virt_to_page returns a pointer to the corresponding + * mem_map entry. + */ +#define virt_to_page(kaddr) \ + (ADDR_TO_MAPBASE(kaddr) + LOCAL_MAP_NR(kaddr)) + +/* + * VALID_PAGE returns a non-zero value if given page pointer is valid. + * This assumes all node's mem_maps are stored within the node they refer to. + */ +#define VALID_PAGE(page) \ +({ unsigned int node = KVADDR_TO_NID(page); \ + ( (node < NR_NODES) && \ + ((unsigned)((page) - NODE_MEM_MAP(node)) < NODE_DATA(node)->node_size) ); \ +}) + +/* + * The PS7211 allows up to 256MB max per DRAM bank, but the EDB7211 + * uses only one of the two banks (bank #1). However, even within + * bank #1, memory is discontiguous. + * + * The EDB7211 has two 8MB DRAM areas with 8MB of empty space between + * them, so we use 24 for the node max shift to get 16MB node sizes. + */ +#define NODE_MAX_MEM_SHIFT 24 +#define NODE_MAX_MEM_SIZE (1<<NODE_MAX_MEM_SHIFT) + +/* + * Given a mem_map_t, LOCAL_MAP_BASE finds the owning node for the + * physical page and returns the kaddr for the mem_map of that node. + */ +#define LOCAL_MAP_BASE(page) \ + NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(page))) + +/* + * Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory + * and returns the kaddr corresponding to first physical page in the + * node's mem_map. + */ +#define LOCAL_BASE_ADDR(kaddr) ((unsigned long)(kaddr) & ~(NODE_MAX_MEM_SIZE-1)) + +/* + * With discontigmem, the conceptual mem_map array starts from PAGE_OFFSET. + * Given a kaddr, MAP_NR returns the appropriate global mem_map index so + * it matches the corresponding node's local mem_map. + */ +#define MAP_NR(kaddr) (LOCAL_MAP_NR((kaddr)) + \ + (((unsigned long)ADDR_TO_MAPBASE((kaddr)) - PAGE_OFFSET) / \ + sizeof(mem_map_t))) + +#else + +#define PHYS_TO_NID(addr) (0) + +#endif /* CONFIG_DISCONTIGMEM */ + +#endif /* CONFIG_ARCH_EDB7211 */ + +#ifndef PHYS_TO_NID +#define PHYS_TO_NID(addr) (0) +#endif + +#endif + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/param.h linux-2.5/include/asm-arm/arch-clps711x/param.h --- linux-2.5.1/include/asm-arm/arch-clps711x/param.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/param.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,21 @@ +/* + * linux/include/asm-arm/arch-clps711x/param.h + * + * 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 + */ + +#define HZ 100 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/syspld.h linux-2.5/include/asm-arm/arch-clps711x/syspld.h --- linux-2.5.1/include/asm-arm/arch-clps711x/syspld.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/syspld.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,121 @@ +/* + * linux/include/asm-arm/arch-clps711x/syspld.h + * + * System Control PLD register definitions. + * + * 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_ARCH_SYSPLD_H +#define __ASM_ARCH_SYSPLD_H + +#define SYSPLD_PHYS_BASE (0x10000000) + +#ifndef __ASSEMBLY__ +#include <asm/types.h> + +#define SYSPLD_REG(type,off) (*(volatile type *)(SYSPLD_BASE + off)) +#else +#define SYSPLD_REG(type,off) (off) +#endif + +#define PLD_INT SYSPLD_REG(u32, 0x000000) +#define PLD_INT_PENIRQ (1 << 5) +#define PLD_INT_UCB_IRQ (1 << 1) +#define PLD_INT_KBD_ATN (1 << 0) /* EINT1 */ + +#define PLD_PWR SYSPLD_REG(u32, 0x000004) +#define PLD_PWR_EXT (1 << 5) +#define PLD_PWR_MODE (1 << 4) /* 1 = PWM, 0 = PFM */ +#define PLD_S4_ON (1 << 3) /* LCD bias voltage enable */ +#define PLD_S3_ON (1 << 2) /* LCD backlight enable */ +#define PLD_S2_ON (1 << 1) /* LCD 3V3 supply enable */ +#define PLD_S1_ON (1 << 0) /* LCD 3V supply enable */ + +#define PLD_KBD SYSPLD_REG(u32, 0x000008) +#define PLD_KBD_WAKE (1 << 1) +#define PLD_KBD_EN (1 << 0) + +#define PLD_SPI SYSPLD_REG(u32, 0x00000c) +#define PLD_SPI_EN (1 << 0) + +#define PLD_IO SYSPLD_REG(u32, 0x000010) +#define PLD_IO_BOOTSEL (1 << 6) /* boot sel switch */ +#define PLD_IO_USER (1 << 5) /* user defined switch */ +#define PLD_IO_LED3 (1 << 4) +#define PLD_IO_LED2 (1 << 3) +#define PLD_IO_LED1 (1 << 2) +#define PLD_IO_LED0 (1 << 1) +#define PLD_IO_LEDEN (1 << 0) + +#define PLD_IRDA SYSPLD_REG(u32, 0x000014) +#define PLD_IRDA_EN (1 << 0) + +#define PLD_COM2 SYSPLD_REG(u32, 0x000018) +#define PLD_COM2_EN (1 << 0) + +#define PLD_COM1 SYSPLD_REG(u32, 0x00001c) +#define PLD_COM1_EN (1 << 0) + +#define PLD_AUD SYSPLD_REG(u32, 0x000020) +#define PLD_AUD_DIV1 (1 << 6) +#define PLD_AUD_DIV0 (1 << 5) +#define PLD_AUD_CLK_SEL1 (1 << 4) +#define PLD_AUD_CLK_SEL0 (1 << 3) +#define PLD_AUD_MIC_PWR (1 << 2) +#define PLD_AUD_MIC_GAIN (1 << 1) +#define PLD_AUD_CODEC_EN (1 << 0) + +#define PLD_CF SYSPLD_REG(u32, 0x000024) +#define PLD_CF2_SLEEP (1 << 5) +#define PLD_CF1_SLEEP (1 << 4) +#define PLD_CF2_nPDREQ (1 << 3) +#define PLD_CF1_nPDREQ (1 << 2) +#define PLD_CF2_nIRQ (1 << 1) +#define PLD_CF1_nIRQ (1 << 0) + +#define PLD_SDC SYSPLD_REG(u32, 0x000028) +#define PLD_SDC_INT_EN (1 << 2) +#define PLD_SDC_WP (1 << 1) +#define PLD_SDC_CD (1 << 0) + +#define PLD_FPGA SYSPLD_REG(u32, 0x00002c) + +#define PLD_CODEC SYSPLD_REG(u32, 0x400000) +#define PLD_CODEC_IRQ3 (1 << 4) +#define PLD_CODEC_IRQ2 (1 << 3) +#define PLD_CODEC_IRQ1 (1 << 2) +#define PLD_CODEC_EN (1 << 0) + +#define PLD_BRITE SYSPLD_REG(u32, 0x400004) +#define PLD_BRITE_UP (1 << 1) +#define PLD_BRITE_DN (1 << 0) + +#define PLD_LCDEN SYSPLD_REG(u32, 0x400008) +#define PLD_LCDEN_EN (1 << 0) + +#define PLD_ID SYSPLD_REG(u32, 0x40000c) + +#define PLD_TCH SYSPLD_REG(u32, 0x400010) +#define PLD_TCH_PENIRQ (1 << 1) +#define PLD_TCH_EN (1 << 0) + +#define PLD_GPIO SYSPLD_REG(u32, 0x400014) +#define PLD_GPIO2 (1 << 2) +#define PLD_GPIO1 (1 << 1) +#define PLD_GPIO0 (1 << 0) + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/system.h linux-2.5/include/asm-arm/arch-clps711x/system.h --- linux-2.5.1/include/asm-arm/arch-clps711x/system.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/system.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,38 @@ +/* + * linux/include/asm-arm/arch-clps711x/system.h + * + * 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_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include <asm/hardware/clps7111.h> + +static void arch_idle(void) +{ + clps_writel(1, HALT); + __asm__ __volatile__( + "mov r0, r0 + mov r0, r0"); +} + +static inline void arch_reset(char mode) +{ + cpu_reset(0); +} + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/time.h linux-2.5/include/asm-arm/arch-clps711x/time.h --- linux-2.5.1/include/asm-arm/arch-clps711x/time.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/time.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,43 @@ +/* + * linux/include/asm-arm/arch-clps711x/time.h + * + * 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 + */ +#include <asm/leds.h> +#include <asm/hardware/clps7111.h> + +extern void clps711x_setup_timer(void); + +/* + * IRQ handler for the timer + */ +static void p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_leds(); + do_timer(regs); + do_profile(regs); +} + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +void __init time_init(void) +{ + clps711x_setup_timer(); + timer_irq.handler = p720t_timer_interrupt; + setup_arm_irq(IRQ_TC2OI, &timer_irq); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/timex.h linux-2.5/include/asm-arm/arch-clps711x/timex.h --- linux-2.5.1/include/asm-arm/arch-clps711x/timex.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/timex.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,23 @@ +/* + * linux/include/asm-arm/arch-clps711x/timex.h + * + * Prospector 720T architecture timex specifications + * + * 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 + */ + +#define CLOCK_TICK_RATE 512000 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/uncompress.h linux-2.5/include/asm-arm/arch-clps711x/uncompress.h --- linux-2.5.1/include/asm-arm/arch-clps711x/uncompress.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/uncompress.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,67 @@ +/* + * linux/include/asm-arm/arch-clps711x/uncompress.h + * + * 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 + */ +#include <linux/config.h> +#include <asm/arch/io.h> +#include <asm/arch/hardware.h> +#include <asm/hardware/clps7111.h> + +#undef CLPS7111_BASE +#define CLPS7111_BASE CLPS7111_PHYS_BASE + +#define barrier() __asm__ __volatile__("": : :"memory") +#define __raw_readl(p) (*(unsigned long *)(p)) +#define __raw_writel(v,p) (*(unsigned long *)(p) = (v)) + +#ifdef CONFIG_DEBUG_CLPS711X_UART2 +#define SYSFLGx SYSFLG2 +#define UARTDRx UARTDR2 +#else +#define SYSFLGx SYSFLG1 +#define UARTDRx UARTDR1 +#endif + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + char c; + + while ((c = *s++) != '\0') { + while (clps_readl(SYSFLGx) & SYSFLG_UTXFF) + barrier(); + clps_writel(c, UARTDRx); + + if (c == '\n') { + while (clps_readl(SYSFLGx) & SYSFLG_UTXFF) + barrier(); + clps_writel('\r', UARTDRx); + } + } + while (clps_readl(SYSFLGx) & SYSFLG_UBUSY) + barrier(); +} + +/* + * nothing to do + */ +#define arch_decomp_setup() + +#define arch_decomp_wdog() diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-clps711x/vmalloc.h linux-2.5/include/asm-arm/arch-clps711x/vmalloc.h --- linux-2.5.1/include/asm-arm/arch-clps711x/vmalloc.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-clps711x/vmalloc.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,32 @@ +/* + * linux/include/asm-arm/arch-clps711x/vmalloc.h + * + * 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 + */ + +/* + * 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. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-ebsa110/io.h linux-2.5/include/asm-arm/arch-ebsa110/io.h --- linux-2.5.1/include/asm-arm/arch-ebsa110/io.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/arch-ebsa110/io.h Sun Jan 6 01:38:27 2002 @@ -15,12 +15,6 @@ #define IO_SPACE_LIMIT 0xffff -/* - * Generic virtual read/write - */ -#define __arch_getw(a) (*(volatile unsigned short *)(a)) -#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) - u8 __inb(int port); u16 __inw(int port); u32 __inl(int port); @@ -53,7 +47,7 @@ #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) +#define __arch_ioremap(cookie,sz,c) ((void *)(cookie)) +#define __arch_iounmap(cookie) do { } while (0) #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-ebsa110/time.h linux-2.5/include/asm-arm/arch-ebsa110/time.h --- linux-2.5.1/include/asm-arm/arch-ebsa110/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-ebsa110/time.h Sun Jan 6 01:38:27 2002 @@ -33,7 +33,7 @@ /* * Set up timer interrupt. */ -static inline void setup_timer(void) +void __init time_init(void) { ebsa110_setup_timer(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-ebsa110/vmalloc.h linux-2.5/include/asm-arm/arch-ebsa110/vmalloc.h --- linux-2.5.1/include/asm-arm/arch-ebsa110/vmalloc.h Mon Sep 18 22:15:23 2000 +++ linux-2.5/include/asm-arm/arch-ebsa110/vmalloc.h Sun Jan 6 01:38:27 2002 @@ -19,4 +19,4 @@ #define VMALLOC_OFFSET (8*1024*1024) #define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END (PAGE_OFFSET + 0x10000000) +#define VMALLOC_END (PAGE_OFFSET + 0x1f000000) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-ebsa285/io.h linux-2.5/include/asm-arm/arch-ebsa285/io.h --- linux-2.5.1/include/asm-arm/arch-ebsa285/io.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-ebsa285/io.h Sun Jan 6 01:38:27 2002 @@ -42,13 +42,4 @@ #define __mem_isa(a) ___mem_isa((unsigned long)(a)) #endif -/* - * Generic virtual read/write - */ -#define __arch_getw(a) (*(volatile unsigned short *)(a)) -#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) - -#define iomem_valid_addr(iomem,sz) (1) -#define iomem_to_phys(iomem) (iomem) - #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-ebsa285/time.h linux-2.5/include/asm-arm/arch-ebsa285/time.h --- linux-2.5.1/include/asm-arm/arch-ebsa285/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-ebsa285/time.h Sun Jan 6 01:38:27 2002 @@ -199,7 +199,7 @@ /* * Set up timer interrupt. */ -static inline void setup_timer(void) +void __init time_init(void) { int irq; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-ebsa285/vmalloc.h linux-2.5/include/asm-arm/arch-ebsa285/vmalloc.h --- linux-2.5.1/include/asm-arm/arch-ebsa285/vmalloc.h Mon Sep 18 22:15:23 2000 +++ linux-2.5/include/asm-arm/arch-ebsa285/vmalloc.h Sun Jan 6 01:38:27 2002 @@ -6,6 +6,8 @@ * published by the Free Software Foundation. */ +#include <linux/config.h> + /* * 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 @@ -17,4 +19,9 @@ #define VMALLOC_OFFSET (8*1024*1024) #define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) + +#ifdef CONFIG_ARCH_FOOTBRIDGE +#define VMALLOC_END (PAGE_OFFSET + 0x30000000) +#else #define VMALLOC_END (PAGE_OFFSET + 0x20000000) +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-epxa10db/ether00.h linux-2.5/include/asm-arm/arch-epxa10db/ether00.h --- linux-2.5.1/include/asm-arm/arch-epxa10db/ether00.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-epxa10db/ether00.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,482 @@ +#ifndef __ETHER00_H +#define __ETHER00_H + + + +/* + * Register definitions for the Ethernet MAC + */ + +/* + * Copyright (c) Altera Corporation 2000. + * All rights reserved. + */ + +/* +* Structures for the DMA controller +*/ +typedef struct fda_desc + { + struct fda_desc * FDNext; + long FDSystem; + long FDStat; + short FDLength; + short FDCtl; + }FDA_DESC; + +typedef struct buf_desc + { + char * BuffData; + short BuffLength; + char BDStat; + char BDCtl; + }BUF_DESC; + +/* +* Control masks for the DMA controller +*/ +#define FDCTL_BDCOUNT_MSK (0x1F) +#define FDCTL_BDCOUNT_OFST (0) +#define FDCTL_FRMOPT_MSK (0x7C00) +#define FDCTL_FRMOPT_OFST (10) +#define FDCTL_COWNSFD_MSK (0x8000) +#define FDCTL_COWNSFD_OFST (15) + +#define BDCTL_RXBDSEQN_MSK (0x7F) +#define BDCTL_RXBDSEQN_OFST (0) +#define BDCTL_COWNSBD_MSK (0x80) +#define BDCTL_COWNSBD_OFST (7) + +#define FDNEXT_EOL_MSK (0x1) +#define FDNEXT_EOL_OFST (0) +#define FDNEXT_EOL_POINTER_MSK (0xFFFFFFF0) +#define FDNEXT_EOL_POINTER_OFST (4) + +#define ETHER_ARC_SIZE (21) + +/* +* Regsiter definitions and masks +*/ +#define ETHER_DMA_CTL(base) (ETHER00_TYPE (base + 0x100)) +#define ETHER_DMA_CTL_DMBURST_OFST (2) +#define ETHER_DMA_CTL_DMBURST_MSK (0x1FC) +#define ETHER_DMA_CTL_POWRMGMNT_OFST (11) +#define ETHER_DMA_CTL_POWRMGMNT_MSK (0x1000) +#define ETHER_DMA_CTL_TXBIGE_OFST (14) +#define ETHER_DMA_CTL_TXBIGE_MSK (0x4000) +#define ETHER_DMA_CTL_RXBIGE_OFST (15) +#define ETHER_DMA_CTL_RXBIGE_MSK (0x8000) +#define ETHER_DMA_CTL_TXWAKEUP_OFST (16) +#define ETHER_DMA_CTL_TXWAKEUP_MSK (0x10000) +#define ETHER_DMA_CTL_SWINTREQ_OFST (17) +#define ETHER_DMA_CTL_SWINTREQ_MSK (0x20000) +#define ETHER_DMA_CTL_INTMASK_OFST (18) +#define ETHER_DMA_CTL_INTMASK_MSK (0x40000) +#define ETHER_DMA_CTL_M66ENSTAT_OFST (19) +#define ETHER_DMA_CTL_M66ENSTAT_MSK (0x80000) +#define ETHER_DMA_CTL_RMTXINIT_OFST (20) +#define ETHER_DMA_CTL_RMTXINIT_MSK (0x100000) +#define ETHER_DMA_CTL_RMRXINIT_OFST (21) +#define ETHER_DMA_CTL_RMRXINIT_MSK (0x200000) +#define ETHER_DMA_CTL_RXALIGN_OFST (22) +#define ETHER_DMA_CTL_RXALIGN_MSK (0xC00000) +#define ETHER_DMA_CTL_RMSWRQ_OFST (24) +#define ETHER_DMA_CTL_RMSWRQ_MSK (0x1000000) +#define ETHER_DMA_CTL_RMEMBANK_OFST (25) +#define ETHER_DMA_CTL_RMEMBANK_MSK (0x2000000) + +#define ETHER_TXFRMPTR(base) (ETHER00_TYPE (base + 0x104)) + +#define ETHER_TXTHRSH(base) (ETHER00_TYPE (base + 0x308)) + +#define ETHER_TXPOLLCTR(base) (ETHER00_TYPE (base + 0x30c)) + +#define ETHER_BLFRMPTR(base) (ETHER00_TYPE (base + 0x110)) +#define ETHER_BLFFRMPTR_EOL_OFST (0) +#define ETHER_BLFFRMPTR_EOL_MSK (0x1) +#define ETHER_BLFFRMPTR_ADDRESS_OFST (4) +#define ETHER_BLFFRMPTR_ADDRESS_MSK (0xFFFFFFF0) + +#define ETHER_RXFRAGSIZE(base) (ETHER00_TYPE (base + 0x114)) +#define ETHER_RXFRAGSIZE_MINFRAG_OFST (2) +#define ETHER_RXFRAGSIZE_MINFRAG_MSK (0xFFC) +#define ETHER_RXFRAGSIZE_ENPACK_OFST (15) +#define ETHER_RXFRAGSIZE_ENPACK_MSK (0x8000) + +#define ETHER_INT_EN(base) (ETHER00_TYPE (base + 0x118)) +#define ETHER_INT_EN_FDAEXEN_OFST (0) +#define ETHER_INT_EN_FDAEXEN_MSK (0x1) +#define ETHER_INT_EN_BLEXEN_OFST (1) +#define ETHER_INT_EN_BLEXN_MSK (0x2) +#define ETHER_INT_EN_STARGABTEN_OFST (2) +#define ETHER_INT_EN_STARGABTEN_MSK (0x4) +#define ETHER_INT_EN_RTARGABTEN_OFST (3) +#define ETHER_INT_EN_RTARGABTEN_MSK (0x8) +#define ETHER_INT_EN_RMASABTEN_OFST (4) +#define ETHER_INT_EN_RMASABTEN_MSK (0x10) +#define ETHER_INT_EN_SSYSERREN_OFST (5) +#define ETHER_INT_EN_SSYSERREN_MSK (0x20) +#define ETHER_INT_EN_DPARERREN_OFST (6) +#define ETHER_INT_EN_DPARERREN_MSK (0x40) +#define ETHER_INT_EN_EARNOTEN_OFST (7) +#define ETHER_INT_EN_EARNOTEN_MSK (0x80) +#define ETHER_INT_EN_DPARDEN_OFST (8) +#define ETHER_INT_EN_DPARDEN_MSK (0x100) +#define ETHER_INT_EN_DMPARERREN_OFST (9) +#define ETHER_INT_EN_DMPARERREN_MSK (0x200) +#define ETHER_INT_EN_TXCTLCMPEN_OFST (10) +#define ETHER_INT_EN_TXCTLCMPEN_MSK (0x400) +#define ETHER_INT_EN_NRABTEN_OFST (11) +#define ETHER_INT_EN_NRABTEN_MSK (0x800) + +#define ETHER_FDA_BAS(base) (ETHER00_TYPE (base + 0x11C)) +#define ETHER_FDA_BAS_ADDRESS_OFST (4) +#define ETHER_FDA_BAS_ADDRESS_MSK (0xFFFFFFF0) + +#define ETHER_FDA_LIM(base) (ETHER00_TYPE (base + 0x120)) +#define ETHER_FDA_LIM_COUNT_OFST (4) +#define ETHER_FDA_LIM_COUNT_MSK (0xFFF0) + +#define ETHER_INT_SRC(base) (ETHER00_TYPE (base + 0x124)) +#define ETHER_INT_SRC_INTMACTX_OFST (0) +#define ETHER_INT_SRC_INTMACTX_MSK (0x1) +#define ETHER_INT_SRC_INTMACRX_OFST (1) +#define ETHER_INT_SRC_INTMACRX_MSK (0x2) +#define ETHER_INT_SRC_INTSBUS_OFST (2) +#define ETHER_INT_SRC_INTSBUS_MSK (0x4) +#define ETHER_INT_SRC_INTFDAEX_OFST (3) +#define ETHER_INT_SRC_INTFDAEX_MSK (0x8) +#define ETHER_INT_SRC_INTBLEX_OFST (4) +#define ETHER_INT_SRC_INTBLEX_MSK (0x10) +#define ETHER_INT_SRC_SWINT_OFST (5) +#define ETHER_INT_SRC_SWINT_MSK (0x20) +#define ETHER_INT_SRC_INTEARNOT_OFST (6) +#define ETHER_INT_SRC_INTEARNOT_MSK (0x40) +#define ETHER_INT_SRC_DMPARERR_OFST (7) +#define ETHER_INT_SRC_DMPARERR_MSK (0x80) +#define ETHER_INT_SRC_INTEXBD_OFST (8) +#define ETHER_INT_SRC_INTEXBD_MSK (0x100) +#define ETHER_INT_SRC_INTTXCTLCMP_OFST (9) +#define ETHER_INT_SRC_INTTXCTLCMP_MSK (0x200) +#define ETHER_INT_SRC_INTNRABT_OFST (10) +#define ETHER_INT_SRC_INTNRABT_MSK (0x400) +#define ETHER_INT_SRC_FDAEX_OFST (11) +#define ETHER_INT_SRC_FDAEX_MSK (0x800) +#define ETHER_INT_SRC_BLEX_OFST (12) +#define ETHER_INT_SRC_BLEX_MSK (0x1000) +#define ETHER_INT_SRC_DMPARERRSTAT_OFST (13) +#define ETHER_INT_SRC_DMPARERRSTAT_MSK (0x2000) +#define ETHER_INT_SRC_NRABT_OFST (14) +#define ETHER_INT_SRC_NRABT_MSK (0x4000) +#define ETHER_INT_SRC_INTLINK_OFST (15) +#define ETHER_INT_SRC_INTLINK_MSK (0x8000) +#define ETHER_INT_SRC_INTEXDEFER_OFST (16) +#define ETHER_INT_SRC_INTEXDEFER_MSK (0x10000) +#define ETHER_INT_SRC_INTRMON_OFST (17) +#define ETHER_INT_SRC_INTRMON_MSK (0x20000) +#define ETHER_INT_SRC_IRQ_MSK (0x83FF) + +#define ETHER_PAUSECNT(base) (ETHER00_TYPE (base + 0x40)) +#define ETHER_PAUSECNT_COUNT_OFST (0) +#define ETHER_PAUSECNT_COUNT_MSK (0xFFFF) + +#define ETHER_REMPAUCNT(base) (ETHER00_TYPE (base + 0x44)) +#define ETHER_REMPAUCNT_COUNT_OFST (0) +#define ETHER_REMPAUCNT_COUNT_MSK (0xFFFF) + +#define ETHER_TXCONFRMSTAT(base) (ETHER00_TYPE (base + 0x348)) +#define ETHER_TXCONFRMSTAT_TS_STAT_VALUE_OFST (0) +#define ETHER_TXCONFRMSTAT_TS_STAT_VALUE_MSK (0x3FFFFF) + +#define ETHER_MAC_CTL(base) (ETHER00_TYPE (base + 0)) +#define ETHER_MAC_CTL_HALTREQ_OFST (0) +#define ETHER_MAC_CTL_HALTREQ_MSK (0x1) +#define ETHER_MAC_CTL_HALTIMM_OFST (1) +#define ETHER_MAC_CTL_HALTIMM_MSK (0x2) +#define ETHER_MAC_CTL_RESET_OFST (2) +#define ETHER_MAC_CTL_RESET_MSK (0x4) +#define ETHER_MAC_CTL_FULLDUP_OFST (3) +#define ETHER_MAC_CTL_FULLDUP_MSK (0x8) +#define ETHER_MAC_CTL_MACLOOP_OFST (4) +#define ETHER_MAC_CTL_MACLOOP_MSK (0x10) +#define ETHER_MAC_CTL_CONN_OFST (5) +#define ETHER_MAC_CTL_CONN_MSK (0x60) +#define ETHER_MAC_CTL_LOOP10_OFST (7) +#define ETHER_MAC_CTL_LOOP10_MSK (0x80) +#define ETHER_MAC_CTL_LNKCHG_OFST (8) +#define ETHER_MAC_CTL_LNKCHG_MSK (0x100) +#define ETHER_MAC_CTL_MISSROLL_OFST (10) +#define ETHER_MAC_CTL_MISSROLL_MSK (0x400) +#define ETHER_MAC_CTL_ENMISSROLL_OFST (13) +#define ETHER_MAC_CTL_ENMISSROLL_MSK (0x2000) +#define ETHER_MAC_CTL_LINK10_OFST (15) +#define ETHER_MAC_CTL_LINK10_MSK (0x8000) + +#define ETHER_ARC_CTL(base) (ETHER00_TYPE (base + 0x4)) +#define ETHER_ARC_CTL_STATIONACC_OFST (0) +#define ETHER_ARC_CTL_STATIONACC_MSK (0x1) +#define ETHER_ARC_CTL_GROUPACC_OFST (1) +#define ETHER_ARC_CTL_GROUPACC_MSK (0x2) +#define ETHER_ARC_CTL_BROADACC_OFST (2) +#define ETHER_ARC_CTL_BROADACC_MSK (0x4) +#define ETHER_ARC_CTL_NEGARC_OFST (3) +#define ETHER_ARC_CTL_NEGARC_MSK (0x8) +#define ETHER_ARC_CTL_COMPEN_OFST (4) +#define ETHER_ARC_CTL_COMPEN_MSK (0x10) + +#define ETHER_TX_CTL(base) (ETHER00_TYPE (base + 0x8)) +#define ETHER_TX_CTL_TXEN_OFST (0) +#define ETHER_TX_CTL_TXEN_MSK (0x1) +#define ETHER_TX_CTL_TXHALT_OFST (1) +#define ETHER_TX_CTL_TXHALT_MSK (0x2) +#define ETHER_TX_CTL_NOPAD_OFST (2) +#define ETHER_TX_CTL_NOPAD_MSK (0x4) +#define ETHER_TX_CTL_NOCRC_OFST (3) +#define ETHER_TX_CTL_NOCRC_MSK (0x8) +#define ETHER_TX_CTL_FBACK_OFST (4) +#define ETHER_TX_CTL_FBACK_MSK (0x10) +#define ETHER_TX_CTL_NOEXDEF_OFST (5) +#define ETHER_TX_CTL_NOEXDEF_MSK (0x20) +#define ETHER_TX_CTL_SDPAUSE_OFST (6) +#define ETHER_TX_CTL_SDPAUSE_MSK (0x40) +#define ETHER_TX_CTL_MII10_OFST (7) +#define ETHER_TX_CTL_MII10_MSK (0x80) +#define ETHER_TX_CTL_ENUNDER_OFST (8) +#define ETHER_TX_CTL_ENUNDER_MSK (0x100) +#define ETHER_TX_CTL_ENEXDEFER_OFST (9) +#define ETHER_TX_CTL_ENEXDEFER_MSK (0x200) +#define ETHER_TX_CTL_ENLCARR_OFST (10) +#define ETHER_TX_CTL_ENLCARR_MSK (0x400) +#define ETHER_TX_CTL_ENEXCOLL_OFST (11) +#define ETHER_TX_CTL_ENEXCOLL_MSK (0x800) +#define ETHER_TX_CTL_ENLATECOLL_OFST (12) +#define ETHER_TX_CTL_ENLATECOLL_MSK (0x1000) +#define ETHER_TX_CTL_ENTXPAR_OFST (13) +#define ETHER_TX_CTL_ENTXPAR_MSK (0x2000) +#define ETHER_TX_CTL_ENCOMP_OFST (14) +#define ETHER_TX_CTL_ENCOMP_MSK (0x4000) + +#define ETHER_TX_STAT(base) (ETHER00_TYPE (base + 0xc)) +#define ETHER_TX_STAT_TXCOLL_OFST (0) +#define ETHER_TX_STAT_TXCOLL_MSK (0xF) +#define ETHER_TX_STAT_EXCOLL_OFST (4) +#define ETHER_TX_STAT_EXCOLL_MSK (0x10) +#define ETHER_TX_STAT_TXDEFER_OFST (5) +#define ETHER_TX_STAT_TXDEFER_MSK (0x20) +#define ETHER_TX_STAT_PAUSED_OFST (6) +#define ETHER_TX_STAT_PAUSED_MSK (0x40) +#define ETHER_TX_STAT_INTTX_OFST (7) +#define ETHER_TX_STAT_INTTX_MSK (0x80) +#define ETHER_TX_STAT_UNDER_OFST (8) +#define ETHER_TX_STAT_UNDER_MSK (0x100) +#define ETHER_TX_STAT_EXDEFER_OFST (9) +#define ETHER_TX_STAT_EXDEFER_MSK (0x200) +#define ETHER_TX_STAT_LCARR_OFST (10) +#define ETHER_TX_STAT_LCARR_MSK (0x400) +#define ETHER_TX_STAT_TX10STAT_OFST (11) +#define ETHER_TX_STAT_TX10STAT_MSK (0x800) +#define ETHER_TX_STAT_LATECOLL_OFST (12) +#define ETHER_TX_STAT_LATECOLL_MSK (0x1000) +#define ETHER_TX_STAT_TXPAR_OFST (13) +#define ETHER_TX_STAT_TXPAR_MSK (0x2000) +#define ETHER_TX_STAT_COMP_OFST (14) +#define ETHER_TX_STAT_COMP_MSK (0x4000) +#define ETHER_TX_STAT_TXHALTED_OFST (15) +#define ETHER_TX_STAT_TXHALTED_MSK (0x8000) +#define ETHER_TX_STAT_SQERR_OFST (16) +#define ETHER_TX_STAT_SQERR_MSK (0x10000) +#define ETHER_TX_STAT_TXMCAST_OFST (17) +#define ETHER_TX_STAT_TXMCAST_MSK (0x20000) +#define ETHER_TX_STAT_TXBCAST_OFST (18) +#define ETHER_TX_STAT_TXBCAST_MSK (0x40000) +#define ETHER_TX_STAT_VLAN_OFST (19) +#define ETHER_TX_STAT_VLAN_MSK (0x80000) +#define ETHER_TX_STAT_MACC_OFST (20) +#define ETHER_TX_STAT_MACC_MSK (0x100000) +#define ETHER_TX_STAT_TXPAUSE_OFST (21) +#define ETHER_TX_STAT_TXPAUSE_MSK (0x200000) + +#define ETHER_RX_CTL(base) (ETHER00_TYPE (base + 0x10)) +#define ETHER_RX_CTL_RXEN_OFST (0) +#define ETHER_RX_CTL_RXEN_MSK (0x1) +#define ETHER_RX_CTL_RXHALT_OFST (1) +#define ETHER_RX_CTL_RXHALT_MSK (0x2) +#define ETHER_RX_CTL_LONGEN_OFST (2) +#define ETHER_RX_CTL_LONGEN_MSK (0x4) +#define ETHER_RX_CTL_SHORTEN_OFST (3) +#define ETHER_RX_CTL_SHORTEN_MSK (0x8) +#define ETHER_RX_CTL_STRIPCRC_OFST (4) +#define ETHER_RX_CTL_STRIPCRC_MSK (0x10) +#define ETHER_RX_CTL_PASSCTL_OFST (5) +#define ETHER_RX_CTL_PASSCTL_MSK (0x20) +#define ETHER_RX_CTL_IGNORECRC_OFST (6) +#define ETHER_RX_CTL_IGNORECRC_MSK (0x40) +#define ETHER_RX_CTL_ENALIGN_OFST (8) +#define ETHER_RX_CTL_ENALIGN_MSK (0x100) +#define ETHER_RX_CTL_ENCRCERR_OFST (9) +#define ETHER_RX_CTL_ENCRCERR_MSK (0x200) +#define ETHER_RX_CTL_ENOVER_OFST (10) +#define ETHER_RX_CTL_ENOVER_MSK (0x400) +#define ETHER_RX_CTL_ENLONGERR_OFST (11) +#define ETHER_RX_CTL_ENLONGERR_MSK (0x800) +#define ETHER_RX_CTL_ENRXPAR_OFST (13) +#define ETHER_RX_CTL_ENRXPAR_MSK (0x2000) +#define ETHER_RX_CTL_ENGOOD_OFST (14) +#define ETHER_RX_CTL_ENGOOD_MSK (0x4000) + +#define ETHER_RX_STAT(base) (ETHER00_TYPE (base + 0x14)) +#define ETHER_RX_STAT_LENERR_OFST (4) +#define ETHER_RX_STAT_LENERR_MSK (0x10) +#define ETHER_RX_STAT_CTLRECD_OFST (5) +#define ETHER_RX_STAT_CTLRECD_MSK (0x20) +#define ETHER_RX_STAT_INTRX_OFST (6) +#define ETHER_RX_STAT_INTRX_MSK (0x40) +#define ETHER_RX_STAT_RX10STAT_OFST (7) +#define ETHER_RX_STAT_RX10STAT_MSK (0x80) +#define ETHER_RX_STAT_ALIGNERR_OFST (8) +#define ETHER_RX_STAT_ALIGNERR_MSK (0x100) +#define ETHER_RX_STAT_CRCERR_OFST (9) +#define ETHER_RX_STAT_CRCERR_MSK (0x200) +#define ETHER_RX_STAT_OVERFLOW_OFST (10) +#define ETHER_RX_STAT_OVERFLOW_MSK (0x400) +#define ETHER_RX_STAT_LONGERR_OFST (11) +#define ETHER_RX_STAT_LONGERR_MSK (0x800) +#define ETHER_RX_STAT_RXPAR_OFST (13) +#define ETHER_RX_STAT_RXPAR_MSK (0x2000) +#define ETHER_RX_STAT_GOOD_OFST (14) +#define ETHER_RX_STAT_GOOD_MSK (0x4000) +#define ETHER_RX_STAT_RXHALTED_OFST (15) +#define ETHER_RX_STAT_RXHALTED_MSK (0x8000) +#define ETHER_RX_STAT_RXMCAST_OFST (17) +#define ETHER_RX_STAT_RXMCAST_MSK (0x10000) +#define ETHER_RX_STAT_RXBCAST_OFST (18) +#define ETHER_RX_STAT_RXBCAST_MSK (0x20000) +#define ETHER_RX_STAT_RXVLAN_OFST (19) +#define ETHER_RX_STAT_RXVLAN_MSK (0x40000) +#define ETHER_RX_STAT_RXPAUSE_OFST (20) +#define ETHER_RX_STAT_RXPAUSE_MSK (0x80000) +#define ETHER_RX_STAT_ARCSTATUS_OFST (21) +#define ETHER_RX_STAT_ARCSTATUS_MSK (0xF00000) +#define ETHER_RX_STAT_ARCENT_OFST (25) +#define ETHER_RX_STAT_ARCENT_MSK (0x1F000000) + +#define ETHER_MD_DATA(base) (ETHER00_TYPE (base + 0x18)) + +#define ETHER_MD_CA(base) (ETHER00_TYPE (base + 0x1c)) +#define ETHER_MD_CA_ADDR_OFST (0) +#define ETHER_MD_CA_ADDR_MSK (0x1F) +#define ETHER_MD_CA_PHY_OFST (5) +#define ETHER_MD_CA_PHY_MSK (0x3E0) +#define ETHER_MD_CA_WR_OFST (10) +#define ETHER_MD_CA_WR_MSK (0x400) +#define ETHER_MD_CA_BUSY_OFST (11) +#define ETHER_MD_CA_BUSY_MSK (0x800) +#define ETHER_MD_CA_PRESUPP_OFST (12) +#define ETHER_MD_CA_PRESUPP_MSK (0x1000) + +#define ETHER_ARC_ADR(base) (ETHER00_TYPE (base + 0x160)) +#define ETHER_ARC_ADR_ARC_LOC_OFST (2) +#define ETHER_ARC_ADR_ARC_LOC_MSK (0xFFC) + +#define ETHER_ARC_DATA(base) (ETHER00_TYPE (base + 0x364)) + +#define ETHER_ARC_ENA(base) (ETHER00_TYPE (base + 0x28)) +#define ETHER_ARC_ENA_MSK (0x1FFFFF) + +#define ETHER_PROM_CTL(base) (ETHER00_TYPE (base + 0x2c)) +#define ETHER_PROM_CTL_PROM_ADDR_OFST (0) +#define ETHER_PROM_CTL_PROM_ADDR_MSK (0x3F) +#define ETHER_PROM_CTL_OPCODE_OFST (13) +#define ETHER_PROM_CTL_OPCODE_MSK (0x6000) +#define ETHER_PROM_CTL_OPCODE_READ_MSK (0x4000) +#define ETHER_PROM_CTL_OPCODE_WRITE_MSK (0x2000) +#define ETHER_PROM_CTL_OPCODE_ERASE_MSK (0x6000) +#define ETHER_PROM_CTL_ENABLE_MSK (0x0030) +#define ETHER_PROM_CTL_DISABLE_MSK (0x0000) +#define ETHER_PROM_CTL_BUSY_OFST (15) +#define ETHER_PROM_CTL_BUSY_MSK (0x8000) + +#define ETHER_PROM_DATA(base) (ETHER00_TYPE (base + 0x30)) + +#define ETHER_MISS_CNT(base) (ETHER00_TYPE (base + 0x3c)) +#define ETHER_MISS_CNT_COUNT_OFST (0) +#define ETHER_MISS_CNT_COUNT_MSK (0xFFFF) + +#define ETHER_CNTDATA(base) (ETHER00_TYPE (base + 0x80)) + +#define ETHER_CNTACC(base) (ETHER00_TYPE (base + 0x84)) +#define ETHER_CNTACC_ADDR_OFST (0) +#define ETHER_CNTACC_ADDR_MSK (0xFF) +#define ETHER_CNTACC_WRRDN_OFST (8) +#define ETHER_CNTACC_WRRDN_MSK (0x100) +#define ETHER_CNTACC_CLEAR_OFST (9) +#define ETHER_CNTACC_CLEAR_MSK (0x200) + +#define ETHER_TXRMINTEN(base) (ETHER00_TYPE (base + 0x88)) +#define ETHER_TXRMINTEN_MSK (0x3FFFFFFF) + +#define ETHER_RXRMINTEN(base) (ETHER00_TYPE (base + 0x8C)) +#define ETHER_RXRMINTEN_MSK (0xFFFFFF) + +/* +* RMON Registers +*/ +#define RMON_COLLISION0 0x0 +#define RMON_COLLISION1 0x1 +#define RMON_COLLISION2 0x2 +#define RMON_COLLISION3 0x3 +#define RMON_COLLISION4 0x4 +#define RMON_COLLISION5 0x5 +#define RMON_COLLISION6 0x6 +#define RMON_COLLISION7 0x7 +#define RMON_COLLISION8 0x8 +#define RMON_COLLISION9 0x9 +#define RMON_COLLISION10 0xa +#define RMON_COLLISION11 0xb +#define RMON_COLLISION12 0xc +#define RMON_COLLISION13 0xd +#define RMON_COLLISION14 0xe +#define RMON_COLLISION15 0xf +#define RMON_COLLISION16 0x10 +#define RMON_FRAMES_WITH_DEFERRED_XMISSIONS 0x11 +#define RMON_LATE_COLLISIONS 0x12 +#define RMON_FRAMES_LOST_DUE_TO_MAC_XMIT 0x13 +#define RMON_CARRIER_SENSE_ERRORS 0x14 +#define RMON_FRAMES_WITH_EXCESSIVE_DEFERAL 0x15 +#define RMON_UNICAST_FRAMES_TRANSMITTED_OK 0x16 +#define RMON_MULTICAST_FRAMES_XMITTED_OK 0x17 +#define RMON_BROADCAST_FRAMES_XMITTED_OK 0x18 +#define RMON_SQE_TEST_ERRORS 0x19 +#define RMON_PAUSE_MACCTRL_FRAMES_XMITTED 0x1A +#define RMON_MACCTRL_FRAMES_XMITTED 0x1B +#define RMON_VLAN_FRAMES_XMITTED 0x1C +#define RMON_OCTETS_XMITTED_OK 0x1D +#define RMON_OCTETS_XMITTED_OK_HI 0x1E + +#define RMON_RX_PACKET_SIZES0 0x40 +#define RMON_RX_PACKET_SIZES1 0x41 +#define RMON_RX_PACKET_SIZES2 0x42 +#define RMON_RX_PACKET_SIZES3 0x43 +#define RMON_RX_PACKET_SIZES4 0x44 +#define RMON_RX_PACKET_SIZES5 0x45 +#define RMON_RX_PACKET_SIZES6 0x46 +#define RMON_RX_PACKET_SIZES7 0x47 +#define RMON_FRAME_CHECK_SEQUENCE_ERRORS 0x48 +#define RMON_ALIGNMENT_ERRORS 0x49 +#define RMON_FRAGMENTS 0x4A +#define RMON_JABBERS 0x4B +#define RMON_FRAMES_LOST_TO_INTMACRCVERR 0x4C +#define RMON_UNICAST_FRAMES_RCVD_OK 0x4D +#define RMON_MULTICAST_FRAMES_RCVD_OK 0x4E +#define RMON_BROADCAST_FRAMES_RCVD_OK 0x4F +#define RMON_IN_RANGE_LENGTH_ERRORS 0x50 +#define RMON_OUT_OF_RANGE_LENGTH_ERRORS 0x51 +#define RMON_VLAN_FRAMES_RCVD 0x52 +#define RMON_PAUSE_MAC_CTRL_FRAMES_RCVD 0x53 +#define RMON_MAC_CTRL_FRAMES_RCVD 0x54 +#define RMON_OCTETS_RCVD_OK 0x55 +#define RMON_OCTETS_RCVD_OK_HI 0x56 +#define RMON_OCTETS_RCVD_OTHER 0x57 +#define RMON_OCTETS_RCVD_OTHER_HI 0x58 + +#endif /* __ETHER00_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-epxa10db/io.h linux-2.5/include/asm-arm/arch-epxa10db/io.h --- linux-2.5.1/include/asm-arm/arch-epxa10db/io.h Thu Oct 25 20:53:53 2001 +++ linux-2.5/include/asm-arm/arch-epxa10db/io.h Sun Jan 6 01:38:27 2002 @@ -26,8 +26,6 @@ /* * Generic virtual read/write */ -#define __arch_getw(a) (*(volatile unsigned short *)(a)) -#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) /*#define outsw __arch_writesw #define outsl __arch_writesl #define outsb __arch_writesb @@ -36,20 +34,6 @@ #define insl __arch_readsl*/ #define __io(a) (a) -#if 0 -#define __mem_pci(a) ((unsigned long)(a)) -#define __mem_isa(a) (PCI_MEMORY_VADDR + (unsigned long)(a)) -/* - * Validate the pci memory address for ioremap. - */ -#define iomem_valid_addr(iomem,size) \ - ((iomem) > 0 && (iomem) + (size) <= 0x20000000) - -/* - * Convert PCI memory space to a CPU physical address - */ -#define iomem_to_phys(iomem) ((iomem) + PHYS_PCI_MEM_BASE) - -#endif +#define __mem_pci(a) (a) #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-epxa10db/tdkphy.h linux-2.5/include/asm-arm/arch-epxa10db/tdkphy.h --- linux-2.5.1/include/asm-arm/arch-epxa10db/tdkphy.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-epxa10db/tdkphy.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,209 @@ +/* + * linux/drivers/tdkphy.h + * + * Copyright (C) 2001 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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 __TDKPHY_H +#define __TDKPHY_H + +/* + * Register definitions for the TDK 78Q2120 PHY + * which is on the Camelot board + */ + +/* + * Copyright (c) Altera Corporation 2000. + * All rights reserved. + */ +#define PHY_CONTROL (0) +#define PHY_CONTROL_COLT_MSK (0x80) +#define PHY_CONTROL_COLT_OFST (7) +#define PHY_CONTROL_DUPLEX_MSK (0x100) +#define PHY_CONTROL_DUPLEX_OFST (8) +#define PHY_CONTROL_RANEG_MSK (0x200) +#define PHY_CONTROL_RANEG_OFST (9) +#define PHY_CONTROL_ISO_MSK (0x400) +#define PHY_CONTROL_ISO_OFST (10) +#define PHY_CONTROL_PWRDN_MSK (0x800) +#define PHY_CONTROL_PWRDN_OFST (11) +#define PHY_CONTROL_ANEGEN_MSK (0x1000) +#define PHY_CONTROL_ANEGEN_OFST (12) +#define PHY_CONTROL_SPEEDSL_MSK (0x2000) +#define PHY_CONTROL_SPEEDSL_OFST (13) +#define PHY_CONTROL_LOOPBK_MSK (0x4000) +#define PHY_CONTROL_LOOPBK_OFST (14) +#define PHY_CONTROL_RESET_MSK (0x8000) +#define PHY_CONTROL_RESET_OFST (15) + +#define PHY_STATUS (1) +#define PHY_STATUS_ETXD_MSK (0x1) +#define PHY_STATUS_EXTD_OFST (0) +#define PHY_STATUS_JAB_MSK (0x2) +#define PHY_STATUS_JAB_OFST (1) +#define PHY_STATUS_LINK_MSK (0x4) +#define PHY_STATUS_LINK_OFST (2) +#define PHY_STATUS_ANEGA_MSK (0x8) +#define PHY_STATUS_ANEGA_OFST (3) +#define PHY_STATUS_RFAULT_MSK (0x10) +#define PHY_STATUS_RFAULT_OFST (4) +#define PHY_STATUS_ANEGC_MSK (0x20) +#define PHY_STATUS_ANEGC_OFST (5) +#define PHY_STATUS_10T_H_MSK (0x800) +#define PHY_STATUS_10T_H_OFST (11) +#define PHY_STATUS_10T_F_MSK (0x1000) +#define PHY_STATUS_10T_F_OFST (12) +#define PHY_STATUS_100_X_H_MSK (0x2000) +#define PHY_STATUS_100_X_H_OFST (13) +#define PHY_STATUS_100_X_F_MSK (0x4000) +#define PHY_STATUS_100_X_F_OFST (14) +#define PHY_STATUS_100T4_MSK (0x8000) +#define PHY_STATUS_100T4_OFST (15) + +#define PHY_ID1 (2) +#define PHY_ID1_OUI_MSK (0xFFFF) +#define PHY_ID1_OUI_OFST (0) + +#define PHY_ID2 (3) +#define PHY_ID2_RN_MSK (0xF) +#define PHY_ID2_RN_OFST (0) +#define PHY_ID2_MN_MSK (0x3F0) +#define PHY_ID2_MN_OFST (4) +#define PHY_ID2_OUI_MSK (0xFC00) +#define PHY_ID2_OUI_OFST (10) + +#define PHY_AUTO_NEG_ADVERTISEMENT (4) +#define PHY_AUTO_NEG_ADVERTISEMENT_SELECTOR_MSK (0x1F) +#define PHY_AUTO_NEG_ADVERTISEMENT_SELECTOR_OFST (0) +#define PHY_AUTO_NEG_ADVERTISEMENT_A0_MSK (0x20) +#define PHY_AUTO_NEG_ADVERTISEMENT_A0_OFST (5) +#define PHY_AUTO_NEG_ADVERTISEMENT_A1_MSK (0x40) +#define PHY_AUTO_NEG_ADVERTISEMENT_A1_OFST (6) +#define PHY_AUTO_NEG_ADVERTISEMENT_A2_MSK (0x80) +#define PHY_AUTO_NEG_ADVERTISEMENT_A2_OFST (7) +#define PHY_AUTO_NEG_ADVERTISEMENT_A3_MSK (0x100) +#define PHY_AUTO_NEG_ADVERTISEMENT_A3_OFST (8) +#define PHY_AUTO_NEG_ADVERTISEMENT_A4_MSK (0x200) +#define PHY_AUTO_NEG_ADVERTISEMENT_A4_OFST (9) +#define PHY_AUTO_NEG_ADVERTISEMENT_TAF_MSK (0x1FE0) +#define PHY_AUTO_NEG_ADVERTISEMENT_TAF_OFST (5) +#define PHY_AUTO_NEG_ADVERTISEMENT_RF_MSK (0x2000) +#define PHY_AUTO_NEG_ADVERTISEMENT_RF_OFST (13) +#define PHY_AUTO_NEG_ADVERTISEMENT_RSVD_MSK (0x4000) +#define PHY_AUTO_NEG_ADVERTISEMENT_RVSD_OFST (14) +#define PHY_AUTO_NEG_ADVERTISEMENT_NP_MSK (0x8000) +#define PHY_AUTO_NEG_ADVERTISEMENT_NP_OFST (15) + +#define PHY_AUTO_NEG_LINK_PARTNER (5) +#define PHY_AUTO_NEG_LINK_PARTNER_S4_MSK (0x1F) +#define PHY_AUTO_NEG_LINK_PARTNER_S4_OFST (0) +#define PHY_AUTO_NEG_LINK_PARTNER_A7_MSK (0x1FE0) +#define PHY_AUTO_NEG_LINK_PARTNER_A7_OFST (5) +#define PHY_AUTO_NEG_LINK_PARTNER_RF_MSK (0x2000) +#define PHY_AUTO_NEG_LINK_PARTNER_RF_OFST (13) +#define PHY_AUTO_NEG_LINK_PARTNER_ACK_MSK (0x4000) +#define PHY_AUTO_NEG_LINK_PARTNER_ACK_OFST (14) +#define PHY_AUTO_NEG_LINK_PARTNER_NP_MSK (0x8000) +#define PHY_AUTO_NEG_LINK_PARTNER_NP_OFST (15) + +#define PHY_AUTO_NEG_EXPANSION (6) +#define PHY_AUTO_NEG_EXPANSION_LPANEGA_MSK (0x1) +#define PHY_AUTO_NEG_EXPANSION_LPANEGA_OFST (0) +#define PHY_AUTO_NEG_EXPANSION_PRX_MSK (0x2) +#define PHY_AUTO_NEG_EXPANSION_PRX_OFST (1) +#define PHY_AUTO_NEG_EXPANSION_NPA_MSK (0x4) +#define PHY_AUTO_NEG_EXPANSION_NPA_OFST (2) +#define PHY_AUTO_NEG_EXPANSION_LPNPA_MSK (0x8) +#define PHY_AUTO_NEG_EXPANSION_LPNPA_OFST (3) +#define PHY_AUTO_NEG_EXPANSION_PDF_MSK (0x10) +#define PHY_AUTO_NEG_EXPANSION_PDF_OFST (4) + +#define PHY_VENDOR_SPECIFIC (16) +#define PHY_VENDOR_SPECIFIC_RXCC_MSK (0x1) +#define PHY_VENDOR_SPECIFIC_RXCC_OFST (0) +#define PHY_VENDOR_SPECIFIC_PCSBP_MSK (0x2) +#define PHY_VENDOR_SPECIFIC_PCSBP_OFST (1) +#define PHY_VENDOR_SPECIFIC_RVSPOL_MSK (0x10) +#define PHY_VENDOR_SPECIFIC_RVSPOL_OFST (4) +#define PHY_VENDOR_SPECIFIC_APOL_MSK (0x20) +#define PHY_VENDOR_SPECIFIC_APOL_OFST (5) +#define PHY_VENDOR_SPECIFIC_GPIO0_DIR_MSK (0x40) +#define PHY_VENDOR_SPECIFIC_GPIO0_DIR_OFST (6) +#define PHY_VENDOR_SPECIFIC_GPIO0_DAT_MSK (0x80) +#define PHY_VENDOR_SPECIFIC_GPIO0_DAT_OFST (7) +#define PHY_VENDOR_SPECIFIC_GPIO1_DIR_MSK (0x100) +#define PHY_VENDOR_SPECIFIC_GPIO1_DIR_OFST (8) +#define PHY_VENDOR_SPECIFIC_GPIO1_DAT_MSK (0x200) +#define PHY_VENDOR_SPECIFIC_GPIO1_DAT_OFST (9) +#define PHY_VENDOR_SPECIFIC_10BT_NATURAL_LOOPBACK_DAT_MSK (0x400) +#define PHY_VENDOR_SPECIFIC_10BT_NATURAL_LOOPBACK_DAT_OFST (10) +#define PHY_VENDOR_SPECIFIC_10BT_SQE_TEST_INHIBIT_MSK (0x800) +#define PHY_VENDOR_SPECIFIC_10BT_SQE_TEST_INHIBIT_OFST (11) +#define PHY_VENDOR_SPECIFIC_TXHIM_MSK (0x1000) +#define PHY_VENDOR_SPECIFIC_TXHIM_OFST (12) +#define PHY_VENDOR_SPECIFIC_INT_LEVEL_MSK (0x4000) +#define PHY_VENDOR_SPECIFIC_INT_LEVEL_OFST (14) +#define PHY_VENDOR_SPECIFIC_RPTR_MSK (0x8000) +#define PHY_VENDOR_SPECIFIC_RPTR_OFST (15) + +#define PHY_IRQ_CONTROL (17) +#define PHY_IRQ_CONTROL_ANEG_COMP_INT_MSK (0x1) +#define PHY_IRQ_CONTROL_ANEG_COMP_INT_OFST (0) +#define PHY_IRQ_CONTROL_RFAULT_INT_MSK (0x2) +#define PHY_IRQ_CONTROL_RFAULT_INT_OFST (1) +#define PHY_IRQ_CONTROL_LS_CHG_INT_MSK (0x4) +#define PHY_IRQ_CONTROL_LS_CHG_INT_OFST (2) +#define PHY_IRQ_CONTROL_LP_ACK_INT_MSK (0x8) +#define PHY_IRQ_CONTROL_LP_ACK_INT_OFST (3) +#define PHY_IRQ_CONTROL_PDF_INT_MSK (0x10) +#define PHY_IRQ_CONTROL_PDF_INT_OFST (4) +#define PHY_IRQ_CONTROL_PRX_INT_MSK (0x20) +#define PHY_IRQ_CONTROL_PRX_INT_OFST (5) +#define PHY_IRQ_CONTROL_RXER_INT_MSK (0x40) +#define PHY_IRQ_CONTROL_RXER_INT_OFST (6) +#define PHY_IRQ_CONTROL_JABBER_INT_MSK (0x80) +#define PHY_IRQ_CONTROL_JABBER_INT_OFST (7) +#define PHY_IRQ_CONTROL_ANEG_COMP_IE_MSK (0x100) +#define PHY_IRQ_CONTROL_ANEG_COMP_IE_OFST (8) +#define PHY_IRQ_CONTROL_RFAULT_IE_MSK (0x200) +#define PHY_IRQ_CONTROL_RFAULT_IE_OFST (9) +#define PHY_IRQ_CONTROL_LS_CHG_IE_MSK (0x400) +#define PHY_IRQ_CONTROL_LS_CHG_IE_OFST (10) +#define PHY_IRQ_CONTROL_LP_ACK_IE_MSK (0x800) +#define PHY_IRQ_CONTROL_LP_ACK_IE_OFST (11) +#define PHY_IRQ_CONTROL_PDF_IE_MSK (0x1000) +#define PHY_IRQ_CONTROL_PDF_IE_OFST (12) +#define PHY_IRQ_CONTROL_PRX_IE_MSK (0x2000) +#define PHY_IRQ_CONTROL_PRX_IE_OFST (13) +#define PHY_IRQ_CONTROL_RXER_IE_MSK (0x4000) +#define PHY_IRQ_CONTROL_RXER_IE_OFST (14) +#define PHY_IRQ_CONTROL_JABBER_IE_MSK (0x8000) +#define PHY_IRQ_CONTROL_JABBER_IE_OFST (15) + +#define PHY_DIAGNOSTIC (18) +#define PHY_DIAGNOSTIC_RX_LOCK_MSK (0x100) +#define PHY_DIAGNOSTIC_RX_LOCK_OFST (8) +#define PHY_DIAGNOSTIC_RX_PASS_MSK (0x200) +#define PHY_DIAGNOSTIC_RX_PASS_OFST (9) +#define PHY_DIAGNOSTIC_RATE_MSK (0x400) +#define PHY_DIAGNOSTIC_RATE_OFST (10) +#define PHY_DIAGNOSTIC_DPLX_MSK (0x800) +#define PHY_DIAGNOSTIC_DPLX_OFST (11) +#define PHY_DIAGNOSTIC_ANEGF_MSK (0x1000) +#define PHY_DIAGNOSTIC_ANEGF_OFST (12) + +#endif /* __TDKPHY_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-epxa10db/time.h linux-2.5/include/asm-arm/arch-epxa10db/time.h --- linux-2.5.1/include/asm-arm/arch-epxa10db/time.h Thu Oct 25 20:53:53 2001 +++ linux-2.5/include/asm-arm/arch-epxa10db/time.h Sun Jan 6 01:38:27 2002 @@ -42,20 +42,17 @@ /* * Set up timer interrupt, and return the current time in seconds. */ -extern __inline__ void setup_timer(void) +void __init time_init(void) { - - timer_irq.handler = excalibur_timer_interrupt; - /* * Make irqs happen for the system timer */ setup_arm_irq(IRQ_TIMER0, &timer_irq); /* Start the timer */ - *TIMER0_LIMIT(IO_ADDRESS(EXC_TIMER00_BASE))=(unsigned int)(EXC_AHB2_CLK_FREQUENCY/50); + *TIMER0_LIMIT(IO_ADDRESS(EXC_TIMER00_BASE))=(unsigned int)(EXC_AHB2_CLK_FREQUENCY/200); *TIMER0_PRESCALE(IO_ADDRESS(EXC_TIMER00_BASE))=1; *TIMER0_CR(IO_ADDRESS(EXC_TIMER00_BASE))=TIMER0_CR_IE_MSK | TIMER0_CR_S_MSK; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-integrator/io.h linux-2.5/include/asm-arm/arch-integrator/io.h --- linux-2.5.1/include/asm-arm/arch-integrator/io.h Thu Jul 5 03:11:17 2001 +++ linux-2.5/include/asm-arm/arch-integrator/io.h Sun Jan 6 01:38:27 2002 @@ -26,20 +26,4 @@ #define __mem_pci(a) ((unsigned long)(a)) #define __mem_isa(a) (PCI_MEMORY_VADDR + (unsigned long)(a)) -/* - * Generic virtual read/write - */ -#define __arch_getw(a) (*(volatile unsigned short *)(a)) -#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) - -/* - * Validate the pci memory address for ioremap. - */ -#define iomem_valid_addr(iomem,size) (1) - -/* - * Convert PCI memory space to a CPU physical address - */ -#define iomem_to_phys(iomem) (iomem) - #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-integrator/time.h linux-2.5/include/asm-arm/arch-integrator/time.h --- linux-2.5.1/include/asm-arm/arch-integrator/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-integrator/time.h Sun Jan 6 01:38:27 2002 @@ -113,7 +113,7 @@ /* * Set up timer interrupt, and return the current time in seconds. */ -static inline void setup_timer(void) +void __init time_init(void) { volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/dma.h linux-2.5/include/asm-arm/arch-iop310/dma.h --- linux-2.5.1/include/asm-arm/arch-iop310/dma.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/dma.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,109 @@ +/* + * linux/include/asm-arm/arch-iop80310/dma.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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. + */ + +#ifndef _IOP310_DMA_H_ +#define _IOP310_DMA_H_ + +/* 2 DMA on primary PCI and 1 on secondary for 80310 */ +#define MAX_IOP310_DMA_CHANNEL 3 +#define MAX_DMA_DESC 64 /*128 */ + +/* + * Make the generic DMA bits go away since we don't use it + */ +#define MAX_DMA_CHANNELS 0 + +#define MAX_DMA_ADDRESS 0xffffffff + +#define IOP310_DMA_P0 0 +#define IOP310_DMA_P1 1 +#define IOP310_DMA_S0 2 + +#define DMA_MOD_READ 0x0001 +#define DMA_MOD_WRITE 0x0002 +#define DMA_MOD_CACHED 0x0004 +#define DMA_MOD_NONCACHED 0x0008 + + +#define DMA_DESC_DONE 0x0010 +#define DMA_INCOMPLETE 0x0020 +#define DMA_HOLD 0x0040 +#define DMA_END_CHAIN 0x0080 +#define DMA_COMPLETE 0x0100 +#define DMA_NOTIFY 0x0200 +#define DMA_NEW_HEAD 0x0400 + +#define DMA_USER_MASK (DMA_NOTIFY | DMA_INCOMPLETE | \ + DMA_HOLD | DMA_COMPLETE) + +#define DMA_DCR_DAC 0x00000020 /* Dual Addr Cycle Enab */ +#define DMA_DCR_IE 0x00000010 /* Interrupt Enable */ +#define DMA_DCR_PCI_IOR 0x00000002 /* I/O Read */ +#define DMA_DCR_PCI_IOW 0x00000003 /* I/O Write */ +#define DMA_DCR_PCI_MR 0x00000006 /* Memory Read */ +#define DMA_DCR_PCI_MW 0x00000007 /* Memory Write */ +#define DMA_DCR_PCI_CR 0x0000000A /* Configuration Read */ +#define DMA_DCR_PCI_CW 0x0000000B /* Configuration Write */ +#define DMA_DCR_PCI_MRM 0x0000000C /* Memory Read Multiple */ +#define DMA_DCR_PCI_MRL 0x0000000E /* Memory Read Line */ +#define DMA_DCR_PCI_MWI 0x0000000F /* Mem Write and Inval */ + +#define DMA_USER_CMD_IE 0x00000001 /* user request int */ +#define DMA_USER_END_CHAIN 0x00000002 /* end of sgl chain flag */ + +/* ATU defines */ +#define IOP310_ATUCR_PRIM_OUT_ENAB /* Configuration */ 0x00000002 +#define IOP310_ATUCR_DIR_ADDR_ENAB /* Configuration */ 0x00000080 + + +typedef void (*dma_callback_t) (void *buf_context); +/* + * DMA Descriptor + */ +typedef struct _dma_desc +{ + u32 NDAR; /* next descriptor adress */ + u32 PDAR; /* PCI address */ + u32 PUADR; /* upper PCI address */ + u32 LADR; /* local address */ + u32 BC; /* byte count */ + u32 DC; /* descriptor control */ +} dma_desc_t; + +typedef struct _dma_sgl +{ + dma_desc_t dma_desc; /* DMA descriptor pointer */ + u32 status; /* descriptor status */ + void *data; /* local virt */ + struct _dma_sgl *next; /* next descriptor */ +} dma_sgl_t; + +/* dma sgl head */ +typedef struct _dma_head +{ + u32 total; /* total elements in SGL */ + u32 status; /* status of sgl */ + u32 mode; /* read or write mode */ + dma_sgl_t *list; /* pointer to list */ + dma_callback_t callback; /* callback function */ +} dma_head_t; + +/* function prototypes */ +int dma_request(dmach_t, const char *); +int dma_queue_buffer(dmach_t, dma_head_t *); +int dma_suspend(dmach_t); +int dma_resume(dmach_t); +int dma_flush_all(dmach_t); +void dma_free(dmach_t); +void dma_set_irq_threshold(dmach_t, int); +dma_sgl_t *dma_get_buffer(dmach_t, int); +void dma_return_buffer(dmach_t, dma_sgl_t *); + +#endif /* _ASM_ARCH_DMA_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/hardware.h linux-2.5/include/asm-arm/arch-iop310/hardware.h --- linux-2.5.1/include/asm-arm/arch-iop310/hardware.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/hardware.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,38 @@ +/* + * linux/include/asm-arm/arch-iop80310/hardware.h + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include <linux/config.h> + +/* + * Note about PCI IO space mappings + * + * To make IO space accesses efficient, we store virtual addresses in + * the IO resources. + * + * The PCI IO space is located at virtual 0xfe000000 from physical + * 0x90000000. The PCI BARs must be programmed with physical addresses, + * but when we read them, we convert them to virtual addresses. See + * arch/arm/mach-iop310/iop310-pci.c + */ + +#define pcibios_assign_all_busses() 1 + +/* + * these are the values for the secondary PCI bus on the 80312 chip. I will + * have to do some fixup in the bus/dev fixup code + */ +#define PCIBIOS_MIN_IO 0 +#define PCIBIOS_MIN_MEM 0x88000000 + +// Generic chipset bits +#include "iop310.h" + +// Board specific +#if defined(CONFIG_ARCH_IQ80310) +#include "iq80310.h" +#endif + +#endif /* _ASM_ARCH_HARDWARE_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/ide.h linux-2.5/include/asm-arm/arch-iop310/ide.h --- linux-2.5.1/include/asm-arm/arch-iop310/ide.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/ide.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,51 @@ +/* + * include/asm-arm/arch-iop310/ide.h + * + * Generic IDE functions for IOP310 systems + * + * Author: Deepak Saxena <dsaxena@mvista.com> + * + * Copyright 2001 MontaVista Software Inc. + * + * 09/26/2001 - Sharon Baartmans + * Fixed so it actually works. + */ + +#ifndef _ASM_ARCH_IDE_H_ +#define _ASM_ARCH_IDE_H_ + +/* + * Set up a hw structure for a specified data port, control port and IRQ. + * This should follow whatever the default interface uses. + */ +static __inline__ void +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) +{ + ide_ioreg_t reg; + int i; + int regincr = 1; + + memset(hw, 0, sizeof(*hw)); + + reg = (ide_ioreg_t)data_port; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += regincr; + } + + hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; + + if (irq) *irq = 0; +} + +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +static __inline__ void ide_init_default_hwifs(void) +{ + /* There are no standard ports */ +} + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/io.h linux-2.5/include/asm-arm/arch-iop310/io.h --- linux-2.5.1/include/asm-arm/arch-iop310/io.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/io.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,20 @@ +/* + * linux/include/asm-arm/arch-iop310/io.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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. + */ + +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(p) ((p)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) ((unsigned long)(a)) + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/iop310.h linux-2.5/include/asm-arm/arch-iop310/iop310.h --- linux-2.5.1/include/asm-arm/arch-iop310/iop310.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/iop310.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,247 @@ +/* + * linux/include/asm/arch-iop310/iop310.h + * + * Intel IOP310 Compainion Chip definitions + * + * 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. + */ + +#ifndef _IOP310_HW_H_ +#define _IOP310_HW_H_ + +/* + * IOP310 I/O and Mem space regions for PCI autoconfiguration + */ +#define IOP310_PCISEC_LOWER_IO 0x90010000 +#define IOP310_PCISEC_UPPER_IO 0x9001ffff +#define IOP310_PCISEC_LOWER_MEM 0x88000000 +#define IOP310_PCISEC_UPPER_MEM 0x8bffffff + +#define IOP310_PCIPRI_LOWER_IO 0x90000000 +#define IOP310_PCIPRI_UPPER_IO 0x9000ffff +#define IOP310_PCIPRI_LOWER_MEM 0x80000000 +#define IOP310_PCIPRI_UPPER_MEM 0x83ffffff + +#define IOP310_PCI_WINDOW_SIZE 64 * 0x100000 + +/* + * IOP310 chipset registers + */ +#define IOP310_VIRT_MEM_BASE 0xe8001000 /* chip virtual mem address*/ +#define IOP310_PHY_MEM_BASE 0x00001000 /* chip physical memory address */ +#define IOP310_REG_ADDR(reg) (IOP310_VIRT_MEM_BASE | IOP310_PHY_MEM_BASE | (reg)) + +/* PCI-to-PCI Bridge Unit 0x00001000 through 0x000010FF */ +#define IOP310_VIDR (volatile u16 *)IOP310_REG_ADDR(0x00001000) +#define IOP310_DIDR (volatile u16 *)IOP310_REG_ADDR(0x00001002) +#define IOP310_PCR (volatile u16 *)IOP310_REG_ADDR(0x00001004) +#define IOP310_PSR (volatile u16 *)IOP310_REG_ADDR(0x00001006) +#define IOP310_RIDR (volatile u8 *)IOP310_REG_ADDR(0x00001008) +#define IOP310_CCR (volatile u32 *)IOP310_REG_ADDR(0x00001009) +#define IOP310_CLSR (volatile u8 *)IOP310_REG_ADDR(0x0000100C) +#define IOP310_PLTR (volatile u8 *)IOP310_REG_ADDR(0x0000100D) +#define IOP310_HTR (volatile u8 *)IOP310_REG_ADDR(0x0000100E) +/* Reserved 0x0000100F through 0x00001017 */ +#define IOP310_PBNR (volatile u8 *)IOP310_REG_ADDR(0x00001018) +#define IOP310_SBNR (volatile u8 *)IOP310_REG_ADDR(0x00001019) +#define IOP310_SUBBNR (volatile u8 *)IOP310_REG_ADDR(0x0000101A) +#define IOP310_SLTR (volatile u8 *)IOP310_REG_ADDR(0x0000101B) +#define IOP310_IOBR (volatile u8 *)IOP310_REG_ADDR(0x0000101C) +#define IOP310_IOLR (volatile u8 *)IOP310_REG_ADDR(0x0000101D) +#define IOP310_SSR (volatile u16 *)IOP310_REG_ADDR(0x0000101E) +#define IOP310_MBR (volatile u16 *)IOP310_REG_ADDR(0x00001020) +#define IOP310_MLR (volatile u16 *)IOP310_REG_ADDR(0x00001022) +#define IOP310_PMBR (volatile u16 *)IOP310_REG_ADDR(0x00001024) +#define IOP310_PMLR (volatile u16 *)IOP310_REG_ADDR(0x00001026) +/* Reserved 0x00001028 through 0x00001033 */ +#define IOP310_CAPR (volatile u8 *)IOP310_REG_ADDR(0x00001034) +/* Reserved 0x00001035 through 0x0000103D */ +#define IOP310_BCR (volatile u16 *)IOP310_REG_ADDR(0x0000103E) +#define IOP310_EBCR (volatile u16 *)IOP310_REG_ADDR(0x00001040) +#define IOP310_SISR (volatile u16 *)IOP310_REG_ADDR(0x00001042) +#define IOP310_PBISR (volatile u32 *)IOP310_REG_ADDR(0x00001044) +#define IOP310_SBISR (volatile u32 *)IOP310_REG_ADDR(0x00001048) +#define IOP310_SACR (volatile u32 *)IOP310_REG_ADDR(0x0000104C) +#define IOP310_PIRSR (volatile u32 *)IOP310_REG_ADDR(0x00001050) +#define IOP310_SIOBR (volatile u8 *)IOP310_REG_ADDR(0x00001054) +#define IOP310_SIOLR (volatile u8 *)IOP310_REG_ADDR(0x00001055) +#define IOP310_SCDR (volatile u8 *)IOP310_REG_ADDR(0x00001056) + +#define IOP310_SMBR (volatile u16 *)IOP310_REG_ADDR(0x00001058) +#define IOP310_SMLR (volatile u16 *)IOP310_REG_ADDR(0x0000105A) +#define IOP310_SDER (volatile u16 *)IOP310_REG_ADDR(0x0000105C) +#define IOP310_QCR (volatile u16 *)IOP310_REG_ADDR(0x0000105E) +#define IOP310_CAPID (volatile u8 *)IOP310_REG_ADDR(0x00001068) +#define IOP310_NIPTR (volatile u8 *)IOP310_REG_ADDR(0x00001069) +#define IOP310_PMCR (volatile u16 *)IOP310_REG_ADDR(0x0000106A) +#define IOP310_PMCSR (volatile u16 *)IOP310_REG_ADDR(0x0000106C) +#define IOP310_PMCSRBSE (volatile u8 *)IOP310_REG_ADDR(0x0000106E) +/* Reserved 0x00001064 through 0x000010FFH */ + +/* Performance monitoring unit 0x00001100 through 0x000011FF*/ +#define IOP310_PMONGTMR (volatile u32 *)IOP310_REG_ADDR(0x00001100) +#define IOP310_PMONESR (volatile u32 *)IOP310_REG_ADDR(0x00001104) +#define IOP310_PMONEMISR (volatile u32 *)IOP310_REG_ADDR(0x00001108) +#define IOP310_PMONGTSR (volatile u32 *)IOP310_REG_ADDR(0x00001110) +#define IOP310_PMONPECR1 (volatile u32 *)IOP310_REG_ADDR(0x00001114) +#define IOP310_PMONPECR2 (volatile u32 *)IOP310_REG_ADDR(0x00001118) +#define IOP310_PMONPECR3 (volatile u32 *)IOP310_REG_ADDR(0x0000111C) +#define IOP310_PMONPECR4 (volatile u32 *)IOP310_REG_ADDR(0x00001120) +#define IOP310_PMONPECR5 (volatile u32 *)IOP310_REG_ADDR(0x00001124) +#define IOP310_PMONPECR6 (volatile u32 *)IOP310_REG_ADDR(0x00001128) +#define IOP310_PMONPECR7 (volatile u32 *)IOP310_REG_ADDR(0x0000112C) +#define IOP310_PMONPECR8 (volatile u32 *)IOP310_REG_ADDR(0x00001130) +#define IOP310_PMONPECR9 (volatile u32 *)IOP310_REG_ADDR(0x00001134) +#define IOP310_PMONPECR10 (volatile u32 *)IOP310_REG_ADDR(0x00001138) +#define IOP310_PMONPECR11 (volatile u32 *)IOP310_REG_ADDR(0x0000113C) +#define IOP310_PMONPECR12 (volatile u32 *)IOP310_REG_ADDR(0x00001140) +#define IOP310_PMONPECR13 (volatile u32 *)IOP310_REG_ADDR(0x00001144) +#define IOP310_PMONPECR14 (volatile u32 *)IOP310_REG_ADDR(0x00001148) + +/* Address Translation Unit 0x00001200 through 0x000012FF */ +#define IOP310_ATUVID (volatile u16 *)IOP310_REG_ADDR(0x00001200) +#define IOP310_ATUDID (volatile u16 *)IOP310_REG_ADDR(0x00001202) +#define IOP310_PATUCMD (volatile u16 *)IOP310_REG_ADDR(0x00001204) +#define IOP310_PATUSR (volatile u16 *)IOP310_REG_ADDR(0x00001206) +#define IOP310_ATURID (volatile u8 *)IOP310_REG_ADDR(0x00001208) +#define IOP310_ATUCCR (volatile u32 *)IOP310_REG_ADDR(0x00001209) +#define IOP310_ATUCLSR (volatile u8 *)IOP310_REG_ADDR(0x0000120C) +#define IOP310_ATULT (volatile u8 *)IOP310_REG_ADDR(0x0000120D) +#define IOP310_ATUHTR (volatile u8 *)IOP310_REG_ADDR(0x0000120E) + +#define IOP310_PIABAR (volatile u32 *)IOP310_REG_ADDR(0x00001210) +/* Reserved 0x00001214 through 0x0000122B */ +#define IOP310_ASVIR (volatile u16 *)IOP310_REG_ADDR(0x0000122C) +#define IOP310_ASIR (volatile u16 *)IOP310_REG_ADDR(0x0000122E) +#define IOP310_ERBAR (volatile u32 *)IOP310_REG_ADDR(0x00001230) +#define IOP310_ATUCAPPTR (volatile u8 *)IOP310_REG_ADDR(0x00001234) +/* Reserved 0x00001235 through 0x0000123B */ +#define IOP310_ATUILR (volatile u8 *)IOP310_REG_ADDR(0x0000123C) +#define IOP310_ATUIPR (volatile u8 *)IOP310_REG_ADDR(0x0000123D) +#define IOP310_ATUMGNT (volatile u8 *)IOP310_REG_ADDR(0x0000123E) +#define IOP310_ATUMLAT (volatile u8 *)IOP310_REG_ADDR(0x0000123F) +#define IOP310_PIALR (volatile u32 *)IOP310_REG_ADDR(0x00001240) +#define IOP310_PIATVR (volatile u32 *)IOP310_REG_ADDR(0x00001244) +#define IOP310_SIABAR (volatile u32 *)IOP310_REG_ADDR(0x00001248) +#define IOP310_SIALR (volatile u32 *)IOP310_REG_ADDR(0x0000124C) +#define IOP310_SIATVR (volatile u32 *)IOP310_REG_ADDR(0x00001250) +#define IOP310_POMWVR (volatile u32 *)IOP310_REG_ADDR(0x00001254) +/* Reserved 0x00001258 through 0x0000125B */ +#define IOP310_POIOWVR (volatile u32 *)IOP310_REG_ADDR(0x0000125C) +#define IOP310_PODWVR (volatile u32 *)IOP310_REG_ADDR(0x00001260) +#define IOP310_POUDR (volatile u32 *)IOP310_REG_ADDR(0x00001264) +#define IOP310_SOMWVR (volatile u32 *)IOP310_REG_ADDR(0x00001268) +#define IOP310_SOIOWVR (volatile u32 *)IOP310_REG_ADDR(0x0000126C) +/* Reserved 0x00001270 through 0x00001273*/ +#define IOP310_ERLR (volatile u32 *)IOP310_REG_ADDR(0x00001274) +#define IOP310_ERTVR (volatile u32 *)IOP310_REG_ADDR(0x00001278) +/* Reserved 0x00001279 through 0x0000127C*/ +#define IOP310_ATUCAPID (volatile u8 *)IOP310_REG_ADDR(0x00001280) +#define IOP310_ATUNIPTR (volatile u8 *)IOP310_REG_ADDR(0x00001281) +#define IOP310_APMCR (volatile u16 *)IOP310_REG_ADDR(0x00001282) +#define IOP310_APMCSR (volatile u16 *)IOP310_REG_ADDR(0x00001284) +/* Reserved 0x00001286 through 0x00001287 */ +#define IOP310_ATUCR (volatile u32 *)IOP310_REG_ADDR(0x00001288) +/* Reserved 0x00001289 through 0x0000128C*/ +#define IOP310_PATUISR (volatile u32 *)IOP310_REG_ADDR(0x00001290) +#define IOP310_SATUISR (volatile u32 *)IOP310_REG_ADDR(0x00001294) +#define IOP310_SATUCMD (volatile u16 *)IOP310_REG_ADDR(0x00001298) +#define IOP310_SATUSR (volatile u16 *)IOP310_REG_ADDR(0x0000129A) +#define IOP310_SODWVR (volatile u32 *)IOP310_REG_ADDR(0x0000129C) +#define IOP310_SOUDR (volatile u32 *)IOP310_REG_ADDR(0x000012A0) +#define IOP310_POCCAR (volatile u32 *)IOP310_REG_ADDR(0x000012A4) +#define IOP310_SOCCAR (volatile u32 *)IOP310_REG_ADDR(0x000012A8) +#define IOP310_POCCDR (volatile u32 *)IOP310_REG_ADDR(0x000012AC) +#define IOP310_SOCCDR (volatile u32 *)IOP310_REG_ADDR(0x000012B0) +#define IOP310_PAQCR (volatile u32 *)IOP310_REG_ADDR(0x000012B4) +#define IOP310_SAQCR (volatile u32 *)IOP310_REG_ADDR(0x000012B8) +#define IOP310_PATUIMR (volatile u32 *)IOP310_REG_ADDR(0x000012BC) +#define IOP310_SATUIMR (volatile u32 *)IOP310_REG_ADDR(0x000012C0) +/* Reserved 0x000012C4 through 0x000012FF */ +/* Messaging Unit 0x00001300 through 0x000013FF */ +#define IOP310_MUIMR0 (volatile u32 *)IOP310_REG_ADDR(0x00001310) +#define IOP310_MUIMR1 (volatile u32 *)IOP310_REG_ADDR(0x00001314) +#define IOP310_MUOMR0 (volatile u32 *)IOP310_REG_ADDR(0x00001318) +#define IOP310_MUOMR1 (volatile u32 *)IOP310_REG_ADDR(0x0000131C) +#define IOP310_MUIDR (volatile u32 *)IOP310_REG_ADDR(0x00001320) +#define IOP310_MUIISR (volatile u32 *)IOP310_REG_ADDR(0x00001324) +#define IOP310_MUIIMR (volatile u32 *)IOP310_REG_ADDR(0x00001328) +#define IOP310_MUODR (volatile u32 *)IOP310_REG_ADDR(0x0000132C) +#define IOP310_MUOISR (volatile u32 *)IOP310_REG_ADDR(0x00001330) +#define IOP310_MUOIMR (volatile u32 *)IOP310_REG_ADDR(0x00001334) +#define IOP310_MUMUCR (volatile u32 *)IOP310_REG_ADDR(0x00001350) +#define IOP310_MUQBAR (volatile u32 *)IOP310_REG_ADDR(0x00001354) +#define IOP310_MUIFHPR (volatile u32 *)IOP310_REG_ADDR(0x00001360) +#define IOP310_MUIFTPR (volatile u32 *)IOP310_REG_ADDR(0x00001364) +#define IOP310_MUIPHPR (volatile u32 *)IOP310_REG_ADDR(0x00001368) +#define IOP310_MUIPTPR (volatile u32 *)IOP310_REG_ADDR(0x0000136C) +#define IOP310_MUOFHPR (volatile u32 *)IOP310_REG_ADDR(0x00001370) +#define IOP310_MUOFTPR (volatile u32 *)IOP310_REG_ADDR(0x00001374) +#define IOP310_MUOPHPR (volatile u32 *)IOP310_REG_ADDR(0x00001378) +#define IOP310_MUOPTPR (volatile u32 *)IOP310_REG_ADDR(0x0000137C) +#define IOP310_MUIAR (volatile u32 *)IOP310_REG_ADDR(0x00001380) +/* DMA Controller 0x00001400 through 0x000014FF */ +#define IOP310_DMA0CCR (volatile u32 *)IOP310_REG_ADDR(0x00001400) +#define IOP310_DMA0CSR (volatile u32 *)IOP310_REG_ADDR(0x00001404) +/* Reserved 0x001408 through 0x00140B */ +#define IOP310_DMA0DAR (volatile u32 *)IOP310_REG_ADDR(0x0000140C) +#define IOP310_DMA0NDAR (volatile u32 *)IOP310_REG_ADDR(0x00001410) +#define IOP310_DMA0PADR (volatile u32 *)IOP310_REG_ADDR(0x00001414) +#define IOP310_DMA0PUADR (volatile u32 *)IOP310_REG_ADDR(0x00001418) +#define IOP310_DMA0LADR (volatile u32 *)IOP310_REG_ADDR(0x0000141C) +#define IOP310_DMA0BCR (volatile u32 *)IOP310_REG_ADDR(0x00001420) +#define IOP310_DMA0DCR (volatile u32 *)IOP310_REG_ADDR(0x00001424) +/* Reserved 0x00001428 through 0x0000143F */ +#define IOP310_DMA1CCR (volatile u32 *)IOP310_REG_ADDR(0x00001440) +#define IOP310_DMA1CSR (volatile u32 *)IOP310_REG_ADDR(0x00001444) +/* Reserved 0x00001448 through 0x0000144B */ +#define IOP310_DMA1DAR (volatile u32 *)IOP310_REG_ADDR(0x0000144C) +#define IOP310_DMA1NDAR (volatile u32 *)IOP310_REG_ADDR(0x00001450) +#define IOP310_DMA1PADR (volatile u32 *)IOP310_REG_ADDR(0x00001454) +#define IOP310_DMA1PUADR (volatile u32 *)IOP310_REG_ADDR(0x00001458) +#define IOP310_DMA1LADR (volatile u32 *)IOP310_REG_ADDR(0x0000145C) +#define IOP310_DMA1BCR (volatile u32 *)IOP310_REG_ADDR(0x00001460) +#define IOP310_DMA1DCR (volatile u32 *)IOP310_REG_ADDR(0x00001464) +/* Reserved 0x00001468 through 0x0000147F */ +#define IOP310_DMA2CCR (volatile u32 *)IOP310_REG_ADDR(0x00001480) +#define IOP310_DMA2CSR (volatile u32 *)IOP310_REG_ADDR(0x00001484) +/* Reserved 0x00001488 through 0x0000148B */ +#define IOP310_DMA2DAR (volatile u32 *)IOP310_REG_ADDR(0x0000148C) +#define IOP310_DMA2NDAR (volatile u32 *)IOP310_REG_ADDR(0x00001490) +#define IOP310_DMA2PADR (volatile u32 *)IOP310_REG_ADDR(0x00001494) +#define IOP310_DMA2PUADR (volatile u32 *)IOP310_REG_ADDR(0x00001498) +#define IOP310_DMA2LADR (volatile u32 *)IOP310_REG_ADDR(0x0000149C) +#define IOP310_DMA2BCR (volatile u32 *)IOP310_REG_ADDR(0x000014A0) +#define IOP310_DMA2DCR (volatile u32 *)IOP310_REG_ADDR(0x000014A4) + +/* Memory controller 0x00001500 through 0x0015FF */ + +/* core interface unit 0x00001640 - 0x0000167F */ +#define IOP310_CIUISR (volatile u32 *)IOP310_REG_ADDR(0x00001644) + +/* PCI and Peripheral Interrupt Controller 0x00001700 - 0x0000171B */ +#define IOP310_IRQISR (volatile u32 *)IOP310_REG_ADDR(0x00001700) +#define IOP310_FIQ2ISR (volatile u32 *)IOP310_REG_ADDR(0x00001704) +#define IOP310_FIQ1ISR (volatile u32 *)IOP310_REG_ADDR(0x00001708) +#define IOP310_PDIDR (volatile u32 *)IOP310_REG_ADDR(0x00001710) + +/* AAU registers. DJ 0x00001800 - 0x00001838 */ +#define IOP310_AAUACR (volatile u32 *)IOP310_REG_ADDR(0x00001800) +#define IOP310_AAUASR (volatile u32 *)IOP310_REG_ADDR(0x00001804) +#define IOP310_AAUADAR (volatile u32 *)IOP310_REG_ADDR(0x00001808) +#define IOP310_AAUANDAR (volatile u32 *)IOP310_REG_ADDR(0x0000180C) +#define IOP310_AAUSAR1 (volatile u32 *)IOP310_REG_ADDR(0x00001810) +#define IOP310_AAUSAR2 (volatile u32 *)IOP310_REG_ADDR(0x00001814) +#define IOP310_AAUSAR3 (volatile u32 *)IOP310_REG_ADDR(0x00001818) +#define IOP310_AAUSAR4 (volatile u32 *)IOP310_REG_ADDR(0x0000181C) +#define IOP310_AAUDAR (volatile u32 *)IOP310_REG_ADDR(0x00001820) +#define IOP310_AAUABCR (volatile u32 *)IOP310_REG_ADDR(0x00001824) +#define IOP310_AAUADCR (volatile u32 *)IOP310_REG_ADDR(0x00001828) +#define IOP310_AAUSAR5 (volatile u32 *)IOP310_REG_ADDR(0x0000182C) +#define IOP310_AAUSAR6 (volatile u32 *)IOP310_REG_ADDR(0x00001830) +#define IOP310_AAUSAR7 (volatile u32 *)IOP310_REG_ADDR(0x00001834) +#define IOP310_AAUSAR8 (volatile u32 *)IOP310_REG_ADDR(0x00001838) + +#endif // _IOP310_HW_H_ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/iq80310.h linux-2.5/include/asm-arm/arch-iop310/iq80310.h --- linux-2.5.1/include/asm-arm/arch-iop310/iq80310.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/iq80310.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,30 @@ +/* + * linux/include/asm/arch-iop80310/iq80310.h + * + * Intel IQ-80310 evaluation board registers + */ + +#ifndef _IQ80310_H_ +#define _IQ80310_H_ + +#define IQ80310_RAMBASE 0xa0000000 +#define IQ80310_UART1 0xfe800000 /* UART #1 */ +#define IQ80310_UART2 0xfe810000 /* UART #2 */ +#define IQ80310_INT_STAT 0xfe820000 /* Interrupt (XINT3#) Status */ +#define IQ80310_BOARD_REV 0xfe830000 /* Board revision register */ +#define IQ80310_CPLD_REV 0xfe840000 /* CPLD revision register */ +#define IQ80310_7SEG_1 0xfe840000 /* 7-Segment MSB */ +#define IQ80310_7SEG_0 0xfe850000 /* 7-Segment LSB (WO) */ +#define IQ80310_PCI_INT_STAT 0xfe850000 /* PCI Interrupt Status */ +#define IQ80310_INT_MASK 0xfe860000 /* Interrupt (XINT3#) Mask */ +#define IQ80310_BACKPLANE 0xfe870000 /* Backplane Detect */ +#define IQ80310_TIMER_LA0 0xfe880000 /* Timer LA0 */ +#define IQ80310_TIMER_LA1 0xfe890000 /* Timer LA1 */ +#define IQ80310_TIMER_LA2 0xfe8a0000 /* Timer LA2 */ +#define IQ80310_TIMER_LA3 0xfe8b0000 /* Timer LA3 */ +#define IQ80310_TIMER_EN 0xfe8c0000 /* Timer Enable */ +#define IQ80310_ROTARY_SW 0xfe8d0000 /* Rotary Switch */ +#define IQ80310_JTAG 0xfe8e0000 /* JTAG Port Access */ +#define IQ80310_BATT_STAT 0xfe8f0000 /* Battery Status */ + +#endif // _IQ80310_H_ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/irq.h linux-2.5/include/asm-arm/arch-iop310/irq.h --- linux-2.5.1/include/asm-arm/arch-iop310/irq.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/irq.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,13 @@ +/* + * linux/include/asm-arm/arch-iop80310/irq.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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. + */ + +#define fixup_irq(irq) (irq) + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/irqs.h linux-2.5/include/asm-arm/arch-iop310/irqs.h --- linux-2.5.1/include/asm-arm/arch-iop310/irqs.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/irqs.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,80 @@ +/* + * linux/include/asm-arm/arch-iop310/irqs.h + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + * 06/13/01: Added 80310 on-chip interrupt sources <dsaxena@mvista.com> + * + */ + + +/* + * XS80200 specific IRQs + */ +#define IRQ_XS80200_BCU 0 /* Bus Control Unit */ +#define IRQ_XS80200_PMU 1 /* Performance Monitoring Unit */ +#define IRQ_XS80200_EXTIRQ 2 /* external IRQ signal */ +#define IRQ_XS80200_EXTFIQ 3 /* external IRQ signal */ + +#define NR_XS80200_IRQS 4 + +#define XSCALE_PMU_IRQ IRQ_XS80200_PMU + +/* + * IOP80310 chipset interrupts + */ +#define IOP310_IRQ_OFS NR_XS80200_IRQS +#define IOP310_IRQ(x) (IOP310_IRQ_OFS + (x)) + +/* + * On FIQ1ISR register + */ +#define IRQ_IOP310_DMA0 IOP310_IRQ(0) /* DMA Channel 0 */ +#define IRQ_IOP310_DMA1 IOP310_IRQ(1) /* DMA Channel 1 */ +#define IRQ_IOP310_DMA2 IOP310_IRQ(2) /* DMA Channel 2 */ +#define IRQ_IOP310_PMON IOP310_IRQ(3) /* Bus performance Unit */ +#define IRQ_IOP310_AAU IOP310_IRQ(4) /* Application Accelator Unit */ + +/* + * On FIQ2ISR register + */ +#define IRQ_IOP310_I2C IOP310_IRQ(5) /* I2C unit */ +#define IRQ_IOP310_MU IOP310_IRQ(6) /* messaging unit */ + +#define NR_IOP310_IRQS (IOP310_IRQ(6) + 1) + +#define NR_IRQS NR_IOP310_IRQS + + +/* + * Interrupts available on the Cyclone IQ80310 board + */ +#ifdef CONFIG_ARCH_IQ80310 + +#define IQ80310_IRQ_OFS NR_IOP310_IRQS +#define IQ80310_IRQ(y) ((IQ80310_IRQ_OFS) + (y)) + +#define IRQ_IQ80310_TIMER IQ80310_IRQ(0) /* Timer Interrupt */ +#define IRQ_IQ80310_I82559 IQ80310_IRQ(1) /* I82559 Ethernet Interrupt */ +#define IRQ_IQ80310_UART1 IQ80310_IRQ(2) /* UART1 Interrupt */ +#define IRQ_IQ80310_UART2 IQ80310_IRQ(3) /* UART2 Interrupt */ +#define IRQ_IQ80310_INTD IQ80310_IRQ(4) /* PCI INTD */ + + +/* + * ONLY AVAILABLE ON REV F OR NEWER BOARDS! + */ +#define IRQ_IQ80310_INTA IQ80310_IRQ(5) /* PCI INTA */ +#define IRQ_IQ80310_INTB IQ80310_IRQ(6) /* PCI INTB */ +#define IRQ_IQ80310_INTC IQ80310_IRQ(7) /* PCI INTC */ + +#undef NR_IRQS +#define NR_IRQS (IQ80310_IRQ(7) + 1) + +#endif // CONFIG_ARCH_IQ80310 + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/memory.h linux-2.5/include/asm-arm/arch-iop310/memory.h --- linux-2.5.1/include/asm-arm/arch-iop310/memory.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/memory.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,58 @@ +/* + * linux/include/asm-arm/arch-iop80310/memory.h + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + + +/* + * Task size: 3GB + */ +#define TASK_SIZE (0xc0000000UL) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +/* + * Page offset: 3GB + */ +#define PAGE_OFFSET (0xc0000000UL) + +/* + * Physical DRAM offset. + */ +#define PHYS_OFFSET (0xa0000000UL) + +/* + * physical vs virtual ram conversion + */ +#define __virt_to_phys__is_a_macro +#define __phys_to_virt__is_a_macro +#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) +#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + */ +#define __virt_to_bus__is_a_macro +#define __bus_to_virt__is_a_macro +#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP310_SIATVR)) | ((*IOP310_SIABAR) & 0xfffffff0)) +#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP310_SIALR)) | ( *IOP310_SIATVR))) + +#define PHYS_TO_NID(x) 0 + +/* boot mem allocate global pointer for MU circular queues QBAR */ +#ifdef CONFIG_IOP310_MU +extern void *mu_mem; +#endif + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/param.h linux-2.5/include/asm-arm/arch-iop310/param.h --- linux-2.5.1/include/asm-arm/arch-iop310/param.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/param.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,3 @@ +/* + * linux/include/asm-arm/arch-iop80310/param.h + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/pmon.h linux-2.5/include/asm-arm/arch-iop310/pmon.h --- linux-2.5.1/include/asm-arm/arch-iop310/pmon.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/pmon.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,50 @@ +/* + * Definitions for XScale 80312 PMON + * (C) 2001 Intel Corporation + * Author: Chen Chen(chen.chen@intel.com) + * + * 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. + */ + +#ifndef _IOP310_PMON_H_ +#define _IOP310_PMON_H_ + +/* + * Different modes for Event Select Register for intel 80312 + */ + +#define IOP310_PMON_MODE0 0x00000000 +#define IOP310_PMON_MODE1 0x00000001 +#define IOP310_PMON_MODE2 0x00000002 +#define IOP310_PMON_MODE3 0x00000003 +#define IOP310_PMON_MODE4 0x00000004 +#define IOP310_PMON_MODE5 0x00000005 +#define IOP310_PMON_MODE6 0x00000006 +#define IOP310_PMON_MODE7 0x00000007 + +typedef struct _iop310_pmon_result +{ + u32 timestamp; /* Global Time Stamp Register */ + u32 timestamp_overflow; /* Time Stamp overflow count */ + u32 event_count[14]; /* Programmable Event Counter + Registers 1-14 */ + u32 event_overflow[14]; /* Overflow counter for PECR1-14 */ +} iop310_pmon_res_t; + +/* function prototypes */ + +/* Claim IQ80312 PMON for usage */ +int iop310_pmon_claim(void); + +/* Start IQ80312 PMON */ +int iop310_pmon_start(int, int); + +/* Stop Performance Monitor Unit */ +int iop310_pmon_stop(iop310_pmon_res_t *); + +/* Release IQ80312 PMON */ +int iop310_pmon_release(int); + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/serial.h linux-2.5/include/asm-arm/arch-iop310/serial.h --- linux-2.5.1/include/asm-arm/arch-iop310/serial.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/serial.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,34 @@ +/* + * include/asm-arm/arch-iop310/serial.h + */ + + +/* + * This assumes you have a 1.8432 MHz clock for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ +#define BASE_BAUD ( 1843200 / 16 ) + +/* Standard COM flags */ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#ifdef CONFIG_ARCH_IQ80310 + +#define IRQ_UART1 IRQ_IQ80310_UART1 +#define IRQ_UART2 IRQ_IQ80310_UART2 + +#define RS_TABLE_SIZE 2 + +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0xfe810000, IRQ_UART2, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0xfe800000, IRQ_UART1, STD_COM_FLAGS } /* ttyS1 */ + +#endif // CONFIG_ARCH_IQ80310 + + +#define EXTRA_SERIAL_PORT_DEFNS + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/system.h linux-2.5/include/asm-arm/arch-iop310/system.h --- linux-2.5.1/include/asm-arm/arch-iop310/system.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/system.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,30 @@ +/* + * linux/include/asm-arm/arch-iop80310/system.h + * + * Copyright (C) 2001 MontaVista Software, Inc. + * + * 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. + */ + +static inline void arch_idle(void) +{ + if (!hlt_counter) + { + cpu_do_idle(0); + } +} + + +static inline void arch_reset(char mode) +{ + if ( 1 && mode == 's') { + /* Jump into ROM at address 0 */ + cpu_reset(0); + } else { + /* No on-chip reset capability */ + cpu_reset(0); + } +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/time.h linux-2.5/include/asm-arm/arch-iop310/time.h --- linux-2.5.1/include/asm-arm/arch-iop310/time.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/time.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,12 @@ +/* + * linux/include/asm-arm/arch-iop80310/time.h + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * 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. + * + */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/timex.h linux-2.5/include/asm-arm/arch-iop310/timex.h --- linux-2.5.1/include/asm-arm/arch-iop310/timex.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/timex.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,23 @@ +/* + * linux/include/asm-arm/arch-iop80310/timex.h + * + * IOP310 architecture timex specifications + */ + + + +#ifdef CONFIG_ARCH_IQ80310 + +#ifndef CONFIG_XSCALE_PMU_TIMER +/* This is for the on-board timer */ +#define CLOCK_TICK_RATE 33000000 /* Underlying HZ */ +#else +/* This is for the underlying xs80200 PMU clock. We run the core @ 733MHz */ +#define CLOCK_TICK_RATE 733000000 +#endif + +#else + +#error "No IOP310 timex information for this architecture" + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/uncompress.h linux-2.5/include/asm-arm/arch-iop310/uncompress.h --- linux-2.5.1/include/asm-arm/arch-iop310/uncompress.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/uncompress.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,33 @@ +/* + * linux/include/asm-arm/arch-iop80310/uncompress.h + */ + +#ifdef CONFIG_ARCH_IQ80310 +#define UART1_BASE ((volatile unsigned char *)0xfe800000) +#define UART2_BASE ((volatile unsigned char *)0xfe810000) +#endif + +static __inline__ void putc(char c) +{ + while ((UART2_BASE[5] & 0x60) != 0x60); + UART2_BASE[0] = c; +} + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + while (*s) { + putc(*s); + if (*s == '\n') + putc('\r'); + s++; + } +} + +/* + * nothing to do + */ +#define arch_decomp_setup() +#define arch_decomp_wdog() diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-iop310/vmalloc.h linux-2.5/include/asm-arm/arch-iop310/vmalloc.h --- linux-2.5.1/include/asm-arm/arch-iop310/vmalloc.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-iop310/vmalloc.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,16 @@ +/* + * linux/include/asm-arm/arch-iop310/vmalloc.h + */ + +/* + * 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. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (0xe8000000) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-l7200/io.h linux-2.5/include/asm-arm/arch-l7200/io.h --- linux-2.5.1/include/asm-arm/arch-l7200/io.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-l7200/io.h Sun Jan 6 01:38:27 2002 @@ -73,6 +73,4 @@ #define outw(v,p) outw_t(v,p) #define outl(v,p) outl_t(v,p) -#define __arch_ioremap __ioremap - #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-l7200/irq.h linux-2.5/include/asm-arm/arch-l7200/irq.h --- linux-2.5.1/include/asm-arm/arch-l7200/irq.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/arch-l7200/irq.h Sun Jan 6 01:38:27 2002 @@ -9,60 +9,4 @@ * 04-15-2000 RS Made dependent on hardware.h * 05-05-2000 SJH Complete rewrite */ - -#include <asm/arch/hardware.h> - -/* - * IRQ base register - */ -#define IRQ_BASE (IO_BASE_2 + 0x1000) - -/* - * Normal IRQ registers - */ -#define IRQ_STATUS (*(volatile unsigned long *) (IRQ_BASE + 0x000)) -#define IRQ_RAWSTATUS (*(volatile unsigned long *) (IRQ_BASE + 0x004)) -#define IRQ_ENABLE (*(volatile unsigned long *) (IRQ_BASE + 0x008)) -#define IRQ_ENABLECLEAR (*(volatile unsigned long *) (IRQ_BASE + 0x00c)) -#define IRQ_SOFT (*(volatile unsigned long *) (IRQ_BASE + 0x010)) -#define IRQ_SOURCESEL (*(volatile unsigned long *) (IRQ_BASE + 0x018)) - -/* - * Fast IRQ registers - */ -#define FIQ_STATUS (*(volatile unsigned long *) (IRQ_BASE + 0x100)) -#define FIQ_RAWSTATUS (*(volatile unsigned long *) (IRQ_BASE + 0x104)) -#define FIQ_ENABLE (*(volatile unsigned long *) (IRQ_BASE + 0x108)) -#define FIQ_ENABLECLEAR (*(volatile unsigned long *) (IRQ_BASE + 0x10c)) -#define FIQ_SOFT (*(volatile unsigned long *) (IRQ_BASE + 0x110)) -#define FIQ_SOURCESEL (*(volatile unsigned long *) (IRQ_BASE + 0x118)) - #define fixup_irq(x) (x) - -static void l7200_mask_irq(unsigned int irq) -{ - IRQ_ENABLECLEAR = 1 << irq; -} - -static void l7200_unmask_irq(unsigned int irq) -{ - IRQ_ENABLE = 1 << irq; -} - -static __inline__ void irq_init_irq(void) -{ - int irq; - - IRQ_ENABLECLEAR = 0xffffffff; /* clear all interrupt enables */ - FIQ_ENABLECLEAR = 0xffffffff; /* clear all fast interrupt enables */ - - for (irq = 0; irq < NR_IRQS; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = l7200_mask_irq; - irq_desc[irq].mask = l7200_mask_irq; - irq_desc[irq].unmask = l7200_unmask_irq; - } - - init_FIQ(); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-l7200/keyboard.h linux-2.5/include/asm-arm/arch-l7200/keyboard.h --- linux-2.5.1/include/asm-arm/arch-l7200/keyboard.h Wed May 16 22:25:16 2001 +++ linux-2.5/include/asm-arm/arch-l7200/keyboard.h Sun Jan 6 01:38:27 2002 @@ -17,6 +17,8 @@ #include <asm/irq.h> +#error This needs fixing --rmk + /* * Layout of L7200 keyboard registers */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-l7200/time.h linux-2.5/include/asm-arm/arch-l7200/time.h --- linux-2.5.1/include/asm-arm/arch-l7200/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-l7200/time.h Sun Jan 6 01:38:27 2002 @@ -52,7 +52,7 @@ /* * Set up RTC timer interrupt, and return the current time in seconds. */ -static inline void setup_timer(void) +void __init time_init(void) { RTC_RTCC = 0; /* Clear interrupt */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-nexuspci/io.h linux-2.5/include/asm-arm/arch-nexuspci/io.h --- linux-2.5.1/include/asm-arm/arch-nexuspci/io.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-nexuspci/io.h Sun Jan 6 01:38:27 2002 @@ -37,12 +37,6 @@ #endif /* - * Generic virtual read/write - */ -#define __arch_getw(a) (*(volatile unsigned short *)(a)) -#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) - -/* * ioremap support - validate a PCI memory address, * and convert a PCI memory address to a physical * address for the page tables. @@ -50,5 +44,16 @@ #define iomem_valid_addr(iomem,sz) \ ((iomem) < 0x80000000 && (iomem) + (sz) <= 0x80000000) #define iomem_to_phys(iomem) ((iomem) + PLX_MEM_START) + +#define __arch_ioremap(off,sz,nocache) \ + ({ \ + unsigned long _off = (off), _size = (sz); \ + void *_ret = (void *)0; \ + if (iomem_valid_addr(_off, _size)) \ + _ret = __ioremap(iomem_to_phys(_off),_size,0); \ + _ret; \ + }) + +#define __arch_iounmap __iounmap #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-nexuspci/irq.h linux-2.5/include/asm-arm/arch-nexuspci/irq.h --- linux-2.5.1/include/asm-arm/arch-nexuspci/irq.h Mon Sep 18 22:15:23 2000 +++ linux-2.5/include/asm-arm/arch-nexuspci/irq.h Sun Jan 6 01:38:27 2002 @@ -10,60 +10,5 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ - -#include <asm/io.h> - #define fixup_irq(x) (x) -extern unsigned long soft_irq_mask; - -static const unsigned char irq_cmd[] = -{ - INTCONT_IRQ_DUART, - INTCONT_IRQ_PLX, - INTCONT_IRQ_D, - INTCONT_IRQ_C, - INTCONT_IRQ_B, - INTCONT_IRQ_A, - INTCONT_IRQ_SYSERR -}; - -static void ftvpci_mask_irq(unsigned int irq) -{ - __raw_writel(irq_cmd[irq], INTCONT_BASE); - soft_irq_mask &= ~(1<<irq); -} - -static void ftvpci_unmask_irq(unsigned int irq) -{ - soft_irq_mask |= (1<<irq); - __raw_writel(irq_cmd[irq] | 1, INTCONT_BASE); -} - -static __inline__ void irq_init_irq(void) -{ - unsigned int i; - - /* Mask all FIQs */ - __raw_writel(INTCONT_FIQ_PLX, INTCONT_BASE); - __raw_writel(INTCONT_FIQ_D, INTCONT_BASE); - __raw_writel(INTCONT_FIQ_C, INTCONT_BASE); - __raw_writel(INTCONT_FIQ_B, INTCONT_BASE); - __raw_writel(INTCONT_FIQ_A, INTCONT_BASE); - __raw_writel(INTCONT_FIQ_SYSERR, INTCONT_BASE); - - /* Disable all interrupts initially. */ - for (i = 0; i < NR_IRQS; i++) { - if (i >= FIRST_IRQ && i <= LAST_IRQ) { - irq_desc[i].valid = 1; - irq_desc[i].probe_ok = 1; - irq_desc[i].mask_ack = ftvpci_mask_irq; - irq_desc[i].mask = ftvpci_mask_irq; - irq_desc[i].unmask = ftvpci_unmask_irq; - ftvpci_mask_irq(i); - } else { - irq_desc[i].valid = 0; - irq_desc[i].probe_ok = 0; - } - } -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-nexuspci/time.h linux-2.5/include/asm-arm/arch-nexuspci/time.h --- linux-2.5.1/include/asm-arm/arch-nexuspci/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-nexuspci/time.h Sun Jan 6 01:38:27 2002 @@ -43,7 +43,7 @@ do_timer(regs); } -static inline void setup_timer(void) +void __init time_init(void) { int tick = 3686400 / 16 / 2 / 100; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-rpc/io.h linux-2.5/include/asm-arm/arch-rpc/io.h --- linux-2.5.1/include/asm-arm/arch-rpc/io.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-rpc/io.h Sun Jan 6 01:38:27 2002 @@ -241,4 +241,10 @@ /* the following macro is depreciated */ #define ioaddr(port) __ioaddr((port)) +#define insb(p,d,l) __raw_readsb(__ioaddr(p),d,l) +#define insw(p,d,l) __raw_readsw(__ioaddr(p),d,l) + +#define outsb(p,d,l) __raw_writesb(__ioaddr(p),d,l) +#define outsw(p,d,l) __raw_writesw(__ioaddr(p),d,l) + #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-rpc/irq.h linux-2.5/include/asm-arm/arch-rpc/irq.h --- linux-2.5.1/include/asm-arm/arch-rpc/irq.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/arch-rpc/irq.h Sun Jan 6 01:38:27 2002 @@ -11,142 +11,4 @@ * 10-10-1996 RMK Brought up to date with arch-sa110eval * 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - 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 val, mask; - - mask = 1 << (irq & 7); - val = iomd_readb(IOMD_FIQMASK); - iomd_writeb(val | mask, IOMD_FIQMASK); -} - -static __inline__ void irq_init_irq(void) -{ - int irq; - - 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) { - case 0 ... 6: - irq_desc[irq].probe_ok = 1; - case 7: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = rpc_mask_irq_ack_a; - irq_desc[irq].mask = rpc_mask_irq_a; - irq_desc[irq].unmask = rpc_unmask_irq_a; - break; - - case 9 ... 15: - irq_desc[irq].probe_ok = 1; - case 8: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = rpc_mask_irq_b; - irq_desc[irq].mask = rpc_mask_irq_b; - irq_desc[irq].unmask = rpc_unmask_irq_b; - break; - - 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 64 ... 71: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = rpc_mask_irq_fiq; - irq_desc[irq].mask = rpc_mask_irq_fiq; - irq_desc[irq].unmask = rpc_unmask_irq_fiq; - break; - } - } - - irq_desc[IRQ_KEYBOARDTX].noautoenable = 1; - - init_FIQ(); -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-rpc/time.h linux-2.5/include/asm-arm/arch-rpc/time.h --- linux-2.5.1/include/asm-arm/arch-rpc/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-rpc/time.h Sun Jan 6 01:38:27 2002 @@ -24,7 +24,7 @@ /* * Set up timer interrupt. */ -static inline void setup_timer(void) +void __init time_init(void) { ioctime_init(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/SA-1111.h linux-2.5/include/asm-arm/arch-sa1100/SA-1111.h --- linux-2.5.1/include/asm-arm/arch-sa1100/SA-1111.h Thu Oct 25 20:53:54 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/SA-1111.h Sun Jan 6 01:38:27 2002 @@ -1,647 +1,5 @@ /* - * linux/include/asm/arch/SA-1111.h - * - * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu> - * - * This file contains definitions for the SA-1111 Companion Chip. - * (Structure and naming borrowed from SA-1101.h, by Peter Danielsson.) - * + * Moved to new location */ - -#ifndef _ASM_ARCH_SA1111 -#define _ASM_ARCH_SA1111 - -#include <asm/arch/bitfield.h> - -/* - * Macro that calculates real address for registers in the SA-1111 - */ - -#define _SA1111( x ) ((x) + SA1111_BASE) - -/* - * 26 bits of the SA-1110 address bus are available to the SA-1111. - * Use these when feeding target addresses to the DMA engines. - */ - -#define SA1111_ADDR_WIDTH (26) -#define SA1111_ADDR_MASK ((1<<SA1111_ADDR_WIDTH)-1) -#define SA1111_DMA_ADDR(x) ((x)&SA1111_ADDR_MASK) - -/* - * Don't ask the (SAC) DMA engines to move less than this amount. - */ - -#define SA1111_SAC_DMA_MIN_XFER (0x800) - -/* - * SA1111 register definitions. - */ -#define __CCREG(x) __REGP(SA1111_VBASE + (x)) - -/* System Bus Interface (SBI) - * - * Registers - * SKCR Control Register - * SMCR Shared Memory Controller Register - * SKID ID Register - */ - -#define _SBI_SKCR _SA1111(0x0000) -#define _SBI_SMCR _SA1111(0x0004) -#define _SBI_SKID _SA1111(0x0008) - -#if LANGUAGE == C - -#define SBI_SKCR __CCREG(0x0000) -#define SBI_SMCR __CCREG(0x0004) -#define SBI_SKID __CCREG(0x0008) - -#endif /* LANGUAGE == C */ - -#define SKCR_PLL_BYPASS (1<<0) -#define SKCR_RCLKEN (1<<1) -#define SKCR_SLEEP (1<<2) -#define SKCR_DOZE (1<<3) -#define SKCR_VCO_OFF (1<<4) -#define SKCR_SCANTSTEN (1<<5) -#define SKCR_CLKTSTEN (1<<6) -#define SKCR_RDYEN (1<<7) -#define SKCR_SELAC (1<<8) -#define SKCR_OPPC (1<<9) -#define SKCR_PLLTSTEN (1<<10) -#define SKCR_USBIOTSTEN (1<<11) -/* - * Don't believe the specs! Take them, throw them outside. Leave them - * there for a week. Spit on them. Walk on them. Stamp on them. - * Pour gasoline over them and finally burn them. Now think about coding. - * - The October 1999 errata (278260-007) says its bit 13, 1 to enable. - * - The Feb 2001 errata (278260-010) says that the previous errata - * (278260-009) is wrong, and its bit actually 12, fixed in spec - * 278242-003. - * - The SA1111 manual (278242) says bit 12, but 0 to enable. - * - Reality is bit 13, 1 to enable. - * -- rmk - */ -#define SKCR_OE_EN (1<<13) - -#define SMCR_DTIM (1<<0) -#define SMCR_MBGE (1<<1) -#define SMCR_DRAC_0 (1<<2) -#define SMCR_DRAC_1 (1<<3) -#define SMCR_DRAC_2 (1<<4) -#define SMCR_DRAC Fld(3, 2) -#define SMCR_CLAT (1<<5) - -#define SKID_SIREV_MASK (0x000000f0) -#define SKID_MTREV_MASK (0x0000000f) -#define SKID_ID_MASK (0xffffff00) -#define SKID_SA1111_ID (0x690cc200) - -/* - * System Controller - * - * Registers - * SKPCR Power Control Register - * SKCDR Clock Divider Register - * SKAUD Audio Clock Divider Register - * SKPMC PS/2 Mouse Clock Divider Register - * SKPTC PS/2 Track Pad Clock Divider Register - * SKPEN0 PWM0 Enable Register - * SKPWM0 PWM0 Clock Register - * SKPEN1 PWM1 Enable Register - * SKPWM1 PWM1 Clock Register - */ - -#define _SKPCR _SA1111(0x0200) -#define _SKCDR _SA1111(0x0204) -#define _SKAUD _SA1111(0x0208) -#define _SKPMC _SA1111(0x020c) -#define _SKPTC _SA1111(0x0210) -#define _SKPEN0 _SA1111(0x0214) -#define _SKPWM0 _SA1111(0x0218) -#define _SKPEN1 _SA1111(0x021c) -#define _SKPWM1 _SA1111(0x0220) - -#if LANGUAGE == C - -#define SKPCR __CCREG(0x0200) -#define SKCDR __CCREG(0x0204) -#define SKAUD __CCREG(0x0208) -#define SKPMC __CCREG(0x020c) -#define SKPTC __CCREG(0x0210) -#define SKPEN0 __CCREG(0x0214) -#define SKPWM0 __CCREG(0x0218) -#define SKPEN1 __CCREG(0x021c) -#define SKPWM1 __CCREG(0x0220) - -#endif /* LANGUAGE == C */ - -#define SKPCR_UCLKEN (1<<0) -#define SKPCR_ACCLKEN (1<<1) -#define SKPCR_I2SCLKEN (1<<2) -#define SKPCR_L3CLKEN (1<<3) -#define SKPCR_SCLKEN (1<<4) -#define SKPCR_PMCLKEN (1<<5) -#define SKPCR_PTCLKEN (1<<6) -#define SKPCR_DCLKEN (1<<7) -#define SKPCR_PWMCLKEN (1<<8) - -/* - * USB Host controller - */ -#define _USB_OHCI_OP_BASE _SA1111( 0x400 ) -#define _USB_STATUS _SA1111( 0x518 ) -#define _USB_RESET _SA1111( 0x51c ) -#define _USB_INTERRUPTEST _SA1111( 0x520 ) - -#define _USB_EXTENT (_USB_INTERRUPTEST - _USB_OHCI_OP_BASE + 4) - -#if LANGUAGE == C - -#define USB_OHCI_OP_BASE __CCREG(0x0400) -#define USB_STATUS __CCREG(0x0518) -#define USB_RESET __CCREG(0x051c) -#define USB_INTERRUPTEST __CCReG(0x0520) - -#endif /* LANGUAGE == C */ - -#define USB_RESET_FORCEIFRESET (1 << 0) -#define USB_RESET_FORCEHCRESET (1 << 1) -#define USB_RESET_CLKGENRESET (1 << 2) -#define USB_RESET_SIMSCALEDOWN (1 << 3) -#define USB_RESET_USBINTTEST (1 << 4) -#define USB_RESET_SLEEPSTBYEN (1 << 5) -#define USB_RESET_PWRSENSELOW (1 << 6) -#define USB_RESET_PWRCTRLLOW (1 << 7) - -/* - * Serial Audio Controller - * - * Registers - * SACR0 Serial Audio Common Control Register - * SACR1 Serial Audio Alternate Mode (I2C/MSB) Control Register - * SACR2 Serial Audio AC-link Control Register - * SASR0 Serial Audio I2S/MSB Interface & FIFO Status Register - * SASR1 Serial Audio AC-link Interface & FIFO Status Register - * SASCR Serial Audio Status Clear Register - * L3_CAR L3 Control Bus Address Register - * L3_CDR L3 Control Bus Data Register - * ACCAR AC-link Command Address Register - * ACCDR AC-link Command Data Register - * ACSAR AC-link Status Address Register - * ACSDR AC-link Status Data Register - * SADTCS Serial Audio DMA Transmit Control/Status Register - * SADTSA Serial Audio DMA Transmit Buffer Start Address A - * SADTCA Serial Audio DMA Transmit Buffer Count Register A - * SADTSB Serial Audio DMA Transmit Buffer Start Address B - * SADTCB Serial Audio DMA Transmit Buffer Count Register B - * SADRCS Serial Audio DMA Receive Control/Status Register - * SADRSA Serial Audio DMA Receive Buffer Start Address A - * SADRCA Serial Audio DMA Receive Buffer Count Register A - * SADRSB Serial Audio DMA Receive Buffer Start Address B - * SADRCB Serial Audio DMA Receive Buffer Count Register B - * SAITR Serial Audio Interrupt Test Register - * SADR Serial Audio Data Register (16 x 32-bit) - */ - -#define _SACR0 _SA1111( 0x0600 ) -#define _SACR1 _SA1111( 0x0604 ) -#define _SACR2 _SA1111( 0x0608 ) -#define _SASR0 _SA1111( 0x060c ) -#define _SASR1 _SA1111( 0x0610 ) -#define _SASCR _SA1111( 0x0618 ) -#define _L3_CAR _SA1111( 0x061c ) -#define _L3_CDR _SA1111( 0x0620 ) -#define _ACCAR _SA1111( 0x0624 ) -#define _ACCDR _SA1111( 0x0628 ) -#define _ACSAR _SA1111( 0x062c ) -#define _ACSDR _SA1111( 0x0630 ) -#define _SADTCS _SA1111( 0x0634 ) -#define _SADTSA _SA1111( 0x0638 ) -#define _SADTCA _SA1111( 0x063c ) -#define _SADTSB _SA1111( 0x0640 ) -#define _SADTCB _SA1111( 0x0644 ) -#define _SADRCS _SA1111( 0x0648 ) -#define _SADRSA _SA1111( 0x064c ) -#define _SADRCA _SA1111( 0x0650 ) -#define _SADRSB _SA1111( 0x0654 ) -#define _SADRCB _SA1111( 0x0658 ) -#define _SAITR _SA1111( 0x065c ) -#define _SADR _SA1111( 0x0680 ) - -#if LANGUAGE == C - -#define SACR0 __CCREG(0x0600) -#define SACR1 __CCREG(0x0604) -#define SACR2 __CCREG(0x0608) -#define SASR0 __CCREG(0x060c) -#define SASR1 __CCREG(0x0610) -#define SASCR __CCREG(0x0618) -#define L3_CAR __CCREG(0x061c) -#define L3_CDR __CCREG(0x0620) -#define ACCAR __CCREG(0x0624) -#define ACCDR __CCREG(0x0628) -#define ACSAR __CCREG(0x062c) -#define ACSDR __CCREG(0x0630) -#define SADTCS __CCREG(0x0634) -#define SADTSA __CCREG(0x0638) -#define SADTCA __CCREG(0x063c) -#define SADTSB __CCREG(0x0640) -#define SADTCB __CCREG(0x0644) -#define SADRCS __CCREG(0x0648) -#define SADRSA __CCREG(0x064c) -#define SADRCA __CCREG(0x0650) -#define SADRSB __CCREG(0x0654) -#define SADRCB __CCREG(0x0658) -#define SAITR __CCREG(0x065c) -#define SADR __CCREG(0x0680) - -#endif /* LANGUAGE == C */ - -#define SACR0_ENB (1<<0) -#define SACR0_BCKD (1<<2) -#define SACR0_RST (1<<3) - -#define SACR1_AMSL (1<<0) -#define SACR1_L3EN (1<<1) -#define SACR1_L3MB (1<<2) -#define SACR1_DREC (1<<3) -#define SACR1_DRPL (1<<4) -#define SACR1_ENLBF (1<<5) - -#define SACR2_TS3V (1<<0) -#define SACR2_TS4V (1<<1) -#define SACR2_WKUP (1<<2) -#define SACR2_DREC (1<<3) -#define SACR2_DRPL (1<<4) -#define SACR2_ENLBF (1<<5) -#define SACR2_RESET (1<<6) - -#define SASR0_TNF (1<<0) -#define SASR0_RNE (1<<1) -#define SASR0_BSY (1<<2) -#define SASR0_TFS (1<<3) -#define SASR0_RFS (1<<4) -#define SASR0_TUR (1<<5) -#define SASR0_ROR (1<<6) -#define SASR0_L3WD (1<<16) -#define SASR0_L3RD (1<<17) - -#define SASR1_TNF (1<<0) -#define SASR1_RNE (1<<1) -#define SASR1_BSY (1<<2) -#define SASR1_TFS (1<<3) -#define SASR1_RFS (1<<4) -#define SASR1_TUR (1<<5) -#define SASR1_ROR (1<<6) -#define SASR1_CADT (1<<16) -#define SASR1_SADR (1<<17) -#define SASR1_RSTO (1<<18) -#define SASR1_CLPM (1<<19) -#define SASR1_CRDY (1<<20) -#define SASR1_RS3V (1<<21) -#define SASR1_RS4V (1<<22) - -#define SASCR_TUR (1<<5) -#define SASCR_ROR (1<<6) -#define SASCR_DTS (1<<16) -#define SASCR_RDD (1<<17) -#define SASCR_STO (1<<18) - -#define SADTCS_TDEN (1<<0) -#define SADTCS_TDIE (1<<1) -#define SADTCS_TDBDA (1<<3) -#define SADTCS_TDSTA (1<<4) -#define SADTCS_TDBDB (1<<5) -#define SADTCS_TDSTB (1<<6) -#define SADTCS_TBIU (1<<7) - -#define SADRCS_RDEN (1<<0) -#define SADRCS_RDIE (1<<1) -#define SADRCS_RDBDA (1<<3) -#define SADRCS_RDSTA (1<<4) -#define SADRCS_RDBDB (1<<5) -#define SADRCS_RDSTB (1<<6) -#define SADRCS_RBIU (1<<7) - -#define SAD_CS_DEN (1<<0) -#define SAD_CS_DIE (1<<1) /* Not functional on metal 1 */ -#define SAD_CS_DBDA (1<<3) /* Not functional on metal 1 */ -#define SAD_CS_DSTA (1<<4) -#define SAD_CS_DBDB (1<<5) /* Not functional on metal 1 */ -#define SAD_CS_DSTB (1<<6) -#define SAD_CS_BIU (1<<7) /* Not functional on metal 1 */ - -#define SAITR_TFS (1<<0) -#define SAITR_RFS (1<<1) -#define SAITR_TUR (1<<2) -#define SAITR_ROR (1<<3) -#define SAITR_CADT (1<<4) -#define SAITR_SADR (1<<5) -#define SAITR_RSTO (1<<6) -#define SAITR_TDBDA (1<<8) -#define SAITR_TDBDB (1<<9) -#define SAITR_RDBDA (1<<10) -#define SAITR_RDBDB (1<<11) - -/* - * General-Purpose I/O Interface - * - * Registers - * PA_DDR GPIO Block A Data Direction - * PA_DRR/PA_DWR GPIO Block A Data Value Register (read/write) - * PA_SDR GPIO Block A Sleep Direction - * PA_SSR GPIO Block A Sleep State - * PB_DDR GPIO Block B Data Direction - * PB_DRR/PB_DWR GPIO Block B Data Value Register (read/write) - * PB_SDR GPIO Block B Sleep Direction - * PB_SSR GPIO Block B Sleep State - * PC_DDR GPIO Block C Data Direction - * PC_DRR/PC_DWR GPIO Block C Data Value Register (read/write) - * PC_SDR GPIO Block C Sleep Direction - * PC_SSR GPIO Block C Sleep State - */ - -#define _PA_DDR _SA1111( 0x1000 ) -#define _PA_DRR _SA1111( 0x1004 ) -#define _PA_DWR _SA1111( 0x1004 ) -#define _PA_SDR _SA1111( 0x1008 ) -#define _PA_SSR _SA1111( 0x100c ) -#define _PB_DDR _SA1111( 0x1010 ) -#define _PB_DRR _SA1111( 0x1014 ) -#define _PB_DWR _SA1111( 0x1014 ) -#define _PB_SDR _SA1111( 0x1018 ) -#define _PB_SSR _SA1111( 0x101c ) -#define _PC_DDR _SA1111( 0x1020 ) -#define _PC_DRR _SA1111( 0x1024 ) -#define _PC_DWR _SA1111( 0x1024 ) -#define _PC_SDR _SA1111( 0x1028 ) -#define _PC_SSR _SA1111( 0x102c ) - -#if LANGUAGE == C - -#define PA_DDR __CCREG(0x1000) -#define PA_DRR __CCREG(0x1004) -#define PA_DWR __CCREG(0x1004) -#define PA_SDR __CCREG(0x1008) -#define PA_SSR __CCREG(0x100c) -#define PB_DDR __CCREG(0x1010) -#define PB_DRR __CCREG(0x1014) -#define PB_DWR __CCREG(0x1014) -#define PB_SDR __CCREG(0x1018) -#define PB_SSR __CCREG(0x101c) -#define PC_DDR __CCREG(0x1020) -#define PC_DRR __CCREG(0x1024) -#define PC_DWR __CCREG(0x1024) -#define PC_SDR __CCREG(0x1028) -#define PC_SSR __CCREG(0x102c) - -#endif /* LANGUAGE == C */ - -/* - * Interrupt Controller - * - * Registers - * INTTEST0 Test register 0 - * INTTEST1 Test register 1 - * INTEN0 Interrupt Enable register 0 - * INTEN1 Interrupt Enable register 1 - * INTPOL0 Interrupt Polarity selection 0 - * INTPOL1 Interrupt Polarity selection 1 - * INTTSTSEL Interrupt source selection - * INTSTATCLR0 Interrupt Status/Clear 0 - * INTSTATCLR1 Interrupt Status/Clear 1 - * INTSET0 Interrupt source set 0 - * INTSET1 Interrupt source set 1 - * WAKE_EN0 Wake-up source enable 0 - * WAKE_EN1 Wake-up source enable 1 - * WAKE_POL0 Wake-up polarity selection 0 - * WAKE_POL1 Wake-up polarity selection 1 - */ - -#define _INTTEST0 _SA1111( 0x1600 ) -#define _INTTEST1 _SA1111( 0x1604 ) -#define _INTEN0 _SA1111( 0x1608 ) -#define _INTEN1 _SA1111( 0x160c ) -#define _INTPOL0 _SA1111( 0x1610 ) -#define _INTPOL1 _SA1111( 0x1614 ) -#define _INTTSTSEL _SA1111( 0x1618 ) -#define _INTSTATCLR0 _SA1111( 0x161c ) -#define _INTSTATCLR1 _SA1111( 0x1620 ) -#define _INTSET0 _SA1111( 0x1624 ) -#define _INTSET1 _SA1111( 0x1628 ) -#define _WAKE_EN0 _SA1111( 0x162c ) -#define _WAKE_EN1 _SA1111( 0x1630 ) -#define _WAKE_POL0 _SA1111( 0x1634 ) -#define _WAKE_POL1 _SA1111( 0x1638 ) - -#if LANGUAGE == C - -#define INTTEST0 __CCREG(0x1600) -#define INTTEST1 __CCREG(0x1604) -#define INTEN0 __CCREG(0x1608) -#define INTEN1 __CCREG(0x160c) -#define INTPOL0 __CCREG(0x1610) -#define INTPOL1 __CCREG(0x1614) -#define INTTSTSEL __CCREG(0x1618) -#define INTSTATCLR0 __CCREG(0x161c) -#define INTSTATCLR1 __CCREG(0x1620) -#define INTSET0 __CCREG(0x1624) -#define INTSET1 __CCREG(0x1628) -#define WAKE_EN0 __CCREG(0x162c) -#define WAKE_EN1 __CCREG(0x1630) -#define WAKE_POL0 __CCREG(0x1634) -#define WAKE_POL1 __CCREG(0x1638) - -#endif /* LANGUAGE == C */ - -/* - * PS/2 Trackpad and Mouse Interfaces - * - * Registers (prefix kbd applies to trackpad interface, mse to mouse) - * KBDCR Control Register - * KBDSTAT Status Register - * KBDDATA Transmit/Receive Data register - * KBDCLKDIV Clock Division Register - * KBDPRECNT Clock Precount Register - * KBDTEST1 Test register 1 - * KBDTEST2 Test register 2 - * KBDTEST3 Test register 3 - * KBDTEST4 Test register 4 - * MSECR - * MSESTAT - * MSEDATA - * MSECLKDIV - * MSEPRECNT - * MSETEST1 - * MSETEST2 - * MSETEST3 - * MSETEST4 - * - */ - -#define _KBD( x ) _SA1111( 0x0A00 ) -#define _MSE( x ) _SA1111( 0x0C00 ) - -#define _KBDCR _SA1111( 0x0A00 ) -#define _KBDSTAT _SA1111( 0x0A04 ) -#define _KBDDATA _SA1111( 0x0A08 ) -#define _KBDCLKDIV _SA1111( 0x0A0C ) -#define _KBDPRECNT _SA1111( 0x0A10 ) -#define _MSECR _SA1111( 0x0C00 ) -#define _MSESTAT _SA1111( 0x0C04 ) -#define _MSEDATA _SA1111( 0x0C08 ) -#define _MSECLKDIV _SA1111( 0x0C0C ) -#define _MSEPRECNT _SA1111( 0x0C10 ) - -#if ( LANGUAGE == C ) - -#define KBDCR __CCREG(0x0a00) -#define KBDSTAT __CCREG(0x0a04) -#define KBDDATA __CCREG(0x0a08) -#define KBDCLKDIV __CCREG(0x0a0c) -#define KBDPRECNT __CCREG(0x0a10) -#define MSECR __CCREG(0x0c00) -#define MSESTAT __CCREG(0x0c04) -#define MSEDATA __CCREG(0x0c08) -#define MSECLKDIV __CCREG(0x0c0c) -#define MSEPRECNT __CCREG(0x0c10) - -#define KBDCR_ENA 0x08 -#define KBDCR_FKD 0x02 -#define KBDCR_FKC 0x01 - -#define KBDSTAT_TXE 0x80 -#define KBDSTAT_TXB 0x40 -#define KBDSTAT_RXF 0x20 -#define KBDSTAT_RXB 0x10 -#define KBDSTAT_ENA 0x08 -#define KBDSTAT_RXP 0x04 -#define KBDSTAT_KBD 0x02 -#define KBDSTAT_KBC 0x01 - -#define KBDCLKDIV_DivVal Fld(4,0) - -#define MSECR_ENA 0x08 -#define MSECR_FKD 0x02 -#define MSECR_FKC 0x01 - -#define MSESTAT_TXE 0x80 -#define MSESTAT_TXB 0x40 -#define MSESTAT_RXF 0x20 -#define MSESTAT_RXB 0x10 -#define MSESTAT_ENA 0x08 -#define MSESTAT_RXP 0x04 -#define MSESTAT_MSD 0x02 -#define MSESTAT_MSC 0x01 - -#define MSECLKDIV_DivVal Fld(4,0) - -#define KBDTEST1_CD 0x80 -#define KBDTEST1_RC1 0x40 -#define KBDTEST1_MC 0x20 -#define KBDTEST1_C Fld(2,3) -#define KBDTEST1_T2 0x40 -#define KBDTEST1_T1 0x20 -#define KBDTEST1_T0 0x10 -#define KBDTEST2_TICBnRES 0x08 -#define KBDTEST2_RKC 0x04 -#define KBDTEST2_RKD 0x02 -#define KBDTEST2_SEL 0x01 -#define KBDTEST3_ms_16 0x80 -#define KBDTEST3_us_64 0x40 -#define KBDTEST3_us_16 0x20 -#define KBDTEST3_DIV8 0x10 -#define KBDTEST3_DIn 0x08 -#define KBDTEST3_CIn 0x04 -#define KBDTEST3_KD 0x02 -#define KBDTEST3_KC 0x01 -#define KBDTEST4_BC12 0x80 -#define KBDTEST4_BC11 0x40 -#define KBDTEST4_TRES 0x20 -#define KBDTEST4_CLKOE 0x10 -#define KBDTEST4_CRES 0x08 -#define KBDTEST4_RXB 0x04 -#define KBDTEST4_TXB 0x02 -#define KBDTEST4_SRX 0x01 - -#define MSETEST1_CD 0x80 -#define MSETEST1_RC1 0x40 -#define MSETEST1_MC 0x20 -#define MSETEST1_C Fld(2,3) -#define MSETEST1_T2 0x40 -#define MSETEST1_T1 0x20 -#define MSETEST1_T0 0x10 -#define MSETEST2_TICBnRES 0x08 -#define MSETEST2_RKC 0x04 -#define MSETEST2_RKD 0x02 -#define MSETEST2_SEL 0x01 -#define MSETEST3_ms_16 0x80 -#define MSETEST3_us_64 0x40 -#define MSETEST3_us_16 0x20 -#define MSETEST3_DIV8 0x10 -#define MSETEST3_DIn 0x08 -#define MSETEST3_CIn 0x04 -#define MSETEST3_KD 0x02 -#define MSETEST3_KC 0x01 -#define MSETEST4_BC12 0x80 -#define MSETEST4_BC11 0x40 -#define MSETEST4_TRES 0x20 -#define MSETEST4_CLKOE 0x10 -#define MSETEST4_CRES 0x08 -#define MSETEST4_RXB 0x04 -#define MSETEST4_TXB 0x02 -#define MSETEST4_SRX 0x01 - -#endif /* LANGUAGE == C */ - -/* - * PCMCIA Interface - * - * Registers - * PCSR Status Register - * PCCR Control Register - * PCSSR Sleep State Register - */ - -#define _PCCR _SA1111( 0x1800 ) -#define _PCSSR _SA1111( 0x1804 ) -#define _PCSR _SA1111( 0x1808 ) - -#if LANGUAGE == C - -#define PCCR __CCREG(0x1800) -#define PCSSR __CCREG(0x1804) -#define PCSR __CCREG(0x1808) - -#endif /* LANGUAGE == C */ - -#define PCSR_S0_READY (1<<0) -#define PCSR_S1_READY (1<<1) -#define PCSR_S0_DETECT (1<<2) -#define PCSR_S1_DETECT (1<<3) -#define PCSR_S0_VS1 (1<<4) -#define PCSR_S0_VS2 (1<<5) -#define PCSR_S1_VS1 (1<<6) -#define PCSR_S1_VS2 (1<<7) -#define PCSR_S0_WP (1<<8) -#define PCSR_S1_WP (1<<9) -#define PCSR_S0_BVD1 (1<<10) -#define PCSR_S0_BVD2 (1<<11) -#define PCSR_S1_BVD1 (1<<12) -#define PCSR_S1_BVD2 (1<<13) - -#define PCCR_S0_RST (1<<0) -#define PCCR_S1_RST (1<<1) -#define PCCR_S0_FLT (1<<2) -#define PCCR_S1_FLT (1<<3) -#define PCCR_S0_PWAITEN (1<<4) -#define PCCR_S1_PWAITEN (1<<5) -#define PCCR_S0_PSE (1<<6) -#define PCCR_S1_PSE (1<<7) - -#define PCSSR_S0_SLEEP (1<<0) -#define PCSSR_S1_SLEEP (1<<1) - -#endif /* _ASM_ARCH_SA1111 */ +#warning using old SA-1111.h - update to <asm/hardware/sa1111.h> +#include <asm/hardware/sa1111.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/assabet.h linux-2.5/include/asm-arm/arch-sa1100/assabet.h --- linux-2.5.1/include/asm-arm/arch-sa1100/assabet.h Thu Oct 25 20:53:54 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/assabet.h Sun Jan 6 01:38:27 2002 @@ -29,19 +29,6 @@ #define ASSABET_BCR_BASE 0xf1000000 #define ASSABET_BCR (*(volatile unsigned int *)(ASSABET_BCR_BASE)) -#define ASSABET_BCR_DB1110 \ - (ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \ - ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \ - ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \ - ASSABET_BCR_IRDA_MD0) - -#define ASSABET_BCR_DB1111 \ - (ASSABET_BCR_SPK_OFF | ASSABET_BCR_QMUTE | \ - ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \ - ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \ - ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \ - ASSABET_BCR_IRDA_MD0 | ASSABET_BCR_CF_RST) - #define ASSABET_BCR_CF_PWR (1<<0) /* Compact Flash Power (1 = 3.3v, 0 = off) */ #define ASSABET_BCR_CF_RST (1<<1) /* Compact Flash Reset (1 = power up reset) */ #define ASSABET_BCR_GFX_RST (1<<1) /* Graphics Accelerator Reset (0 = hold reset) */ @@ -69,9 +56,15 @@ #define ASSABET_BCR_SPK_OFF (1<<23) /* 1 = Speaker amplifier power off */ extern unsigned long SCR_value; -extern unsigned long BCR_value; -#define ASSABET_BCR_set(x) ASSABET_BCR = (BCR_value |= (x)) -#define ASSABET_BCR_clear(x) ASSABET_BCR = (BCR_value &= ~(x)) + +#ifdef CONFIG_SA1100_ASSABET +extern void ASSABET_BCR_frob(unsigned int mask, unsigned int set); +#else +#define ASSABET_BCR_frob(x) do { } while (0) +#endif + +#define ASSABET_BCR_set(x) ASSABET_BCR_frob((x), (x)) +#define ASSABET_BCR_clear(x) ASSABET_BCR_frob((x), 0) #define ASSABET_BSR_BASE 0xf1000000 #define ASSABET_BSR (*(volatile unsigned int*)(ASSABET_BSR_BASE)) @@ -88,37 +81,25 @@ /* GPIOs for which the generic definition doesn't say much */ #define ASSABET_GPIO_RADIO_IRQ GPIO_GPIO (14) /* Radio interrupt request */ -#define ASSABET_GPIO_L3_I2C_SDA GPIO_GPIO (15) /* L3 and SMB control ports */ #define ASSABET_GPIO_PS_MODE_SYNC GPIO_GPIO (16) /* Power supply mode/sync */ -#define ASSABET_GPIO_L3_MODE GPIO_GPIO (17) /* L3 mode signal with LED */ -#define ASSABET_GPIO_L3_I2C_SCL GPIO_GPIO (18) /* L3 and I2C control ports */ #define ASSABET_GPIO_STEREO_64FS_CLK GPIO_GPIO (19) /* SSP UDA1341 clock input */ #define ASSABET_GPIO_CF_IRQ GPIO_GPIO (21) /* CF IRQ */ #define ASSABET_GPIO_CF_CD GPIO_GPIO (22) /* CF CD */ -#define ASSABET_GPIO_UCB1300_IRQ GPIO_GPIO (23) /* UCB GPIO and touchscreen */ #define ASSABET_GPIO_CF_BVD2 GPIO_GPIO (24) /* CF BVD */ #define ASSABET_GPIO_GFX_IRQ GPIO_GPIO (24) /* Graphics IRQ */ #define ASSABET_GPIO_CF_BVD1 GPIO_GPIO (25) /* CF BVD */ -#define ASSABET_GPIO_NEP_IRQ GPIO_GPIO (25) /* Neponset IRQ */ #define ASSABET_GPIO_BATT_LOW GPIO_GPIO (26) /* Low battery */ #define ASSABET_GPIO_RCLK GPIO_GPIO (26) /* CCLK/2 */ #define ASSABET_IRQ_GPIO_CF_IRQ IRQ_GPIO21 #define ASSABET_IRQ_GPIO_CF_CD IRQ_GPIO22 -#define ASSABET_IRQ_GPIO_UCB1300_IRQ IRQ_GPIO23 #define ASSABET_IRQ_GPIO_CF_BVD2 IRQ_GPIO24 #define ASSABET_IRQ_GPIO_CF_BVD1 IRQ_GPIO25 -#define ASSABET_IRQ_GPIO_NEP_IRQ IRQ_GPIO25 /* * Neponset definitions: */ - -#define SA1111_BASE (0x40000000) - -#define NEPONSET_ETHERNET_IRQ MISC_IRQ0 -#define NEPONSET_USAR_IRQ MISC_IRQ1 #define NEPONSET_CPLD_BASE (0x10000000) #define Nep_p2v( x ) ((x) - NEPONSET_CPLD_BASE + 0xf3000000) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/dma.h linux-2.5/include/asm-arm/arch-sa1100/dma.h --- linux-2.5.1/include/asm-arm/arch-sa1100/dma.h Thu Oct 11 16:04:57 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/dma.h Sun Jan 6 01:38:27 2002 @@ -28,34 +28,16 @@ */ #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 - +#define SA1100_DMA_CHANNELS 6 /* - * 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. + * Maximum physical DMA buffer size */ -#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 - +#define MAX_DMA_SIZE 0x1fff +#define CUT_DMA_SIZE 0x1000 /* * All possible SA1100 devices a DMA channel can be attached to. @@ -81,29 +63,72 @@ DMA_Ser4SSPRd = DDAR_Ser4SSPRd /* Ser. port 4 SSP Read (16 bits) */ } dma_device_t; +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; + +typedef void (*dma_callback_t)(void *data); + +/* + * DMA function prototypes + */ -typedef void (*dma_callback_t)( void *buf_id, int size ); +extern int sa1100_request_dma( dma_device_t device, const char *device_id, + dma_callback_t callback, void *data, + dma_regs_t **regs ); +extern void sa1100_free_dma( dma_regs_t *regs ); +extern int sa1100_start_dma( dma_regs_t *regs, dma_addr_t dma_ptr, u_int size ); +extern dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs); +extern void sa1100_reset_dma(dma_regs_t *regs); + +/** + * sa1100_stop_dma - stop DMA in progress + * @regs: identifier for the channel to use + * + * This stops DMA without clearing buffer pointers. Unlike + * sa1100_clear_dma() this allows subsequent use of sa1100_resume_dma() + * or sa1100_get_dma_pos(). + * + * The @regs identifier is provided by a successful call to + * sa1100_request_dma(). + **/ + +#define sa1100_stop_dma(regs) ((regs)->ClrDCSR = DCSR_IE|DCSR_RUN) + +/** + * sa1100_resume_dma - resume DMA on a stopped channel + * @regs: identifier for the channel to use + * + * This resumes DMA on a channel previously stopped with + * sa1100_stop_dma(). + * + * The @regs identifier is provided by a successful call to + * sa1100_request_dma(). + **/ + +#define sa1100_resume_dma(regs) ((regs)->SetDCSR = DCSR_IE|DCSR_RUN) + +/** + * sa1100_clear_dma - clear DMA pointers + * @regs: identifier for the channel to use + * + * This clear any DMA state so the DMA engine is ready to restart + * with new buffers through sa1100_start_dma(). Any buffers in flight + * are discarded. + * + * The @regs identifier is provided by a successful call to + * sa1100_request_dma(). + **/ +#define sa1100_clear_dma(regs) ((regs)->ClrDCSR = DCSR_IE|DCSR_RUN|DCSR_STRTA|DCSR_STRTB) -/* SA1100 DMA API */ -extern int sa1100_request_dma( dmach_t *channel, const char *device_id, - dma_device_t device ); -extern int sa1100_dma_set_callback( dmach_t channel, dma_callback_t cb ); -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 ); -extern int sa1100_dma_sleep( dmach_t channel ); -extern int sa1100_dma_wakeup( 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 ); #ifdef CONFIG_SA1111 static inline void diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/flexanet.h linux-2.5/include/asm-arm/arch-sa1100/flexanet.h --- linux-2.5.1/include/asm-arm/arch-sa1100/flexanet.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/flexanet.h Sun Jan 6 01:38:27 2002 @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/arch-sa1100/flexanet.h + * include/asm-arm/arch-sa1100/flexanet.h * * Created 2001/05/04 by Jordi Colomer <jco@ict.es> * @@ -11,39 +11,79 @@ #error "include <asm/hardware.h> instead" #endif - /* Board Control Register (virtual address) */ -#define BCR_PHYS 0x10000000 -#define BCR_VIRT 0xf0000000 -#define BCR (*(volatile unsigned int *)(BCR_VIRT)) +#define FHH_BCR_PHYS 0x10000000 +#define FHH_BCR_VIRT 0xf0000000 +#define FHH_BCR (*(volatile unsigned int *)(FHH_BCR_VIRT)) /* Power-up value */ -#define BCR_POWERUP 0x00000000 +#define FHH_BCR_POWERUP 0x00000000 /* Mandatory bits */ -#define BCR_LED_GREEN (1<<0) /* General-purpose green LED (1 = on) */ -#define BCR_GUI_NRST (1<<4) /* GUI board reset (0 = reset) */ - -/* Board Status Register (virtual address) */ -#define BSR_BASE BCR_BASE -#define BSR (*(volatile unsigned int *)(BSR_BASE)) - +#define FHH_BCR_LED_GREEN (1<<0) /* General-purpose green LED (1 = on) */ +#define FHH_BCR_SPARE_1 (1<<1) /* Not defined */ +#define FHH_BCR_CF1_RST (1<<2) /* Compact Flash Slot #1 Reset (1 = reset) */ +#define FHH_BCR_CF2_RST (1<<3) /* Compact Flash Slot #2 Reset (1 = reset) */ +#define FHH_BCR_GUI_NRST (1<<4) /* GUI board reset (0 = reset) */ +#define FHH_BCR_RTS1 (1<<5) /* RS232 RTS for UART-1 */ +#define FHH_BCR_RTS3 (1<<6) /* RS232 RTS for UART-3 */ +#define FHH_BCR_XCDBG0 (1<<7) /* Not defined. Wired to XPLA3 for debug */ + +/* BCR extension, only required by L3-bus in some audio codecs */ +#define FHH_BCR_L3MOD (1<<8) /* L3-bus MODE signal */ +#define FHH_BCR_L3DAT (1<<9) /* L3-bus DATA signal */ +#define FHH_BCR_L3CLK (1<<10) /* L3-bus CLK signal */ +#define FHH_BCR_SPARE_11 (1<<11) /* Not defined */ +#define FHH_BCR_SPARE_12 (1<<12) /* Not defined */ +#define FHH_BCR_SPARE_13 (1<<13) /* Not defined */ +#define FHH_BCR_SPARE_14 (1<<14) /* Not defined */ +#define FHH_BCR_SPARE_15 (1<<15) /* Not defined */ + + /* Board Status Register (virtual address) */ +#define FHH_BSR_BASE FHH_BCR_VIRT +#define FHH_BSR (*(volatile unsigned int *)(FHH_BSR_BASE)) + +#define FHH_BSR_CTS1 (1<<0) /* RS232 CTS for UART-1 */ +#define FHH_BSR_CTS3 (1<<1) /* RS232 CTS for UART-3 */ +#define FHH_BSR_DSR1 (1<<2) /* RS232 DSR for UART-1 */ +#define FHH_BSR_DSR3 (1<<3) /* RS232 DSR for UART-3 */ +#define FHH_BSR_ID0 (1<<4) /* Board identification */ +#define FHH_BSR_ID1 (1<<5) +#define FHH_BSR_CFG0 (1<<6) /* Board configuration options */ +#define FHH_BSR_CFG1 (1<<7) #ifndef __ASSEMBLY__ -extern unsigned long BCR_value; /* Image of the BCR */ -#define BCR_set( x ) BCR = (BCR_value |= (x)) -#define BCR_clear( x ) BCR = (BCR_value &= ~(x)) +extern unsigned long flexanet_BCR; /* Image of the BCR */ +#define FLEXANET_BCR_set( x ) FHH_BCR = (flexanet_BCR |= (x)) +#define FLEXANET_BCR_clear( x ) FHH_BCR = (flexanet_BCR &= ~(x)) #endif - /* GPIOs for which the generic definition doesn't say much */ -#define GPIO_GUI_IRQ GPIO_GPIO (23) /* IRQ from GUI board (i.e., UCB1300) */ -#define GPIO_ETH_IRQ GPIO_GPIO (24) /* IRQ from Ethernet controller */ -#define GPIO_LED_RED GPIO_GPIO (26) /* General-purpose red LED */ +#define GPIO_CF1_NCD GPIO_GPIO (14) /* Card Detect from CF slot #1 */ +#define GPIO_CF2_NCD GPIO_GPIO (15) /* Card Detect from CF slot #2 */ +#define GPIO_CF1_IRQ GPIO_GPIO (16) /* IRQ from CF slot #1 */ +#define GPIO_CF2_IRQ GPIO_GPIO (17) /* IRQ from CF slot #2 */ +#define GPIO_APP_IRQ GPIO_GPIO (18) /* Extra IRQ from application bus */ +#define GPIO_RADIO_REF GPIO_GPIO (20) /* Ref. clock for UART3 (Radio) */ +#define GPIO_CF1_BVD1 GPIO_GPIO (21) /* BVD1 from CF slot #1 */ +#define GPIO_CF2_BVD1 GPIO_GPIO (22) /* BVD1 from CF slot #2 */ +#define GPIO_GUI_IRQ GPIO_GPIO (23) /* IRQ from GUI board (i.e., UCB1300) */ +#define GPIO_ETH_IRQ GPIO_GPIO (24) /* IRQ from Ethernet controller */ +#define GPIO_INTIP_IRQ GPIO_GPIO (25) /* Measurement IRQ (INTIP) */ +#define GPIO_LED_RED GPIO_GPIO (26) /* General-purpose red LED */ /* IRQ sources from GPIOs */ -#define IRQ_GPIO_GUI IRQ_GPIO23 -#define IRQ_GPIO_ETH IRQ_GPIO24 +#define IRQ_GPIO_CF1_CD IRQ_GPIO14 +#define IRQ_GPIO_CF2_CD IRQ_GPIO15 +#define IRQ_GPIO_CF1_IRQ IRQ_GPIO16 +#define IRQ_GPIO_CF2_IRQ IRQ_GPIO17 +#define IRQ_GPIO_APP IRQ_GPIO18 +#define IRQ_GPIO_CF1_BVD1 IRQ_GPIO21 +#define IRQ_GPIO_CF2_BVD1 IRQ_GPIO22 +#define IRQ_GPIO_GUI IRQ_GPIO23 +#define IRQ_GPIO_ETH IRQ_GPIO24 +#define IRQ_GPIO_INTIP IRQ_GPIO25 + /* On-Board Ethernet */ #define _FHH_ETH_IOBASE 0x18000000 /* I/O base (physical addr) */ @@ -57,15 +97,4 @@ #define FHH_ETH_IOBASE FHH_ETH_p2v(_FHH_ETH_IOBASE) /* Virtual base addr */ #define FHH_ETH_MMBASE FHH_ETH_p2v(_FHH_ETH_MMBASE) - -/* Types of GUI */ -#ifndef __ASSEMBLY__ -extern unsigned long GUI_type; -#endif - -#define FHH_GUI_ERROR 0xFFFFFFFF -#define FHH_GUI_NONE 0x0000000F -#define FHH_GUI_TYPE_0 0 -#define FHH_GUI_TYPE_1 1 -#define FHH_GUI_TYPE_2 2 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/graphicsmaster.h linux-2.5/include/asm-arm/arch-sa1100/graphicsmaster.h --- linux-2.5.1/include/asm-arm/arch-sa1100/graphicsmaster.h Thu Oct 11 16:04:57 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/graphicsmaster.h Sun Jan 6 01:38:27 2002 @@ -62,5 +62,3 @@ #endif #define SA1111_BASE (0x18000000) - -#include "SA-1111.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/h3600.h linux-2.5/include/asm-arm/arch-sa1100/h3600.h --- linux-2.5.1/include/asm-arm/arch-sa1100/h3600.h Thu Oct 11 16:04:57 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/h3600.h Sun Jan 6 01:38:27 2002 @@ -1,81 +1,138 @@ /* -* -* Definitions for H3600 Handheld Computer -* -* Copyright 2000 Compaq Computer Corporation. -* -* Use consistent with the GNU GPL is permitted, -* provided that this copyright notice is -* preserved in its entirety in all copies and derived works. -* -* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, -* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS -* FITNESS FOR ANY PARTICULAR PURPOSE. -* -* Author: Jamey Hicks. -* -*/ + * + * Definitions for H3600 Handheld Computer + * + * Copyright 2000 Compaq Computer Corporation. + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Author: Jamey Hicks. + * + * History: + * + * 2001-10-?? Andrew Christian Added support for iPAQ H3800 + * + */ #ifndef _INCLUDE_H3600_H_ #define _INCLUDE_H3600_H_ -#define GPIO_H3600_NPOWER_BUTTON GPIO_GPIO (0) -#define GPIO_H3600_ACTION_BUTTON GPIO_GPIO (18) +/* generalized support for H3xxx series Compaq Pocket PC's */ +#define machine_is_h3xxx() (machine_is_h3100() || machine_is_h3600() || machine_is_h3800()) + +/* Virtual memory regions corresponding to chip selects 2 & 4 (used on sleeves) */ +#define H3600_EGPIO_VIRT 0xf0000000 +#define H3600_BANK_2_VIRT 0xf1000000 +#define H3600_BANK_4_VIRT 0xf3800000 + +/* + Machine-independent GPIO definitions + --- these are common across all current iPAQ platforms +*/ + +#define GPIO_H3600_NPOWER_BUTTON GPIO_GPIO (0) /* Also known as the "off button" */ +#define GPIO_H3600_MICROCONTROLLER GPIO_GPIO (1) /* From ASIC2 on H3800 */ -#define GPIO_H3600_PCMCIA_CD0 GPIO_GPIO (17) #define GPIO_H3600_PCMCIA_CD1 GPIO_GPIO (10) -#define GPIO_H3600_PCMCIA_IRQ0 GPIO_GPIO (21) #define GPIO_H3600_PCMCIA_IRQ1 GPIO_GPIO (11) -/* audio sample rate clock generator */ -#define GPIO_H3600_CLK_SET0 GPIO_GPIO (12) -#define GPIO_H3600_CLK_SET1 GPIO_GPIO (13) - /* UDA1341 L3 Interface */ #define GPIO_H3600_L3_DATA GPIO_GPIO (14) -#define GPIO_H3600_L3_CLOCK GPIO_GPIO (16) #define GPIO_H3600_L3_MODE GPIO_GPIO (15) +#define GPIO_H3600_L3_CLOCK GPIO_GPIO (16) -#define GPIO_H3600_OPT_LOCK GPIO_GPIO (22) -#define GPIO_H3600_OPT_IRQ GPIO_GPIO (24) -#define GPIO_H3600_OPT_DET GPIO_GPIO (27) +#define GPIO_H3600_PCMCIA_CD0 GPIO_GPIO (17) +#define GPIO_H3600_SYS_CLK GPIO_GPIO (19) +#define GPIO_H3600_PCMCIA_IRQ0 GPIO_GPIO (21) #define GPIO_H3600_COM_DCD GPIO_GPIO (23) +#define GPIO_H3600_OPT_IRQ GPIO_GPIO (24) #define GPIO_H3600_COM_CTS GPIO_GPIO (25) #define GPIO_H3600_COM_RTS GPIO_GPIO (26) #define IRQ_GPIO_H3600_NPOWER_BUTTON IRQ_GPIO0 -#define IRQ_GPIO_H3600_ACTION_BUTTON IRQ_GPIO18 -#define IRQ_GPIO_H3600_PCMCIA_CD0 IRQ_GPIO17 +#define IRQ_GPIO_H3600_MICROCONTROLLER IRQ_GPIO1 #define IRQ_GPIO_H3600_PCMCIA_CD1 IRQ_GPIO10 -#define IRQ_GPIO_H3600_PCMCIA_IRQ0 IRQ_GPIO21 #define IRQ_GPIO_H3600_PCMCIA_IRQ1 IRQ_GPIO11 -#define IRQ_GPIO_H3600_OPT_IRQ IRQ_GPIO24 -#define IRQ_GPIO_H3600_OPT_DET IRQ_GPIO27 +#define IRQ_GPIO_H3600_PCMCIA_CD0 IRQ_GPIO17 +#define IRQ_GPIO_H3600_PCMCIA_IRQ0 IRQ_GPIO21 #define IRQ_GPIO_H3600_COM_DCD IRQ_GPIO23 +#define IRQ_GPIO_H3600_OPT_IRQ IRQ_GPIO24 #define IRQ_GPIO_H3600_COM_CTS IRQ_GPIO25 -#define EGPIO_H3600_VPP_ON (1 << 0) -#define EGPIO_H3600_CARD_RESET (1 << 1) /* reset the attached pcmcia/compactflash card. active high. */ -#define EGPIO_H3600_OPT_RESET (1 << 2) /* reset the attached option pack. active high. */ -#define EGPIO_H3600_CODEC_NRESET (1 << 3) /* reset the onboard UDA1341. active low. */ -#define EGPIO_H3600_OPT_NVRAM_ON (1 << 4) /* apply power to optionpack nvram, active high. */ -#define EGPIO_H3600_OPT_ON (1 << 5) /* full power to option pack. active high. */ -#define EGPIO_H3600_LCD_ON (1 << 6) /* enable 3.3V to LCD. active high. */ -#define EGPIO_H3600_RS232_ON (1 << 7) /* UART3 transceiver force on. Active high. */ -#define EGPIO_H3600_LCD_PCI (1 << 8) /* LCD control IC enable. active high. */ -#define EGPIO_H3600_IR_ON (1 << 9) /* apply power to IR module. active high. */ -#define EGPIO_H3600_AUD_AMP_ON (1 << 10) /* apply power to audio power amp. active high. */ -#define EGPIO_H3600_AUD_PWR_ON (1 << 11) /* apply poewr to reset of audio circuit. active high. */ -#define EGPIO_H3600_QMUTE (1 << 12) /* mute control for onboard UDA1341. active high. */ -#define EGPIO_H3600_IR_FSEL (1 << 13) /* IR speed select: 1->fast, 0->slow */ -#define EGPIO_H3600_LCD_5V_ON (1 << 14) /* enable 5V to LCD. active high. */ -#define EGPIO_H3600_LVDD_ON (1 << 15) /* enable 9V and -6.5V to LCD. */ #ifndef __ASSEMBLY__ -#define H3600_EGPIO (*(volatile int *)0xf0000000) -extern void clr_h3600_egpio(unsigned long x); -extern void set_h3600_egpio(unsigned long x); -#endif +enum ipaq_model { + IPAQ_H3100, + IPAQ_H3600, + IPAQ_H3800 +}; + +enum ipaq_egpio_type { + IPAQ_EGPIO_LCD_ON, /* Power to the LCD panel */ + IPAQ_EGPIO_CODEC_NRESET, /* Clear to reset the audio codec (remember to return high) */ + IPAQ_EGPIO_AUDIO_ON, /* Audio power */ + IPAQ_EGPIO_QMUTE, /* Audio muting */ + IPAQ_EGPIO_OPT_NVRAM_ON, /* Non-volatile RAM on extension sleeves (SPI interface) */ + IPAQ_EGPIO_OPT_ON, /* Power to extension sleeves */ + IPAQ_EGPIO_CARD_RESET, /* Reset PCMCIA cards on extension sleeve (???) */ + IPAQ_EGPIO_OPT_RESET, /* Reset option pack (???) */ + IPAQ_EGPIO_IR_ON, /* IR sensor/emitter power */ + IPAQ_EGPIO_IR_FSEL, /* IR speed selection 1->fast, 0->slow */ + IPAQ_EGPIO_RS232_ON, /* Maxim RS232 chip power */ + IPAQ_EGPIO_VPP_ON, /* Turn on power to flash programming */ +}; + +struct ipaq_model_ops { + enum ipaq_model model; + const char *generic_name; + void (*initialize)(void); + void (*control)(enum ipaq_egpio_type, int); + unsigned long (*read)(void); +}; + +extern struct ipaq_model_ops ipaq_model_ops; + +static __inline__ enum ipaq_model h3600_model( void ) { + return ipaq_model_ops.model; +} + +static __inline__ const char * h3600_generic_name( void ) { + return ipaq_model_ops.generic_name; +} + +static __inline__ void init_h3600_egpio( void ) { + if (ipaq_model_ops.initialize) + ipaq_model_ops.initialize(); +} + +static __inline__ void assign_h3600_egpio( enum ipaq_egpio_type x, int level ) { + if (ipaq_model_ops.control) + ipaq_model_ops.control(x,level); +} + +static __inline__ void clr_h3600_egpio( enum ipaq_egpio_type x ) { + if (ipaq_model_ops.control) + ipaq_model_ops.control(x,0); +} + +static __inline__ void set_h3600_egpio( enum ipaq_egpio_type x ) { + if (ipaq_model_ops.control) + ipaq_model_ops.control(x,1); +} + +static __inline__ unsigned long read_h3600_egpio( void ) { + if (ipaq_model_ops.read) + return ipaq_model_ops.read(); + return 0; +} + +#endif /* ASSEMBLY */ -#endif +#endif /* _INCLUDE_H3600_H_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/h3600_gpio.h linux-2.5/include/asm-arm/arch-sa1100/h3600_gpio.h --- linux-2.5.1/include/asm-arm/arch-sa1100/h3600_gpio.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-sa1100/h3600_gpio.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,540 @@ +/* + * + * Definitions for H3600 Handheld Computer + * + * Copyright 2000 Compaq Computer Corporation. + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Author: Jamey Hicks. + * + * History: + * + * 2001-10-?? Andrew Christian Added support for iPAQ H3800 + * + */ + +#ifndef _INCLUDE_H3600_GPIO_H_ +#define _INCLUDE_H3600_GPIO_H_ + +/* + * GPIO lines that are common across ALL iPAQ models are in "h3600.h" + * This file contains machine-specific definitions + */ + +#define GPIO_H3600_SUSPEND GPIO_GPIO (0) +/* GPIO[2:9] used by LCD on H3600/3800, used as GPIO on H3100 */ +#define GPIO_H3100_BT_ON GPIO_GPIO (2) +#define GPIO_H3100_GPIO3 GPIO_GPIO (3) +#define GPIO_H3100_QMUTE GPIO_GPIO (4) +#define GPIO_H3100_LCD_3V_ON GPIO_GPIO (5) +#define GPIO_H3100_AUD_ON GPIO_GPIO (6) +#define GPIO_H3100_AUD_PWR_ON GPIO_GPIO (7) +#define GPIO_H3100_IR_ON GPIO_GPIO (8) +#define GPIO_H3100_IR_FSEL GPIO_GPIO (9) + +/* for H3600, audio sample rate clock generator */ +#define GPIO_H3600_CLK_SET0 GPIO_GPIO (12) +#define GPIO_H3600_CLK_SET1 GPIO_GPIO (13) + +#define GPIO_H3600_ACTION_BUTTON GPIO_GPIO (18) +#define GPIO_H3600_SOFT_RESET GPIO_GPIO (20) /* Also known as BATT_FAULT */ +#define GPIO_H3600_OPT_LOCK GPIO_GPIO (22) +#define GPIO_H3600_OPT_DET GPIO_GPIO (27) + +/* H3800 specific pins */ +#define GPIO_H3800_AC_IN GPIO_GPIO (12) +#define GPIO_H3800_COM_DSR GPIO_GPIO (13) +#define GPIO_H3800_MMC_INT GPIO_GPIO (18) +#define GPIO_H3800_NOPT_IND GPIO_GPIO (20) /* Almost exactly the same as GPIO_H3600_OPT_DET */ +#define GPIO_H3800_OPT_BAT_FAULT GPIO_GPIO (22) +#define GPIO_H3800_CLK_OUT GPIO_GPIO (27) + +/****************************************************/ + +#define IRQ_GPIO_H3600_ACTION_BUTTON IRQ_GPIO18 +#define IRQ_GPIO_H3600_OPT_DET IRQ_GPIO27 + +#define IRQ_GPIO_H3800_MMC_INT IRQ_GPIO18 +#define IRQ_GPIO_H3800_NOPT_IND IRQ_GPIO20 /* almost same as OPT_DET */ + +/* H3100 / 3600 EGPIO pins */ +#define EGPIO_H3600_VPP_ON (1 << 0) +#define EGPIO_H3600_CARD_RESET (1 << 1) /* reset the attached pcmcia/compactflash card. active high. */ +#define EGPIO_H3600_OPT_RESET (1 << 2) /* reset the attached option pack. active high. */ +#define EGPIO_H3600_CODEC_NRESET (1 << 3) /* reset the onboard UDA1341. active low. */ +#define EGPIO_H3600_OPT_NVRAM_ON (1 << 4) /* apply power to optionpack nvram, active high. */ +#define EGPIO_H3600_OPT_ON (1 << 5) /* full power to option pack. active high. */ +#define EGPIO_H3600_LCD_ON (1 << 6) /* enable 3.3V to LCD. active high. */ +#define EGPIO_H3600_RS232_ON (1 << 7) /* UART3 transceiver force on. Active high. */ + +/* H3600 only EGPIO pins */ +#define EGPIO_H3600_LCD_PCI (1 << 8) /* LCD control IC enable. active high. */ +#define EGPIO_H3600_IR_ON (1 << 9) /* apply power to IR module. active high. */ +#define EGPIO_H3600_AUD_AMP_ON (1 << 10) /* apply power to audio power amp. active high. */ +#define EGPIO_H3600_AUD_PWR_ON (1 << 11) /* apply power to reset of audio circuit. active high. */ +#define EGPIO_H3600_QMUTE (1 << 12) /* mute control for onboard UDA1341. active high. */ +#define EGPIO_H3600_IR_FSEL (1 << 13) /* IR speed select: 1->fast, 0->slow */ +#define EGPIO_H3600_LCD_5V_ON (1 << 14) /* enable 5V to LCD. active high. */ +#define EGPIO_H3600_LVDD_ON (1 << 15) /* enable 9V and -6.5V to LCD. */ + +/********************* H3800, ASIC #2 ********************/ + +#define _H3800_ASIC2_Base (H3600_EGPIO_VIRT) +#define H3800_ASIC2_OFFSET(s,x,y) \ + (*((volatile s *) (_H3800_ASIC2_Base + _H3800_ASIC2_ ## x ## _Base + _H3800_ASIC2_ ## x ## _ ## y))) +#define H3800_ASIC2_NOFFSET(s,x,n,y) \ + (*((volatile s *) (_H3800_ASIC2_Base + _H3800_ASIC2_ ## x ## _ ## n ## _Base + _H3800_ASIC2_ ## x ## _ ## y))) + +#define _H3800_ASIC2_GPIO_Base 0x0000 +#define _H3800_ASIC2_GPIO_Direction 0x0000 /* R/W, 16 bits 1:input, 0:output */ +#define _H3800_ASIC2_GPIO_InterruptType 0x0004 /* R/W, 12 bits 1:edge, 0:level */ +#define _H3800_ASIC2_GPIO_InterruptEdgeType 0x0008 /* R/W, 12 bits 1:rising, 0:falling */ +#define _H3800_ASIC2_GPIO_InterruptLevelType 0x000C /* R/W, 12 bits 1:high, 0:low */ +#define _H3800_ASIC2_GPIO_InterruptClear 0x0010 /* W, 12 bits */ +#define _H3800_ASIC2_GPIO_InterruptFlag 0x0010 /* R, 12 bits - reads int status */ +#define _H3800_ASIC2_GPIO_Data 0x0014 /* R/W, 16 bits */ +#define _H3800_ASIC2_GPIO_BattFaultOut 0x0018 /* R/W, 16 bit - sets level on batt fault */ +#define _H3800_ASIC2_GPIO_InterruptEnable 0x001c /* R/W, 12 bits 1:enable interrupt */ +#define _H3800_ASIC2_GPIO_Alternate 0x003c /* R/W, 12+1 bits - set alternate functions */ + +#define H3800_ASIC2_GPIO_Direction H3800_ASIC2_OFFSET( u16, GPIO, Direction ) +#define H3800_ASIC2_GPIO_InterruptType H3800_ASIC2_OFFSET( u16, GPIO, InterruptType ) +#define H3800_ASIC2_GPIO_InterruptEdgeType H3800_ASIC2_OFFSET( u16, GPIO, InterruptEdgeType ) +#define H3800_ASIC2_GPIO_InterruptLevelType H3800_ASIC2_OFFSET( u16, GPIO, InterruptLevelType ) +#define H3800_ASIC2_GPIO_InterruptClear H3800_ASIC2_OFFSET( u16, GPIO, InterruptClear ) +#define H3800_ASIC2_GPIO_InterruptFlag H3800_ASIC2_OFFSET( u16, GPIO, InterruptFlag ) +#define H3800_ASIC2_GPIO_Data H3800_ASIC2_OFFSET( u16, GPIO, Data ) +#define H3800_ASIC2_GPIO_BattFaultOut H3800_ASIC2_OFFSET( u16, GPIO, BattFaultOut ) +#define H3800_ASIC2_GPIO_InterruptEnable H3800_ASIC2_OFFSET( u16, GPIO, InterruptEnable ) +#define H3800_ASIC2_GPIO_Alternate H3800_ASIC2_OFFSET( u16, GPIO, Alternate ) + +#define GPIO_H3800_ASIC2_IN_Y1_N (1 << 0) /* Output: Touchscreen Y1 */ +#define GPIO_H3800_ASIC2_IN_X0 (1 << 1) /* Output: Touchscreen X0 */ +#define GPIO_H3800_ASIC2_IN_Y0 (1 << 2) /* Output: Touchscreen Y0 */ +#define GPIO_H3800_ASIC2_IN_X1_N (1 << 3) /* Output: Touchscreen X1 */ +#define GPIO_H3800_ASIC2_BT_RST (1 << 4) /* Output: Bluetooth reset */ +#define GPIO_H3800_ASIC2_PEN_IRQ (1 << 5) /* Input : Pen down */ +#define GPIO_H3800_ASIC2_SD_DETECT (1 << 6) /* Input : SD detect */ +#define GPIO_H3800_ASIC2_EAR_IN_N (1 << 7) /* Input : Audio jack plug inserted */ +#define GPIO_H3800_ASIC2_OPT_PCM_RESET (1 << 8) /* Output: */ +#define GPIO_H3800_ASIC2_OPT_RESET (1 << 9) /* Output: */ +#define GPIO_H3800_ASIC2_USB_DETECT_N (1 << 10) /* Input : */ +#define GPIO_H3800_ASIC2_SD_CON_SLT (1 << 11) /* Input : */ + +#define _H3800_ASIC2_KPIO_Base 0x0200 +#define _H3800_ASIC2_KPIO_Direction 0x0000 /* R/W, 12 bits 1:input, 0:output */ +#define _H3800_ASIC2_KPIO_InterruptType 0x0004 /* R/W, 12 bits 1:edge, 0:level */ +#define _H3800_ASIC2_KPIO_InterruptEdgeType 0x0008 /* R/W, 12 bits 1:rising, 0:falling */ +#define _H3800_ASIC2_KPIO_InterruptLevelType 0x000C /* R/W, 12 bits 1:high, 0:low */ +#define _H3800_ASIC2_KPIO_InterruptClear 0x0010 /* W, 20 bits - 8 special */ +#define _H3800_ASIC2_KPIO_InterruptFlag 0x0010 /* R, 20 bits - 8 special - reads int status */ +#define _H3800_ASIC2_KPIO_Data 0x0014 /* R/W, 16 bits */ +#define _H3800_ASIC2_KPIO_BattFaultOut 0x0018 /* R/W, 16 bit - sets level on batt fault */ +#define _H3800_ASIC2_KPIO_InterruptEnable 0x001c /* R/W, 20 bits - 8 special */ +#define _H3800_ASIC2_KPIO_Alternate 0x003c /* R/W, 6 bits */ + +#define H3800_ASIC2_KPIO_Direction H3800_ASIC2_OFFSET( u16, KPIO, Direction ) +#define H3800_ASIC2_KPIO_InterruptType H3800_ASIC2_OFFSET( u16, KPIO, InterruptType ) +#define H3800_ASIC2_KPIO_InterruptEdgeType H3800_ASIC2_OFFSET( u16, KPIO, InterruptEdgeType ) +#define H3800_ASIC2_KPIO_InterruptLevelType H3800_ASIC2_OFFSET( u16, KPIO, InterruptLevelType ) +#define H3800_ASIC2_KPIO_InterruptClear H3800_ASIC2_OFFSET( u32, KPIO, InterruptClear ) +#define H3800_ASIC2_KPIO_InterruptFlag H3800_ASIC2_OFFSET( u32, KPIO, InterruptFlag ) +#define H3800_ASIC2_KPIO_Data H3800_ASIC2_OFFSET( u16, KPIO, Data ) +#define H3800_ASIC2_KPIO_BattFaultOut H3800_ASIC2_OFFSET( u16, KPIO, BattFaultOut ) +#define H3800_ASIC2_KPIO_InterruptEnable H3800_ASIC2_OFFSET( u32, KPIO, InterruptEnable ) +#define H3800_ASIC2_KPIO_Alternate H3800_ASIC2_OFFSET( u16, KPIO, Alternate ) + +#define H3800_ASIC2_KPIO_SPI_INT ( 1 << 16 ) +#define H3800_ASIC2_KPIO_OWM_INT ( 1 << 17 ) +#define H3800_ASIC2_KPIO_ADC_INT ( 1 << 18 ) +#define H3800_ASIC2_KPIO_UART_0_INT ( 1 << 19 ) +#define H3800_ASIC2_KPIO_UART_1_INT ( 1 << 20 ) +#define H3800_ASIC2_KPIO_TIMER_0_INT ( 1 << 21 ) +#define H3800_ASIC2_KPIO_TIMER_1_INT ( 1 << 22 ) +#define H3800_ASIC2_KPIO_TIMER_2_INT ( 1 << 23 ) + +#define KPIO_H3800_ASIC2_RECORD_BTN_N (1 << 0) /* Record button */ +#define KPIO_H3800_ASIC2_KEY_5W1_N (1 << 1) /* Keypad */ +#define KPIO_H3800_ASIC2_KEY_5W2_N (1 << 2) /* */ +#define KPIO_H3800_ASIC2_KEY_5W3_N (1 << 3) /* */ +#define KPIO_H3800_ASIC2_KEY_5W4_N (1 << 4) /* */ +#define KPIO_H3800_ASIC2_KEY_5W5_N (1 << 5) /* */ +#define KPIO_H3800_ASIC2_KEY_LEFT_N (1 << 6) /* */ +#define KPIO_H3800_ASIC2_KEY_RIGHT_N (1 << 7) /* */ +#define KPIO_H3800_ASIC2_KEY_AP1_N (1 << 8) /* Old "Calendar" */ +#define KPIO_H3800_ASIC2_KEY_AP2_N (1 << 9) /* Old "Schedule" */ +#define KPIO_H3800_ASIC2_KEY_AP3_N (1 << 10) /* Old "Q" */ +#define KPIO_H3800_ASIC2_KEY_AP4_N (1 << 11) /* Old "Undo" */ + +/* Alternate KPIO functions (set by default) */ +#define KPIO_ALT_H3800_ASIC2_KEY_5W1_N (1 << 1) /* Action key */ +#define KPIO_ALT_H3800_ASIC2_KEY_5W2_N (1 << 2) /* J1 of keypad input */ +#define KPIO_ALT_H3800_ASIC2_KEY_5W3_N (1 << 3) /* J2 of keypad input */ +#define KPIO_ALT_H3800_ASIC2_KEY_5W4_N (1 << 4) /* J3 of keypad input */ +#define KPIO_ALT_H3800_ASIC2_KEY_5W5_N (1 << 5) /* J4 of keypad input */ + +#define _H3800_ASIC2_SPI_Base 0x0400 +#define _H3800_ASIC2_SPI_Control 0x0000 /* R/W 8 bits */ +#define _H3800_ASIC2_SPI_Data 0x0004 /* R/W 8 bits */ +#define _H3800_ASIC2_SPI_ChipSelectDisabled 0x0008 /* W 8 bits */ + +#define H3800_ASIC2_SPI_Control H3800_ASIC2_OFFSET( u8, SPI, Control ) +#define H3800_ASIC2_SPI_Data H3800_ASIC2_OFFSET( u8, SPI, Data ) +#define H3800_ASIC2_SPI_ChipSelectDisabled H3800_ASIC2_OFFSET( u8, SPI, ChipSelectDisabled ) + +#define _H3800_ASIC2_PWM_0_Base 0x0600 +#define _H3800_ASIC2_PWM_1_Base 0x0700 +#define _H3800_ASIC2_PWM_TimeBase 0x0000 /* R/W 6 bits */ +#define _H3800_ASIC2_PWM_PeriodTime 0x0004 /* R/W 12 bits */ +#define _H3800_ASIC2_PWM_DutyTime 0x0008 /* R/W 12 bits */ + +#define H3800_ASIC2_PWM_0_TimeBase H3800_ASIC2_NOFFSET( u8, PWM, 0, TimeBase ) +#define H3800_ASIC2_PWM_0_PeriodTime H3800_ASIC2_NOFFSET( u16, PWM, 0, PeriodTime ) +#define H3800_ASIC2_PWM_0_DutyTime H3800_ASIC2_NOFFSET( u16, PWM, 0, DutyTime ) + +#define H3800_ASIC2_PWM_1_TimeBase H3800_ASIC2_NOFFSET( u8, PWM, 1, TimeBase ) +#define H3800_ASIC2_PWM_1_PeriodTime H3800_ASIC2_NOFFSET( u16, PWM, 1, PeriodTime ) +#define H3800_ASIC2_PWM_1_DutyTime H3800_ASIC2_NOFFSET( u16, PWM, 1, DutyTime ) + +#define H3800_ASIC2_PWM_TIMEBASE_MASK 0xf /* Low 4 bits sets time base, max = 8 */ +#define H3800_ASIC2_PWM_TIMEBASE_ENABLE ( 1 << 4 ) /* Enable clock */ +#define H3800_ASIC2_PWM_TIMEBASE_CLEAR ( 1 << 5 ) /* Clear the PWM */ + +#define _H3800_ASIC2_LED_0_Base 0x0800 +#define _H3800_ASIC2_LED_1_Base 0x0880 +#define _H3800_ASIC2_LED_2_Base 0x0900 +#define _H3800_ASIC2_LED_TimeBase 0x0000 /* R/W 7 bits */ +#define _H3800_ASIC2_LED_PeriodTime 0x0004 /* R/W 12 bits */ +#define _H3800_ASIC2_LED_DutyTime 0x0008 /* R/W 12 bits */ +#define _H3800_ASIC2_LED_AutoStopCount 0x000c /* R/W 16 bits */ + +#define H3800_ASIC2_LED_0_TimeBase H3800_ASIC2_NOFFSET( u8, LED, 0, TimeBase ) +#define H3800_ASIC2_LED_0_PeriodTime H3800_ASIC2_NOFFSET( u16, LED, 0, PeriodTime ) +#define H3800_ASIC2_LED_0_DutyTime H3800_ASIC2_NOFFSET( u16, LED, 0, DutyTime ) +#define H3800_ASIC2_LED_0_AutoStopClock H3800_ASIC2_NOFFSET( u16, LED, 0, AutoStopClock ) + +#define H3800_ASIC2_LED_1_TimeBase H3800_ASIC2_NOFFSET( u8, LED, 1, TimeBase ) +#define H3800_ASIC2_LED_1_PeriodTime H3800_ASIC2_NOFFSET( u16, LED, 1, PeriodTime ) +#define H3800_ASIC2_LED_1_DutyTime H3800_ASIC2_NOFFSET( u16, LED, 1, DutyTime ) +#define H3800_ASIC2_LED_1_AutoStopClock H3800_ASIC2_NOFFSET( u16, LED, 1, AutoStopClock ) + +#define H3800_ASIC2_LED_2_TimeBase H3800_ASIC2_NOFFSET( u8, LED, 2, TimeBase ) +#define H3800_ASIC2_LED_2_PeriodTime H3800_ASIC2_NOFFSET( u16, LED, 2, PeriodTime ) +#define H3800_ASIC2_LED_2_DutyTime H3800_ASIC2_NOFFSET( u16, LED, 2, DutyTime ) +#define H3800_ASIC2_LED_2_AutoStopClock H3800_ASIC2_NOFFSET( u16, LED, 2, AutoStopClock ) + +#define H3800_ASIC2_LED_TIMEBASE_MASK 0x0f /* Low 4 bits sets time base, max = 13 */ +#define H3800_ASIC2_LED_TIMEBASE_BLINK ( 1 << 4 ) /* Enable blinking */ +#define H3800_ASIC2_LED_TIMEBASE_AUTOSTOP ( 1 << 5 ) +#define H3800_ASIC2_LED_TIMEBASE_ALWAYS ( 1 << 6 ) /* Enable blink always */ + +#define _H3800_ASIC2_UART_0_Base 0x0A00 +#define _H3800_ASIC2_UART_1_Base 0x0C00 +#define _H3800_ASIC2_UART_Receive 0x0000 /* R 8 bits */ +#define _H3800_ASIC2_UART_Transmit 0x0000 /* W 8 bits */ +#define _H3800_ASIC2_UART_IntEnable 0x0004 /* R/W 8 bits */ +#define _H3800_ASIC2_UART_IntVerify 0x0008 /* R/W 8 bits */ +#define _H3800_ASIC2_UART_FIFOControl 0x000c /* R/W 8 bits */ +#define _H3800_ASIC2_UART_LineControl 0x0010 /* R/W 8 bits */ +#define _H3800_ASIC2_UART_ModemStatus 0x0014 /* R/W 8 bits */ +#define _H3800_ASIC2_UART_LineStatus 0x0018 /* R/W 8 bits */ +#define _H3800_ASIC2_UART_ScratchPad 0x001c /* R/W 8 bits */ +#define _H3800_ASIC2_UART_DivisorLatchL 0x0020 /* R/W 8 bits */ +#define _H3800_ASIC2_UART_DivisorLatchH 0x0024 /* R/W 8 bits */ + +#define H3800_ASIC2_UART_0_Receive H3800_ASIC2_NOFFSET( u8, UART, 0, Receive ) +#define H3800_ASIC2_UART_0_Transmit H3800_ASIC2_NOFFSET( u8, UART, 0, Transmit ) +#define H3800_ASIC2_UART_0_IntEnable H3800_ASIC2_NOFFSET( u8, UART, 0, IntEnable ) +#define H3800_ASIC2_UART_0_IntVerify H3800_ASIC2_NOFFSET( u8, UART, 0, IntVerify ) +#define H3800_ASIC2_UART_0_FIFOControl H3800_ASIC2_NOFFSET( u8, UART, 0, FIFOControl ) +#define H3800_ASIC2_UART_0_LineControl H3800_ASIC2_NOFFSET( u8, UART, 0, LineControl ) +#define H3800_ASIC2_UART_0_ModemStatus H3800_ASIC2_NOFFSET( u8, UART, 0, ModemStatus ) +#define H3800_ASIC2_UART_0_LineStatus H3800_ASIC2_NOFFSET( u8, UART, 0, LineStatus ) +#define H3800_ASIC2_UART_0_ScratchPad H3800_ASIC2_NOFFSET( u8, UART, 0, ScratchPad ) +#define H3800_ASIC2_UART_0_DivisorLatchL H3800_ASIC2_NOFFSET( u8, UART, 0, DivisorLatchL ) +#define H3800_ASIC2_UART_0_DivisorLatchH H3800_ASIC2_NOFFSET( u8, UART, 0, DivisorLatchH ) + +#define H3800_ASIC2_UART_1_Receive H3800_ASIC2_NOFFSET( u8, UART, 1, Receive ) +#define H3800_ASIC2_UART_1_Transmit H3800_ASIC2_NOFFSET( u8, UART, 1, Transmit ) +#define H3800_ASIC2_UART_1_IntEnable H3800_ASIC2_NOFFSET( u8, UART, 1, IntEnable ) +#define H3800_ASIC2_UART_1_IntVerify H3800_ASIC2_NOFFSET( u8, UART, 1, IntVerify ) +#define H3800_ASIC2_UART_1_FIFOControl H3800_ASIC2_NOFFSET( u8, UART, 1, FIFOControl ) +#define H3800_ASIC2_UART_1_LineControl H3800_ASIC2_NOFFSET( u8, UART, 1, LineControl ) +#define H3800_ASIC2_UART_1_ModemStatus H3800_ASIC2_NOFFSET( u8, UART, 1, ModemStatus ) +#define H3800_ASIC2_UART_1_LineStatus H3800_ASIC2_NOFFSET( u8, UART, 1, LineStatus ) +#define H3800_ASIC2_UART_1_ScratchPad H3800_ASIC2_NOFFSET( u8, UART, 1, ScratchPad ) +#define H3800_ASIC2_UART_1_DivisorLatchL H3800_ASIC2_NOFFSET( u8, UART, 1, DivisorLatchL ) +#define H3800_ASIC2_UART_1_DivisorLatchH H3800_ASIC2_NOFFSET( u8, UART, 1, DivisorLatchH ) + +#define _H3800_ASIC2_TIMER_Base 0x0E00 +#define _H3800_ASIC2_TIMER_Command 0x0000 /* R/W 8 bits */ + +#define H3800_ASIC2_TIMER_Command H3800_ASIC2_OFFSET( u8, Timer, Command ) + +#define H3800_ASIC2_TIMER_GAT_0 ( 1 << 0 ) /* Gate enable, counter 0 */ +#define H3800_ASIC2_TIMER_GAT_1 ( 1 << 1 ) /* Gate enable, counter 1 */ +#define H3800_ASIC2_TIMER_GAT_2 ( 1 << 2 ) /* Gate enable, counter 2 */ +#define H3800_ASIC2_TIMER_CLK_0 ( 1 << 3 ) /* Clock enable, counter 0 */ +#define H3800_ASIC2_TIMER_CLK_1 ( 1 << 4 ) /* Clock enable, counter 1 */ +#define H3800_ASIC2_TIMER_CLK_2 ( 1 << 5 ) /* Clock enable, counter 2 */ +#define H3800_ASIC2_TIMER_MODE_0 ( 1 << 6 ) /* Mode 0 enable, counter 0 */ +#define H3800_ASIC2_TIMER_MODE_1 ( 1 << 7 ) /* Mode 0 enable, counter 1 */ + +#define _H3800_ASIC2_CLOCK_Base 0x1000 +#define _H3800_ASIC2_CLOCK_Enable 0x0000 /* R/W 18 bits */ + +#define H3800_ASIC2_CLOCK_Enable H3800_ASIC2_OFFSET( u32, CLOCK, Enable ) + +#define H3800_ASIC2_CLOCK_AUDIO_1 0x0001 /* Enable 4.1 MHz clock for 8Khz and 4khz sample rate */ +#define H3800_ASIC2_CLOCK_AUDIO_2 0x0002 /* Enable 12.3 MHz clock for 48Khz and 32khz sample rate */ +#define H3800_ASIC2_CLOCK_AUDIO_3 0x0004 /* Enable 5.6 MHz clock for 11 kHZ sample rate */ +#define H3800_ASIC2_CLOCK_AUDIO_4 0x0008 /* Enable 11.289 MHz clock for 44 and 22 kHz sample rate */ +#define H3800_ASIC2_CLOCK_ADC ( 1 << 4 ) /* 1.024 MHz clock to ADC */ +#define H3800_ASIC2_CLOCK_SPI ( 1 << 5 ) /* 4.096 MHz clock to SPI */ +#define H3800_ASIC2_CLOCK_OWM ( 1 << 6 ) /* 4.096 MHz clock to OWM */ +#define H3800_ASIC2_CLOCK_PWM ( 1 << 7 ) /* 2.048 MHz clock to PWM */ +#define H3800_ASIC2_CLOCK_UART_1 ( 1 << 8 ) /* 24.576 MHz clock to UART1 (turn off bit 16) */ +#define H3800_ASIC2_CLOCK_UART_0 ( 1 << 9 ) /* 24.576 MHz clock to UART0 (turn off bit 17) */ +#define H3800_ASIC2_CLOCK_SD_1 ( 1 << 10 ) /* 16.934 MHz to SD */ +#define H3800_ASIC2_CLOCK_SD_2 ( 2 << 10 ) /* 24.576 MHz to SD */ +#define H3800_ASIC2_CLOCK_SD_3 ( 3 << 10 ) /* 33.869 MHz to SD */ +#define H3800_ASIC2_CLOCK_SD_4 ( 4 << 10 ) /* 49.152 MHz to SD */ +#define H3800_ASIC2_CLOCK_EX0 ( 1 << 13 ) /* Enable 32.768 kHz crystal */ +#define H3800_ASIC2_CLOCK_EX1 ( 1 << 14 ) /* Enable 24.576 MHz crystal */ +#define H3800_ASIC2_CLOCK_EX2 ( 1 << 15 ) /* Enable 33.869 MHz crystal */ +#define H3800_ASIC2_CLOCK_SLOW_UART_1 ( 1 << 16 ) /* Enable 3.686 MHz to UART1 (turn off bit 8) */ +#define H3800_ASIC2_CLOCK_SLOW_UART_0 ( 1 << 17 ) /* Enable 3.686 MHz to UART0 (turn off bit 9) */ + +#define _H3800_ASIC2_ADC_Base 0x1200 +#define _H3800_ASIC2_ADC_Multiplexer 0x0000 /* R/W 4 bits - low 3 bits set channel */ +#define _H3800_ASIC2_ADC_ControlStatus 0x0004 /* R/W 8 bits */ +#define _H3800_ASIC2_ADC_Data 0x0008 /* R 10 bits */ + +#define H3800_ASIC2_ADC_Multiplexer H3800_ASIC2_OFFSET( u8, ADC, Multiplexer ) +#define H3800_ASIC2_ADC_ControlStatus H3800_ASIC2_OFFSET( u8, ADC, ControlStatus ) +#define H3800_ASIC2_ADC_Data H3800_ASIC2_OFFSET( u16, ADC, Data ) + +#define H3600_ASIC2_ADC_MUX_CHANNEL_MASK 0x07 /* Low 3 bits sets channel. max = 4 */ +#define H3600_ASIC2_ADC_MUX_CLKEN ( 1 << 3 ) /* Enable clock */ + +#define H3600_ASIC2_ADC_CSR_ADPS_MASK 0x0f /* Low 4 bits sets prescale, max = 8 */ +#define H3600_ASIC2_ADC_CSR_FREE_RUN ( 1 << 4 ) +#define H3600_ASIC2_ADC_CSR_INT_ENABLE ( 1 << 5 ) +#define H3600_ASIC2_ADC_CSR_START ( 1 << 6 ) /* Set to start conversion. Goes to 0 when done */ +#define H3600_ASIC2_ADC_CSR_ENABLE ( 1 << 7 ) /* 1:power up ADC, 0:power down */ + + +#define _H3800_ASIC2_INTR_Base 0x1600 +#define _H3800_ASIC2_INTR_MaskAndFlag 0x0000 /* R/(W) 8bits */ +#define _H3800_ASIC2_INTR_ClockPrescale 0x0004 /* R/(W) 5bits */ +#define _H3800_ASIC2_INTR_TimerSet 0x0008 /* R/(W) 8bits */ + +#define H3800_ASIC2_INTR_MaskAndFlag H3800_ASIC2_OFFSET( u8, INTR, MaskAndFlag ) +#define H3800_ASIC2_INTR_ClockPrescale H3800_ASIC2_OFFSET( u8, INTR, ClockPrescale ) +#define H3800_ASIC2_INTR_TimerSet H3800_ASIC2_OFFSET( u8, INTR, TimerSet ) + +#define H3800_ASIC2_INTR_GLOBAL_MASK ( 1 << 0 ) /* Global interrupt mask */ +#define H3800_ASIC2_INTR_POWER_ON_RESET ( 1 << 1 ) /* 01: Power on reset (bits 1 & 2 ) */ +#define H3800_ASIC2_INTR_EXTERNAL_RESET ( 2 << 1 ) /* 10: External reset (bits 1 & 2 ) */ +#define H3800_ASIC2_INTR_MASK_UART_0 ( 1 << 4 ) +#define H3800_ASIC2_INTR_MASK_UART_1 ( 1 << 5 ) +#define H3800_ASIC2_INTR_MASK_TIMER ( 1 << 6 ) +#define H3800_ASIC2_INTR_MASK_OWM ( 1 << 7 ) + +#define H3800_ASIC2_INTR_CLOCK_PRESCALE 0x0f /* 4 bits, max 14 */ +#define H3800_ASIC2_INTR_SET ( 1 << 4 ) /* Time base enable */ + + +#define _H3800_ASIC2_OWM_Base 0x1800 +#define _H3800_ASIC2_OWM_Command 0x0000 /* R/W 4 bits command register */ +#define _H3800_ASIC2_OWM_Data 0x0004 /* R/W 8 bits, transmit / receive buffer */ +#define _H3800_ASIC2_OWM_Interrupt 0x0008 /* R/W Command register */ +#define _H3800_ASIC2_OWM_InterruptEnable 0x000c /* R/W Command register */ +#define _H3800_ASIC2_OWM_ClockDivisor 0x0010 /* R/W 5 bits of divisor and pre-scale */ + +#define H3800_ASIC2_OWM_Command H3800_ASIC2_OFFSET( u8, OWM, Command ) +#define H3800_ASIC2_OWM_Data H3800_ASIC2_OFFSET( u8, OWM, Data ) +#define H3800_ASIC2_OWM_Interrupt H3800_ASIC2_OFFSET( u8, OWM, Interrupt ) +#define H3800_ASIC2_OWM_InterruptEnable H3800_ASIC2_OFFSET( u8, OWM, InterruptEnable ) +#define H3800_ASIC2_OWM_ClockDivisor H3800_ASIC2_OFFSET( u8, OWM, ClockDivisor ) + +#define H3800_ASIC2_OWM_CMD_ONE_WIRE_RESET ( 1 << 0 ) /* Set to force reset on 1-wire bus */ +#define H3800_ASIC2_OWM_CMD_SRA ( 1 << 1 ) /* Set to switch to Search ROM accelerator mode */ +#define H3800_ASIC2_OWM_CMD_DQ_OUTPUT ( 1 << 2 ) /* Write only - forces bus low */ +#define H3800_ASIC2_OWM_CMD_DQ_INPUT ( 1 << 3 ) /* Read only - reflects state of bus */ + +#define H3800_ASIC2_OWM_INT_PD ( 1 << 0 ) /* Presence detect */ +#define H3800_ASIC2_OWM_INT_PDR ( 1 << 1 ) /* Presence detect result */ +#define H3800_ASIC2_OWM_INT_TBE ( 1 << 2 ) /* Transmit buffer empty */ +#define H3800_ASIC2_OWM_INT_TEMT ( 1 << 3 ) /* Transmit shift register empty */ +#define H3800_ASIC2_OWM_INT_RBF ( 1 << 4 ) /* Receive buffer full */ + +#define H3800_ASIC2_OWM_INTEN_EPD ( 1 << 0 ) /* Enable receive buffer full interrupt */ +#define H3800_ASIC2_OWM_INTEN_IAS ( 1 << 1 ) /* Enable transmit shift register empty interrupt */ +#define H3800_ASIC2_OWM_INTEN_ETBE ( 1 << 2 ) /* Enable transmit buffer empty interrupt */ +#define H3800_ASIC2_OWM_INTEN_ETMT ( 1 << 3 ) /* INTR active state */ +#define H3800_ASIC2_OWM_INTEN_ERBF ( 1 << 4 ) /* Enable presence detect interrupt */ + +#define _H3800_ASIC2_FlashCtl_Base 0x1A00 + +/****************************************************/ +/* H3800, ASIC #1 + * This ASIC is accesed through ASIC #2, and + * mapped into the 1c00 - 1f00 region + */ + +#define H3800_ASIC1_OFFSET(s,x,y) \ + (*((volatile s *) (_H3800_ASIC2_Base + _H3800_ASIC1_ ## x ## _Base + (_H3800_ASIC1_ ## x ## _ ## y << 1)))) + +#define _H3800_ASIC1_MMC_Base 0x1c00 + +#define _H3800_ASIC1_MMC_StartStopClock 0x00 /* R/W 8bit */ +#define _H3800_ASIC1_MMC_Status 0x02 /* R See below, default 0x0040 */ +#define _H3800_ASIC1_MMC_ClockRate 0x04 /* R/W 8bit, low 3 bits are clock divisor */ +#define _H3800_ASIC1_MMC_SPIRegister 0x08 /* R/W 8bit, see below */ +#define _H3800_ASIC1_MMC_CmdDataCont 0x0a /* R/W 8bit, write to start MMC adapter */ +#define _H3800_ASIC1_MMC_ResponseTimeout 0x0c /* R/W 8bit, clocks before response timeout */ +#define _H3800_ASIC1_MMC_ReadTimeout 0x0e /* R/W 16bit, clocks before received data timeout */ +#define _H3800_ASIC1_MMC_BlockLength 0x10 /* R/W 10bit */ +#define _H3800_ASIC1_MMC_NumOfBlocks 0x12 /* R/W 16bit, in block mode, number of blocks */ +#define _H3800_ASIC1_MMC_InterruptMask 0x1a /* R/W 8bit */ +#define _H3800_ASIC1_MMC_CommandNumber 0x1c /* R/W 6 bits */ +#define _H3800_ASIC1_MMC_ArgumentH 0x1e /* R/W 16 bits */ +#define _H3800_ASIC1_MMC_ArgumentL 0x20 /* R/W 16 bits */ +#define _H3800_ASIC1_MMC_ResFifo 0x22 /* R 8 x 16 bits - contains response FIFO */ +#define _H3800_ASIC1_MMC_BufferPartFull 0x28 /* R/W 8 bits */ + +#define H3800_ASIC1_MMC_StartStopClock H3800_ASIC1_OFFSET( u8, MMC, StartStopClock ) +#define H3800_ASIC1_MMC_Status H3800_ASIC1_OFFSET( u16, MMC, Status ) +#define H3800_ASIC1_MMC_ClockRate H3800_ASIC1_OFFSET( u8, MMC, ClockRate ) +#define H3800_ASIC1_MMC_SPIRegister H3800_ASIC1_OFFSET( u8, MMC, SPIRegister ) +#define H3800_ASIC1_MMC_CmdDataCont H3800_ASIC1_OFFSET( u8, MMC, CmdDataCont ) +#define H3800_ASIC1_MMC_ResponseTimeout H3800_ASIC1_OFFSET( u8, MMC, ResponseTimeout ) +#define H3800_ASIC1_MMC_ReadTimeout H3800_ASIC1_OFFSET( u16, MMC, ReadTimeout ) +#define H3800_ASIC1_MMC_BlockLength H3800_ASIC1_OFFSET( u16, MMC, BlockLength ) +#define H3800_ASIC1_MMC_NumOfBlocks H3800_ASIC1_OFFSET( u16, MMC, NumOfBlocks ) +#define H3800_ASIC1_MMC_InterruptMask H3800_ASIC1_OFFSET( u8, MMC, InterruptMask ) +#define H3800_ASIC1_MMC_CommandNumber H3800_ASIC1_OFFSET( u8, MMC, CommandNumber ) +#define H3800_ASIC1_MMC_ArgumentH H3800_ASIC1_OFFSET( u16, MMC, ArgumentH ) +#define H3800_ASIC1_MMC_ArgumentL H3800_ASIC1_OFFSET( u16, MMC, ArgumentL ) +#define H3800_ASIC1_MMC_ResFifo H3800_ASIC1_OFFSET( u16, MMC, ResFifo ) +#define H3800_ASIC1_MMC_BufferPartFull H3800_ASIC1_OFFSET( u8, MMC, BufferPartFull ) + +#define H3800_ASIC1_MMC_STOP_CLOCK (1 << 0) /* Write to "StartStopClock" register */ +#define H3800_ASIC1_MMC_START_CLOCK (1 << 1) + +#define H3800_ASIC1_MMC_STATUS_READ_TIMEOUT (1 << 0) +#define H3800_ASIC1_MMC_STATUS_RESPONSE_TIMEOUT (1 << 1) +#define H3800_ASIC1_MMC_STATUS_CRC_WRITE_ERROR (1 << 2) +#define H3800_ASIC1_MMC_STATUS_CRC_READ_ERROR (1 << 3) +#define H3800_ASIC1_MMC_STATUS_SPI_READ_ERROR (1 << 4) /* SPI data token error received */ +#define H3800_ASIC1_MMC_STATUS_CRC_RESPONSE_ERROR (1 << 5) +#define H3800_ASIC1_MMC_STATUS_FIFO_EMPTY (1 << 6) +#define H3800_ASIC1_MMC_STATUS_FIFO_FULL (1 << 7) +#define H3800_ASIC1_MMC_STATUS_CLOCK_ENABLE (1 << 8) /* MultiMediaCard clock stopped */ +#define H3800_ASIC1_MMC_STATUS_DATA_TRANSFER_DONE (1 << 11) /* Write operation, indicates transfer finished */ +#define H3800_ASIC1_MMC_STATUS_END_PROGRAM (1 << 12) /* End write and read operations */ +#define H3800_ASIC1_MMC_STATUS_END_COMMAND_RESPONSE (1 << 13) /* End command response */ + +#define H3800_ASIC1_MMC_SPI_REG_SPI_ENABLE (1 << 0) /* Enables SPI mode */ +#define H3800_ASIC1_MMC_SPI_REG_CRC_ON (1 << 1) /* 1:turn on CRC */ +#define H3800_ASIC1_MMC_SPI_REG_SPI_CS_ENABLE (1 << 2) /* 1:turn on SPI CS */ +#define H3800_ASIC1_MMC_SPI_REG_CS_ADDRESS_MASK 0x38 /* Bits 3,4,5 are the SPI CS relative address */ + +#define H3800_ASIC1_MMC_CMD_DATA_CONT_FORMAT_NO_RESPONSE 0x00 +#define H3800_ASIC1_MMC_CMD_DATA_CONT_FORMAT_R1 0x01 +#define H3800_ASIC1_MMC_CMD_DATA_CONT_FORMAT_R2 0x02 +#define H3800_ASIC1_MMC_CMD_DATA_CONT_FORMAT_R3 0x03 +#define H3800_ASIC1_MMC_CMD_DATA_CONT_DATA_ENABLE (1 << 2) /* This command contains a data transfer */ +#define H3800_ASIC1_MMC_CMD_DATA_CONT_WRITE (1 << 3) /* This data transfer is a write */ +#define H3800_ASIC1_MMC_CMD_DATA_CONT_STREAM_MODE (1 << 4) /* This data transfer is in stream mode */ +#define H3800_ASIC1_MMC_CMD_DATA_CONT_BUSY_BIT (1 << 5) /* Busy signal expected after current cmd */ +#define H3800_ASIC1_MMC_CMD_DATA_CONT_INITIALIZE (1 << 6) /* Enables the 80 bits for initializing card */ + +#define H3800_ASIC1_MMC_INT_MASK_DATA_TRANSFER_DONE (1 << 0) +#define H3800_ASIC1_MMC_INT_MASK_PROGRAM_DONE (1 << 1) +#define H3800_ASIC1_MMC_INT_MASK_END_COMMAND_RESPONSE (1 << 2) +#define H3800_ASIC1_MMC_INT_MASK_BUFFER_READY (1 << 3) + +#define H3800_ASIC1_MMC_BUFFER_PART_FULL (1 << 0) + +/********* GPIO **********/ + +#define _H3800_ASIC1_GPIO_Base 0x1e00 + +#define _H3800_ASIC1_GPIO_Mask 0x30 /* R/W 0:don't mask, 1:mask interrupt */ +#define _H3800_ASIC1_GPIO_Direction 0x32 /* R/W 0:input, 1:output */ +#define _H3800_ASIC1_GPIO_Out 0x34 /* R/W 0:output low, 1:output high */ +#define _H3800_ASIC1_GPIO_TriggerType 0x36 /* R/W 0:level, 1:edge */ +#define _H3800_ASIC1_GPIO_EdgeTrigger 0x38 /* R/W 0:falling, 1:rising */ +#define _H3800_ASIC1_GPIO_LevelTrigger 0x3A /* R/W 0:low, 1:high level detect */ +#define _H3800_ASIC1_GPIO_LevelStatus 0x3C /* R/W 0:none, 1:detect */ +#define _H3800_ASIC1_GPIO_EdgeStatus 0x3E /* R/W 0:none, 1:detect */ +#define _H3800_ASIC1_GPIO_State 0x40 /* R See masks below (default 0) */ +#define _H3800_ASIC1_GPIO_Reset 0x42 /* R/W See masks below (default 0x04) */ +#define _H3800_ASIC1_GPIO_SleepMask 0x44 /* R/W 0:don't mask, 1:mask trigger in sleep mode */ +#define _H3800_ASIC1_GPIO_SleepDir 0x46 /* R/W direction 0:input, 1:ouput in sleep mode */ +#define _H3800_ASIC1_GPIO_SleepOut 0x48 /* R/W level 0:low, 1:high in sleep mode */ +#define _H3800_ASIC1_GPIO_Status 0x4A /* R Pin status */ +#define _H3800_ASIC1_GPIO_BattFaultDir 0x4C /* R/W direction 0:input, 1:output in batt_fault */ +#define _H3800_ASIC1_GPIO_BattFaultOut 0x4E /* R/W level 0:low, 1:high in batt_fault */ + +#define H3800_ASIC1_GPIO_Mask H3800_ASIC1_OFFSET( u16, GPIO, Mask ) +#define H3800_ASIC1_GPIO_Direction H3800_ASIC1_OFFSET( u16, GPIO, Direction ) +#define H3800_ASIC1_GPIO_Out H3800_ASIC1_OFFSET( u16, GPIO, Out ) +#define H3800_ASIC1_GPIO_TriggerType H3800_ASIC1_OFFSET( u16, GPIO, TriggerType ) +#define H3800_ASIC1_GPIO_EdgeTrigger H3800_ASIC1_OFFSET( u16, GPIO, EdgeTrigger ) +#define H3800_ASIC1_GPIO_LevelTrigger H3800_ASIC1_OFFSET( u16, GPIO, LevelTrigger ) +#define H3800_ASIC1_GPIO_LevelStatus H3800_ASIC1_OFFSET( u16, GPIO, LevelStatus ) +#define H3800_ASIC1_GPIO_EdgeStatus H3800_ASIC1_OFFSET( u16, GPIO, EdgeStatus ) +#define H3800_ASIC1_GPIO_State H3800_ASIC1_OFFSET( u8, GPIO, State ) +#define H3800_ASIC1_GPIO_Reset H3800_ASIC1_OFFSET( u8, GPIO, Reset ) +#define H3800_ASIC1_GPIO_SleepMask H3800_ASIC1_OFFSET( u16, GPIO, SleepMask ) +#define H3800_ASIC1_GPIO_SleepDir H3800_ASIC1_OFFSET( u16, GPIO, SleepDir ) +#define H3800_ASIC1_GPIO_SleepOut H3800_ASIC1_OFFSET( u16, GPIO, SleepOut ) +#define H3800_ASIC1_GPIO_Status H3800_ASIC1_OFFSET( u16, GPIO, Status ) +#define H3800_ASIC1_GPIO_BattFaultDir H3800_ASIC1_OFFSET( u16, GPIO, BattFaultDir ) +#define H3800_ASIC1_GPIO_BattFaultOut H3800_ASIC1_OFFSET( u16, GPIO, BattFaultOut ) + +#define H3800_ASIC1_GPIO_STATE_MASK (1 << 0) +#define H3800_ASIC1_GPIO_STATE_DIRECTION (1 << 1) +#define H3800_ASIC1_GPIO_STATE_OUT (1 << 2) +#define H3800_ASIC1_GPIO_STATE_TRIGGER_TYPE (1 << 3) +#define H3800_ASIC1_GPIO_STATE_EDGE_TRIGGER (1 << 4) +#define H3800_ASIC1_GPIO_STATE_LEVEL_TRIGGER (1 << 5) + +#define H3800_ASIC1_GPIO_RESET_SOFTWARE (1 << 0) +#define H3800_ASIC1_GPIO_RESET_AUTO_SLEEP (1 << 1) +#define H3800_ASIC1_GPIO_RESET_FIRST_PWR_ON (1 << 2) + +/* These are all outputs */ +#define GPIO_H3800_ASIC1_IR_ON_N (1 << 0) /* Apply power to the IR Module */ +#define GPIO_H3800_ASIC1_SD_PWR_ON (1 << 1) /* Secure Digital power on */ +#define GPIO_H3800_ASIC1_RS232_ON (1 << 2) /* Turn on power to the RS232 chip ? */ +#define GPIO_H3800_ASIC1_PULSE_GEN (1 << 3) /* Goes to speaker / earphone */ +#define GPIO_H3800_ASIC1_CH_TIMER (1 << 4) /* */ +#define GPIO_H3800_ASIC1_LCD_5V_ON (1 << 5) /* Enables LCD_5V */ +#define GPIO_H3800_ASIC1_LCD_ON (1 << 6) /* Enables LCD_3V */ +#define GPIO_H3800_ASIC1_LCD_PCI (1 << 7) /* Connects to PDWN on LCD controller */ +#define GPIO_H3800_ASIC1_VGH_ON (1 << 8) /* Drives VGH on the LCD (+9??) */ +#define GPIO_H3800_ASIC1_VGL_ON (1 << 9) /* Drivers VGL on the LCD (-6??) */ +#define GPIO_H3800_ASIC1_FL_PWR_ON (1 << 10) /* Frontlight power on */ +#define GPIO_H3800_ASIC1_BT_PWR_ON (1 << 11) /* Bluetooth power on */ +#define GPIO_H3800_ASIC1_SPK_ON (1 << 12) /* */ +#define GPIO_H3800_ASIC1_EAR_ON_N (1 << 13) /* */ +#define GPIO_H3800_ASIC1_AUD_PWR_ON (1 << 14) /* */ + +/* Write enable for the flash */ + +#define _H3800_ASIC1_FlashWP_Base 0x1F00 +#define _H3800_ASIC1_FlashWP_VPP_ON 0x00 /* R 1: write, 0: protect */ +#define H3800_ASIC1_FlashWP_VPP_ON H3800_ASIC1_OFFSET( u8, FlashWP, VPP_ON ) + +#endif /* _INCLUDE_H3600_GPIO_H_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/hardware.h linux-2.5/include/asm-arm/arch-sa1100/hardware.h --- linux-2.5.1/include/asm-arm/arch-sa1100/hardware.h Fri Nov 9 22:11:15 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/hardware.h Sun Jan 6 01:38:27 2002 @@ -60,6 +60,7 @@ ( (((x)&0x00ffffff) | (((x)&(0x30000000>>VIO_SHIFT))<<VIO_SHIFT)) + PIO_START ) #ifndef __ASSEMBLY__ +#include <asm/types.h> #if 0 # define __REG(x) (*((volatile u32 *)io_p2v(x))) @@ -93,17 +94,12 @@ * This must be called *before* the corresponding IRQ is registered. * Use this instead of directly setting GRER/GFER. */ +#define GPIO_NO_EDGES 0 #define GPIO_FALLING_EDGE 1 #define GPIO_RISING_EDGE 2 #define GPIO_BOTH_EDGES 3 #ifndef __ASSEMBLY__ extern void set_GPIO_IRQ_edge( int gpio_mask, int edge_mask ); - -/* - * Return the current CPU clock frequency in units of 100kHz - */ -extern unsigned short get_cclk_frequency(void); - #endif @@ -145,9 +141,7 @@ #include "empeg.h" #endif -#ifdef CONFIG_SA1100_H3600 #include "h3600.h" -#endif #ifdef CONFIG_SA1100_ITSY #include "itsy.h" @@ -185,6 +179,8 @@ #include "adsbitsy.h" #endif +#include "system3.h" + #ifdef CONFIG_SA1101 /* @@ -209,21 +205,6 @@ #if defined(CONFIG_SA1100_FLEXANET) #include "flexanet.h" -#endif - -#ifdef CONFIG_SA1111 - -/* - * The SA1111 is always located at virtual 0xf4000000. - */ - -#define SA1111_VBASE 0xf4000000 - -#define SA1111_p2v( x ) ((x) - SA1111_BASE + SA1111_VBASE) -#define SA1111_v2p( x ) ((x) - SA1111_VBASE + SA1111_BASE) - -#include "SA-1111.h" - #endif #endif /* _ASM_ARCH_HARDWARE_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/io.h linux-2.5/include/asm-arm/arch-sa1100/io.h --- linux-2.5.1/include/asm-arm/arch-sa1100/io.h Fri Feb 9 00:32:44 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/io.h Sun Jan 6 01:38:27 2002 @@ -20,13 +20,4 @@ #define __mem_pci(a) ((unsigned long)(a)) #define __mem_isa(a) ((unsigned long)(a)) -/* - * Generic virtual read/write - */ -#define __arch_getw(a) (*(volatile unsigned short *)(a)) -#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) - -#define iomem_valid_addr(iomem,sz) (1) -#define iomem_to_phys(iomem) (iomem) - #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/irqs.h linux-2.5/include/asm-arm/arch-sa1100/irqs.h --- linux-2.5.1/include/asm-arm/arch-sa1100/irqs.h Thu Oct 11 16:04:57 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/irqs.h Sun Jan 6 01:38:27 2002 @@ -4,154 +4,150 @@ * Copyright (C) 1996 Russell King * Copyright (C) 1998 Deborah Wallach (updates for SA1100/Brutus). * Copyright (C) 1999 Nicolas Pitre (full GPIO irq isolation) + * + * 2001/11/14 RMK Cleaned up and standardised a lot of the IRQs. */ - #include <linux/config.h> -#define SA1100_IRQ(x) (0 + (x)) - -#define IRQ_GPIO0 SA1100_IRQ(0) -#define IRQ_GPIO1 SA1100_IRQ(1) -#define IRQ_GPIO2 SA1100_IRQ(2) -#define IRQ_GPIO3 SA1100_IRQ(3) -#define IRQ_GPIO4 SA1100_IRQ(4) -#define IRQ_GPIO5 SA1100_IRQ(5) -#define IRQ_GPIO6 SA1100_IRQ(6) -#define IRQ_GPIO7 SA1100_IRQ(7) -#define IRQ_GPIO8 SA1100_IRQ(8) -#define IRQ_GPIO9 SA1100_IRQ(9) -#define IRQ_GPIO10 SA1100_IRQ(10) -#define IRQ_GPIO11_27 SA1100_IRQ(11) -#define IRQ_LCD SA1100_IRQ(12) /* LCD controller */ -#define IRQ_Ser0UDC SA1100_IRQ(13) /* Ser. port 0 UDC */ -#define IRQ_Ser1SDLC SA1100_IRQ(14) /* Ser. port 1 SDLC */ -#define IRQ_Ser1UART SA1100_IRQ(15) /* Ser. port 1 UART */ -#define IRQ_Ser2ICP SA1100_IRQ(16) /* Ser. port 2 ICP */ -#define IRQ_Ser3UART SA1100_IRQ(17) /* Ser. port 3 UART */ -#define IRQ_Ser4MCP SA1100_IRQ(18) /* Ser. port 4 MCP */ -#define IRQ_Ser4SSP SA1100_IRQ(19) /* Ser. port 4 SSP */ -#define IRQ_DMA0 SA1100_IRQ(20) /* DMA controller channel 0 */ -#define IRQ_DMA1 SA1100_IRQ(21) /* DMA controller channel 1 */ -#define IRQ_DMA2 SA1100_IRQ(22) /* DMA controller channel 2 */ -#define IRQ_DMA3 SA1100_IRQ(23) /* DMA controller channel 3 */ -#define IRQ_DMA4 SA1100_IRQ(24) /* DMA controller channel 4 */ -#define IRQ_DMA5 SA1100_IRQ(25) /* DMA controller channel 5 */ -#define IRQ_OST0 SA1100_IRQ(26) /* OS Timer match 0 */ -#define IRQ_OST1 SA1100_IRQ(27) /* OS Timer match 1 */ -#define IRQ_OST2 SA1100_IRQ(28) /* OS Timer match 2 */ -#define IRQ_OST3 SA1100_IRQ(29) /* OS Timer match 3 */ -#define IRQ_RTC1Hz SA1100_IRQ(30) /* RTC 1 Hz clock */ -#define IRQ_RTCAlrm SA1100_IRQ(31) /* RTC Alarm */ - -#define IRQ_GPIO_11_27(x) (32 + (x) - 11) - -#define IRQ_GPIO11 IRQ_GPIO_11_27(11) -#define IRQ_GPIO12 IRQ_GPIO_11_27(12) -#define IRQ_GPIO13 IRQ_GPIO_11_27(13) -#define IRQ_GPIO14 IRQ_GPIO_11_27(14) -#define IRQ_GPIO15 IRQ_GPIO_11_27(15) -#define IRQ_GPIO16 IRQ_GPIO_11_27(16) -#define IRQ_GPIO17 IRQ_GPIO_11_27(17) -#define IRQ_GPIO18 IRQ_GPIO_11_27(18) -#define IRQ_GPIO19 IRQ_GPIO_11_27(19) -#define IRQ_GPIO20 IRQ_GPIO_11_27(20) -#define IRQ_GPIO21 IRQ_GPIO_11_27(21) -#define IRQ_GPIO22 IRQ_GPIO_11_27(22) -#define IRQ_GPIO23 IRQ_GPIO_11_27(23) -#define IRQ_GPIO24 IRQ_GPIO_11_27(24) -#define IRQ_GPIO25 IRQ_GPIO_11_27(25) -#define IRQ_GPIO26 IRQ_GPIO_11_27(26) -#define IRQ_GPIO27 IRQ_GPIO_11_27(27) - -#define SA1100_GPIO_TO_IRQ(i) (((i) < 11) ? SA1100_IRQ(i) : IRQ_GPIO_11_27(i)) - -/* To get the GPIO number from an IRQ number */ -#define GPIO_11_27_IRQ(i) (11 + (i) - 32) -#define SA1100_IRQ_TO_GPIO(i) (((i) < 11) ? (i) : GPIO_11_27_IRQ(i)) - -#define NR_IRQS (IRQ_GPIO27 + 1) - - -#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || defined(CONFIG_SA1100_GRAPHICSMASTER) -#define ADS_EXT_IRQ(x) (IRQ_GPIO27 + 1 + (x)) -#undef NR_IRQS -#define NR_IRQS (ADS_EXT_IRQ(15) + 1) -#endif +#define IRQ_GPIO0 0 +#define IRQ_GPIO1 1 +#define IRQ_GPIO2 2 +#define IRQ_GPIO3 3 +#define IRQ_GPIO4 4 +#define IRQ_GPIO5 5 +#define IRQ_GPIO6 6 +#define IRQ_GPIO7 7 +#define IRQ_GPIO8 8 +#define IRQ_GPIO9 9 +#define IRQ_GPIO10 10 +#define IRQ_GPIO11_27 11 +#define IRQ_LCD 12 /* LCD controller */ +#define IRQ_Ser0UDC 13 /* Ser. port 0 UDC */ +#define IRQ_Ser1SDLC 14 /* Ser. port 1 SDLC */ +#define IRQ_Ser1UART 15 /* Ser. port 1 UART */ +#define IRQ_Ser2ICP 16 /* Ser. port 2 ICP */ +#define IRQ_Ser3UART 17 /* Ser. port 3 UART */ +#define IRQ_Ser4MCP 18 /* Ser. port 4 MCP */ +#define IRQ_Ser4SSP 19 /* Ser. port 4 SSP */ +#define IRQ_DMA0 20 /* DMA controller channel 0 */ +#define IRQ_DMA1 21 /* DMA controller channel 1 */ +#define IRQ_DMA2 22 /* DMA controller channel 2 */ +#define IRQ_DMA3 23 /* DMA controller channel 3 */ +#define IRQ_DMA4 24 /* DMA controller channel 4 */ +#define IRQ_DMA5 25 /* DMA controller channel 5 */ +#define IRQ_OST0 26 /* OS Timer match 0 */ +#define IRQ_OST1 27 /* OS Timer match 1 */ +#define IRQ_OST2 28 /* OS Timer match 2 */ +#define IRQ_OST3 29 /* OS Timer match 3 */ +#define IRQ_RTC1Hz 30 /* RTC 1 Hz clock */ +#define IRQ_RTCAlrm 31 /* RTC Alarm */ + +#define IRQ_GPIO11 32 +#define IRQ_GPIO12 33 +#define IRQ_GPIO13 34 +#define IRQ_GPIO14 35 +#define IRQ_GPIO15 36 +#define IRQ_GPIO16 37 +#define IRQ_GPIO17 38 +#define IRQ_GPIO18 39 +#define IRQ_GPIO19 40 +#define IRQ_GPIO20 41 +#define IRQ_GPIO21 42 +#define IRQ_GPIO22 43 +#define IRQ_GPIO23 44 +#define IRQ_GPIO24 45 +#define IRQ_GPIO25 46 +#define IRQ_GPIO26 47 +#define IRQ_GPIO27 48 +/* + * To get the GPIO number from an IRQ number + */ +#define GPIO_11_27_IRQ(i) ((i) - 21) -#if defined(CONFIG_SA1111) +/* + * The next 16 interrupts are for board specific purposes. Since + * the kernel can only run on one machine at a time, we can re-use + * these. If you need more, increase IRQ_BOARD_END, but keep it + * within sensible limits. IRQs 49 to 64 are available. + */ +#define IRQ_BOARD_START 49 +#define IRQ_BOARD_END 65 -#if defined(CONFIG_SA1100_GRAPHICSMASTER) -#define SA1111_IRQ(x) (ADS_EXT_IRQ(15) + 1 + 1 + (x)) +#define IRQ_SA1111_START (IRQ_BOARD_END) +#define IRQ_GPAIN0 (IRQ_BOARD_END + 0) +#define IRQ_GPAIN1 (IRQ_BOARD_END + 1) +#define IRQ_GPAIN2 (IRQ_BOARD_END + 2) +#define IRQ_GPAIN3 (IRQ_BOARD_END + 3) +#define IRQ_GPBIN0 (IRQ_BOARD_END + 4) +#define IRQ_GPBIN1 (IRQ_BOARD_END + 5) +#define IRQ_GPBIN2 (IRQ_BOARD_END + 6) +#define IRQ_GPBIN3 (IRQ_BOARD_END + 7) +#define IRQ_GPBIN4 (IRQ_BOARD_END + 8) +#define IRQ_GPBIN5 (IRQ_BOARD_END + 9) +#define IRQ_GPCIN0 (IRQ_BOARD_END + 10) +#define IRQ_GPCIN1 (IRQ_BOARD_END + 11) +#define IRQ_GPCIN2 (IRQ_BOARD_END + 12) +#define IRQ_GPCIN3 (IRQ_BOARD_END + 13) +#define IRQ_GPCIN4 (IRQ_BOARD_END + 14) +#define IRQ_GPCIN5 (IRQ_BOARD_END + 15) +#define IRQ_GPCIN6 (IRQ_BOARD_END + 16) +#define IRQ_GPCIN7 (IRQ_BOARD_END + 17) +#define IRQ_MSTXINT (IRQ_BOARD_END + 18) +#define IRQ_MSRXINT (IRQ_BOARD_END + 19) +#define IRQ_MSSTOPERRINT (IRQ_BOARD_END + 20) +#define IRQ_TPTXINT (IRQ_BOARD_END + 21) +#define IRQ_TPRXINT (IRQ_BOARD_END + 22) +#define IRQ_TPSTOPERRINT (IRQ_BOARD_END + 23) +#define SSPXMTINT (IRQ_BOARD_END + 24) +#define SSPRCVINT (IRQ_BOARD_END + 25) +#define SSPROR (IRQ_BOARD_END + 26) +#define AUDXMTDMADONEA (IRQ_BOARD_END + 32) +#define AUDRCVDMADONEA (IRQ_BOARD_END + 33) +#define AUDXMTDMADONEB (IRQ_BOARD_END + 34) +#define AUDRCVDMADONEB (IRQ_BOARD_END + 35) +#define AUDTFSR (IRQ_BOARD_END + 36) +#define AUDRFSR (IRQ_BOARD_END + 37) +#define AUDTUR (IRQ_BOARD_END + 38) +#define AUDROR (IRQ_BOARD_END + 39) +#define AUDDTS (IRQ_BOARD_END + 40) +#define AUDRDD (IRQ_BOARD_END + 41) +#define AUDSTO (IRQ_BOARD_END + 42) +#define USBPWR (IRQ_BOARD_END + 43) +#define NIRQHCIM (IRQ_BOARD_END + 44) +#define IRQHCIBUFFACC (IRQ_BOARD_END + 45) +#define IRQHCIRMTWKP (IRQ_BOARD_END + 46) +#define NHCIMFCIR (IRQ_BOARD_END + 47) +#define USB_PORT_RESUME (IRQ_BOARD_END + 48) +#define S0_READY_NINT (IRQ_BOARD_END + 49) +#define S1_READY_NINT (IRQ_BOARD_END + 50) +#define S0_CD_VALID (IRQ_BOARD_END + 51) +#define S1_CD_VALID (IRQ_BOARD_END + 52) +#define S0_BVD1_STSCHG (IRQ_BOARD_END + 53) +#define S1_BVD1_STSCHG (IRQ_BOARD_END + 54) + +/* + * Figure out the MAX IRQ number. + * + * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1. + * If graphicsclient or graphicsmaster, we don't have a SA1111. + * Otherwise, we have the standard IRQs only. + */ +#ifdef CONFIG_SA1111 +#define NR_IRQS (S1_BVD1_STSCHG + 1) +#elif defined(CONFIG_SA1100_GRAPHICSCLIENT) || \ + defined(CONFIG_SA1100_GRAPHICSMASTER) +#define NR_IRQS (IRQ_BOARD_END) #else -#define SA1111_IRQ(x) (IRQ_GPIO27 + 1 + (x)) +#define NR_IRQS (IRQ_BOARD_START) #endif -#define GPAIN0 SA1111_IRQ(0) -#define GPAIN1 SA1111_IRQ(1) -#define GPAIN2 SA1111_IRQ(2) -#define GPAIN3 SA1111_IRQ(3) -#define GPBIN0 SA1111_IRQ(4) -#define GPBIN1 SA1111_IRQ(5) -#define GPBIN2 SA1111_IRQ(6) -#define GPBIN3 SA1111_IRQ(7) -#define GPBIN4 SA1111_IRQ(8) -#define GPBIN5 SA1111_IRQ(9) -#define GPCIN0 SA1111_IRQ(10) -#define GPCIN1 SA1111_IRQ(11) -#define GPCIN2 SA1111_IRQ(12) -#define GPCIN3 SA1111_IRQ(13) -#define GPCIN4 SA1111_IRQ(14) -#define GPCIN5 SA1111_IRQ(15) -#define GPCIN6 SA1111_IRQ(16) -#define GPCIN7 SA1111_IRQ(17) -#define MSTXINT SA1111_IRQ(18) -#define MSRXINT SA1111_IRQ(19) -#define MSSTOPERRINT SA1111_IRQ(20) -#define TPTXINT SA1111_IRQ(21) -#define TPRXINT SA1111_IRQ(22) -#define TPSTOPERRINT SA1111_IRQ(23) -#define SSPXMTINT SA1111_IRQ(24) -#define SSPRCVINT SA1111_IRQ(25) -#define SSPROR SA1111_IRQ(26) -#define AUDXMTDMADONEA SA1111_IRQ(32) -#define AUDRCVDMADONEA SA1111_IRQ(33) -#define AUDXMTDMADONEB SA1111_IRQ(34) -#define AUDRCVDMADONEB SA1111_IRQ(35) -#define AUDTFSR SA1111_IRQ(36) -#define AUDRFSR SA1111_IRQ(37) -#define AUDTUR SA1111_IRQ(38) -#define AUDROR SA1111_IRQ(39) -#define AUDDTS SA1111_IRQ(40) -#define AUDRDD SA1111_IRQ(41) -#define AUDSTO SA1111_IRQ(42) -#define USBPWR SA1111_IRQ(43) -#define NIRQHCIM SA1111_IRQ(44) -#define IRQHCIBUFFACC SA1111_IRQ(45) -#define IRQHCIRMTWKP SA1111_IRQ(46) -#define NHCIMFCIR SA1111_IRQ(47) -#define USB_PORT_RESUME SA1111_IRQ(48) -#define S0_READY_NINT SA1111_IRQ(49) -#define S1_READY_NINT SA1111_IRQ(50) -#define S0_CD_VALID SA1111_IRQ(51) -#define S1_CD_VALID SA1111_IRQ(52) -#define S0_BVD1_STSCHG SA1111_IRQ(53) -#define S1_BVD1_STSCHG SA1111_IRQ(54) - -#define SA1111_IRQ_MAX SA1111_IRQ(54) - -#undef NR_IRQS -#define NR_IRQS (SA1111_IRQ_MAX + 1) - - -#ifdef CONFIG_ASSABET_NEPONSET - -#define MISC_IRQ0 SA1111_IRQ(55) -#define MISC_IRQ1 SA1111_IRQ(56) - -#undef NR_IRQS -#define NR_IRQS (SA1111_IRQ_MAX + 3) - -#endif /* CONFIG_ASSABET_NEPONSET */ +/* + * Board specific IRQs. Define them here. + * Do not surround them with ifdefs. + */ +#define IRQ_NEPONSET_SMC9196 (IRQ_BOARD_START + 0) +#define IRQ_NEPONSET_USAR (IRQ_BOARD_START + 1) -#endif /* CONFIG_SA1111 */ +/* PT Digital Board Interrupts (CONFIG_SA1100_PT_SYSTEM3) */ +#define IRQ_SYSTEM3_SMC9196 (IRQ_BOARD_START + 0) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/keyboard.h linux-2.5/include/asm-arm/arch-sa1100/keyboard.h --- linux-2.5.1/include/asm-arm/arch-sa1100/keyboard.h Thu Oct 25 20:53:54 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/keyboard.h Sun Jan 6 01:38:27 2002 @@ -13,7 +13,7 @@ #define kbd_disable_irq() do { } while(0); #define kbd_enable_irq() do { } while(0); -extern void sa1111_kbd_init_hw(void); +extern int sa1111_kbd_init_hw(void); extern void gc_kbd_init_hw(void); extern void smartio_kbd_init_hw(void); extern void cerf_kbd_init_hw(void); @@ -30,6 +30,11 @@ #ifdef CONFIG_SA1100_CERF_CPLD if (machine_is_cerf()) cerf_kbd_init_hw(); +#endif +#ifdef CONFIG_SA1100_PT_SYSTEM3 + /* TODO: add system 3 board specific functions here */ + if (machine_is_pt_system3()) + sa1111_kbd_init_hw(); #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/pcmcia.h linux-2.5/include/asm-arm/arch-sa1100/pcmcia.h --- linux-2.5.1/include/asm-arm/arch-sa1100/pcmcia.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/pcmcia.h Thu Jan 1 00:00:00 1970 @@ -1,70 +0,0 @@ -/* - * 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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/shannon.h linux-2.5/include/asm-arm/arch-sa1100/shannon.h --- linux-2.5.1/include/asm-arm/arch-sa1100/shannon.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-sa1100/shannon.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,43 @@ +#ifndef _INCLUDE_SHANNON_H +#define _INCLUDE_SHANNON_H + +/* taken from comp.os.inferno Tue, 12 Sep 2000 09:21:50 GMT, + * written by <forsyth@vitanuova.com> */ + +#define SHANNON_GPIO_SPI_FLASH GPIO_GPIO (0) /* Output - Driven low, enables SPI to flash */ +#define SHANNON_GPIO_SPI_DSP GPIO_GPIO (1) /* Output - Driven low, enables SPI to DSP */ +/* lcd lower = GPIO 2-9 */ +#define SHANNON_GPIO_SPI_OUTPUT GPIO_GPIO (10) /* Output - SPI output to DSP */ +#define SHANNON_GPIO_SPI_INPUT GPIO_GPIO (11) /* Input - SPI input from DSP */ +#define SHANNON_GPIO_SPI_CLOCK GPIO_GPIO (12) /* Output - Clock for SPI */ +#define SHANNON_GPIO_SPI_FRAME GPIO_GPIO (13) /* Output - Frame marker - not used */ +#define SHANNON_GPIO_SPI_RTS GPIO_GPIO (14) /* Input - SPI Ready to Send */ +#define SHANNON_IRQ_GPIO_SPI_RTS IRQ_GPIO14 +#define SHANNON_GPIO_SPI_CTS GPIO_GPIO (15) /* Output - SPI Clear to Send */ +#define SHANNON_GPIO_IRQ_CODEC GPIO_GPIO (16) /* in, irq from ucb1200 */ +#define SHANNON_IRQ_GPIO_IRQ_CODEC IRQ_GPIO16 +#define SHANNON_GPIO_DSP_RESET GPIO_GPIO (17) /* Output - Drive low to reset the DSP */ +#define SHANNON_GPIO_CODEC_RESET GPIO_GPIO (18) /* Output - Drive low to reset the UCB1x00 */ +#define SHANNON_GPIO_U3_RTS GPIO_GPIO (19) /* ?? */ +#define SHANNON_GPIO_U3_CTS GPIO_GPIO (20) /* ?? */ +#define SHANNON_GPIO_SENSE_12V GPIO_GPIO (21) /* Input, 12v flash unprotect detected */ +#define SHANNON_GPIO_DISP_EN GPIO_GPIO (22) /* out */ +/* XXX GPIO 23 unaccounted for */ +#define SHANNON_GPIO_EJECT_0 GPIO_GPIO (24) /* in */ +#define SHANNON_IRQ_GPIO_EJECT_0 IRQ_GPIO24 +#define SHANNON_GPIO_EJECT_1 GPIO_GPIO (25) /* in */ +#define SHANNON_IRQ_GPIO_EJECT_1 IRQ_GPIO25 +#define SHANNON_GPIO_RDY_0 GPIO_GPIO (26) /* in */ +#define SHANNON_IRQ_GPIO_RDY_0 IRQ_GPIO26 +#define SHANNON_GPIO_RDY_1 GPIO_GPIO (27) /* in */ +#define SHANNON_IRQ_GPIO_RDY_1 IRQ_GPIO27 + +/* MCP UCB codec GPIO pins... */ + +#define SHANNON_UCB_GPIO_BACKLIGHT 9 +#define SHANNON_UCB_GPIO_BRIGHT_MASK 7 +#define SHANNON_UCB_GPIO_BRIGHT 6 +#define SHANNON_UCB_GPIO_CONTRAST_MASK 0x3f +#define SHANNON_UCB_GPIO_CONTRAST 0 + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/system3.h linux-2.5/include/asm-arm/arch-sa1100/system3.h --- linux-2.5.1/include/asm-arm/arch-sa1100/system3.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/arch-sa1100/system3.h Sun Jan 6 13:28:16 2002 @@ -0,0 +1,116 @@ +/* + * linux/include/asm-arm/arch-sa1100/system3.h + * + * Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de> + * + * $Id: system3.h,v 1.1 2002/01/06 13:28:16 davej Exp $ + * + * 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. + * + * $Log: system3.h,v $ + * Revision 1.1 2002/01/06 13:28:16 davej + * extra arm includes + * + * Revision 1.2.4.2 2001/12/04 14:58:50 seletz + * - removed neponset hack + * - removed irq definitions (now in irqs.h) + * + * Revision 1.2.4.1 2001/12/04 12:51:18 seletz + * - re-added from linux_2_4_8_ac12_rmk1_np1_pt1 + * + * Revision 1.2.2.2 2001/11/16 13:58:43 seletz + * - simplified cpld register access + * + * Revision 1.2.2.1 2001/10/15 16:17:20 seletz + * - first revision + * + * + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#error "include <asm/hardware.h> instead" +#endif + +/* System 3 LCD */ +#define SYS3LCD SKPEN0 +#define SYS3LCDBACKL SKPEN1 +#define SYS3LCDBRIGHT SKPWM0 +#define SYS3LCDCONTR SKPWM1 + +#define PT_CPLD_BASE (0x10000000) +#define PT_SMC_BASE (0x18000000) +#define PT_SA1111_BASE (0x40000000) + +#define SA1111_BASE PT_SA1111_BASE + +#define Ptcpld_p2v( x ) ((x) - PT_CPLD_BASE + 0xf3000000) +#define Ptcpld_v2p( x ) ((x) - 0xf3000000 + PT_CPLD_BASE) + +#define _PT_SYSID ( PT_CPLD_BASE + 0x00 ) +#define _PT_IRQSR ( PT_CPLD_BASE + 0x24 ) +#define _PT_CTRL0 ( PT_CPLD_BASE + 0x90 ) +#define _PT_CTRL1 ( PT_CPLD_BASE + 0xA0 ) +#define _PT_CTRL2 ( PT_CPLD_BASE + 0xB0 ) + +#define PT_SYSID (*((volatile u_char *)Ptcpld_p2v( _PT_SYSID ))) +#define PT_IRQSR (*((volatile u_char *)Ptcpld_p2v( _PT_IRQSR ))) +#define PT_CTRL0 (*((volatile u_char *)Ptcpld_p2v( _PT_CTRL0 ))) +#define PT_CTRL1 (*((volatile u_char *)Ptcpld_p2v( _PT_CTRL1 ))) +#define PT_CTRL2 (*((volatile u_char *)Ptcpld_p2v( _PT_CTRL2 ))) + +#define PTCTRL0_set( x ) PT_CTRL0 |= (x) +#define PTCTRL1_set( x ) PT_CTRL1 |= (x) +#define PTCTRL2_set( x ) PT_CTRL2 |= (x) +#define PTCTRL0_clear( x ) PT_CTRL0 &= ~(x) +#define PTCTRL1_clear( x ) PT_CTRL1 &= ~(x) +#define PTCTRL2_clear( x ) PT_CTRL2 &= ~(x) + +/* System ID register */ + +/* IRQ Source Register */ +#define PT_IRQ_LAN ( 1<<0 ) +#define PT_IRQ_X ( 1<<1 ) +#define PT_IRQ_SA1111 ( 1<<2 ) +#define PT_IRQ_RS1 ( 1<<3 ) +#define PT_IRQ_RS1_RING ( 1<<4 ) +#define PT_IRQ_RS1_DCD ( 1<<5 ) +#define PT_IRQ_RS1_DSR ( 1<<6 ) +#define PT_IRQ_RS2 ( 1<<7 ) + +/* FIXME */ +#define PT_IRQ_USAR ( 1<<1 ) + +/* CTRL 0 */ +#define PT_CTRL0_USBSLAVE ( 1<<0 ) +#define PT_CTRL0_USBHOST ( 1<<1 ) +#define PT_CTRL0_LCD_BL ( 1<<2 ) +#define PT_CTRL0_LAN_EN ( 1<<3 ) /* active low */ +#define PT_CTRL0_IRDA_M(x) ( (((u_char)x)&0x03)<<4 ) +#define PT_CTRL0_IRDA_M0 ( 1<<4 ) +#define PT_CTRL0_IRDA_M1 ( 1<<5 ) +#define PT_CTRL0_IRDA_FSEL ( 1<<6 ) +#define PT_CTRL0_LCD_EN ( 1<<7 ) + +#define PT_CTRL0_INIT ( PT_CTRL0_USBSLAVE | PT_CTRL0_USBHOST | \ + PT_CTRL0_LCD_BL | PT_CTRL0_LAN_EN | PT_CTRL0_LCD_EN ) + +/* CTRL 1 */ +#define PT_CTRL1_RS3_MUX(x) ( (((u_char)x)&0x03)<<0 ) +#define PT_CTRL1_RS3_MUX0 ( 1<<0 ) +#define PT_CTRL1_RS3_MUX1 ( 1<<1 ) +#define PT_CTRL1_RS3_RST ( 1<<2 ) +#define PT_CTRL1_RS3_RS485_TERM ( 1<<4 ) +#define PT_CTRL1_X ( 1<<4 ) +#define PT_CTRL1_PCMCIA_A0VPP ( 1<<6 ) +#define PT_CTRL1_PCMCIA_A1VPP ( 1<<7 ) + +#define PT_RS3_MUX_ALIRS ( 0 ) +#define PT_RS3_MUX_IDATA ( 1 ) +#define PT_RS3_MUX_RADIO ( 2 ) +#define PT_RS3_MUX_RS485 ( 3 ) + +/* CTRL 2 */ +#define PT_CTRL2_RS1_RTS ( 1<<0 ) +#define PT_CTRL2_RS1_DTR ( 1<<1 ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-sa1100/time.h linux-2.5/include/asm-arm/arch-sa1100/time.h --- linux-2.5.1/include/asm-arm/arch-sa1100/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-sa1100/time.h Sun Jan 6 01:38:27 2002 @@ -10,7 +10,7 @@ */ -#define RTC_DEF_DIVIDER 32768 - 1 +#define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 static unsigned long __init sa1100_get_rtc_time(void) @@ -63,29 +63,34 @@ return usec; } +/* + * We will be entered with IRQs enabled. + * + * Loop until we get ahead of the free running timer. + * This ensures an exact clock tick count and time acuracy. + * IRQs are disabled inside the loop to ensure coherence between + * lost_ticks (updated in do_timer()) and the match reg value, so we + * can use do_gettimeofday() from interrupt handlers. + */ static void sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - long flags; - int next_match; + unsigned int next_match; + unsigned long flags; - /* Loop until we get ahead of the free running timer. - * This ensures an exact clock tick count and time acuracy. - * IRQs are disabled inside the loop to ensure coherence between - * lost_ticks (updated in do_timer()) and the match reg value, so we - * can use do_gettimeofday() from interrupt handlers. - */ do { do_leds(); - do_set_rtc(); - save_flags_cli( flags ); + local_irq_save(flags); do_timer(regs); OSSR = OSSR_M0; /* Clear match on timer 0 */ next_match = (OSMR0 += LATCH); - restore_flags( flags ); - } while( (signed long)(next_match - OSCR) <= 0 ); + local_irq_restore(flags); + do_set_rtc(); + } while ((signed long)(next_match - OSCR) <= 0); + + do_profile(regs); } -static inline void setup_timer (void) +void __init time_init(void) { gettimeoffset = sa1100_gettimeoffset; set_rtc = sa1100_set_rtc; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-shark/io.h linux-2.5/include/asm-arm/arch-shark/io.h --- linux-2.5.1/include/asm-arm/arch-shark/io.h Thu Oct 25 20:53:55 2001 +++ linux-2.5/include/asm-arm/arch-shark/io.h Sun Jan 6 01:38:27 2002 @@ -11,9 +11,6 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H -#define iomem_valid_addr(off,sz) (1) -#define iomem_to_phys(off) (off) - #define IO_SPACE_LIMIT 0xffffffff /* @@ -181,9 +178,6 @@ #define outb(v,p) (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p)) #define outw(v,p) (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p)) #define outl(v,p) (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p)) - -#define __arch_getw(addr) (*(volatile unsigned short *)(addr)) -#define __arch_putw(b,addr) (*(volatile unsigned short *)(addr) = (b)) /* * Translated address IO functions diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-shark/irq.h linux-2.5/include/asm-arm/arch-shark/irq.h --- linux-2.5.1/include/asm-arm/arch-shark/irq.h Thu Oct 25 20:53:55 2001 +++ linux-2.5/include/asm-arm/arch-shark/irq.h Sun Jan 6 01:38:27 2002 @@ -7,118 +7,4 @@ * include/asm-arm/arch-ebsa110/irq.h * Copyright (C) 1996-1998 Russell King */ - -#include <asm/io.h> #define fixup_irq(x) (x) - -/* - * 8259A PIC functions to handle ISA devices: - */ - -/* - * This contains the irq mask for both 8259A irq controllers, - * Let through the cascade-interrupt no. 2 (ff-(1<<2)==fb) - */ -static unsigned char cached_irq_mask[2] = { 0xfb, 0xff }; - -/* - * These have to be protected by the irq controller spinlock - * before being called. - */ -static void shark_disable_8259A_irq(unsigned int irq) -{ - unsigned int mask; - if (irq<8) { - mask = 1 << irq; - cached_irq_mask[0] |= mask; - } else { - mask = 1 << (irq-8); - cached_irq_mask[1] |= mask; - } - outb(cached_irq_mask[1],0xA1); - outb(cached_irq_mask[0],0x21); -} - -static void shark_enable_8259A_irq(unsigned int irq) -{ - unsigned int mask; - if (irq<8) { - mask = ~(1 << irq); - cached_irq_mask[0] &= mask; - } else { - mask = ~(1 << (irq-8)); - cached_irq_mask[1] &= mask; - } - outb(cached_irq_mask[1],0xA1); - outb(cached_irq_mask[0],0x21); -} - -/* - * Careful! The 8259A is a fragile beast, it pretty - * much _has_ to be done exactly like this (mask it - * first, _then_ send the EOI, and the order of EOI - * to the two 8259s is important! - */ -static void shark_mask_and_ack_8259A_irq(unsigned int irq) -{ - if (irq & 8) { - cached_irq_mask[1] |= 1 << (irq-8); - inb(0xA1); /* DUMMY */ - outb(cached_irq_mask[1],0xA1); - } else { - cached_irq_mask[0] |= 1 << irq; - outb(cached_irq_mask[0],0x21); - } -} - -static void bogus_int(int irq, void *dev_id, struct pt_regs *regs) -{ - printk("Got interrupt %i!\n",irq); -} - -static struct irqaction cascade; - -static __inline__ void irq_init_irq(void) -{ - int irq; - - for (irq = 0; irq < NR_IRQS; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = shark_mask_and_ack_8259A_irq; - irq_desc[irq].mask = shark_disable_8259A_irq; - irq_desc[irq].unmask = shark_enable_8259A_irq; - } - - /* The PICs are initialized to level triggered and auto eoi! - * If they are set to edge triggered they lose some IRQs, - * if they are set to manual eoi they get locked up after - * a short time - */ - - /* init master interrupt controller */ - outb(0x19, 0x20); /* Start init sequence, level triggered */ - outb(0x00, 0x21); /* Vector base */ - outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */ - outb(0x03, 0x21); /* Select 8086 mode , auto eoi*/ - outb(0x0A, 0x20); - /* init slave interrupt controller */ - outb(0x19, 0xA0); /* Start init sequence, level triggered */ - outb(0x08, 0xA1); /* Vector base */ - outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */ - outb(0x03, 0xA1); /* Select 8086 mode, auto eoi */ - outb(0x0A, 0xA0); - outb(cached_irq_mask[1],0xA1); - outb(cached_irq_mask[0],0x21); - //request_region(0x20,0x2,"pic1"); - //request_region(0xA0,0x2,"pic2"); - - cascade.handler = bogus_int; - cascade.flags = 0; - cascade.mask = 0; - cascade.name = "cascade"; - cascade.next = NULL; - cascade.dev_id = NULL; - setup_arm_irq(2,&cascade); - -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-shark/time.h linux-2.5/include/asm-arm/arch-shark/time.h --- linux-2.5.1/include/asm-arm/arch-shark/time.h Thu Oct 25 20:53:55 2001 +++ linux-2.5/include/asm-arm/arch-shark/time.h Sun Jan 6 01:38:27 2002 @@ -46,7 +46,7 @@ /* * Set up timer interrupt, and return the current time in seconds. */ -static inline void setup_timer(void) +void __init time_init(void) { struct rtc_time r_time; unsigned long flags; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-tbox/irq.h linux-2.5/include/asm-arm/arch-tbox/irq.h --- linux-2.5.1/include/asm-arm/arch-tbox/irq.h Mon Sep 18 22:15:23 2000 +++ linux-2.5/include/asm-arm/arch-tbox/irq.h Sun Jan 6 01:38:27 2002 @@ -10,41 +10,4 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ - -#include <asm/io.h> - #define fixup_irq(x) (x) - -extern unsigned long soft_irq_mask; - -static void tbox_mask_irq(unsigned int irq) -{ - __raw_writel(0, INTCONT + (irq << 2)); - soft_irq_mask &= ~(1<<irq); -} - -static void tbox_unmask_irq(unsigned int irq) -{ - soft_irq_mask |= (1<<irq); - __raw_writel(1, INTCONT + (irq << 2)); -} - -static __inline__ void irq_init_irq(void) -{ - unsigned int i; - - /* Disable all interrupts initially. */ - for (i = 0; i < NR_IRQS; i++) { - if (i <= 10 || (i >= 12 && i <= 13)) { - irq_desc[i].valid = 1; - irq_desc[i].probe_ok = 0; - irq_desc[i].mask_ack = tbox_mask_irq; - irq_desc[i].mask = tbox_mask_irq; - irq_desc[i].unmask = tbox_unmask_irq; - tbox_mask_irq(i); - } else { - irq_desc[i].valid = 0; - irq_desc[i].probe_ok = 0; - } - } -} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-tbox/time.h linux-2.5/include/asm-arm/arch-tbox/time.h --- linux-2.5.1/include/asm-arm/arch-tbox/time.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/arch-tbox/time.h Sun Jan 6 01:38:27 2002 @@ -29,15 +29,8 @@ do_timer(regs); } -static inline void setup_timer (void) +void __init time_init(void) { - /* - * Default the date to 1 Jan 1970 0:0:0 - * You will have to run a time daemon to set the - * clock correctly at bootup - */ - xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0); - timer_irq.handler = timer_interrupt; setup_arm_irq(IRQ_TIMER, &timer_irq); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/arch-tbox/vmalloc.h linux-2.5/include/asm-arm/arch-tbox/vmalloc.h --- linux-2.5.1/include/asm-arm/arch-tbox/vmalloc.h Mon Sep 18 22:15:23 2000 +++ linux-2.5/include/asm-arm/arch-tbox/vmalloc.h Sun Jan 6 01:38:27 2002 @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/arch-rpc/vmalloc.h + * linux/include/asm-arm/arch-tbox/vmalloc.h */ /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/assembler.h linux-2.5/include/asm-arm/assembler.h --- linux-2.5.1/include/asm-arm/assembler.h Sun Aug 13 16:54:15 2000 +++ linux-2.5/include/asm-arm/assembler.h Sun Jan 6 01:38:27 2002 @@ -13,3 +13,16 @@ #include <asm/proc/ptrace.h> #include <asm/proc/assembler.h> + +/* + * Endian independent macros for shifting bytes within registers. + */ +#ifndef __ARMEB__ +#define pull lsr +#define push lsl +#define byte(x) (x*8) +#else +#define pull lsl +#define push lsr +#define byte(x) ((3-x)*8) +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/bitops.h linux-2.5/include/asm-arm/bitops.h --- linux-2.5.1/include/asm-arm/bitops.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/bitops.h Sun Jan 6 01:38:27 2002 @@ -2,6 +2,8 @@ * Copyright 1995, Russell King. * Various bits and pieces copyrights include: * Linus Torvalds (test_bit). + * Big endian support: Copyright 2001, Nicolas Pitre + * reworked by rmk. * * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). * @@ -17,81 +19,271 @@ #ifdef __KERNEL__ +#include <asm/system.h> + #define smp_mb__before_clear_bit() do { } while (0) #define smp_mb__after_clear_bit() do { } while (0) /* - * Function prototypes to keep gcc -Wall happy. + * These functions are the basis of our bit ops. + * First, the atomic bitops. + * + * The endian issue for these functions is handled by the macros below. */ -extern void set_bit(int nr, volatile void * addr); +static inline void +____atomic_set_bit_mask(unsigned int mask, volatile unsigned char *p) +{ + unsigned long flags; + + local_irq_save(flags); + *p |= mask; + local_irq_restore(flags); +} -static inline void __set_bit(int nr, volatile void *addr) +static inline void +____atomic_clear_bit_mask(unsigned int mask, volatile unsigned char *p) { - ((unsigned char *) addr)[nr >> 3] |= (1U << (nr & 7)); + unsigned long flags; + + local_irq_save(flags); + *p &= ~mask; + local_irq_restore(flags); } -extern void clear_bit(int nr, volatile void * addr); +static inline void +____atomic_change_bit_mask(unsigned int mask, volatile unsigned char *p) +{ + unsigned long flags; + + local_irq_save(flags); + *p ^= mask; + local_irq_restore(flags); +} -static inline void __clear_bit(int nr, volatile void *addr) +static inline int +____atomic_test_and_set_bit_mask(unsigned int mask, volatile unsigned char *p) { - ((unsigned char *) addr)[nr >> 3] &= ~(1U << (nr & 7)); + unsigned long flags; + unsigned int res; + + local_irq_save(flags); + res = *p; + *p = res | mask; + local_irq_restore(flags); + + return res & mask; } -extern void change_bit(int nr, volatile void * addr); +static inline int +____atomic_test_and_clear_bit_mask(unsigned int mask, volatile unsigned char *p) +{ + unsigned long flags; + unsigned int res; -static inline void __change_bit(int nr, volatile void *addr) + local_irq_save(flags); + res = *p; + *p = res & ~mask; + local_irq_restore(flags); + + return res & mask; +} + +static inline int +____atomic_test_and_change_bit_mask(unsigned int mask, volatile unsigned char *p) { - ((unsigned char *) addr)[nr >> 3] ^= (1U << (nr & 7)); + unsigned long flags; + unsigned int res; + + local_irq_save(flags); + res = *p; + *p = res ^ mask; + local_irq_restore(flags); + + return res & mask; } -extern int test_and_set_bit(int nr, volatile void * addr); +/* + * Now the non-atomic variants. We let the compiler handle all optimisations + * for these. + */ +static inline void ____nonatomic_set_bit(int nr, volatile void *p) +{ + ((unsigned char *) p)[nr >> 3] |= (1U << (nr & 7)); +} + +static inline void ____nonatomic_clear_bit(int nr, volatile void *p) +{ + ((unsigned char *) p)[nr >> 3] &= ~(1U << (nr & 7)); +} + +static inline void ____nonatomic_change_bit(int nr, volatile void *p) +{ + ((unsigned char *) p)[nr >> 3] ^= (1U << (nr & 7)); +} -static inline int __test_and_set_bit(int nr, volatile void *addr) +static inline int ____nonatomic_test_and_set_bit(int nr, volatile void *p) { unsigned int mask = 1 << (nr & 7); unsigned int oldval; - oldval = ((unsigned char *) addr)[nr >> 3]; - ((unsigned char *) addr)[nr >> 3] = oldval | mask; + oldval = ((unsigned char *) p)[nr >> 3]; + ((unsigned char *) p)[nr >> 3] = oldval | mask; return oldval & mask; } -extern int test_and_clear_bit(int nr, volatile void * addr); - -static inline int __test_and_clear_bit(int nr, volatile void *addr) +static inline int ____nonatomic_test_and_clear_bit(int nr, volatile void *p) { unsigned int mask = 1 << (nr & 7); unsigned int oldval; - oldval = ((unsigned char *) addr)[nr >> 3]; - ((unsigned char *) addr)[nr >> 3] = oldval & ~mask; + oldval = ((unsigned char *) p)[nr >> 3]; + ((unsigned char *) p)[nr >> 3] = oldval & ~mask; return oldval & mask; } -extern int test_and_change_bit(int nr, volatile void * addr); - -static inline int __test_and_change_bit(int nr, volatile void *addr) +static inline int ____nonatomic_test_and_change_bit(int nr, volatile void *p) { unsigned int mask = 1 << (nr & 7); unsigned int oldval; - oldval = ((unsigned char *) addr)[nr >> 3]; - ((unsigned char *) addr)[nr >> 3] = oldval ^ mask; + oldval = ((unsigned char *) p)[nr >> 3]; + ((unsigned char *) p)[nr >> 3] = oldval ^ mask; return oldval & mask; } -extern int find_first_zero_bit(void * addr, unsigned size); -extern int find_next_zero_bit(void * addr, int size, int offset); - /* * This routine doesn't need to be atomic. */ -static inline int test_bit(int nr, const void * addr) +static inline int ____test_bit(int nr, const void * p) { - return ((unsigned char *) addr)[nr >> 3] & (1U << (nr & 7)); + return ((volatile unsigned char *) p)[nr >> 3] & (1U << (nr & 7)); } /* + * A note about Endian-ness. + * ------------------------- + * + * When the ARM is put into big endian mode via CR15, the processor + * merely swaps the order of bytes within words, thus: + * + * ------------ physical data bus bits ----------- + * D31 ... D24 D23 ... D16 D15 ... D8 D7 ... D0 + * little byte 3 byte 2 byte 1 byte 0 + * big byte 0 byte 1 byte 2 byte 3 + * + * This means that reading a 32-bit word at address 0 returns the same + * value irrespective of the endian mode bit. + * + * Peripheral devices should be connected with the data bus reversed in + * "Big Endian" mode. ARM Application Note 61 is applicable, and is + * available from http://www.arm.com/. + * + * The following assumes that the data bus connectivity for big endian + * mode has been followed. + * + * Note that bit 0 is defined to be 32-bit word bit 0, not byte 0 bit 0. + */ + +/* + * Little endian assembly bitops. nr = 0 -> byte 0 bit 0. + */ +extern void _set_bit_le(int nr, volatile void * p); +extern void _clear_bit_le(int nr, volatile void * p); +extern void _change_bit_le(int nr, volatile void * p); +extern int _test_and_set_bit_le(int nr, volatile void * p); +extern int _test_and_clear_bit_le(int nr, volatile void * p); +extern int _test_and_change_bit_le(int nr, volatile void * p); +extern int _find_first_zero_bit_le(void * p, unsigned size); +extern int _find_next_zero_bit_le(void * p, int size, int offset); + +/* + * Big endian assembly bitops. nr = 0 -> byte 3 bit 0. + */ +extern void _set_bit_be(int nr, volatile void * p); +extern void _clear_bit_be(int nr, volatile void * p); +extern void _change_bit_be(int nr, volatile void * p); +extern int _test_and_set_bit_be(int nr, volatile void * p); +extern int _test_and_clear_bit_be(int nr, volatile void * p); +extern int _test_and_change_bit_be(int nr, volatile void * p); +extern int _find_first_zero_bit_be(void * p, unsigned size); +extern int _find_next_zero_bit_be(void * p, int size, int offset); + + +/* + * The __* form of bitops are non-atomic and may be reordered. + */ +#define ATOMIC_BITOP_LE(name,nr,p) \ + (__builtin_constant_p(nr) ? \ + ____atomic_##name##_mask(1 << ((nr) & 7), \ + ((unsigned char *)(p)) + ((nr) >> 3)) : \ + _##name##_le(nr,p)) + +#define ATOMIC_BITOP_BE(name,nr,p) \ + (__builtin_constant_p(nr) ? \ + ____atomic_##name##_mask(1 << ((nr) & 7), \ + ((unsigned char *)(p)) + (((nr) >> 3) ^ 3)) : \ + _##name##_be(nr,p)) + +#define NONATOMIC_BITOP_LE(name,nr,p) \ + (____nonatomic_##name(nr, p)) + +#define NONATOMIC_BITOP_BE(name,nr,p) \ + (____nonatomic_##name(nr ^ 0x18, p)) + +#ifndef __ARMEB__ +/* + * These are the little endian, atomic definitions. + */ +#define set_bit(nr,p) ATOMIC_BITOP_LE(set_bit,nr,p) +#define clear_bit(nr,p) ATOMIC_BITOP_LE(clear_bit,nr,p) +#define change_bit(nr,p) ATOMIC_BITOP_LE(change_bit,nr,p) +#define test_and_set_bit(nr,p) ATOMIC_BITOP_LE(test_and_set_bit,nr,p) +#define test_and_clear_bit(nr,p) ATOMIC_BITOP_LE(test_and_clear_bit,nr,p) +#define test_and_change_bit(nr,p) ATOMIC_BITOP_LE(test_and_change_bit,nr,p) +#define test_bit(nr,p) ____test_bit(nr,p) +#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) +#define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) + +/* + * These are the little endian, non-atomic definitions. + */ +#define __set_bit(nr,p) NONATOMIC_BITOP_LE(set_bit,nr,p) +#define __clear_bit(nr,p) NONATOMIC_BITOP_LE(clear_bit,nr,p) +#define __change_bit(nr,p) NONATOMIC_BITOP_LE(change_bit,nr,p) +#define __test_and_set_bit(nr,p) NONATOMIC_BITOP_LE(test_and_set_bit,nr,p) +#define __test_and_clear_bit(nr,p) NONATOMIC_BITOP_LE(test_and_clear_bit,nr,p) +#define __test_and_change_bit(nr,p) NONATOMIC_BITOP_LE(test_and_change_bit,nr,p) +#define __test_bit(nr,p) ____test_bit(nr,p) + +#else + +/* + * These are the big endian, atomic definitions. + */ +#define set_bit(nr,p) ATOMIC_BITOP_BE(set_bit,nr,p) +#define clear_bit(nr,p) ATOMIC_BITOP_BE(clear_bit,nr,p) +#define change_bit(nr,p) ATOMIC_BITOP_BE(change_bit,nr,p) +#define test_and_set_bit(nr,p) ATOMIC_BITOP_BE(test_and_set_bit,nr,p) +#define test_and_clear_bit(nr,p) ATOMIC_BITOP_BE(test_and_clear_bit,nr,p) +#define test_and_change_bit(nr,p) ATOMIC_BITOP_BE(test_and_change_bit,nr,p) +#define test_bit(nr,p) ____test_bit((nr) ^ 0x18, p) +#define find_first_zero_bit(p,sz) _find_first_zero_bit_be(p,sz) +#define find_next_zero_bit(p,sz,off) _find_next_zero_bit_be(p,sz,off) + +/* + * These are the big endian, non-atomic definitions. + */ +#define __set_bit(nr,p) NONATOMIC_BITOP_BE(set_bit,nr,p) +#define __clear_bit(nr,p) NONATOMIC_BITOP_BE(clear_bit,nr,p) +#define __change_bit(nr,p) NONATOMIC_BITOP_BE(change_bit,nr,p) +#define __test_and_set_bit(nr,p) NONATOMIC_BITOP_BE(test_and_set_bit,nr,p) +#define __test_and_clear_bit(nr,p) NONATOMIC_BITOP_BE(test_and_clear_bit,nr,p) +#define __test_and_change_bit(nr,p) NONATOMIC_BITOP_BE(test_and_change_bit,nr,p) +#define __test_bit(nr,p) ____test_bit((nr) ^ 0x18, p) + +#endif + +/* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. */ @@ -126,18 +318,25 @@ #define hweight16(x) generic_hweight16(x) #define hweight8(x) generic_hweight8(x) -#define ext2_set_bit test_and_set_bit -#define ext2_clear_bit test_and_clear_bit -#define ext2_test_bit test_bit -#define ext2_find_first_zero_bit find_first_zero_bit -#define ext2_find_next_zero_bit find_next_zero_bit - -/* Bitmap functions for the minix filesystem. */ -#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr) -#define minix_set_bit(nr,addr) set_bit(nr,addr) -#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr) -#define minix_test_bit(nr,addr) test_bit(nr,addr) -#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) +/* + * Ext2 is defined to use little-endian byte ordering. + * These do not need to be atomic. + */ +#define ext2_set_bit(nr,p) NONATOMIC_BITOP_LE(test_and_set_bit,nr,p) +#define ext2_clear_bit(nr,p) NONATOMIC_BITOP_LE(test_and_clear_bit,nr,p) +#define ext2_test_bit(nr,p) __test_bit(nr,p) +#define ext2_find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) +#define ext2_find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) + +/* + * Minix is defined to use little-endian byte ordering. + * These do not need to be atomic. + */ +#define minix_set_bit(nr,p) NONATOMIC_BITOP_LE(set_bit,nr,p) +#define minix_test_bit(nr,p) __test_bit(nr,p) +#define minix_test_and_set_bit(nr,p) NONATOMIC_BITOP_LE(test_and_set_bit,nr,p) +#define minix_test_and_clear_bit(nr,p) NONATOMIC_BITOP_LE(test_and_clear_bit,nr,p) +#define minix_find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/checksum.h linux-2.5/include/asm-arm/checksum.h --- linux-2.5.1/include/asm-arm/checksum.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/checksum.h Sun Jan 6 01:38:27 2002 @@ -55,25 +55,24 @@ unsigned int sum, tmp1; __asm__ __volatile__( - "ldr %0, [%1], #4 @ ip_fast_csum - ldr %3, [%1], #4 - sub %2, %2, #5 - adds %0, %0, %3 - ldr %3, [%1], #4 - adcs %0, %0, %3 - ldr %3, [%1], #4 - adcs %0, %0, %3 -1: ldr %3, [%1], #4 - adcs %0, %0, %3 - tst %2, #15 - subne %2, %2, #1 - bne 1b - adc %0, %0, #0 - adds %0, %0, %0, lsl #16 - addcs %0, %0, #0x10000 - mvn %0, %0 - mov %0, %0, lsr #16 - " + "ldr %0, [%1], #4 @ ip_fast_csum \n\ + ldr %3, [%1], #4 \n\ + sub %2, %2, #5 \n\ + adds %0, %0, %3 \n\ + ldr %3, [%1], #4 \n\ + adcs %0, %0, %3 \n\ + ldr %3, [%1], #4 \n\ +1: adcs %0, %0, %3 \n\ + ldr %3, [%1], #4 \n\ + tst %2, #15 @ do this carefully \n\ + subne %2, %2, #1 @ without destroying \n\ + bne 1b @ the carry flag \n\ + adcs %0, %0, %3 \n\ + adc %0, %0, #0 \n\ + adds %0, %0, %0, lsl #16 \n\ + addcs %0, %0, #0x10000 \n\ + mvn %0, %0 \n\ + mov %0, %0, lsr #16" : "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (tmp1) : "1" (iph), "2" (ihl) : "cc"); @@ -87,7 +86,7 @@ csum_fold(unsigned int sum) { __asm__( - "adds %0, %1, %1, lsl #16 @ csum_fold + "adds %0, %1, %1, lsl #16 @ csum_fold \n\ addcs %0, %0, #0x10000" : "=r" (sum) : "r" (sum) @@ -100,10 +99,10 @@ unsigned int proto, unsigned int sum) { __asm__( - "adds %0, %1, %2 @ csum_tcpudp_nofold - adcs %0, %0, %3 - adcs %0, %0, %4 - adcs %0, %0, %5 + "adds %0, %1, %2 @ csum_tcpudp_nofold \n\ + adcs %0, %0, %3 \n\ + adcs %0, %0, %4 \n\ + adcs %0, %0, %5 \n\ adc %0, %0, #0" : "=&r"(sum) : "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len) << 16), "Ir" (proto << 8) @@ -119,13 +118,13 @@ unsigned int proto, unsigned int sum) { __asm__( - "adds %0, %1, %2 @ csum_tcpudp_magic - adcs %0, %0, %3 - adcs %0, %0, %4 - adcs %0, %0, %5 - adc %0, %0, #0 - adds %0, %0, %0, lsl #16 - addcs %0, %0, #0x10000 + "adds %0, %1, %2 @ csum_tcpudp_magic \n\ + adcs %0, %0, %3 \n\ + adcs %0, %0, %4 \n\ + adcs %0, %0, %5 \n\ + adc %0, %0, #0 \n\ + adds %0, %0, %0, lsl #16 \n\ + addcs %0, %0, #0x10000 \n\ mvn %0, %0" : "=&r"(sum) : "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len)), "Ir" (proto << 8) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/cpu-multi32.h linux-2.5/include/asm-arm/cpu-multi32.h --- linux-2.5.1/include/asm-arm/cpu-multi32.h Thu Oct 11 16:04:57 2001 +++ linux-2.5/include/asm-arm/cpu-multi32.h Sun Jan 6 01:38:27 2002 @@ -122,6 +122,11 @@ */ void (*set_pte)(pte_t *ptep, pte_t pte); } pgtable; + + struct { /* other */ + void (*clear_user_page)(void *page, unsigned long u_addr); + void (*copy_user_page)(void *to, void *from, unsigned long u_addr); + } misc; } processor; extern const struct processor arm6_processor_functions; @@ -154,6 +159,9 @@ #define cpu_set_pgd(pgd) processor.pgtable.set_pgd(pgd) #define cpu_set_pmd(pmdp, pmd) processor.pgtable.set_pmd(pmdp, pmd) #define cpu_set_pte(ptep, pte) processor.pgtable.set_pte(ptep, pte) + +#define cpu_copy_user_page(to,from,uaddr) processor.misc.copy_user_page(to,from,uaddr) +#define cpu_clear_user_page(page,uaddr) processor.misc.clear_user_page(page,uaddr) #define cpu_switch_mm(pgd,tsk) cpu_set_pgd(__virt_to_phys((unsigned long)(pgd))) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/cpu-single.h linux-2.5/include/asm-arm/cpu-single.h --- linux-2.5.1/include/asm-arm/cpu-single.h Thu Oct 11 16:04:57 2001 +++ linux-2.5/include/asm-arm/cpu-single.h Sun Jan 6 01:38:27 2002 @@ -11,43 +11,40 @@ * Single CPU */ #ifdef __STDC__ -#define __cpu_fn(name,x) cpu_##name##x +#define __catify_fn(name,x) name##x #else -#define __cpu_fn(name,x) cpu_/**/name/**/x +#define __catify_fn(name,x) name/**/x #endif -#define cpu_fn(name,x) __cpu_fn(name,x) +#define __cpu_fn(name,x) __catify_fn(name,x) /* * If we are supporting multiple CPUs, then we must use a table of * function pointers for this lot. Otherwise, we can optimise the * table away. */ -#define cpu_data_abort cpu_fn(CPU_NAME,_data_abort) -#define cpu_check_bugs cpu_fn(CPU_NAME,_check_bugs) -#define cpu_proc_init cpu_fn(CPU_NAME,_proc_init) -#define cpu_proc_fin cpu_fn(CPU_NAME,_proc_fin) -#define cpu_reset cpu_fn(CPU_NAME,_reset) -#define cpu_do_idle cpu_fn(CPU_NAME,_do_idle) - -#define cpu_cache_clean_invalidate_all cpu_fn(CPU_NAME,_cache_clean_invalidate_all) -#define cpu_cache_clean_invalidate_range cpu_fn(CPU_NAME,_cache_clean_invalidate_range) -#define cpu_flush_ram_page cpu_fn(CPU_NAME,_flush_ram_page) - -#define cpu_dcache_invalidate_range cpu_fn(CPU_NAME,_dcache_invalidate_range) -#define cpu_dcache_clean_range cpu_fn(CPU_NAME,_dcache_clean_range) -#define cpu_dcache_clean_page cpu_fn(CPU_NAME,_dcache_clean_page) -#define cpu_dcache_clean_entry cpu_fn(CPU_NAME,_dcache_clean_entry) - -#define cpu_icache_invalidate_range cpu_fn(CPU_NAME,_icache_invalidate_range) -#define cpu_icache_invalidate_page cpu_fn(CPU_NAME,_icache_invalidate_page) - -#define cpu_tlb_invalidate_all cpu_fn(CPU_NAME,_tlb_invalidate_all) -#define cpu_tlb_invalidate_range cpu_fn(CPU_NAME,_tlb_invalidate_range) -#define cpu_tlb_invalidate_page cpu_fn(CPU_NAME,_tlb_invalidate_page) - -#define cpu_set_pgd cpu_fn(CPU_NAME,_set_pgd) -#define cpu_set_pmd cpu_fn(CPU_NAME,_set_pmd) -#define cpu_set_pte cpu_fn(CPU_NAME,_set_pte) +#define cpu_data_abort __cpu_fn(CPU_ABRT,_abort) +#define cpu_check_bugs __cpu_fn(CPU_NAME,_check_bugs) +#define cpu_proc_init __cpu_fn(CPU_NAME,_proc_init) +#define cpu_proc_fin __cpu_fn(CPU_NAME,_proc_fin) +#define cpu_reset __cpu_fn(CPU_NAME,_reset) +#define cpu_do_idle __cpu_fn(CPU_NAME,_do_idle) +#define cpu_cache_clean_invalidate_all __cpu_fn(CPU_NAME,_cache_clean_invalidate_all) +#define cpu_cache_clean_invalidate_range __cpu_fn(CPU_NAME,_cache_clean_invalidate_range) +#define cpu_flush_ram_page __cpu_fn(CPU_NAME,_flush_ram_page) +#define cpu_dcache_invalidate_range __cpu_fn(CPU_NAME,_dcache_invalidate_range) +#define cpu_dcache_clean_range __cpu_fn(CPU_NAME,_dcache_clean_range) +#define cpu_dcache_clean_page __cpu_fn(CPU_NAME,_dcache_clean_page) +#define cpu_dcache_clean_entry __cpu_fn(CPU_NAME,_dcache_clean_entry) +#define cpu_icache_invalidate_range __cpu_fn(CPU_NAME,_icache_invalidate_range) +#define cpu_icache_invalidate_page __cpu_fn(CPU_NAME,_icache_invalidate_page) +#define cpu_tlb_invalidate_all __cpu_fn(CPU_NAME,_tlb_invalidate_all) +#define cpu_tlb_invalidate_range __cpu_fn(CPU_NAME,_tlb_invalidate_range) +#define cpu_tlb_invalidate_page __cpu_fn(CPU_NAME,_tlb_invalidate_page) +#define cpu_set_pgd __cpu_fn(CPU_NAME,_set_pgd) +#define cpu_set_pmd __cpu_fn(CPU_NAME,_set_pmd) +#define cpu_set_pte __cpu_fn(CPU_NAME,_set_pte) +#define cpu_copy_user_page __cpu_fn(MMU_ARCH,_copy_user_page) +#define cpu_clear_user_page __cpu_fn(MMU_ARCH,_clear_user_page) #ifndef __ASSEMBLY__ @@ -83,6 +80,10 @@ extern void cpu_set_pgd(unsigned long pgd_phys); extern void cpu_set_pmd(pmd_t *pmdp, pmd_t pmd); extern void cpu_set_pte(pte_t *ptep, pte_t pte); + +extern void cpu_copy_user_page(void *to, void *from, unsigned long u_addr); +extern void cpu_clear_user_page(void *page, unsigned long u_addr); + extern volatile void cpu_reset(unsigned long addr); #define cpu_switch_mm(pgd,tsk) cpu_set_pgd(__virt_to_phys((unsigned long)(pgd))) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/hardware/clps7111.h linux-2.5/include/asm-arm/hardware/clps7111.h --- linux-2.5.1/include/asm-arm/hardware/clps7111.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/hardware/clps7111.h Sun Jan 6 01:38:27 2002 @@ -27,8 +27,10 @@ #ifndef __ASSEMBLY__ #define clps_readb(off) __raw_readb(CLPS7111_BASE + (off)) +#define clps_readw(off) __raw_readw(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_writew(val,off) __raw_writew(val, CLPS7111_BASE + (off)) #define clps_writel(val,off) __raw_writel(val, CLPS7111_BASE + (off)) #endif @@ -48,6 +50,7 @@ #define INTSR1 (0x0240) #define INTMR1 (0x0280) #define LCDCON (0x02c0) +#define TC1D (0x0300) #define TC2D (0x0340) #define RTCDR (0x0380) #define RTCMR (0x03c0) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/hardware/cs89712.h linux-2.5/include/asm-arm/hardware/cs89712.h --- linux-2.5.1/include/asm-arm/hardware/cs89712.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/hardware/cs89712.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,49 @@ +/* + * linux/include/asm-arm/hardware/cs89712.h + * + * This file contains the hardware definitions of the CS89712 + * additional internal registers. + * + * Copyright (C) 2001 Thomas Gleixner autronix automation <gleixner@autronix.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_HARDWARE_CS89712_H +#define __ASM_HARDWARE_CS89712_H + +/* +* CS89712 additional registers +*/ + +#define PCDR 0x0002 /* Port C Data register ---------------------------- */ +#define PCDDR 0x0042 /* Port C Data Direction register ------------------ */ +#define SDCONF 0x2300 /* SDRAM Configuration register ---------------------*/ +#define SDRFPR 0x2340 /* SDRAM Refresh period register --------------------*/ + +#define SDCONF_ACTIVE (1 << 10) +#define SDCONF_CLKCTL (1 << 9) +#define SDCONF_WIDTH_4 (0 << 7) +#define SDCONF_WIDTH_8 (1 << 7) +#define SDCONF_WIDTH_16 (2 << 7) +#define SDCONF_WIDTH_32 (3 << 7) +#define SDCONF_SIZE_16 (0 << 5) +#define SDCONF_SIZE_64 (1 << 5) +#define SDCONF_SIZE_128 (2 << 5) +#define SDCONF_SIZE_256 (3 << 5) +#define SDCONF_CASLAT_2 (2) +#define SDCONF_CASLAT_3 (3) + +#endif /* __ASM_HARDWARE_CS89712_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/hardware/ep7212.h linux-2.5/include/asm-arm/hardware/ep7212.h --- linux-2.5.1/include/asm-arm/hardware/ep7212.h Thu Oct 25 20:53:55 2001 +++ linux-2.5/include/asm-arm/hardware/ep7212.h Sun Jan 6 01:38:27 2002 @@ -23,8 +23,6 @@ #ifndef __ASM_HARDWARE_EP7212_H #define __ASM_HARDWARE_EP7212_H -#include <linux/config.h> - /* * define EP7212_BASE to be the base address of the region * you want to access. @@ -49,10 +47,6 @@ #define INTSR3 0x2240 #define INTMR3 0x2280 #define LEDFLSH 0x22c0 -#if defined (CONFIG_ARCH_CDB89712) -#define SDCONF 0x2300 -#define SDRFPR 0x2340 -#endif #define DAIR_DAIEN (1 << 16) #define DAIR_ECS (1 << 17) @@ -85,20 +79,5 @@ #define SYSCON3_ADCCKNSEN (1 << 4) #define SYSCON3_FASTWAKE (1 << 8) #define SYSCON3_DAIEN (1 << 9) - -#if defined (CONFIG_ARCH_CDB89712) -#define SDCONF_ACTIVE (1 << 10) -#define SDCONF_CLKCTL (1 << 9) -#define SDCONF_WIDTH_4 (0 << 7) -#define SDCONF_WIDTH_8 (1 << 7) -#define SDCONF_WIDTH_16 (2 << 7) -#define SDCONF_WIDTH_32 (3 << 7) -#define SDCONF_SIZE_16 (0 << 5) -#define SDCONF_SIZE_64 (1 << 5) -#define SDCONF_SIZE_128 (2 << 5) -#define SDCONF_SIZE_256 (3 << 5) -#define SDCONF_CASLAT_2 (2) -#define SDCONF_CASLAT_3 (3) -#endif #endif /* __ASM_HARDWARE_EP7212_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/hardware/ioc.h linux-2.5/include/asm-arm/hardware/ioc.h --- linux-2.5.1/include/asm-arm/hardware/ioc.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/hardware/ioc.h Sun Jan 6 01:38:27 2002 @@ -19,8 +19,8 @@ * 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)) +#define ioc_readb(off) __raw_readb(IOC_BASE + (off)) +#define ioc_writeb(val,off) __raw_writeb(val, IOC_BASE + (off)) #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/hardware/iomd.h linux-2.5/include/asm-arm/hardware/iomd.h --- linux-2.5.1/include/asm-arm/hardware/iomd.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/hardware/iomd.h Sun Jan 6 01:38:27 2002 @@ -21,10 +21,10 @@ * 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)) +#define iomd_readb(off) __raw_readb(IOMD_BASE + (off)) +#define iomd_readl(off) __raw_readl(IOMD_BASE + (off)) +#define iomd_writeb(val,off) __raw_writeb(val, IOMD_BASE + (off)) +#define iomd_writel(val,off) __raw_writel(val, IOMD_BASE + (off)) #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/hardware/linkup-l1110.h linux-2.5/include/asm-arm/hardware/linkup-l1110.h --- linux-2.5.1/include/asm-arm/hardware/linkup-l1110.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/hardware/linkup-l1110.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,48 @@ +/* +* +* Definitions for H3600 Handheld Computer +* +* Copyright 2001 Compaq Computer Corporation. +* +* Use consistent with the GNU GPL is permitted, +* provided that this copyright notice is +* preserved in its entirety in all copies and derived works. +* +* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, +* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS +* FITNESS FOR ANY PARTICULAR PURPOSE. +* +* Author: Jamey Hicks. +* +*/ + +/* LinkUp Systems PCCard/CompactFlash Interface for SA-1100 */ + +/* PC Card Status Register */ +#define LINKUP_PRS_S1 (1 << 0) /* voltage control bits S1-S4 */ +#define LINKUP_PRS_S2 (1 << 1) +#define LINKUP_PRS_S3 (1 << 2) +#define LINKUP_PRS_S4 (1 << 3) +#define LINKUP_PRS_BVD1 (1 << 4) +#define LINKUP_PRS_BVD2 (1 << 5) +#define LINKUP_PRS_VS1 (1 << 6) +#define LINKUP_PRS_VS2 (1 << 7) +#define LINKUP_PRS_RDY (1 << 8) +#define LINKUP_PRS_CD1 (1 << 9) +#define LINKUP_PRS_CD2 (1 << 10) + +/* PC Card Command Register */ +#define LINKUP_PRC_S1 (1 << 0) +#define LINKUP_PRC_S2 (1 << 1) +#define LINKUP_PRC_S3 (1 << 2) +#define LINKUP_PRC_S4 (1 << 3) +#define LINKUP_PRC_RESET (1 << 4) +#define LINKUP_PRC_APOE (1 << 5) /* Auto Power Off Enable: clears S1-S4 when either nCD goes high */ +#define LINKUP_PRC_CFE (1 << 6) /* CompactFlash mode Enable: addresses A[10:0] only, A[25:11] high */ +#define LINKUP_PRC_SOE (1 << 7) /* signal output driver enable */ +#define LINKUP_PRC_SSP (1 << 8) /* sock select polarity: 0 for socket 0, 1 for socket 1 */ +#define LINKUP_PRC_MBZ (1 << 15) /* must be zero */ + +struct linkup_l1110 { + volatile short prc; +}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/hardware/sa1111.h linux-2.5/include/asm-arm/hardware/sa1111.h --- linux-2.5.1/include/asm-arm/hardware/sa1111.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-arm/hardware/sa1111.h Sun Jan 6 01:38:27 2002 @@ -0,0 +1,678 @@ +/* + * linux/include/asm-arm/hardware/SA-1111.h + * + * Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu> + * + * This file contains definitions for the SA-1111 Companion Chip. + * (Structure and naming borrowed from SA-1101.h, by Peter Danielsson.) + * + * Macro that calculates real address for registers in the SA-1111 + */ + +#ifndef _ASM_ARCH_SA1111 +#define _ASM_ARCH_SA1111 + +#include <asm/arch/bitfield.h> + +/* + * The SA1111 is always located at virtual 0xf4000000, and is always + * "native" endian. + */ + +#define SA1111_VBASE 0xf4000000 + +/* Don't use these! */ +#define SA1111_p2v( x ) ((x) - SA1111_BASE + SA1111_VBASE) +#define SA1111_v2p( x ) ((x) - SA1111_VBASE + SA1111_BASE) + +#ifndef __ASSEMBLY__ + +extern struct resource sa1111_resource; +#define _SA1111(x) ((x) + sa1111_resource.start) +#endif + +/* + * 26 bits of the SA-1110 address bus are available to the SA-1111. + * Use these when feeding target addresses to the DMA engines. + */ + +#define SA1111_ADDR_WIDTH (26) +#define SA1111_ADDR_MASK ((1<<SA1111_ADDR_WIDTH)-1) +#define SA1111_DMA_ADDR(x) ((x)&SA1111_ADDR_MASK) + +/* + * Don't ask the (SAC) DMA engines to move less than this amount. + */ + +#define SA1111_SAC_DMA_MIN_XFER (0x800) + +/* + * SA1111 register definitions. + */ +#define __CCREG(x) __REGP(SA1111_VBASE + (x)) + +/* System Bus Interface (SBI) + * + * Registers + * SKCR Control Register + * SMCR Shared Memory Controller Register + * SKID ID Register + */ +#define SA1111_SKCR 0x0000 +#define SA1111_SMCR 0x0004 +#define SA1111_SKID 0x0008 + +#define _SBI_SKCR _SA1111(SA1111_SKCR) +#define _SBI_SMCR _SA1111(SA1111_SMCR) +#define _SBI_SKID _SA1111(SA1111_SKID) + +#if LANGUAGE == C + +#define SBI_SKCR __CCREG(SA1111_SKCR) +#define SBI_SMCR __CCREG(SA1111_SMCR) +#define SBI_SKID __CCREG(SA1111_SKID) + +#endif /* LANGUAGE == C */ + +#define SKCR_PLL_BYPASS (1<<0) +#define SKCR_RCLKEN (1<<1) +#define SKCR_SLEEP (1<<2) +#define SKCR_DOZE (1<<3) +#define SKCR_VCO_OFF (1<<4) +#define SKCR_SCANTSTEN (1<<5) +#define SKCR_CLKTSTEN (1<<6) +#define SKCR_RDYEN (1<<7) +#define SKCR_SELAC (1<<8) +#define SKCR_OPPC (1<<9) +#define SKCR_PLLTSTEN (1<<10) +#define SKCR_USBIOTSTEN (1<<11) +/* + * Don't believe the specs! Take them, throw them outside. Leave them + * there for a week. Spit on them. Walk on them. Stamp on them. + * Pour gasoline over them and finally burn them. Now think about coding. + * - The October 1999 errata (278260-007) says its bit 13, 1 to enable. + * - The Feb 2001 errata (278260-010) says that the previous errata + * (278260-009) is wrong, and its bit actually 12, fixed in spec + * 278242-003. + * - The SA1111 manual (278242) says bit 12, but 0 to enable. + * - Reality is bit 13, 1 to enable. + * -- rmk + */ +#define SKCR_OE_EN (1<<13) + +#define SMCR_DTIM (1<<0) +#define SMCR_MBGE (1<<1) +#define SMCR_DRAC_0 (1<<2) +#define SMCR_DRAC_1 (1<<3) +#define SMCR_DRAC_2 (1<<4) +#define SMCR_DRAC Fld(3, 2) +#define SMCR_CLAT (1<<5) + +#define SKID_SIREV_MASK (0x000000f0) +#define SKID_MTREV_MASK (0x0000000f) +#define SKID_ID_MASK (0xffffff00) +#define SKID_SA1111_ID (0x690cc200) + +/* + * System Controller + * + * Registers + * SKPCR Power Control Register + * SKCDR Clock Divider Register + * SKAUD Audio Clock Divider Register + * SKPMC PS/2 Mouse Clock Divider Register + * SKPTC PS/2 Track Pad Clock Divider Register + * SKPEN0 PWM0 Enable Register + * SKPWM0 PWM0 Clock Register + * SKPEN1 PWM1 Enable Register + * SKPWM1 PWM1 Clock Register + */ + +#define _SKPCR _SA1111(0x0200) +#define _SKCDR _SA1111(0x0204) +#define _SKAUD _SA1111(0x0208) +#define _SKPMC _SA1111(0x020c) +#define _SKPTC _SA1111(0x0210) +#define _SKPEN0 _SA1111(0x0214) +#define _SKPWM0 _SA1111(0x0218) +#define _SKPEN1 _SA1111(0x021c) +#define _SKPWM1 _SA1111(0x0220) + +#if LANGUAGE == C + +#define SKPCR __CCREG(0x0200) +#define SKCDR __CCREG(0x0204) +#define SKAUD __CCREG(0x0208) +#define SKPMC __CCREG(0x020c) +#define SKPTC __CCREG(0x0210) +#define SKPEN0 __CCREG(0x0214) +#define SKPWM0 __CCREG(0x0218) +#define SKPEN1 __CCREG(0x021c) +#define SKPWM1 __CCREG(0x0220) + +#endif /* LANGUAGE == C */ + +#define SKPCR_UCLKEN (1<<0) +#define SKPCR_ACCLKEN (1<<1) +#define SKPCR_I2SCLKEN (1<<2) +#define SKPCR_L3CLKEN (1<<3) +#define SKPCR_SCLKEN (1<<4) +#define SKPCR_PMCLKEN (1<<5) +#define SKPCR_PTCLKEN (1<<6) +#define SKPCR_DCLKEN (1<<7) +#define SKPCR_PWMCLKEN (1<<8) + +/* + * USB Host controller + */ +#define _USB_OHCI_OP_BASE _SA1111( 0x400 ) +#define _USB_STATUS _SA1111( 0x518 ) +#define _USB_RESET _SA1111( 0x51c ) +#define _USB_INTERRUPTEST _SA1111( 0x520 ) + +#define _USB_EXTENT (_USB_INTERRUPTEST - _USB_OHCI_OP_BASE + 4) + +#if LANGUAGE == C + +#define USB_OHCI_OP_BASE __CCREG(0x0400) +#define USB_STATUS __CCREG(0x0518) +#define USB_RESET __CCREG(0x051c) +#define USB_INTERRUPTEST __CCReG(0x0520) + +#endif /* LANGUAGE == C */ + +#define USB_RESET_FORCEIFRESET (1 << 0) +#define USB_RESET_FORCEHCRESET (1 << 1) +#define USB_RESET_CLKGENRESET (1 << 2) +#define USB_RESET_SIMSCALEDOWN (1 << 3) +#define USB_RESET_USBINTTEST (1 << 4) +#define USB_RESET_SLEEPSTBYEN (1 << 5) +#define USB_RESET_PWRSENSELOW (1 << 6) +#define USB_RESET_PWRCTRLLOW (1 << 7) + +/* + * Serial Audio Controller + * + * Registers + * SACR0 Serial Audio Common Control Register + * SACR1 Serial Audio Alternate Mode (I2C/MSB) Control Register + * SACR2 Serial Audio AC-link Control Register + * SASR0 Serial Audio I2S/MSB Interface & FIFO Status Register + * SASR1 Serial Audio AC-link Interface & FIFO Status Register + * SASCR Serial Audio Status Clear Register + * L3_CAR L3 Control Bus Address Register + * L3_CDR L3 Control Bus Data Register + * ACCAR AC-link Command Address Register + * ACCDR AC-link Command Data Register + * ACSAR AC-link Status Address Register + * ACSDR AC-link Status Data Register + * SADTCS Serial Audio DMA Transmit Control/Status Register + * SADTSA Serial Audio DMA Transmit Buffer Start Address A + * SADTCA Serial Audio DMA Transmit Buffer Count Register A + * SADTSB Serial Audio DMA Transmit Buffer Start Address B + * SADTCB Serial Audio DMA Transmit Buffer Count Register B + * SADRCS Serial Audio DMA Receive Control/Status Register + * SADRSA Serial Audio DMA Receive Buffer Start Address A + * SADRCA Serial Audio DMA Receive Buffer Count Register A + * SADRSB Serial Audio DMA Receive Buffer Start Address B + * SADRCB Serial Audio DMA Receive Buffer Count Register B + * SAITR Serial Audio Interrupt Test Register + * SADR Serial Audio Data Register (16 x 32-bit) + */ + +#define _SACR0 _SA1111( 0x0600 ) +#define _SACR1 _SA1111( 0x0604 ) +#define _SACR2 _SA1111( 0x0608 ) +#define _SASR0 _SA1111( 0x060c ) +#define _SASR1 _SA1111( 0x0610 ) +#define _SASCR _SA1111( 0x0618 ) +#define _L3_CAR _SA1111( 0x061c ) +#define _L3_CDR _SA1111( 0x0620 ) +#define _ACCAR _SA1111( 0x0624 ) +#define _ACCDR _SA1111( 0x0628 ) +#define _ACSAR _SA1111( 0x062c ) +#define _ACSDR _SA1111( 0x0630 ) +#define _SADTCS _SA1111( 0x0634 ) +#define _SADTSA _SA1111( 0x0638 ) +#define _SADTCA _SA1111( 0x063c ) +#define _SADTSB _SA1111( 0x0640 ) +#define _SADTCB _SA1111( 0x0644 ) +#define _SADRCS _SA1111( 0x0648 ) +#define _SADRSA _SA1111( 0x064c ) +#define _SADRCA _SA1111( 0x0650 ) +#define _SADRSB _SA1111( 0x0654 ) +#define _SADRCB _SA1111( 0x0658 ) +#define _SAITR _SA1111( 0x065c ) +#define _SADR _SA1111( 0x0680 ) + +#if LANGUAGE == C + +#define SACR0 __CCREG(0x0600) +#define SACR1 __CCREG(0x0604) +#define SACR2 __CCREG(0x0608) +#define SASR0 __CCREG(0x060c) +#define SASR1 __CCREG(0x0610) +#define SASCR __CCREG(0x0618) +#define L3_CAR __CCREG(0x061c) +#define L3_CDR __CCREG(0x0620) +#define ACCAR __CCREG(0x0624) +#define ACCDR __CCREG(0x0628) +#define ACSAR __CCREG(0x062c) +#define ACSDR __CCREG(0x0630) +#define SADTCS __CCREG(0x0634) +#define SADTSA __CCREG(0x0638) +#define SADTCA __CCREG(0x063c) +#define SADTSB __CCREG(0x0640) +#define SADTCB __CCREG(0x0644) +#define SADRCS __CCREG(0x0648) +#define SADRSA __CCREG(0x064c) +#define SADRCA __CCREG(0x0650) +#define SADRSB __CCREG(0x0654) +#define SADRCB __CCREG(0x0658) +#define SAITR __CCREG(0x065c) +#define SADR __CCREG(0x0680) + +#endif /* LANGUAGE == C */ + +#define SACR0_ENB (1<<0) +#define SACR0_BCKD (1<<2) +#define SACR0_RST (1<<3) + +#define SACR1_AMSL (1<<0) +#define SACR1_L3EN (1<<1) +#define SACR1_L3MB (1<<2) +#define SACR1_DREC (1<<3) +#define SACR1_DRPL (1<<4) +#define SACR1_ENLBF (1<<5) + +#define SACR2_TS3V (1<<0) +#define SACR2_TS4V (1<<1) +#define SACR2_WKUP (1<<2) +#define SACR2_DREC (1<<3) +#define SACR2_DRPL (1<<4) +#define SACR2_ENLBF (1<<5) +#define SACR2_RESET (1<<6) + +#define SASR0_TNF (1<<0) +#define SASR0_RNE (1<<1) +#define SASR0_BSY (1<<2) +#define SASR0_TFS (1<<3) +#define SASR0_RFS (1<<4) +#define SASR0_TUR (1<<5) +#define SASR0_ROR (1<<6) +#define SASR0_L3WD (1<<16) +#define SASR0_L3RD (1<<17) + +#define SASR1_TNF (1<<0) +#define SASR1_RNE (1<<1) +#define SASR1_BSY (1<<2) +#define SASR1_TFS (1<<3) +#define SASR1_RFS (1<<4) +#define SASR1_TUR (1<<5) +#define SASR1_ROR (1<<6) +#define SASR1_CADT (1<<16) +#define SASR1_SADR (1<<17) +#define SASR1_RSTO (1<<18) +#define SASR1_CLPM (1<<19) +#define SASR1_CRDY (1<<20) +#define SASR1_RS3V (1<<21) +#define SASR1_RS4V (1<<22) + +#define SASCR_TUR (1<<5) +#define SASCR_ROR (1<<6) +#define SASCR_DTS (1<<16) +#define SASCR_RDD (1<<17) +#define SASCR_STO (1<<18) + +#define SADTCS_TDEN (1<<0) +#define SADTCS_TDIE (1<<1) +#define SADTCS_TDBDA (1<<3) +#define SADTCS_TDSTA (1<<4) +#define SADTCS_TDBDB (1<<5) +#define SADTCS_TDSTB (1<<6) +#define SADTCS_TBIU (1<<7) + +#define SADRCS_RDEN (1<<0) +#define SADRCS_RDIE (1<<1) +#define SADRCS_RDBDA (1<<3) +#define SADRCS_RDSTA (1<<4) +#define SADRCS_RDBDB (1<<5) +#define SADRCS_RDSTB (1<<6) +#define SADRCS_RBIU (1<<7) + +#define SAD_CS_DEN (1<<0) +#define SAD_CS_DIE (1<<1) /* Not functional on metal 1 */ +#define SAD_CS_DBDA (1<<3) /* Not functional on metal 1 */ +#define SAD_CS_DSTA (1<<4) +#define SAD_CS_DBDB (1<<5) /* Not functional on metal 1 */ +#define SAD_CS_DSTB (1<<6) +#define SAD_CS_BIU (1<<7) /* Not functional on metal 1 */ + +#define SAITR_TFS (1<<0) +#define SAITR_RFS (1<<1) +#define SAITR_TUR (1<<2) +#define SAITR_ROR (1<<3) +#define SAITR_CADT (1<<4) +#define SAITR_SADR (1<<5) +#define SAITR_RSTO (1<<6) +#define SAITR_TDBDA (1<<8) +#define SAITR_TDBDB (1<<9) +#define SAITR_RDBDA (1<<10) +#define SAITR_RDBDB (1<<11) + +/* + * General-Purpose I/O Interface + * + * Registers + * PA_DDR GPIO Block A Data Direction + * PA_DRR/PA_DWR GPIO Block A Data Value Register (read/write) + * PA_SDR GPIO Block A Sleep Direction + * PA_SSR GPIO Block A Sleep State + * PB_DDR GPIO Block B Data Direction + * PB_DRR/PB_DWR GPIO Block B Data Value Register (read/write) + * PB_SDR GPIO Block B Sleep Direction + * PB_SSR GPIO Block B Sleep State + * PC_DDR GPIO Block C Data Direction + * PC_DRR/PC_DWR GPIO Block C Data Value Register (read/write) + * PC_SDR GPIO Block C Sleep Direction + * PC_SSR GPIO Block C Sleep State + */ + +#define _PA_DDR _SA1111( 0x1000 ) +#define _PA_DRR _SA1111( 0x1004 ) +#define _PA_DWR _SA1111( 0x1004 ) +#define _PA_SDR _SA1111( 0x1008 ) +#define _PA_SSR _SA1111( 0x100c ) +#define _PB_DDR _SA1111( 0x1010 ) +#define _PB_DRR _SA1111( 0x1014 ) +#define _PB_DWR _SA1111( 0x1014 ) +#define _PB_SDR _SA1111( 0x1018 ) +#define _PB_SSR _SA1111( 0x101c ) +#define _PC_DDR _SA1111( 0x1020 ) +#define _PC_DRR _SA1111( 0x1024 ) +#define _PC_DWR _SA1111( 0x1024 ) +#define _PC_SDR _SA1111( 0x1028 ) +#define _PC_SSR _SA1111( 0x102c ) + +#if LANGUAGE == C + +#define PA_DDR __CCREG(0x1000) +#define PA_DRR __CCREG(0x1004) +#define PA_DWR __CCREG(0x1004) +#define PA_SDR __CCREG(0x1008) +#define PA_SSR __CCREG(0x100c) +#define PB_DDR __CCREG(0x1010) +#define PB_DRR __CCREG(0x1014) +#define PB_DWR __CCREG(0x1014) +#define PB_SDR __CCREG(0x1018) +#define PB_SSR __CCREG(0x101c) +#define PC_DDR __CCREG(0x1020) +#define PC_DRR __CCREG(0x1024) +#define PC_DWR __CCREG(0x1024) +#define PC_SDR __CCREG(0x1028) +#define PC_SSR __CCREG(0x102c) + +#endif /* LANGUAGE == C */ + +/* + * Interrupt Controller + * + * Registers + * INTTEST0 Test register 0 + * INTTEST1 Test register 1 + * INTEN0 Interrupt Enable register 0 + * INTEN1 Interrupt Enable register 1 + * INTPOL0 Interrupt Polarity selection 0 + * INTPOL1 Interrupt Polarity selection 1 + * INTTSTSEL Interrupt source selection + * INTSTATCLR0 Interrupt Status/Clear 0 + * INTSTATCLR1 Interrupt Status/Clear 1 + * INTSET0 Interrupt source set 0 + * INTSET1 Interrupt source set 1 + * WAKE_EN0 Wake-up source enable 0 + * WAKE_EN1 Wake-up source enable 1 + * WAKE_POL0 Wake-up polarity selection 0 + * WAKE_POL1 Wake-up polarity selection 1 + */ + +#define SA1111_INTTEST0 0x1600 +#define SA1111_INTTEST1 0x1604 +#define SA1111_INTEN0 0x1608 +#define SA1111_INTEN1 0x160c +#define SA1111_INTPOL0 0x1610 +#define SA1111_INTPOL1 0x1614 +#define SA1111_INTTSTSEL 0x1618 +#define SA1111_INTSTATCLR0 0x161c +#define SA1111_INTSTATCLR1 0x1620 +#define SA1111_INTSET0 0x1624 +#define SA1111_INTSET1 0x1628 +#define SA1111_WAKE_EN0 0x162c +#define SA1111_WAKE_EN1 0x1630 +#define SA1111_WAKE_POL0 0x1634 +#define SA1111_WAKE_POL1 0x1638 + +#define _INTTEST0 _SA1111(SA1111_INTTEST0) +#define _INTTEST1 _SA1111(SA1111_INTTEST1) +#define _INTEN0 _SA1111(SA1111_INTEN0) +#define _INTEN1 _SA1111(SA1111_INTEN1) +#define _INTPOL0 _SA1111(SA1111_INTPOL0) +#define _INTPOL1 _SA1111(SA1111_INTPOL1) +#define _INTTSTSEL _SA1111(SA1111_INTTSTSEL) +#define _INTSTATCLR0 _SA1111(SA1111_INTSTATCLR0) +#define _INTSTATCLR1 _SA1111(SA1111_INTSTATCLR1) +#define _INTSET0 _SA1111(SA1111_INTSET0) +#define _INTSET1 _SA1111(SA1111_INTSET1) +#define _WAKE_EN0 _SA1111(SA1111_WAKE_EN0) +#define _WAKE_EN1 _SA1111(SA1111_WAKE_EN1) +#define _WAKE_POL0 _SA1111(SA1111_WAKE_POL0) +#define _WAKE_POL1 _SA1111(SA1111_WAKE_POL1) + +#if LANGUAGE == C + +#define INTTEST0 __CCREG(SA1111_INTTEST0) +#define INTTEST1 __CCREG(SA1111_INTTEST1) +#define INTEN0 __CCREG(SA1111_INTEN0) +#define INTEN1 __CCREG(SA1111_INTEN1) +#define INTPOL0 __CCREG(SA1111_INTPOL0) +#define INTPOL1 __CCREG(SA1111_INTPOL1) +#define INTTSTSEL __CCREG(SA1111_INTTSTSEL) +#define INTSTATCLR0 __CCREG(SA1111_INTSTATCLR0) +#define INTSTATCLR1 __CCREG(SA1111_INTSTATCLR1) +#define INTSET0 __CCREG(SA1111_INTSET0) +#define INTSET1 __CCREG(SA1111_INTSET1) +#define WAKE_EN0 __CCREG(SA1111_WAKE_EN0) +#define WAKE_EN1 __CCREG(SA1111_WAKE_EN1) +#define WAKE_POL0 __CCREG(SA1111_WAKE_POL0) +#define WAKE_POL1 __CCREG(SA1111_WAKE_POL1) + +#endif /* LANGUAGE == C */ + +/* + * PS/2 Trackpad and Mouse Interfaces + * + * Registers (prefix kbd applies to trackpad interface, mse to mouse) + * KBDCR Control Register + * KBDSTAT Status Register + * KBDDATA Transmit/Receive Data register + * KBDCLKDIV Clock Division Register + * KBDPRECNT Clock Precount Register + * KBDTEST1 Test register 1 + * KBDTEST2 Test register 2 + * KBDTEST3 Test register 3 + * KBDTEST4 Test register 4 + * MSECR + * MSESTAT + * MSEDATA + * MSECLKDIV + * MSEPRECNT + * MSETEST1 + * MSETEST2 + * MSETEST3 + * MSETEST4 + * + */ + +#define _KBD( x ) _SA1111( 0x0A00 ) +#define _MSE( x ) _SA1111( 0x0C00 ) + +#define _KBDCR _SA1111( 0x0A00 ) +#define _KBDSTAT _SA1111( 0x0A04 ) +#define _KBDDATA _SA1111( 0x0A08 ) +#define _KBDCLKDIV _SA1111( 0x0A0C ) +#define _KBDPRECNT _SA1111( 0x0A10 ) +#define _MSECR _SA1111( 0x0C00 ) +#define _MSESTAT _SA1111( 0x0C04 ) +#define _MSEDATA _SA1111( 0x0C08 ) +#define _MSECLKDIV _SA1111( 0x0C0C ) +#define _MSEPRECNT _SA1111( 0x0C10 ) + +#if ( LANGUAGE == C ) + +#define KBDCR __CCREG(0x0a00) +#define KBDSTAT __CCREG(0x0a04) +#define KBDDATA __CCREG(0x0a08) +#define KBDCLKDIV __CCREG(0x0a0c) +#define KBDPRECNT __CCREG(0x0a10) +#define MSECR __CCREG(0x0c00) +#define MSESTAT __CCREG(0x0c04) +#define MSEDATA __CCREG(0x0c08) +#define MSECLKDIV __CCREG(0x0c0c) +#define MSEPRECNT __CCREG(0x0c10) + +#define KBDCR_ENA 0x08 +#define KBDCR_FKD 0x02 +#define KBDCR_FKC 0x01 + +#define KBDSTAT_TXE 0x80 +#define KBDSTAT_TXB 0x40 +#define KBDSTAT_RXF 0x20 +#define KBDSTAT_RXB 0x10 +#define KBDSTAT_ENA 0x08 +#define KBDSTAT_RXP 0x04 +#define KBDSTAT_KBD 0x02 +#define KBDSTAT_KBC 0x01 + +#define KBDCLKDIV_DivVal Fld(4,0) + +#define MSECR_ENA 0x08 +#define MSECR_FKD 0x02 +#define MSECR_FKC 0x01 + +#define MSESTAT_TXE 0x80 +#define MSESTAT_TXB 0x40 +#define MSESTAT_RXF 0x20 +#define MSESTAT_RXB 0x10 +#define MSESTAT_ENA 0x08 +#define MSESTAT_RXP 0x04 +#define MSESTAT_MSD 0x02 +#define MSESTAT_MSC 0x01 + +#define MSECLKDIV_DivVal Fld(4,0) + +#define KBDTEST1_CD 0x80 +#define KBDTEST1_RC1 0x40 +#define KBDTEST1_MC 0x20 +#define KBDTEST1_C Fld(2,3) +#define KBDTEST1_T2 0x40 +#define KBDTEST1_T1 0x20 +#define KBDTEST1_T0 0x10 +#define KBDTEST2_TICBnRES 0x08 +#define KBDTEST2_RKC 0x04 +#define KBDTEST2_RKD 0x02 +#define KBDTEST2_SEL 0x01 +#define KBDTEST3_ms_16 0x80 +#define KBDTEST3_us_64 0x40 +#define KBDTEST3_us_16 0x20 +#define KBDTEST3_DIV8 0x10 +#define KBDTEST3_DIn 0x08 +#define KBDTEST3_CIn 0x04 +#define KBDTEST3_KD 0x02 +#define KBDTEST3_KC 0x01 +#define KBDTEST4_BC12 0x80 +#define KBDTEST4_BC11 0x40 +#define KBDTEST4_TRES 0x20 +#define KBDTEST4_CLKOE 0x10 +#define KBDTEST4_CRES 0x08 +#define KBDTEST4_RXB 0x04 +#define KBDTEST4_TXB 0x02 +#define KBDTEST4_SRX 0x01 + +#define MSETEST1_CD 0x80 +#define MSETEST1_RC1 0x40 +#define MSETEST1_MC 0x20 +#define MSETEST1_C Fld(2,3) +#define MSETEST1_T2 0x40 +#define MSETEST1_T1 0x20 +#define MSETEST1_T0 0x10 +#define MSETEST2_TICBnRES 0x08 +#define MSETEST2_RKC 0x04 +#define MSETEST2_RKD 0x02 +#define MSETEST2_SEL 0x01 +#define MSETEST3_ms_16 0x80 +#define MSETEST3_us_64 0x40 +#define MSETEST3_us_16 0x20 +#define MSETEST3_DIV8 0x10 +#define MSETEST3_DIn 0x08 +#define MSETEST3_CIn 0x04 +#define MSETEST3_KD 0x02 +#define MSETEST3_KC 0x01 +#define MSETEST4_BC12 0x80 +#define MSETEST4_BC11 0x40 +#define MSETEST4_TRES 0x20 +#define MSETEST4_CLKOE 0x10 +#define MSETEST4_CRES 0x08 +#define MSETEST4_RXB 0x04 +#define MSETEST4_TXB 0x02 +#define MSETEST4_SRX 0x01 + +#endif /* LANGUAGE == C */ + +/* + * PCMCIA Interface + * + * Registers + * PCSR Status Register + * PCCR Control Register + * PCSSR Sleep State Register + */ + +#define _PCCR _SA1111( 0x1800 ) +#define _PCSSR _SA1111( 0x1804 ) +#define _PCSR _SA1111( 0x1808 ) + +#if LANGUAGE == C + +#define PCCR __CCREG(0x1800) +#define PCSSR __CCREG(0x1804) +#define PCSR __CCREG(0x1808) + +#endif /* LANGUAGE == C */ + +#define PCSR_S0_READY (1<<0) +#define PCSR_S1_READY (1<<1) +#define PCSR_S0_DETECT (1<<2) +#define PCSR_S1_DETECT (1<<3) +#define PCSR_S0_VS1 (1<<4) +#define PCSR_S0_VS2 (1<<5) +#define PCSR_S1_VS1 (1<<6) +#define PCSR_S1_VS2 (1<<7) +#define PCSR_S0_WP (1<<8) +#define PCSR_S1_WP (1<<9) +#define PCSR_S0_BVD1 (1<<10) +#define PCSR_S0_BVD2 (1<<11) +#define PCSR_S1_BVD1 (1<<12) +#define PCSR_S1_BVD2 (1<<13) + +#define PCCR_S0_RST (1<<0) +#define PCCR_S1_RST (1<<1) +#define PCCR_S0_FLT (1<<2) +#define PCCR_S1_FLT (1<<3) +#define PCCR_S0_PWAITEN (1<<4) +#define PCCR_S1_PWAITEN (1<<5) +#define PCCR_S0_PSE (1<<6) +#define PCCR_S1_PSE (1<<7) + +#define PCSSR_S0_SLEEP (1<<0) +#define PCSSR_S1_SLEEP (1<<1) + +#endif /* _ASM_ARCH_SA1111 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/hdreg.h linux-2.5/include/asm-arm/hdreg.h --- linux-2.5.1/include/asm-arm/hdreg.h Thu May 13 18:00:08 1999 +++ linux-2.5/include/asm-arm/hdreg.h Sun Jan 6 01:38:27 2002 @@ -7,7 +7,7 @@ #ifndef __ASMARM_HDREG_H #define __ASMARM_HDREG_H -typedef unsigned long ide_ioreg_t; +typedef unsigned int ide_ioreg_t; #endif /* __ASMARM_HDREG_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/io.h linux-2.5/include/asm-arm/io.h --- linux-2.5.1/include/asm-arm/io.h Thu Oct 11 16:04:57 2001 +++ linux-2.5/include/asm-arm/io.h Sun Jan 6 01:38:27 2002 @@ -23,20 +23,14 @@ #ifdef __KERNEL__ #include <linux/types.h> +#include <asm/byteorder.h> #include <asm/memory.h> #include <asm/arch/hardware.h> /* - * Generic virtual read/write. Note that we don't support half-word - * read/writes. We define __arch_*[bl] here, and leave __arch_*w - * to the architecture specific code. + * Generic IO read/write. These perform native-endian accesses. Note + * that some architectures will want to re-define __raw_{read,write}w. */ -#define __arch_getb(a) (*(volatile unsigned char *)(a)) -#define __arch_getl(a) (*(volatile unsigned int *)(a)) - -#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) -#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) - extern void __raw_writesb(unsigned int addr, void *data, int bytelen); extern void __raw_writesw(unsigned int addr, void *data, int wordlen); extern void __raw_writesl(unsigned int addr, void *data, int longlen); @@ -45,116 +39,85 @@ extern void __raw_readsw(unsigned int addr, void *data, int wordlen); extern void __raw_readsl(unsigned int addr, void *data, int longlen); -#define __raw_writeb(v,a) __arch_putb(v,a) -#define __raw_writew(v,a) __arch_putw(v,a) -#define __raw_writel(v,a) __arch_putl(v,a) - -#define __raw_readb(a) __arch_getb(a) -#define __raw_readw(a) __arch_getw(a) -#define __raw_readl(a) __arch_getl(a) - -/* - * The compiler seems to be incapable of optimising constants - * properly. Spell it out to the compiler in some cases. - * These are only valid for small values of "off" (< 1<<12) - */ -#define __raw_base_writeb(val,base,off) __arch_base_putb(val,base,off) -#define __raw_base_writew(val,base,off) __arch_base_putw(val,base,off) -#define __raw_base_writel(val,base,off) __arch_base_putl(val,base,off) - -#define __raw_base_readb(base,off) __arch_base_getb(base,off) -#define __raw_base_readw(base,off) __arch_base_getw(base,off) -#define __raw_base_readl(base,off) __arch_base_getl(base,off) +#define __raw_writeb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __raw_writew(v,a) (*(volatile unsigned short *)(a) = (v)) +#define __raw_writel(v,a) (*(volatile unsigned int *)(a) = (v)) + +#define __raw_readb(a) (*(volatile unsigned char *)(a)) +#define __raw_readw(a) (*(volatile unsigned short *)(a)) +#define __raw_readl(a) (*(volatile unsigned int *)(a)) + +/* + * Bad read/write accesses... + */ +extern void __readwrite_bug(const char *fn); /* * Now, pick up the machine-defined IO definitions */ #include <asm/arch/io.h> +#ifdef __io_pci +#warning machine class uses buggy __io_pci +#endif +#if defined(__arch_putb) || defined(__arch_putw) || defined(__arch_putl) || \ + defined(__arch_getb) || defined(__arch_getw) || defined(__arch_getl) +#warning machine class uses old __arch_putw or __arch_getw +#endif + /* - * IO definitions. We define {out,in,outs,ins}[bwl] if __io is defined - * by the machine. Otherwise, these definitions are left for the machine - * specific header files to pick up. + * IO port access primitives + * ------------------------- + * + * The ARM doesn't have special IO access instructions; all IO is memory + * mapped. Note that these are defined to perform little endian accesses + * only. Their primary purpose is to access PCI and ISA peripherals. + * + * Note that for a big endian machine, this implies that the following + * big endian mode connectivity is in place, as described by numerious + * ARM documents: + * + * PCI: D0-D7 D8-D15 D16-D23 D24-D31 + * ARM: D24-D31 D16-D23 D8-D15 D0-D7 + * + * The machine specific io.h include defines __io to translate an "IO" + * address to a memory address. * * Note that we prevent GCC re-ordering or caching values in expressions * by introducing sequence points into the in*() definitions. Note that * __raw_* do not guarantee this behaviour. */ #ifdef __io -#define outb(v,p) __raw_writeb(v,__io(p)) -#define outw(v,p) __raw_writew(v,__io(p)) -#define outl(v,p) __raw_writel(v,__io(p)) - -#define inb(p) ({ unsigned int __v = __raw_readb(__io(p)); __v; }) -#define inw(p) ({ unsigned int __v = __raw_readw(__io(p)); __v; }) -#define inl(p) ({ unsigned int __v = __raw_readl(__io(p)); __v; }) - -#define outsb(p,d,l) __raw_writesb(__io(p),d,l) -#define outsw(p,d,l) __raw_writesw(__io(p),d,l) -#define outsl(p,d,l) __raw_writesl(__io(p),d,l) - -#define insb(p,d,l) __raw_readsb(__io(p),d,l) -#define insw(p,d,l) __raw_readsw(__io(p),d,l) -#define insl(p,d,l) __raw_readsl(__io(p),d,l) +#define outb(v,p) __raw_writeb(v,__io(p)) +#define outw(v,p) __raw_writew(cpu_to_le16(v),__io(p)) +#define outl(v,p) __raw_writel(cpu_to_le32(v),__io(p)) + +#define inb(p) ({ unsigned int __v = __raw_readb(__io(p)); __v; }) +#define inw(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; }) +#define inl(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; }) + +#define outsb(p,d,l) __raw_writesb(__io(p),d,l) +#define outsw(p,d,l) __raw_writesw(__io(p),d,l) +#define outsl(p,d,l) __raw_writesl(__io(p),d,l) + +#define insb(p,d,l) __raw_readsb(__io(p),d,l) +#define insw(p,d,l) __raw_readsw(__io(p),d,l) +#define insl(p,d,l) __raw_readsl(__io(p),d,l) #endif -#define outb_p(val,port) outb((val),(port)) -#define outw_p(val,port) outw((val),(port)) -#define outl_p(val,port) outl((val),(port)) -#define inb_p(port) inb((port)) -#define inw_p(port) inw((port)) -#define inl_p(port) inl((port)) - -#define outsb_p(port,from,len) outsb(port,from,len) -#define outsw_p(port,from,len) outsw(port,from,len) -#define outsl_p(port,from,len) outsl(port,from,len) -#define insb_p(port,to,len) insb(port,to,len) -#define insw_p(port,to,len) insw(port,to,len) -#define insl_p(port,to,len) insl(port,to,len) - -/* - * ioremap and friends. - * - * ioremap takes a PCI memory address, as specified in - * linux/Documentation/IO-mapping.txt. If you want a - * physical address, use __ioremap instead. - */ -extern void * __ioremap(unsigned long offset, size_t size, unsigned long flags); -extern void __iounmap(void *addr); - -/* - * Generic ioremap support. - * - * Define: - * iomem_valid_addr(off,size) - * iomem_to_phys(off) - */ -#ifdef iomem_valid_addr -#define __arch_ioremap(off,sz,nocache) \ - ({ \ - unsigned long _off = (off), _size = (sz); \ - void *_ret = (void *)0; \ - if (iomem_valid_addr(_off, _size)) \ - _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) __arch_iounmap(_addr) - -/* - * DMA-consistent mapping functions. These allocate/free a region of - * uncached, unwrite-buffered mapped memory space for use with DMA - * devices. This is the "generic" version. The PCI specific version - * is in pci.h - */ -extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle); -extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle); -extern void consistent_sync(void *vaddr, size_t size, int rw); +#define outb_p(val,port) outb((val),(port)) +#define outw_p(val,port) outw((val),(port)) +#define outl_p(val,port) outl((val),(port)) +#define inb_p(port) inb((port)) +#define inw_p(port) inw((port)) +#define inl_p(port) inl((port)) + +#define outsb_p(port,from,len) outsb(port,from,len) +#define outsw_p(port,from,len) outsw(port,from,len) +#define outsl_p(port,from,len) outsl(port,from,len) +#define insb_p(port,to,len) insb(port,to,len) +#define insw_p(port,to,len) insw(port,to,len) +#define insl_p(port,to,len) insl(port,to,len) /* * String version of IO memory access ops: @@ -163,29 +126,31 @@ extern void _memcpy_toio(unsigned long, const void *, size_t); extern void _memset_io(unsigned long, int, size_t); -extern void __readwrite_bug(const char *fn); - /* - * If this architecture has PCI memory IO, then define the read/write - * macros. These should only be used with the cookie passed from - * ioremap. + * Memory access primitives + * ------------------------ + * + * These perform PCI memory accesses via an ioremap region. They don't + * take an address as such, but a cookie. + * + * Again, this are defined to perform little endian accesses. See the + * IO port primitives for more information. */ #ifdef __mem_pci +#define readb(c) ({ unsigned int __v = __raw_readb(__mem_pci(c)); __v; }) +#define readw(c) ({ unsigned int __v = le16_to_cpu(__raw_readw(__mem_pci(c))); __v; }) +#define readl(c) ({ unsigned int __v = le32_to_cpu(__raw_readl(__mem_pci(c))); __v; }) + +#define writeb(v,c) __raw_writeb(v,__mem_pci(c)) +#define writew(v,c) __raw_writew(cpu_to_le16(v),__mem_pci(c)) +#define writel(v,c) __raw_writel(cpu_to_le32(v),__mem_pci(c)) + +#define memset_io(c,v,l) _memset_io(__mem_pci(c),(v),(l)) +#define memcpy_fromio(a,c,l) _memcpy_fromio((a),__mem_pci(c),(l)) +#define memcpy_toio(c,a,l) _memcpy_toio(__mem_pci(c),(a),(l)) -#define readb(addr) ({ unsigned int __v = __raw_readb(__mem_pci(addr)); __v; }) -#define readw(addr) ({ unsigned int __v = __raw_readw(__mem_pci(addr)); __v; }) -#define readl(addr) ({ unsigned int __v = __raw_readl(__mem_pci(addr)); __v; }) - -#define writeb(val,addr) __raw_writeb(val,__mem_pci(addr)) -#define writew(val,addr) __raw_writew(val,__mem_pci(addr)) -#define writel(val,addr) __raw_writel(val,__mem_pci(addr)) - -#define memset_io(a,b,c) _memset_io(__mem_pci(a),(b),(c)) -#define memcpy_fromio(a,b,c) _memcpy_fromio((a),__mem_pci(b),(c)) -#define memcpy_toio(a,b,c) _memcpy_toio(__mem_pci(a),(b),(c)) - -#define eth_io_copy_and_sum(a,b,c,d) \ - eth_copy_and_sum((a),__mem_pci(b),(c),(d)) +#define eth_io_copy_and_sum(s,c,l,b) \ + eth_copy_and_sum((s),__mem_pci(c),(l),(b)) static inline int check_signature(unsigned long io_addr, const unsigned char *signature, @@ -206,28 +171,20 @@ #elif !defined(readb) -#define readb(addr) (__readwrite_bug("readb"),0) -#define readw(addr) (__readwrite_bug("readw"),0) -#define readl(addr) (__readwrite_bug("readl"),0) -#define writeb(v,addr) __readwrite_bug("writeb") -#define writew(v,addr) __readwrite_bug("writew") -#define writel(v,addr) __readwrite_bug("writel") +#define readb(c) (__readwrite_bug("readb"),0) +#define readw(c) (__readwrite_bug("readw"),0) +#define readl(c) (__readwrite_bug("readl"),0) +#define writeb(v,c) __readwrite_bug("writeb") +#define writew(v,c) __readwrite_bug("writew") +#define writel(v,c) __readwrite_bug("writel") -#define eth_io_copy_and_sum(a,b,c,d) __readwrite_bug("eth_io_copy_and_sum") +#define eth_io_copy_and_sum(s,c,l,b) __readwrite_bug("eth_io_copy_and_sum") #define check_signature(io,sig,len) (0) #endif /* __mem_pci */ /* - * remap a physical address `phys' of size `size' with page protection `prot' - * into virtual address `from' - */ -#define io_remap_page_range(from,phys,size,prot) \ - remap_page_range(from,phys,size,prot) - - -/* * If this architecture has ISA IO, then define the isa_read/isa_write * macros. */ @@ -281,5 +238,51 @@ #define isa_check_signature(io,sig,len) (0) #endif /* __mem_isa */ + +/* + * ioremap and friends. + * + * ioremap takes a PCI memory address, as specified in + * linux/Documentation/IO-mapping.txt. + */ +extern void * __ioremap(unsigned long, size_t, unsigned long, unsigned long); +extern void __iounmap(void *addr); + +#ifndef __arch_ioremap +#define ioremap(cookie,size) __ioremap(cookie,size,0,1) +#define ioremap_nocache(cookie,size) __ioremap(cookie,size,0,1) +#define iounmap(cookie) __iounmap(cookie) +#else +#define ioremap(cookie,size) __arch_ioremap((cookie),(size),0,1) +#define ioremap_nocache(cookie,size) __arch_ioremap((cookie),(size),0,1) +#define iounmap(cookie) __arch_iounmap(cookie) +#endif + +/* + * DMA-consistent mapping functions. These allocate/free a region of + * uncached, unwrite-buffered mapped memory space for use with DMA + * devices. This is the "generic" version. The PCI specific version + * is in pci.h + */ +extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle); +extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle); +extern void consistent_sync(void *vaddr, size_t size, int rw); + +/* + * FIXME: I'm sure these will need to be changed for DISCONTIG + */ +/* + * Change "struct page" to physical address. + */ +#define page_to_phys(page) (PHYS_OFFSET + ((page - mem_map) << PAGE_SHIFT)) +#define page_to_bus(page) (PHYS_OFFSET + ((page - mem_map) << PAGE_SHIFT)) + +/* + * can the hardware map this into one segment or not, given no other + * constraints. + */ +#define BIOVEC_MERGEABLE(vec1, vec2) \ + ((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) + #endif /* __KERNEL__ */ #endif /* __ASM_ARM_IO_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/mach/pci.h linux-2.5/include/asm-arm/mach/pci.h --- linux-2.5.1/include/asm-arm/mach/pci.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/mach/pci.h Sun Jan 6 01:38:27 2002 @@ -7,7 +7,12 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +struct pci_sys_data; +struct pci_bus; + struct hw_pci { + /* START OF OLD STUFF */ /* Initialise the hardware */ void (*init)(void *); @@ -25,10 +30,55 @@ /* IRQ mapping */ int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); + + /* END OF OLD STUFF */ + + /* NEW STUFF */ + int nr_controllers; + int (*setup)(int nr, struct pci_sys_data *); + struct pci_bus *(*scan)(int nr, struct pci_sys_data *); + void (*preinit)(void); + void (*postinit)(void); +}; + +/* + * Per-controller structure + */ +struct pci_sys_data { + int busnr; /* primary bus number */ + unsigned long mem_offset; /* bus->cpu memory mapping offset */ + unsigned long io_offset; /* bus->cpu IO mapping offset */ + struct pci_bus *bus; /* PCI bus */ + struct resource *resource[3]; /* Primary PCI bus resources */ + /* Bridge swizzling */ + u8 (*swizzle)(struct pci_dev *, u8 *); + /* IRQ mapping */ + int (*map_irq)(struct pci_dev *, u8, u8); + struct hw_pci *hw; }; -extern u8 no_swizzle(struct pci_dev *dev, u8 *pin); -extern void __init dc21285_setup_resources(struct resource **resource); -extern void __init dc21285_init(void *sysdata); +/* + * This is the standard PCI-PCI bridge swizzling algorithm. + */ +u8 pci_std_swizzle(struct pci_dev *dev, u8 *pinp); + +/* + * PCI controllers + */ +extern int iop310_setup(int nr, struct pci_sys_data *); +extern struct pci_bus *iop310_scan_bus(int nr, struct pci_sys_data *); + +extern int dc21285_setup(int nr, struct pci_sys_data *); +extern struct pci_bus *dc21285_scan_bus(int nr, struct pci_sys_data *); +extern void dc21285_preinit(void); +extern void dc21285_postinit(void); + +extern int via82c505_setup(int nr, struct pci_sys_data *); +extern struct pci_bus *via82c505_scan_bus(int nr, struct pci_sys_data *); extern void __init via82c505_init(void *sysdata); + +extern int pci_v3_setup(int nr, struct pci_sys_data *); +extern struct pci_bus *pci_v3_scan_bus(int nr, struct pci_sys_data *); +extern void pci_v3_preinit(void); +extern void pci_v3_postinit(void); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/mach/serial_sa1100.h linux-2.5/include/asm-arm/mach/serial_sa1100.h --- linux-2.5.1/include/asm-arm/mach/serial_sa1100.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/mach/serial_sa1100.h Sun Jan 6 01:38:27 2002 @@ -18,9 +18,10 @@ */ struct sa1100_port_fns { void (*set_mctrl)(struct uart_port *, u_int); - int (*get_mctrl)(struct uart_port *); + u_int (*get_mctrl)(struct uart_port *); void (*enable_ms)(struct uart_port *); void (*pm)(struct uart_port *, u_int, u_int); + int (*set_wake)(struct uart_port *, u_int); int (*open)(struct uart_port *, struct uart_info *); void (*close)(struct uart_port *, struct uart_info *); }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/page.h linux-2.5/include/asm-arm/page.h --- linux-2.5.1/include/asm-arm/page.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/page.h Sun Jan 6 01:38:27 2002 @@ -3,8 +3,8 @@ #include <asm/proc/page.h> -#define PAGE_SIZE (1UL << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) #ifdef __KERNEL__ #ifndef __ASSEMBLY__ @@ -14,8 +14,8 @@ #define clear_page(page) memzero((void *)(page), PAGE_SIZE) extern void copy_page(void *to, void *from); -#define clear_user_page(page, vaddr) clear_page(page) -#define copy_user_page(to, from, vaddr) copy_page(to, from) +#define clear_user_page(page, vaddr) cpu_clear_user_page(page,vaddr) +#define copy_user_page(to, from, vaddr) cpu_copy_user_page(to,from,vaddr) #ifdef STRICT_MM_TYPECHECKS /* @@ -63,10 +63,20 @@ #ifndef __ASSEMBLY__ +#ifdef CONFIG_DEBUG_BUGVERBOSE extern void __bug(const char *file, int line, void *data); +/* give file/line information */ #define BUG() __bug(__FILE__, __LINE__, NULL) #define PAGE_BUG(page) __bug(__FILE__, __LINE__, page) + +#else + +/* these just cause an oops */ +#define BUG() (*(int *)0 = 0) +#define PAGE_BUG(page) (*(int *)0 = 0) + +#endif /* Pure 2^n version of get_order */ static inline int get_order(unsigned long size) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/pci.h linux-2.5/include/asm-arm/pci.h --- linux-2.5.1/include/asm-arm/pci.h Fri Nov 9 22:11:15 2001 +++ linux-2.5/include/asm-arm/pci.h Sun Jan 6 01:38:27 2002 @@ -3,7 +3,14 @@ #ifdef __KERNEL__ +#include <linux/mm.h> /* bah! */ + #include <asm/arch/hardware.h> +#include <asm/scatterlist.h> +#include <asm/page.h> +#include <asm/io.h> + +struct pci_dev; static inline void pcibios_set_master(struct pci_dev *dev) { @@ -15,10 +22,11 @@ /* We don't do dynamic PCI IRQ allocation */ } -#include <asm/scatterlist.h> -#include <asm/io.h> - -struct pci_dev; +/* The PCI address space does equal the physical memory + * address space. The networking and block device layers use + * this boolean for bounce buffer decisions. + */ +#define PCI_DMA_BUS_IS_PHYS (0) /* Allocate and map kernel buffer using consistent mode DMA for a device. * hwdev should be valid struct pci_dev pointer for PCI devices, @@ -87,6 +95,31 @@ /* nothing to do */ } +/* Whether pci_unmap_{single,page} is a nop depends upon the + * configuration. + */ +#ifdef CONFIG_SA1111 +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) +#else /* !(CONFIG_SA1111) */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) (0) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) do { } while (0) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) (0) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) do { } while (0) +#endif /* CONFIG_SA1111 */ + /* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the * above pci_map_single interface. Here the scatter gather list @@ -108,8 +141,20 @@ int i; for (i = 0; i < nents; i++, sg++) { - consistent_sync(sg->address, sg->length, direction); - sg->dma_address = virt_to_bus(sg->address); + char *virt; + if (sg->address && sg->page) + BUG(); + else if (!sg->address && !sg->page) + BUG(); + + if (sg->address) { + sg->dma_address = virt_to_bus(sg->address); + virt = sg->address; + } else { + sg->dma_address = page_to_bus(sg->page) + sg->offset; + virt = page_address(sg->page) + sg->offset; + } + consistent_sync(virt, sg->length, direction); } return nents; @@ -151,8 +196,15 @@ { int i; - for (i = 0; i < nelems; i++, sg++) - consistent_sync(sg->address, sg->length, direction); + for (i = 0; i < nelems; i++, sg++) { + char *virt; + + if (sg->address) + virt = sg->address; + else + virt = page_address(sg->page) + sg->offset; + consistent_sync(virt, sg->length, direction); + } } /* Return whether the given PCI device DMA address mask can diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/pgtable.h linux-2.5/include/asm-arm/pgtable.h --- linux-2.5.1/include/asm-arm/pgtable.h Thu Oct 11 16:04:57 2001 +++ linux-2.5/include/asm-arm/pgtable.h Sun Jan 6 01:38:27 2002 @@ -12,6 +12,7 @@ #include <linux/config.h> #include <asm/arch/memory.h> +#include <asm/arch/vmalloc.h> #include <asm/proc-fns.h> /* @@ -176,6 +177,13 @@ #include <asm-generic/pgtable.h> extern void pgtable_cache_init(void); + +/* + * remap a physical address `phys' of size `size' with page protection `prot' + * into virtual address `from' + */ +#define io_remap_page_range(from,phys,size,prot) \ + remap_page_range(from,phys,size,prot) #endif /* !__ASSEMBLY__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/proc-armo/ptrace.h linux-2.5/include/asm-arm/proc-armo/ptrace.h --- linux-2.5.1/include/asm-arm/proc-armo/ptrace.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/proc-armo/ptrace.h Sun Jan 6 01:38:27 2002 @@ -10,21 +10,21 @@ #ifndef __ASM_PROC_PTRACE_H #define __ASM_PROC_PTRACE_H -#define USR26_MODE 0x00 -#define FIQ26_MODE 0x01 -#define IRQ26_MODE 0x02 -#define SVC26_MODE 0x03 +#define USR26_MODE 0x00000000 +#define FIQ26_MODE 0x00000001 +#define IRQ26_MODE 0x00000002 +#define SVC26_MODE 0x00000003 #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) -#define CC_V_BIT (1 << 28) -#define CC_C_BIT (1 << 29) -#define CC_Z_BIT (1 << 30) -#define CC_N_BIT (1 << 31) +#define MODE_MASK 0x00000003 +#define PSR_F_BIT 0x04000000 +#define PSR_I_BIT 0x08000000 +#define PSR_V_BIT 0x10000000 +#define PSR_C_BIT 0x20000000 +#define PSR_Z_BIT 0x40000000 +#define PSR_N_BIT 0x80000000 #define PCMASK 0xfc000003 #ifndef __ASSEMBLY__ @@ -65,13 +65,13 @@ #define thumb_mode(regs) (0) #define interrupts_enabled(regs) \ - (!((regs)->ARM_pc & I_BIT)) + (!((regs)->ARM_pc & PSR_I_BIT)) #define fast_interrupts_enabled(regs) \ - (!((regs)->ARM_pc & F_BIT)) + (!((regs)->ARM_pc & PSR_F_BIT)) #define condition_codes(regs) \ - ((regs)->ARM_pc & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT)) + ((regs)->ARM_pc & (PSR_V_BIT|PSR_C_BIT|PSR_Z_BIT|PSR_N_BIT)) /* Are the current registers suitable for user mode? * (used to maintain security in signal handlers) @@ -79,13 +79,13 @@ static inline int valid_user_regs(struct pt_regs *regs) { if (user_mode(regs) && - (regs->ARM_pc & (F_BIT | I_BIT)) == 0) + (regs->ARM_pc & (PSR_F_BIT | PSR_I_BIT)) == 0) return 1; /* * force it to be something sensible */ - regs->ARM_pc &= ~(MODE_MASK | F_BIT | I_BIT); + regs->ARM_pc &= ~(MODE_MASK | PSR_F_BIT | PSR_I_BIT); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/proc-armv/assembler.h linux-2.5/include/asm-arm/proc-armv/assembler.h --- linux-2.5.1/include/asm-arm/proc-armv/assembler.h Mon Sep 18 22:15:24 2000 +++ linux-2.5/include/asm-arm/proc-armv/assembler.h Sun Jan 6 01:38:27 2002 @@ -40,7 +40,7 @@ */ .macro save_and_disable_irqs, oldcpsr, temp mrs \oldcpsr, cpsr - mov \temp, #I_BIT | MODE_SVC + mov \temp, #PSR_I_BIT | MODE_SVC msr cpsr_c, \temp .endm diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/proc-armv/cache.h linux-2.5/include/asm-arm/proc-armv/cache.h --- linux-2.5.1/include/asm-arm/proc-armv/cache.h Thu Oct 25 20:53:55 2001 +++ linux-2.5/include/asm-arm/proc-armv/cache.h Sun Jan 6 01:38:27 2002 @@ -44,13 +44,13 @@ #define flush_cache_range(_mm,_start,_end) \ do { \ - if ((_mm) == current->mm) \ + if ((_mm) == current->active_mm) \ cpu_cache_clean_invalidate_range((_start), (_end), 1); \ } while (0) #define flush_cache_page(_vma,_vmaddr) \ do { \ - if ((_vma)->vm_mm == current->mm) { \ + if ((_vma)->vm_mm == current->active_mm) { \ cpu_cache_clean_invalidate_range((_vmaddr), \ (_vmaddr) + PAGE_SIZE, \ ((_vma)->vm_flags & VM_EXEC)); \ @@ -62,36 +62,68 @@ * in the cache for this page. This does not invalidate either I or D caches. * * Called from: - * 1. mm/filemap.c:filemap_nopage - * 2. mm/filemap.c:filemap_nopage - * [via do_no_page - ok] - * - * 3. mm/memory.c:break_cow - * [copy_cow_page doesn't do anything to the cache; insufficient cache - * handling. Need to add flush_dcache_page() here] - * - * 4. mm/memory.c:do_swap_page - * [read_swap_cache_async doesn't do anything to the cache: insufficient - * cache handling. Need to add flush_dcache_page() here] - * - * 5. mm/memory.c:do_anonymous_page - * [zero page, never written by kernel - ok] - * - * 6. mm/memory.c:do_no_page - * [we will be calling update_mmu_cache, which will catch on PG_dcache_dirty] - * - * 7. mm/shmem.c:shmem_nopage - * 8. mm/shmem.c:shmem_nopage - * [via do_no_page - ok] - * - * 9. fs/exec.c:put_dirty_page - * [we call flush_dcache_page prior to this, which will flush out the - * kernel virtual addresses from the dcache - ok] + * 1. fs/exec.c:put_dirty_page - ok + * - page came from alloc_page(), so page->mapping = NULL. + * - flush_dcache_page called immediately prior. + * + * 2. kernel/ptrace.c:access_one_page - flush_icache_page + * - flush_cache_page takes care of the user space side of the mapping. + * - page is either a page cache page (with page->mapping set, and + * hence page->mapping->i_mmap{,shared} also set) or an anonymous + * page. I think this is ok. + * + * 3. kernel/ptrace.c:access_one_page - bad + * - flush_cache_page takes care of the user space side of the mapping. + * - no apparant cache protection, reading the kernel virtual alias + * + * 4. mm/filemap.c:filemap_no_page - ok + * - add_to_page_cache_* clears PG_arch_1. + * - page->mapping != NULL. + * - i_mmap or i_mmap_shared will be non-null if mmap'd + * - called from (8). + * + * 5. mm/memory.c:break_cow,do_wp_page - {copy,clear}_user_page + * - need to ensure that copy_cow_page has pushed all data from the dcache + * to the page. + * - calls + * - clear_user_highpage -> clear_user_page + * - copy_user_highpage -> copy_user_page + * + * 6. mm/memory.c:do_swap_page - flush_icache_page + * - flush_icache_page called afterwards - if flush_icache_page does the + * same as flush_dcache_page, update_mmu_cache will do the work for us. + * - update_mmu_cache called. + * + * 7. mm/memory.c:do_anonymous_page - {copy,clear}_user_page + * - calls clear_user_highpage. See (5) + * + * 8. mm/memory.c:do_no_page - flush_icache_page + * - flush_icache_page called afterwards - if flush_icache_page does the + * same as flush_dcache_page, update_mmu_cache will do the work for us. + * - update_mmu_cache called. + * - When we place a user mapping, we will call update_mmu_cache, + * which will catch PG_arch_1 set. + * + * 9. mm/shmem.c:shmem_no_page - ok + * - shmem_get_page clears PG_arch_1, as does add_to_page_cache (duplicate) + * - page->mapping != NULL. + * - i_mmap or i_mmap_shared will be non-null if mmap'd + * - called from (8). + * + * 10. mm/swapfile.c:try_to_unuse - bad + * - this looks really dodgy - we're putting pages from the swap cache + * straight into processes, and the only cache handling appears to + * be flush_page_to_ram. */ +#define flush_page_to_ram_ok +#ifdef flush_page_to_ram_ok +#define flush_page_to_ram(page) do { } while (0) +#else static __inline__ void flush_page_to_ram(struct page *page) { cpu_flush_ram_page(page_address(page)); } +#endif /* * D cache only @@ -101,6 +133,8 @@ #define clean_dcache_range(_s,_e) cpu_dcache_clean_range((_s),(_e)) #define flush_dcache_range(_s,_e) cpu_cache_clean_invalidate_range((_s),(_e),0) +#define mapping_mapped(map) ((map)->i_mmap || (map)->i_mmap_shared) + /* * flush_dcache_page is used when the kernel has written to the page * cache page at virtual address page->virtual. @@ -116,8 +150,7 @@ */ static inline void flush_dcache_page(struct page *page) { - if (page->mapping && !(page->mapping->i_mmap) && - !(page->mapping->i_mmap_shared)) + if (page->mapping && !mapping_mapped(page->mapping)) set_bit(PG_dcache_dirty, &page->flags); else { unsigned long virt = (unsigned long)page_address(page); @@ -125,6 +158,30 @@ } } +/* + * flush_icache_page makes the kernel page address consistent with the + * user space mappings. The functionality is the same as flush_dcache_page, + * except we can do an optimisation and only clean the caches here if + * vma->vm_mm == current->active_mm. + * + * This function is misnamed IMHO. There are three places where it + * is called, each of which is preceded immediately by a call to + * flush_page_to_ram: + */ +#ifdef flush_page_to_ram_ok +static inline void flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + if (page->mapping && !mapping_mapped(page->mapping)) + set_bit(PG_dcache_dirty, &page->flags); + else if (vma->vm_mm == current->active_mm) { + unsigned long virt = (unsigned long)page_address(page); + cpu_cache_clean_invalidate_range(virt, virt + PAGE_SIZE, 0); + } +} +#else +#define flush_icache_page(vma,pg) do { } while (0) +#endif + #define clean_dcache_entry(_s) cpu_dcache_clean_entry((unsigned long)(_s)) /* @@ -141,32 +198,6 @@ do { \ cpu_icache_invalidate_range((_s), (_e)); \ } while (0) - -/* - * This function is misnamed IMHO. There are three places where it - * is called, each of which is preceded immediately by a call to - * flush_page_to_ram: - * - * 1. kernel/ptrace.c:access_one_page - * called after we have written to the kernel view of a user page. - * The user page has been expundged from the cache by flush_cache_page. - * [we don't need to do anything here if we add a call to - * flush_dcache_page] - * - * 2. mm/memory.c:do_swap_page - * called after we have (possibly) written to the kernel view of a - * user page, which has previously been removed (ie, has been through - * the swap cache). - * [if the flush_page_to_ram() conditions are satisfied, then ok] - * - * 3. mm/memory.c:do_no_page - * [if the flush_page_to_ram() conditions are satisfied, then ok] - * - * Invalidating the icache at the kernels virtual page isn't really - * going to do us much good, since we wouldn't have executed any - * instructions there. - */ -#define flush_icache_page(vma,pg) do { } while (0) /* * Old ARM MEMC stuff. This supports the reversed mapping handling that diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/proc-armv/pgalloc.h linux-2.5/include/asm-arm/proc-armv/pgalloc.h --- linux-2.5.1/include/asm-arm/proc-armv/pgalloc.h Thu Apr 12 19:20:31 2001 +++ linux-2.5/include/asm-arm/proc-armv/pgalloc.h Sun Jan 6 01:38:27 2002 @@ -46,13 +46,12 @@ * 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)); \ +#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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/proc-armv/pgtable.h linux-2.5/include/asm-arm/proc-armv/pgtable.h --- linux-2.5.1/include/asm-arm/proc-armv/pgtable.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/proc-armv/pgtable.h Sun Jan 6 01:38:27 2002 @@ -15,9 +15,6 @@ #ifndef __ASM_PROC_PGTABLE_H #define __ASM_PROC_PGTABLE_H -#include <asm/proc/domain.h> -#include <asm/arch/vmalloc.h> - /* * entries per page directory level: they are two-level, so * we don't really have any PMD directory. @@ -26,27 +23,91 @@ #define PTRS_PER_PMD 1 #define PTRS_PER_PGD 4096 -/**************** -* PMD functions * -****************/ - -/* PMD types (actually level 1 descriptor) */ -#define PMD_TYPE_MASK 0x0003 -#define PMD_TYPE_FAULT 0x0000 -#define PMD_TYPE_TABLE 0x0001 -#define PMD_TYPE_SECT 0x0002 -#define PMD_UPDATABLE 0x0010 -#define PMD_SECT_CACHEABLE 0x0008 -#define PMD_SECT_BUFFERABLE 0x0004 -#define PMD_SECT_AP_WRITE 0x0400 -#define PMD_SECT_AP_READ 0x0800 +/* + * Hardware page table definitions. + * + * + Level 1 descriptor (PMD) + * - common + */ +#define PMD_TYPE_MASK (3 << 0) +#define PMD_TYPE_FAULT (0 << 0) +#define PMD_TYPE_TABLE (1 << 0) +#define PMD_TYPE_SECT (2 << 0) +#define PMD_UPDATABLE (1 << 4) #define PMD_DOMAIN(x) ((x) << 5) +#define PMD_PROTECTION (1 << 9) /* v5 */ +/* + * - section + */ +#define PMD_SECT_BUFFERABLE (1 << 2) +#define PMD_SECT_CACHEABLE (1 << 3) +#define PMD_SECT_AP_WRITE (1 << 10) +#define PMD_SECT_AP_READ (1 << 11) +#define PMD_SECT_TEX(x) ((x) << 12) /* v5 */ +/* + * - coarse table (not used) + */ + +/* + * + Level 2 descriptor (PTE) + * - common + */ +#define PTE_TYPE_MASK (3 << 0) +#define PTE_TYPE_FAULT (0 << 0) +#define PTE_TYPE_LARGE (1 << 0) +#define PTE_TYPE_SMALL (2 << 0) +#define PTE_TYPE_EXT (3 << 0) /* v5 */ +#define PTE_BUFFERABLE (1 << 2) +#define PTE_CACHEABLE (1 << 3) + +/* + * - extended small page/tiny page + */ +#define PTE_EXT_AP_UNO_SRO (0 << 4) +#define PTE_EXT_AP_UNO_SRW (1 << 4) +#define PTE_EXT_AP_URO_SRW (2 << 4) +#define PTE_EXT_AP_URW_SRW (3 << 4) +#define PTE_EXT_TEX(x) ((x) << 6) /* v5 */ + +/* + * - small page + */ +#define PTE_SMALL_AP_UNO_SRO (0x00 << 4) +#define PTE_SMALL_AP_UNO_SRW (0x55 << 4) +#define PTE_SMALL_AP_URO_SRW (0xaa << 4) +#define PTE_SMALL_AP_URW_SRW (0xff << 4) +#define PTE_AP_READ PTE_SMALL_AP_URO_SRW +#define PTE_AP_WRITE PTE_SMALL_AP_UNO_SRW + +/* + * "Linux" PTE definitions. + * + * We keep two sets of PTEs - the hardware and the linux version. + * This allows greater flexibility in the way we map the Linux bits + * onto the hardware tables, and allows us to have YOUNG and DIRTY + * bits. + * + * The PTE table pointer refers to the hardware entries; the "Linux" + * entries are stored 1024 bytes below. + */ +#define L_PTE_PRESENT (1 << 0) +#define L_PTE_YOUNG (1 << 1) +#define L_PTE_BUFFERABLE (1 << 2) /* matches PTE */ +#define L_PTE_CACHEABLE (1 << 3) /* matches PTE */ +#define L_PTE_USER (1 << 4) +#define L_PTE_WRITE (1 << 5) +#define L_PTE_EXEC (1 << 6) +#define L_PTE_DIRTY (1 << 7) + +#ifndef __ASSEMBLY__ + +#include <asm/proc/domain.h> #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER)) #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL)) #define pmd_bad(pmd) (pmd_val(pmd) & 2) -#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp,pmd) +#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp, pmd) static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) { @@ -75,49 +136,8 @@ return __phys_to_virt(ptr); } -/**************** -* PTE functions * -****************/ - -/* PTE types (actually level 2 descriptor) */ -#define PTE_TYPE_MASK 0x0003 -#define PTE_TYPE_FAULT 0x0000 -#define PTE_TYPE_LARGE 0x0001 -#define PTE_TYPE_SMALL 0x0002 -#define PTE_AP_READ 0x0aa0 -#define PTE_AP_WRITE 0x0550 -#define PTE_CACHEABLE 0x0008 -#define PTE_BUFFERABLE 0x0004 - #define set_pte(ptep, pte) cpu_set_pte(ptep,pte) -/* We now keep two sets of ptes - the physical and the linux version. - * This gives us many advantages, and allows us greater flexibility. - * - * The Linux pte's contain: - * bit meaning - * 0 page present - * 1 young - * 2 bufferable - matches physical pte - * 3 cacheable - matches physical pte - * 4 user - * 5 write - * 6 execute - * 7 dirty - * 8-11 unused - * 12-31 virtual page address - * - * These are stored at the pte pointer; the physical PTE is at -1024bytes - */ -#define L_PTE_PRESENT (1 << 0) -#define L_PTE_YOUNG (1 << 1) -#define L_PTE_BUFFERABLE (1 << 2) -#define L_PTE_CACHEABLE (1 << 3) -#define L_PTE_USER (1 << 4) -#define L_PTE_WRITE (1 << 5) -#define L_PTE_EXEC (1 << 6) -#define L_PTE_DIRTY (1 << 7) - /* * The following macros handle the cache and bufferable bits... */ @@ -162,5 +182,7 @@ * Mark the prot value as uncacheable and unbufferable. */ #define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE)) + +#endif /* __ASSEMBLY__ */ #endif /* __ASM_PROC_PGTABLE_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/proc-armv/ptrace.h linux-2.5/include/asm-arm/proc-armv/ptrace.h --- linux-2.5.1/include/asm-arm/proc-armv/ptrace.h Tue Nov 28 01:07:59 2000 +++ linux-2.5/include/asm-arm/proc-armv/ptrace.h Sun Jan 6 01:38:27 2002 @@ -12,27 +12,51 @@ #include <linux/config.h> -#define USR26_MODE 0x00 -#define FIQ26_MODE 0x01 -#define IRQ26_MODE 0x02 -#define SVC26_MODE 0x03 -#define USR_MODE 0x10 -#define FIQ_MODE 0x11 -#define IRQ_MODE 0x12 -#define SVC_MODE 0x13 -#define ABT_MODE 0x17 -#define UND_MODE 0x1b -#define SYSTEM_MODE 0x1f -#define MODE_MASK 0x1f -#define T_BIT 0x20 -#define F_BIT 0x40 -#define I_BIT 0x80 -#define CC_V_BIT (1 << 28) -#define CC_C_BIT (1 << 29) -#define CC_Z_BIT (1 << 30) -#define CC_N_BIT (1 << 31) +/* + * PSR bits + */ +#define USR26_MODE 0x00000000 +#define FIQ26_MODE 0x00000001 +#define IRQ26_MODE 0x00000002 +#define SVC26_MODE 0x00000003 +#define USR_MODE 0x00000010 +#define FIQ_MODE 0x00000011 +#define IRQ_MODE 0x00000012 +#define SVC_MODE 0x00000013 +#define ABT_MODE 0x00000017 +#define UND_MODE 0x0000001b +#define SYSTEM_MODE 0x0000001f +#define MODE32_BIT 0x00000010 +#define MODE_MASK 0x0000001f +#define PSR_T_BIT 0x00000020 +#define PSR_F_BIT 0x00000040 +#define PSR_I_BIT 0x00000080 +#define PSR_J_BIT 0x01000000 +#define PSR_V_BIT 0x10000000 +#define PSR_C_BIT 0x20000000 +#define PSR_Z_BIT 0x40000000 +#define PSR_N_BIT 0x80000000 #define PCMASK 0 +/* + * CR1 bits + */ +#define CR1_M 0x00000001 /* MMU */ +#define CR1_A 0x00000002 /* Alignment fault */ +#define CR1_C 0x00000004 /* Dcache */ +#define CR1_W 0x00000008 /* Write buffer */ +#define CR1_P 0x00000010 /* Prog32 */ +#define CR1_D 0x00000020 /* Data32 */ +#define CR1_L 0x00000040 /* Late abort */ +#define CR1_B 0x00000080 /* Big endian */ +#define CR1_S 0x00000100 /* System protection */ +#define CR1_R 0x00000200 /* ROM protection */ +#define CR1_F 0x00000400 +#define CR1_Z 0x00000800 /* BTB enable */ +#define CR1_I 0x00001000 /* Icache */ +#define CR1_V 0x00002000 /* Vector relocation */ +#define CR1_RR 0x00004000 /* Round Robin */ + #ifndef __ASSEMBLY__ /* this struct defines the way the registers are stored on the @@ -68,7 +92,7 @@ #ifdef CONFIG_ARM_THUMB #define thumb_mode(regs) \ - (((regs)->ARM_cpsr & T_BIT)) + (((regs)->ARM_cpsr & PSR_T_BIT)) #else #define thumb_mode(regs) (0) #endif @@ -77,27 +101,27 @@ ((regs)->ARM_cpsr & MODE_MASK) #define interrupts_enabled(regs) \ - (!((regs)->ARM_cpsr & I_BIT)) + (!((regs)->ARM_cpsr & PSR_I_BIT)) #define fast_interrupts_enabled(regs) \ - (!((regs)->ARM_cpsr & F_BIT)) + (!((regs)->ARM_cpsr & PSR_F_BIT)) #define condition_codes(regs) \ - ((regs)->ARM_cpsr & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT)) + ((regs)->ARM_cpsr & (PSR_V_BIT|PSR_C_BIT|PSR_Z_BIT|PSR_N_BIT)) /* Are the current registers suitable for user mode? * (used to maintain security in signal handlers) */ static inline int valid_user_regs(struct pt_regs *regs) { - if ((regs->ARM_cpsr & 0xf) == 0 && - (regs->ARM_cpsr & (F_BIT|I_BIT)) == 0) + if (user_mode(regs) && + (regs->ARM_cpsr & (PSR_F_BIT|PSR_I_BIT)) == 0) return 1; /* * Force CPSR to something logical... */ - regs->ARM_cpsr &= (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT|0x10); + regs->ARM_cpsr &= (PSR_V_BIT|PSR_C_BIT|PSR_Z_BIT|PSR_N_BIT|MODE32_BIT); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/proc-armv/uaccess.h linux-2.5/include/asm-arm/proc-armv/uaccess.h --- linux-2.5.1/include/asm-arm/proc-armv/uaccess.h Thu Oct 25 20:53:55 2001 +++ linux-2.5/include/asm-arm/proc-armv/uaccess.h Sun Jan 6 01:38:27 2002 @@ -54,6 +54,7 @@ : "=r" (err) \ : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err)) +#ifndef __ARMEB__ #define __put_user_asm_half(x,addr,err) \ ({ \ unsigned long __temp = (unsigned long)(x); \ @@ -61,6 +62,15 @@ __put_user_asm_byte(__temp, __ptr, err); \ __put_user_asm_byte(__temp >> 8, __ptr + 1, err); \ }) +#else +#define __put_user_asm_half(x,addr,err) \ +({ \ + unsigned long __temp = (unsigned long)(x); \ + unsigned long __ptr = (unsigned long)(addr); \ + __put_user_asm_byte(__temp >> 8, __ptr, err); \ + __put_user_asm_byte(__temp, __ptr + 1, err); \ +}) +#endif #define __put_user_asm_word(x,addr,err) \ __asm__ __volatile__( \ @@ -95,6 +105,7 @@ : "=r" (err), "=&r" (x) \ : "r" (addr), "i" (-EFAULT), "0" (err)) +#ifndef __ARMEB__ #define __get_user_asm_half(x,addr,err) \ ({ \ unsigned long __b1, __b2, __ptr = (unsigned long)addr; \ @@ -102,7 +113,15 @@ __get_user_asm_byte(__b2, __ptr + 1, err); \ (x) = __b1 | (__b2 << 8); \ }) - +#else +#define __get_user_asm_half(x,addr,err) \ +({ \ + unsigned long __b1, __b2; \ + __get_user_asm_byte(__b1, addr, err); \ + __get_user_asm_byte(__b2, (int)(addr) + 1, err); \ + (x) = (__b1 << 8) | __b2; \ +}) +#endif #define __get_user_asm_word(x,addr,err) \ __asm__ __volatile__( \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/proc-fns.h linux-2.5/include/asm-arm/proc-fns.h --- linux-2.5.1/include/asm-arm/proc-fns.h Fri Nov 9 22:11:15 2001 +++ linux-2.5/include/asm-arm/proc-fns.h Sun Jan 6 01:38:27 2002 @@ -26,6 +26,12 @@ # define MULTI_CPU #endif +/* + * CPU_NAME - the prefix for CPU related functions + * CPU_ABRT - the prefix for the CPU abort decoding function + * MMU_ARCH - the prefix for copy_user_page/clear_user_page + */ + #ifdef CONFIG_CPU_32 # define CPU_INCLUDE_NAME "asm/cpu-multi32.h" # ifdef CONFIG_CPU_ARM610 @@ -33,7 +39,9 @@ # undef MULTI_CPU # define MULTI_CPU # else -# define CPU_NAME arm6 +# define CPU_NAME cpu_arm6 +# define CPU_ABRT cpu_arm6 +# define MMU_ARCH armv3 # endif # endif # ifdef CONFIG_CPU_ARM710 @@ -41,7 +49,9 @@ # undef MULTI_CPU # define MULTI_CPU # else -# define CPU_NAME arm7 +# define CPU_NAME cpu_arm7 +# define CPU_ABRT cpu_arm7 +# define MMU_ARCH armv3 # endif # endif # ifdef CONFIG_CPU_ARM720T @@ -49,7 +59,9 @@ # undef MULTI_CPU # define MULTI_CPU # else -# define CPU_NAME arm720 +# define CPU_NAME cpu_arm720 +# define CPU_ABRT armv4t_late +# define MMU_ARCH armv4 # endif # endif # ifdef CONFIG_CPU_ARM920T @@ -57,7 +69,19 @@ # undef MULTI_CPU # define MULTI_CPU # else -# define CPU_NAME arm920 +# define CPU_NAME cpu_arm920 +# define CPU_ABRT armv4t_early +# define MMU_ARCH armv4 +# endif +# endif +# ifdef CONFIG_CPU_ARM922T +# ifdef CPU_NAME +# undef MULTI_CPU +# define MULTI_CPU +# else +# define CPU_NAME cpu_arm922 +# define CPU_ABRT armv4t_early +# define MMU_ARCH armv4 # endif # endif # ifdef CONFIG_CPU_ARM926T @@ -65,7 +89,9 @@ # undef MULTI_CPU # define MULTI_CPU # else -# define CPU_NAME arm926 +# define CPU_NAME cpu_arm926 +# define CPU_ABRT armv5ej_early +# define MMU_ARCH armv4 # endif # endif # ifdef CONFIG_CPU_SA110 @@ -73,7 +99,9 @@ # undef MULTI_CPU # define MULTI_CPU # else -# define CPU_NAME sa110 +# define CPU_NAME cpu_sa110 +# define CPU_ABRT armv4_early +# define MMU_ARCH armv4 # endif # endif # ifdef CONFIG_CPU_SA1100 @@ -81,7 +109,29 @@ # undef MULTI_CPU # define MULTI_CPU # else -# define CPU_NAME sa1100 +# define CPU_NAME cpu_sa1100 +# define CPU_ABRT armv4_early +# define MMU_ARCH armv4_mc +# endif +# endif +# ifdef CONFIG_CPU_ARM1020 +# ifdef CPU_NAME +# undef MULTI_CPU +# define MULTI_CPU +# else +# define CPU_NAME cpu_arm1020 +# define CPU_ABRT armv4t_early +# define MMU_ARCH armv4 +# endif +# endif +# ifdef CONFIG_CPU_XSCALE +# ifdef CPU_NAME +# undef MULTI_CPU +# define MULTI_CPU +# else +# define CPU_NAME cpu_xscale +# define CPU_ABRT armv4t_early +# define MMU_ARCH armv5te # endif # endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/processor.h linux-2.5/include/asm-arm/processor.h --- linux-2.5.1/include/asm-arm/processor.h Thu Oct 11 16:04:57 2001 +++ linux-2.5/include/asm-arm/processor.h Sun Jan 6 01:38:27 2002 @@ -68,13 +68,6 @@ EXTRA_THREAD_STRUCT }; -#define INIT_MMAP { \ - vm_mm: &init_mm, \ - vm_page_prot: PAGE_SHARED, \ - vm_flags: VM_READ | VM_WRITE | VM_EXEC, \ - vm_avl_height: 1, \ -} - #define INIT_THREAD { \ refcount: ATOMIC_INIT(1), \ EXTRA_THREAD_STRUCT_INIT \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/scatterlist.h linux-2.5/include/asm-arm/scatterlist.h --- linux-2.5.1/include/asm-arm/scatterlist.h Fri Oct 12 22:35:54 2001 +++ linux-2.5/include/asm-arm/scatterlist.h Sun Jan 6 01:38:27 2002 @@ -5,8 +5,11 @@ struct scatterlist { char *address; /* virtual address */ + struct page *page; /* Location for highmem page, if any */ + unsigned int offset; /* for highmem, page offset */ dma_addr_t dma_address; /* dma address */ unsigned int length; /* length */ + char *__address; /* for set_dma_addr */ }; /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/types.h linux-2.5/include/asm-arm/types.h --- linux-2.5.1/include/asm-arm/types.h Mon Feb 7 01:45:26 2000 +++ linux-2.5/include/asm-arm/types.h Sun Jan 6 01:38:27 2002 @@ -44,6 +44,7 @@ /* Dma addresses are 32-bits wide. */ typedef u32 dma_addr_t; +typedef u32 dma64_addr_t; #endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/unaligned.h linux-2.5/include/asm-arm/unaligned.h --- linux-2.5.1/include/asm-arm/unaligned.h Sun Aug 13 16:54:15 2000 +++ linux-2.5/include/asm-arm/unaligned.h Sun Jan 6 01:38:27 2002 @@ -39,24 +39,30 @@ * out of long long >> 32, or the low word from long long << 32 */ -#define __get_unaligned_2(__p) \ +#define __get_unaligned_2_le(__p) \ (__p[0] | __p[1] << 8) -#define __get_unaligned_4(__p) \ +#define __get_unaligned_2_be(__p) \ + (__p[0] << 8 | __p[1]) + +#define __get_unaligned_4_le(__p) \ (__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24) -#define get_unaligned(ptr) \ +#define __get_unaligned_4_be(__p) \ + (__p[0] << 24 | __p[1] << 16 | __p[2] << 8 | __p[3]) + +#define __get_unaligned_le(ptr) \ ({ \ __typeof__(*(ptr)) __v; \ __u8 *__p = (__u8 *)(ptr); \ switch (sizeof(*(ptr))) { \ case 1: __v = *(ptr); break; \ - case 2: __v = __get_unaligned_2(__p); break; \ - case 4: __v = __get_unaligned_4(__p); break; \ + case 2: __v = __get_unaligned_2_le(__p); break; \ + case 4: __v = __get_unaligned_4_le(__p); break; \ case 8: { \ unsigned int __v1, __v2; \ - __v2 = __get_unaligned_4((__p+4)); \ - __v1 = __get_unaligned_4(__p); \ + __v2 = __get_unaligned_4_le((__p+4)); \ + __v1 = __get_unaligned_4_le(__p); \ __v = ((unsigned long long)__v2 << 32 | __v1); \ } \ break; \ @@ -65,44 +71,105 @@ __v; \ }) +#define __get_unaligned_be(ptr) \ + ({ \ + __typeof__(*(ptr)) __v; \ + __u8 *__p = (__u8 *)(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: __v = *(ptr); break; \ + case 2: __v = __get_unaligned_2_be(__p); break; \ + case 4: __v = __get_unaligned_4_be(__p); break; \ + case 8: { \ + unsigned int __v1, __v2; \ + __v2 = __get_unaligned_4_be(__p); \ + __v1 = __get_unaligned_4_be((__p+4)); \ + __v = ((unsigned long long)__v2 << 32 | __v1); \ + } \ + break; \ + default: __v = __bug_unaligned_x(__p); break; \ + } \ + __v; \ + }) -static inline void __put_unaligned_2(__u32 __v, register __u8 *__p) + +static inline void __put_unaligned_2_le(__u32 __v, register __u8 *__p) { *__p++ = __v; *__p++ = __v >> 8; } -static inline void __put_unaligned_4(__u32 __v, register __u8 *__p) +static inline void __put_unaligned_2_be(__u32 __v, register __u8 *__p) +{ + *__p++ = __v >> 8; + *__p++ = __v; +} + +static inline void __put_unaligned_4_le(__u32 __v, register __u8 *__p) +{ + __put_unaligned_2_le(__v >> 16, __p + 2); + __put_unaligned_2_le(__v, __p); +} + +static inline void __put_unaligned_4_be(__u32 __v, register __u8 *__p) { - __put_unaligned_2(__v >> 16, __p + 2); - __put_unaligned_2(__v, __p); + __put_unaligned_2_be(__v >> 16, __p); + __put_unaligned_2_be(__v, __p + 2); } -static inline void __put_unaligned_8(const unsigned long long __v, register __u8 *__p) +static inline void __put_unaligned_8_le(const unsigned long long __v, register __u8 *__p) { /* * tradeoff: 8 bytes of stack for all unaligned puts (2 * instructions), or an extra register in the long long * case - go for the extra register. */ - __put_unaligned_4(__v >> 32, __p+4); - __put_unaligned_4(__v, __p); + __put_unaligned_4_le(__v >> 32, __p+4); + __put_unaligned_4_le(__v, __p); +} + +static inline void __put_unaligned_8_be(const unsigned long long __v, register __u8 *__p) +{ + /* + * tradeoff: 8 bytes of stack for all unaligned puts (2 + * instructions), or an extra register in the long long + * case - go for the extra register. + */ + __put_unaligned_4_be(__v >> 32, __p); + __put_unaligned_4_be(__v, __p+4); } /* * Try to store an unaligned value as efficiently as possible. */ -#define put_unaligned(val,ptr) \ +#define __put_unaligned_le(val,ptr) \ + ({ \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(ptr) = (val); \ + break; \ + case 2: __put_unaligned_2_le((val),(__u8 *)(ptr)); \ + break; \ + case 4: __put_unaligned_4_le((val),(__u8 *)(ptr)); \ + break; \ + case 8: __put_unaligned_8_le((val),(__u8 *)(ptr)); \ + break; \ + default: __bug_unaligned_x(ptr); \ + break; \ + } \ + (void) 0; \ + }) + +#define put_unaligned_be(val,ptr) \ ({ \ switch (sizeof(*(ptr))) { \ case 1: \ *(ptr) = (val); \ break; \ - case 2: __put_unaligned_2((val),(__u8 *)(ptr)); \ + case 2: __put_unaligned_2_be((val),(__u8 *)(ptr)); \ break; \ - case 4: __put_unaligned_4((val),(__u8 *)(ptr)); \ + case 4: __put_unaligned_4_be((val),(__u8 *)(ptr)); \ break; \ - case 8: __put_unaligned_8((val),(__u8 *)(ptr)); \ + case 8: __put_unaligned_8_be((val),(__u8 *)(ptr)); \ break; \ default: __bug_unaligned_x(ptr); \ break; \ @@ -110,5 +177,15 @@ (void) 0; \ }) +/* + * Select endianness + */ +#ifndef __ARMEB__ +#define get_unaligned __get_unaligned_le +#define put_unaligned __put_unaligned_le +#else +#define get_unaligned __get_unaligned_be +#define put_unaligned __put_unaligned_be +#endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/unistd.h linux-2.5/include/asm-arm/unistd.h --- linux-2.5.1/include/asm-arm/unistd.h Sun Aug 12 18:14:00 2001 +++ linux-2.5/include/asm-arm/unistd.h Sun Jan 6 01:38:27 2002 @@ -240,6 +240,10 @@ #define __NR_mincore (__NR_SYSCALL_BASE+219) #define __NR_madvise (__NR_SYSCALL_BASE+220) #define __NR_fcntl64 (__NR_SYSCALL_BASE+221) + /* 222 for tux */ +#define __NR_security (__NR_SYSCALL_BASE+223) +#define __NR_gettid (__NR_SYSCALL_BASE+224) +#define __NR_readahead (__NR_SYSCALL_BASE+225) /* * The following SWIs are ARM private. @@ -356,6 +360,9 @@ } #ifdef __KERNEL_SYSCALLS__ + +struct rusage; +asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); static inline long idle(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-arm/vt.h linux-2.5/include/asm-arm/vt.h --- linux-2.5.1/include/asm-arm/vt.h Wed Jan 21 00:39:43 1998 +++ linux-2.5/include/asm-arm/vt.h Thu Jan 1 00:00:00 1970 @@ -1,8 +0,0 @@ -#ifndef _ASMARM_VT_H -#define _ASMARM_VT_H - -#define VT_GETSCRINFO 0x56FD /* get screen info */ -#define VT_GETPALETTE 0x56FE /* get palette */ -#define VT_SETPALETTE 0x56FF /* set palette */ - -#endif /* _ASMARM_VT_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-cris/bitops.h linux-2.5/include/asm-cris/bitops.h --- linux-2.5.1/include/asm-cris/bitops.h Mon Oct 8 18:43:54 2001 +++ linux-2.5/include/asm-cris/bitops.h Thu Jan 10 22:41:07 2002 @@ -331,6 +331,17 @@ #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) +/* + * 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) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) + #define ext2_set_bit test_and_set_bit #define ext2_clear_bit test_and_clear_bit #define ext2_test_bit test_bit diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-cris/elf.h linux-2.5/include/asm-cris/elf.h --- linux-2.5.1/include/asm-cris/elf.h Tue May 1 23:05:00 2001 +++ linux-2.5/include/asm-cris/elf.h Thu Jan 10 22:41:07 2002 @@ -9,8 +9,9 @@ typedef unsigned long elf_greg_t; -/* These probably need fixing. */ -#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) +/* Note that NGREG is defined to ELF_NGREG in include/linux/elfcore.h, and is + thus exposed to user-space. */ +#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) typedef elf_greg_t elf_gregset_t[ELF_NGREG]; /* A placeholder; CRIS does not have any fp regs. */ @@ -45,7 +46,52 @@ (_r)->r1 = 0; (_r)->r0 = 0; (_r)->mof = 0; (_r)->srp = 0; \ } while (0) -#undef USE_ELF_CORE_DUMP +#define USE_ELF_CORE_DUMP + +/* The additional layer below is because the stack pointer is missing in + the pt_regs struct, but needed in a core dump. pr_reg is a elf_gregset_t, + and should be filled in according to the layout of the user_regs_struct + struct; regs is a pt_regs struct. We dump all registers, though several are + obviously unnecessary. That way there's less need for intelligence at + the receiving end (i.e. gdb). */ +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + pr_reg[0] = regs->r0; \ + pr_reg[1] = regs->r1; \ + pr_reg[2] = regs->r2; \ + pr_reg[3] = regs->r3; \ + pr_reg[4] = regs->r4; \ + pr_reg[5] = regs->r5; \ + pr_reg[6] = regs->r6; \ + pr_reg[7] = regs->r7; \ + pr_reg[8] = regs->r8; \ + pr_reg[9] = regs->r9; \ + pr_reg[10] = regs->r10; \ + pr_reg[11] = regs->r11; \ + pr_reg[12] = regs->r12; \ + pr_reg[13] = regs->r13; \ + pr_reg[14] = rdusp(); /* sp */ \ + pr_reg[15] = regs->irp; /* pc */ \ + pr_reg[16] = 0; /* p0 */ \ + pr_reg[17] = rdvr(); /* vr */ \ + pr_reg[18] = 0; /* p2 */ \ + pr_reg[19] = 0; /* p3 */ \ + pr_reg[20] = 0; /* p4 */ \ + pr_reg[21] = (regs->dccr & 0xffff); /* ccr */ \ + pr_reg[22] = 0; /* p6 */ \ + pr_reg[23] = regs->mof; /* mof */ \ + pr_reg[24] = 0; /* p8 */ \ + pr_reg[25] = 0; /* ibr */ \ + pr_reg[26] = 0; /* irp */ \ + pr_reg[27] = regs->srp; /* srp */ \ + pr_reg[28] = 0; /* bar */ \ + pr_reg[29] = regs->dccr; /* dccr */ \ + pr_reg[30] = 0; /* brp */ \ + pr_reg[31] = rdusp(); /* usp */ \ + pr_reg[32] = 0; /* csrinstr */ \ + pr_reg[33] = 0; /* csraddr */ \ + pr_reg[34] = 0; /* csrdata */ + + #define ELF_EXEC_PAGESIZE 8192 /* This is the location that an ET_DYN program is loaded if exec'ed. Typical diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-cris/irq.h linux-2.5/include/asm-cris/irq.h --- linux-2.5.1/include/asm-cris/irq.h Mon Oct 8 18:43:54 2001 +++ linux-2.5/include/asm-cris/irq.h Thu Jan 10 22:41:07 2002 @@ -126,6 +126,9 @@ /* the asm IRQ handler makes sure the causing IRQ is blocked, then it calls * do_IRQ (with irq disabled still). after that it unblocks and jumps to * ret_from_intr (entry.S) + * + * The reason the IRQ is blocked is to allow an sti() before the handler which + * will acknowledge the interrupt is run. */ #define BUILD_IRQ(nr,mask) \ @@ -151,6 +154,41 @@ "reti\n\t" \ "nop\n"); +/* This is subtle. The timer interrupt is crucial and it should not be disabled for + * too long. However, if it had been a normal interrupt as per BUILD_IRQ, it would + * have been BLOCK'ed, and then softirq's are run before we return here to UNBLOCK. + * If the softirq's take too much time to run, the timer irq won't run and the + * watchdog will kill us. + * + * Furthermore, if a lot of other irq's occur before we return here, the multiple_irq + * handler is run and it prioritizes the timer interrupt. However if we had BLOCK'ed + * it here, we would not get the multiple_irq at all. + * + * The non-blocking here is based on the knowledge that the timer interrupt is + * registred as a fast interrupt (SA_INTERRUPT) so that we _know_ there will not + * be an sti() before the timer irq handler is run to acknowledge the interrupt. + */ + +#define BUILD_TIMER_IRQ(nr,mask) \ +void IRQ_NAME(nr); \ +void sIRQ_NAME(nr); \ +void BAD_IRQ_NAME(nr); \ +__asm__ ( \ + ".text\n\t" \ + "IRQ" #nr "_interrupt:\n\t" \ + SAVE_ALL \ + "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \ + "moveq "#nr",$r10\n\t" \ + "move.d $sp,$r11\n\t" \ + "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \ + "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \ + "jump ret_from_intr\n\t" \ + "bad_IRQ" #nr "_interrupt:\n\t" \ + "push $r0\n\t" \ + BLOCK_IRQ(mask,nr) \ + "pop $r0\n\t" \ + "reti\n\t" \ + "nop\n"); #endif /* _ASM_IRQ_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-cris/pgtable.h linux-2.5/include/asm-cris/pgtable.h --- linux-2.5.1/include/asm-cris/pgtable.h Fri Nov 9 22:11:15 2001 +++ linux-2.5/include/asm-cris/pgtable.h Thu Jan 10 22:41:07 2002 @@ -3,6 +3,12 @@ * HISTORY: * * $Log: pgtable.h,v $ + * Revision 1.14 2001/12/10 03:08:50 bjornw + * Added pgtable_cache_init dummy + * + * Revision 1.13 2001/11/12 18:05:38 pkj + * Added declaration of paging_init(). + * * Revision 1.12 2001/08/11 00:28:00 bjornw * PAGE_CHG_MASK and PAGE_NONE had somewhat untraditional values * @@ -106,6 +112,8 @@ * the CRIS page table tree. */ +extern void paging_init(void); + /* The cache doesn't need to be flushed when TLB entries change because * the cache is mapped to physical memory, not virtual memory */ @@ -507,6 +515,6 @@ /* * No page table caches to initialise */ -#define pgtable_cache_init() do { } while (0) +#define pgtable_cache_init() do { } while (0) #endif /* _CRIS_PGTABLE_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-cris/processor.h linux-2.5/include/asm-cris/processor.h --- linux-2.5.1/include/asm-cris/processor.h Mon Oct 8 18:43:54 2001 +++ linux-2.5/include/asm-cris/processor.h Thu Jan 10 22:41:07 2002 @@ -142,6 +142,6 @@ #define init_task (init_task_union.task) #define init_stack (init_task_union.stack) -#define cpu_relax() do { } while (0) +#define cpu_relax() do { } while (0) #endif /* __ASM_CRIS_PROCESSOR_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-cris/unistd.h linux-2.5/include/asm-cris/unistd.h --- linux-2.5.1/include/asm-cris/unistd.h Fri Nov 9 22:11:15 2001 +++ linux-2.5/include/asm-cris/unistd.h Thu Jan 10 22:41:07 2002 @@ -378,6 +378,7 @@ static inline _syscall1(int,close,int,fd) static inline _syscall1(int,_exit,int,exitcode) static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) +static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) /* the following are just while developing the elinux port! */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-cris/user.h linux-2.5/include/asm-cris/user.h --- linux-2.5.1/include/asm-cris/user.h Fri Feb 9 00:32:44 2001 +++ linux-2.5/include/asm-cris/user.h Thu Jan 10 22:41:07 2002 @@ -28,8 +28,51 @@ * to write an integer number of pages. */ +/* User mode registers, used for core dumps. In order to keep ELF_NGREG + sensible we let all registers be 32 bits. The csr registers are included + for future use. */ +struct user_regs_struct { + unsigned long r0; /* General registers. */ + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + unsigned long r12; + unsigned long r13; + unsigned long sp; /* Stack pointer. */ + unsigned long pc; /* Program counter. */ + unsigned long p0; /* Constant zero (only 8 bits). */ + unsigned long vr; /* Version register (only 8 bits). */ + unsigned long p2; /* Reserved. */ + unsigned long p3; /* Reserved. */ + unsigned long p4; /* Constant zero (only 16 bits). */ + unsigned long ccr; /* Condition code register (only 16 bits). */ + unsigned long p6; /* Reserved. */ + unsigned long mof; /* Multiply overflow register. */ + unsigned long p8; /* Constant zero. */ + unsigned long ibr; /* Not accessible. */ + unsigned long irp; /* Not accessible. */ + unsigned long srp; /* Subroutine return pointer. */ + unsigned long bar; /* Not accessible. */ + unsigned long dccr; /* Dword condition code register. */ + unsigned long brp; /* Not accessible. */ + unsigned long usp; /* User-mode stack pointer. Same as sp when + in user mode. */ + unsigned long csrinstr; /* Internal status registers. */ + unsigned long csraddr; + unsigned long csrdata; +}; + + struct user { - struct pt_regs regs; /* entire machine state */ + struct user_regs_struct regs; /* entire machine state */ size_t u_tsize; /* text size (pages) */ size_t u_dsize; /* data size (pages) */ size_t u_ssize; /* stack size (pages) */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/bitops.h linux-2.5/include/asm-i386/bitops.h --- linux-2.5.1/include/asm-i386/bitops.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/bitops.h Mon Jan 14 14:31:05 2002 @@ -75,6 +75,14 @@ :"=m" (ADDR) :"Ir" (nr)); } + +static __inline__ void __clear_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( + "btrl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} #define smp_mb__before_clear_bit() barrier() #define smp_mb__after_clear_bit() barrier() diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/cpufeature.h linux-2.5/include/asm-i386/cpufeature.h --- linux-2.5.1/include/asm-i386/cpufeature.h Mon Nov 13 05:55:50 2000 +++ linux-2.5/include/asm-i386/cpufeature.h Tue Jan 1 03:24:58 2002 @@ -40,12 +40,14 @@ #define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */ #define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */ #define X86_FEATURE_SELFSNOOP (0*32+27) /* CPU self snoop */ +#define X86_FEATURE_HT (0*32+28) /* Hyper-Threading */ #define X86_FEATURE_ACC (0*32+29) /* Automatic clock control */ #define X86_FEATURE_IA64 (0*32+30) /* IA-64 processor */ /* AMD-defined CPU features, CPUID level 0x80000001, word 1 */ /* Don't duplicate feature flags which are redundant with Intel! */ #define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */ +#define X86_FEATURE_MP (1*32+19) /* MP Capable. */ #define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */ #define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */ #define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/desc.h linux-2.5/include/asm-i386/desc.h --- linux-2.5.1/include/asm-i386/desc.h Thu Jul 26 20:40:32 2001 +++ linux-2.5/include/asm-i386/desc.h Sun Jan 13 19:02:53 2002 @@ -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 -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/fixmap.h linux-2.5/include/asm-i386/fixmap.h --- linux-2.5.1/include/asm-i386/fixmap.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/fixmap.h Mon Jan 14 14:31:06 2002 @@ -65,6 +65,11 @@ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, #endif + __end_of_permanent_fixed_addresses, + /* temporary boot-time mappings, used before ioremap() is functional */ +#define NR_FIX_BTMAPS 16 + FIX_BTMAP_END = __end_of_permanent_fixed_addresses, + FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1, __end_of_fixed_addresses }; @@ -86,8 +91,8 @@ * at the top of mem.. */ #define FIXADDR_TOP (0xffffe000UL) -#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) -#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) +#define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) +#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE) #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/hardirq.h linux-2.5/include/asm-i386/hardirq.h --- linux-2.5.1/include/asm-i386/hardirq.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/hardirq.h Mon Jan 14 14:31:06 2002 @@ -26,6 +26,17 @@ #define in_irq() (local_irq_count(smp_processor_id()) != 0) +/* + * Are interrupts enabled via __sti() or disabled via __cli()? + */ +#define irqs_enabled() \ +({ \ + unsigned int __flags; \ + \ + __save_flags(__flags); \ + __flags & (1 << 9); \ +}) + #ifndef CONFIG_SMP #define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/io.h linux-2.5/include/asm-i386/io.h --- linux-2.5.1/include/asm-i386/io.h Sun Dec 16 23:43:31 2001 +++ linux-2.5/include/asm-i386/io.h Mon Jan 14 14:31:20 2002 @@ -95,6 +95,14 @@ extern void iounmap(void *addr); /* + * bt_ioremap() and bt_iounmap() are for temporary early boot-time + * mappings, before the real ioremap() is functional. + * A boot-time mapping is currently limited to at most 16 pages. + */ +extern void *bt_ioremap(unsigned long offset, unsigned long size); +extern void bt_iounmap(void *addr, unsigned long size); + +/* * IO bus memory addresses are also 1:1 with the physical address */ #define virt_to_bus virt_to_phys diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/mmu_context.h linux-2.5/include/asm-i386/mmu_context.h --- linux-2.5.1/include/asm-i386/mmu_context.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/mmu_context.h Thu Jan 1 00:00:00 1970 @@ -1,67 +0,0 @@ -#ifndef __I386_MMU_CONTEXT_H -#define __I386_MMU_CONTEXT_H - -#include <linux/config.h> -#include <asm/desc.h> -#include <asm/atomic.h> -#include <asm/pgalloc.h> - -/* - * possibly do the LDT unload here? - */ -#define destroy_context(mm) do { } while(0) -#define init_new_context(tsk,mm) 0 - -#ifdef CONFIG_SMP - -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) -{ - if(cpu_tlbstate[cpu].state == TLBSTATE_OK) - cpu_tlbstate[cpu].state = TLBSTATE_LAZY; -} -#else -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) -{ -} -#endif - -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) -{ - if (prev != next) { - /* stop flush ipis for the previous mm */ - clear_bit(cpu, &prev->cpu_vm_mask); - /* - * Re-load LDT if necessary - */ - if (prev->context.segments != next->context.segments) - load_LDT(next); -#ifdef CONFIG_SMP - cpu_tlbstate[cpu].state = TLBSTATE_OK; - cpu_tlbstate[cpu].active_mm = next; -#endif - set_bit(cpu, &next->cpu_vm_mask); - set_bit(cpu, &next->context.cpuvalid); - /* Re-load page tables */ - asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd))); - } -#ifdef CONFIG_SMP - else { - cpu_tlbstate[cpu].state = TLBSTATE_OK; - if(cpu_tlbstate[cpu].active_mm != next) - BUG(); - if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) { - /* We were in lazy tlb mode and leave_mm disabled - * tlb flush IPI delivery. We must flush our tlb. - */ - local_flush_tlb(); - } - if (!test_and_set_bit(cpu, &next->context.cpuvalid)) - load_LDT(next); - } -#endif -} - -#define activate_mm(prev, next) \ - switch_mm((prev),(next),NULL,smp_processor_id()) - -#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/msr.h linux-2.5/include/asm-i386/msr.h --- linux-2.5.1/include/asm-i386/msr.h Sat Sep 1 18:01:28 2001 +++ linux-2.5/include/asm-i386/msr.h Thu Dec 13 16:32:37 2001 @@ -81,6 +81,7 @@ #define MSR_K7_EVNTSEL0 0xC0010000 #define MSR_K7_PERFCTR0 0xC0010004 +#define MSR_K7_HWCR 0xC0010015 /* Centaur-Hauls/IDT defined MSRs. */ #define MSR_IDT_FCR1 0x107 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/page.h linux-2.5/include/asm-i386/page.h --- linux-2.5.1/include/asm-i386/page.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/page.h Mon Jan 14 14:31:06 2002 @@ -80,6 +80,12 @@ #define __PAGE_OFFSET (0xC0000000) +/* + * This much address space is reserved for vmalloc() and iomap() + * as well as fixmap mappings. + */ +#define __VMALLOC_RESERVE (128 << 20) + #ifndef __ASSEMBLY__ /* @@ -118,6 +124,9 @@ #endif /* __ASSEMBLY__ */ #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) +#define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) +#define __MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) +#define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/pci.h linux-2.5/include/asm-i386/pci.h --- linux-2.5.1/include/asm-i386/pci.h Sun Dec 16 23:43:50 2001 +++ linux-2.5/include/asm-i386/pci.h Mon Jan 14 14:32:46 2002 @@ -114,6 +114,14 @@ /* Nothing to do */ } +/* pci_unmap_{page,single} is a nop so... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) (0) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) do { } while (0) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) (0) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) do { } while (0) + /* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the * above pci_map_single interface. Here the scatter gather list diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/pgalloc.h linux-2.5/include/asm-i386/pgalloc.h --- linux-2.5.1/include/asm-i386/pgalloc.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/pgalloc.h Mon Jan 14 14:31:06 2002 @@ -139,9 +139,14 @@ free_page((unsigned long)pte); } -#define pte_free(pte) pte_free_slow(pte) +#define pte_free(pte) pte_free_fast(pte) +#ifdef CONFIG_X86_PAE +#define pgd_alloc(mm) get_pgd_slow() #define pgd_free(pgd) free_pgd_slow(pgd) +#else #define pgd_alloc(mm) get_pgd_fast() +#define pgd_free(pgd) free_pgd_fast(pgd) +#endif /* * allocating and freeing a pmd is trivial: the 1-entry pmd is @@ -224,6 +229,7 @@ { struct mm_struct *active_mm; int state; + char __cacheline_padding[24]; }; extern struct tlb_state cpu_tlbstate[NR_CPUS]; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/processor.h linux-2.5/include/asm-i386/processor.h --- linux-2.5.1/include/asm-i386/processor.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/processor.h Mon Jan 14 14:31:06 2002 @@ -90,6 +90,7 @@ #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)) +#define cpu_has_mp (test_bit(X86_FEATURE_MP, boot_cpu_data.x86_capability)) extern char ignore_irq13; @@ -248,11 +249,7 @@ /* * Bus types (default is ISA, but people can check others with these..) */ -#ifdef CONFIG_EISA extern int EISA_bus; -#else -#define EISA_bus (0) -#endif extern int MCA_bus; /* from system description table in BIOS. Mostly for MCA use, but @@ -504,6 +501,38 @@ } #define spin_lock_prefetch(x) prefetchw(x) +#endif + +#ifdef ARCH_HAS_PREFETCH +#define ARCH_HAS_PRELOAD_CACHE +static inline void preload_cache(const void *from, unsigned long n) +{ + if (n>=128) { + int __pf, linestofetch; + + if (n >= boot_cpu_data.x86_cache_size*1024) { + /* Size is bigger than cache, just fill cache. */ + linestofetch = (boot_cpu_data.x86_cache_size*1024) + / L1_CACHE_BYTES; + } else { + /* Size is smaller than cache, read whole chunk. */ + linestofetch = n/L1_CACHE_BYTES; + } + +#ifdef CONFIG_MPENTIUMIII + /* Prime the TLB */ + __asm__ __volatile__ ( + "movb %0, %%eax\n\t" + "movb %1, %%eax\n\t" + : : "m" (from), "m" (from+n-4) + : "eax"); +#endif + for (__pf=0 ; __pf<(linestofetch/2) ; __pf+=L1_CACHE_BYTES*2) { + prefetch (from+__pf); + prefetch (from+__pf+L1_CACHE_BYTES*2); + } + } +} #endif #endif /* __ASM_I386_PROCESSOR_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/rwlock.h linux-2.5/include/asm-i386/rwlock.h --- linux-2.5.1/include/asm-i386/rwlock.h Fri Sep 22 21:07:43 2000 +++ linux-2.5/include/asm-i386/rwlock.h Sat Dec 29 11:10:40 2001 @@ -17,6 +17,8 @@ #ifndef _ASM_I386_RWLOCK_H #define _ASM_I386_RWLOCK_H +#include <linux/stringify.h> + #define RW_LOCK_BIAS 0x01000000 #define RW_LOCK_BIAS_STR "0x01000000" @@ -24,23 +26,29 @@ asm volatile(LOCK "subl $1,(%0)\n\t" \ "js 2f\n" \ "1:\n" \ - ".section .text.lock,\"ax\"\n" \ + ".subsection 1\n" \ + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ + ".endif\n" \ "2:\tcall " helper "\n\t" \ "jmp 1b\n" \ - ".previous" \ + ".subsection 0\n" \ ::"a" (rw) : "memory") #define __build_read_lock_const(rw, helper) \ asm volatile(LOCK "subl $1,%0\n\t" \ "js 2f\n" \ "1:\n" \ - ".section .text.lock,\"ax\"\n" \ + ".subsection 1\n" \ + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ + ".endif\n" \ "2:\tpushl %%eax\n\t" \ "leal %0,%%eax\n\t" \ "call " helper "\n\t" \ "popl %%eax\n\t" \ "jmp 1b\n" \ - ".previous" \ + ".subsection 0\n" \ :"=m" (*(volatile int *)rw) : : "memory") #define __build_read_lock(rw, helper) do { \ @@ -54,23 +62,29 @@ asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ "jnz 2f\n" \ "1:\n" \ - ".section .text.lock,\"ax\"\n" \ + ".subsection 1\n" \ + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ + ".endif\n" \ "2:\tcall " helper "\n\t" \ "jmp 1b\n" \ - ".previous" \ + ".subsection 0\n" \ ::"a" (rw) : "memory") #define __build_write_lock_const(rw, helper) \ asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ "jnz 2f\n" \ "1:\n" \ - ".section .text.lock,\"ax\"\n" \ + ".subsection 1\n" \ + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ + ".endif\n" \ "2:\tpushl %%eax\n\t" \ "leal %0,%%eax\n\t" \ "call " helper "\n\t" \ "popl %%eax\n\t" \ "jmp 1b\n" \ - ".previous" \ + ".subsection 0\n" \ :"=m" (*(volatile int *)rw) : : "memory") #define __build_write_lock(rw, helper) do { \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/rwsem.h linux-2.5/include/asm-i386/rwsem.h --- linux-2.5.1/include/asm-i386/rwsem.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/rwsem.h Mon Jan 14 14:31:06 2002 @@ -40,6 +40,7 @@ #include <linux/list.h> #include <linux/spinlock.h> +#include <linux/stringify.h> struct rwsem_waiter; @@ -101,7 +102,10 @@ 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" + ".subsection 1\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\n\t" " pushl %%ecx\n\t" " pushl %%edx\n\t" @@ -109,7 +113,7 @@ " popl %%edx\n\t" " popl %%ecx\n\t" " jmp 1b\n" - ".previous" + ".subsection 0\n" "# ending down_read\n\t" : "+m"(sem->count) : "a"(sem) @@ -130,13 +134,16 @@ " 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" + ".subsection 1\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\n\t" " pushl %%ecx\n\t" " call rwsem_down_write_failed\n\t" " popl %%ecx\n\t" " jmp 1b\n" - ".previous\n" + ".subsection 0\n" "# ending down_write" : "+d"(tmp), "+m"(sem->count) : "a"(sem) @@ -154,7 +161,10 @@ LOCK_PREFIX " xadd %%edx,(%%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" + ".subsection 1\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\n\t" " decw %%dx\n\t" /* do nothing if still outstanding active readers */ " jnz 1b\n\t" @@ -162,7 +172,7 @@ " call rwsem_wake\n\t" " popl %%ecx\n\t" " jmp 1b\n" - ".previous\n" + ".subsection 0\n" "# ending __up_read\n" : "+m"(sem->count), "+d"(tmp) : "a"(sem) @@ -180,7 +190,10 @@ LOCK_PREFIX " xaddl %%edx,(%%eax)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */ " jnz 2f\n\t" /* jump if the lock is being waited upon */ "1:\n\t" - ".section .text.lock,\"ax\"\n" + ".subsection 1\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\n\t" " decw %%dx\n\t" /* did the active count reduce to 0? */ " jnz 1b\n\t" /* jump back if not */ @@ -188,7 +201,7 @@ " call rwsem_wake\n\t" " popl %%ecx\n\t" " jmp 1b\n" - ".previous\n" + ".subsection 0\n" "# ending __up_write\n" : "+m"(sem->count) : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/sched.h linux-2.5/include/asm-i386/sched.h --- linux-2.5.1/include/asm-i386/sched.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-i386/sched.h Mon Jan 14 14:31:07 2002 @@ -0,0 +1,89 @@ +#ifndef __I386_SCHED_H +#define __I386_SCHED_H + +#include <linux/config.h> +#include <asm/desc.h> +#include <asm/atomic.h> +#include <asm/pgalloc.h> + +/* + * Every architecture must define this function. It's the fastest + * way of searching a 168-bit bitmap where the first 128 bits are + * unlikely to be set. It's guaranteed that at least one of the 168 + * bits is cleared. + */ +#if MAX_RT_PRIO != 128 || MAX_PRIO != 168 +# error update this function. +#endif + +static inline int sched_find_first_zero_bit(unsigned long *b) +{ + unsigned int rt; + + rt = b[0] & b[1] & b[2] & b[3]; + if (unlikely(rt != 0xffffffff)) + return find_first_zero_bit(b, MAX_RT_PRIO); + + if (b[4] != ~0) + return ffz(b[4]) + MAX_RT_PRIO; + return ffz(b[5]) + 32 + MAX_RT_PRIO; +} +/* + * possibly do the LDT unload here? + */ +#define destroy_context(mm) do { } while(0) +#define init_new_context(tsk,mm) 0 + +#ifdef CONFIG_SMP + +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +{ + if(cpu_tlbstate[cpu].state == TLBSTATE_OK) + cpu_tlbstate[cpu].state = TLBSTATE_LAZY; +} +#else +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +{ +} +#endif + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) +{ + if (prev != next) { + /* stop flush ipis for the previous mm */ + clear_bit(cpu, &prev->cpu_vm_mask); + /* + * Re-load LDT if necessary + */ + if (prev->context.segments != next->context.segments) + load_LDT(next); +#ifdef CONFIG_SMP + cpu_tlbstate[cpu].state = TLBSTATE_OK; + cpu_tlbstate[cpu].active_mm = next; +#endif + set_bit(cpu, &next->cpu_vm_mask); + set_bit(cpu, &next->context.cpuvalid); + /* Re-load page tables */ + asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd))); + } +#ifdef CONFIG_SMP + else { + cpu_tlbstate[cpu].state = TLBSTATE_OK; + if(cpu_tlbstate[cpu].active_mm != next) + BUG(); + if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) { + /* We were in lazy tlb mode and leave_mm disabled + * tlb flush IPI delivery. We must flush our tlb. + */ + local_flush_tlb(); + } + if (!test_and_set_bit(cpu, &next->context.cpuvalid)) + load_LDT(next); + } +#endif +} + +#define activate_mm(prev, next) \ + switch_mm((prev),(next),NULL,smp_processor_id()) + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/semaphore.h linux-2.5/include/asm-i386/semaphore.h --- linux-2.5.1/include/asm-i386/semaphore.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/semaphore.h Mon Jan 14 14:31:06 2002 @@ -40,6 +40,7 @@ #include <asm/atomic.h> #include <linux/wait.h> #include <linux/rwsem.h> +#include <linux/stringify.h> struct semaphore { atomic_t count; @@ -122,10 +123,13 @@ LOCK "decl %0\n\t" /* --sem->count */ "js 2f\n" "1:\n" - ".section .text.lock,\"ax\"\n" + ".subsection 1\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\tcall __down_failed\n\t" "jmp 1b\n" - ".previous" + ".subsection 0\n" :"=m" (sem->count) :"c" (sem) :"memory"); @@ -149,10 +153,13 @@ "js 2f\n\t" "xorl %0,%0\n" "1:\n" - ".section .text.lock,\"ax\"\n" + ".subsection 1\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\tcall __down_failed_interruptible\n\t" "jmp 1b\n" - ".previous" + ".subsection 0\n" :"=a" (result), "=m" (sem->count) :"c" (sem) :"memory"); @@ -177,10 +184,13 @@ "js 2f\n\t" "xorl %0,%0\n" "1:\n" - ".section .text.lock,\"ax\"\n" + ".subsection 1\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\tcall __down_failed_trylock\n\t" "jmp 1b\n" - ".previous" + ".subsection 0\n" :"=a" (result), "=m" (sem->count) :"c" (sem) :"memory"); @@ -203,10 +213,13 @@ LOCK "incl %0\n\t" /* ++sem->count */ "jle 2f\n" "1:\n" - ".section .text.lock,\"ax\"\n" + ".subsection 1\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\tcall __up_wakeup\n\t" "jmp 1b\n" - ".previous" + ".subsection 0\n" :"=m" (sem->count) :"c" (sem) :"memory"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/smp.h linux-2.5/include/asm-i386/smp.h --- linux-2.5.1/include/asm-i386/smp.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/smp.h Mon Jan 14 14:31:06 2002 @@ -57,9 +57,13 @@ extern unsigned long cpu_online_map; extern volatile unsigned long smp_invalidate_needed; extern int pic_mode; +extern int smp_num_siblings; +extern int cpu_sibling_map[]; + 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 void smp_send_reschedule_all(void); extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); extern void zap_low_mappings (void); @@ -101,7 +105,7 @@ * so this is correct in the x86 case. */ -#define smp_processor_id() (current->processor) +#define smp_processor_id() (current->cpu) static __inline int hard_smp_processor_id(void) { @@ -118,18 +122,6 @@ #endif /* !__ASSEMBLY__ */ #define NO_PROC_ID 0xFF /* No processor magic marker */ - -/* - * 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 */ #endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/smplock.h linux-2.5/include/asm-i386/smplock.h --- linux-2.5.1/include/asm-i386/smplock.h Sun Dec 16 23:43:26 2001 +++ linux-2.5/include/asm-i386/smplock.h Mon Jan 14 14:31:20 2002 @@ -15,21 +15,22 @@ /* * Release global kernel lock and global interrupt lock */ -#define release_kernel_lock(task, cpu) \ -do { \ - if (task->lock_depth >= 0) \ - spin_unlock(&kernel_flag); \ - release_irqlock(cpu); \ - __sti(); \ +#define release_kernel_lock(task, cpu) \ +do { \ + if (unlikely(task->lock_depth >= 0)) { \ + spin_unlock(&kernel_flag); \ + if (global_irq_holder == (cpu)) \ + BUG(); \ + } \ } while (0) /* * Re-acquire the kernel lock */ -#define reacquire_kernel_lock(task) \ -do { \ - if (task->lock_depth >= 0) \ - spin_lock(&kernel_flag); \ +#define reacquire_kernel_lock(task) \ +do { \ + if (unlikely(task->lock_depth >= 0)) \ + spin_lock(&kernel_flag); \ } while (0) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/softirq.h linux-2.5/include/asm-i386/softirq.h --- linux-2.5.1/include/asm-i386/softirq.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/softirq.h Mon Jan 14 14:31:07 2002 @@ -3,6 +3,7 @@ #include <asm/atomic.h> #include <asm/hardirq.h> +#include <linux/stringify.h> #define __cpu_bh_enable(cpu) \ do { barrier(); local_bh_count(cpu)--; } while (0) @@ -33,12 +34,15 @@ "jnz 2f;" \ "1:;" \ \ - ".section .text.lock,\"ax\";" \ + ".subsection 1;" \ + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ + ".endif\n" \ "2: pushl %%eax; pushl %%ecx; pushl %%edx;" \ "call %c1;" \ "popl %%edx; popl %%ecx; popl %%eax;" \ "jmp 1b;" \ - ".previous;" \ + ".subsection 0;" \ \ : /* no output */ \ : "r" (ptr), "i" (do_softirq) \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/spinlock.h linux-2.5/include/asm-i386/spinlock.h --- linux-2.5.1/include/asm-i386/spinlock.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/spinlock.h Mon Jan 14 14:31:06 2002 @@ -5,6 +5,7 @@ #include <asm/rwlock.h> #include <asm/page.h> #include <linux/config.h> +#include <linux/stringify.h> extern int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); @@ -56,13 +57,16 @@ "\n1:\t" \ "lock ; decb %0\n\t" \ "js 2f\n" \ - ".section .text.lock,\"ax\"\n" \ + ".subsection 1\n" \ + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ + ".endif\n" \ "2:\t" \ "cmpb $0,%0\n\t" \ "rep;nop\n\t" \ "jle 2b\n\t" \ "jmp 1b\n" \ - ".previous" + ".subsection 0\n" /* * This works. Despite all the confusion. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/string.h linux-2.5/include/asm-i386/string.h --- linux-2.5.1/include/asm-i386/string.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/asm-i386/string.h Mon Jan 14 14:31:06 2002 @@ -12,7 +12,7 @@ * Also, the byte strings actually work correctly. Forget * the i486 routines for now as they may be broken.. */ -#if FIXED_486_STRING && defined(CONFIG_X86_USE_STRING_486) +#if defined (CONFIG_DEBUG_486_STRING) && defined(CONFIG_X86_USE_STRING_486) #include <asm/string-486.h> #else diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-i386/uaccess.h linux-2.5/include/asm-i386/uaccess.h --- linux-2.5.1/include/asm-i386/uaccess.h Sun Dec 16 23:43:26 2001 +++ linux-2.5/include/asm-i386/uaccess.h Mon Jan 14 14:31:07 2002 @@ -576,6 +576,24 @@ return n; } +#ifdef ARCH_HAS_PRELOAD_CACHE +static inline unsigned long +__constant_copy_to_user_nocheck_prefetch(void *to, const void *from, unsigned long n) +{ + preload_cache (from, n); + __constant_copy_user(to,from,n); + return n; +} + +static inline unsigned long +__generic_copy_to_user_nocheck_prefetch(void *to, const void *from, unsigned long n) +{ + preload_cache (from, n); + __copy_user(to,from,n); + return n; +} +#endif + #define copy_to_user(to,from,n) \ (__builtin_constant_p(n) ? \ __constant_copy_to_user((to),(from),(n)) : \ @@ -590,6 +608,11 @@ (__builtin_constant_p(n) ? \ __constant_copy_to_user_nocheck((to),(from),(n)) : \ __generic_copy_to_user_nocheck((to),(from),(n))) + +#define __copy_to_user_prefetch(to,from,n) \ + (__builtin_constant_p(n) ? \ + __constant_copy_to_user_nocheck_prefetch((to),(from),(n)) : \ + __generic_copy_to_user_nocheck_prefetch((to),(from),(n))) #define __copy_from_user(to,from,n) \ (__builtin_constant_p(n) ? \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ia64/pal.h linux-2.5/include/asm-ia64/pal.h --- linux-2.5.1/include/asm-ia64/pal.h Fri Nov 9 22:26:17 2001 +++ linux-2.5/include/asm-ia64/pal.h Thu Dec 13 16:32:37 2001 @@ -88,10 +88,10 @@ typedef s64 pal_status_t; #define PAL_STATUS_SUCCESS 0 /* No error */ -#define PAL_STATUS_UNIMPLEMENTED -1 /* Unimplemented procedure */ -#define PAL_STATUS_EINVAL -2 /* Invalid argument */ -#define PAL_STATUS_ERROR -3 /* Error */ -#define PAL_STATUS_CACHE_INIT_FAIL -4 /* Could not initialize the +#define PAL_STATUS_UNIMPLEMENTED (-1) /* Unimplemented procedure */ +#define PAL_STATUS_EINVAL (-2) /* Invalid argument */ +#define PAL_STATUS_ERROR (-3) /* Error */ +#define PAL_STATUS_CACHE_INIT_FAIL (-4) /* Could not initialize the * specified level and type of * cache without sideeffects * and "restrict" was 1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ia64/pci.h linux-2.5/include/asm-ia64/pci.h --- linux-2.5.1/include/asm-ia64/pci.h Fri Nov 9 22:26:17 2001 +++ linux-2.5/include/asm-ia64/pci.h Thu Dec 27 16:32:31 2001 @@ -46,6 +46,20 @@ #define pci_dma_sync_sg platform_pci_dma_sync_sg #define sg_dma_address platform_pci_dma_address +/* pci_unmap_{single,page} is not a nop, thus... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) + /* * 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 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ia64/processor.h linux-2.5/include/asm-ia64/processor.h --- linux-2.5.1/include/asm-ia64/processor.h Fri Nov 9 22:26:17 2001 +++ linux-2.5/include/asm-ia64/processor.h Thu Dec 27 15:14:59 2001 @@ -50,7 +50,6 @@ * Bus types */ #define EISA_bus 0 -#define EISA_bus__is_a_macro /* for versions in ksyms.c */ #define MCA_bus 0 #define MCA_bus__is_a_macro /* for versions in ksyms.c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ia64/siginfo.h linux-2.5/include/asm-ia64/siginfo.h --- linux-2.5.1/include/asm-ia64/siginfo.h Thu Apr 5 19:51:47 2001 +++ linux-2.5/include/asm-ia64/siginfo.h Thu Dec 13 16:32:37 2001 @@ -119,11 +119,11 @@ #define SI_USER 0 /* sent by kill, sigsend, raise */ #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ -#define SI_QUEUE -1 /* sent by sigqueue */ +#define SI_QUEUE (-1) /* sent by sigqueue */ #define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */ -#define SI_MESGQ -3 /* sent by real time mesq state change */ -#define SI_ASYNCIO -4 /* sent by AIO completion */ -#define SI_SIGIO -5 /* sent by queued SIGIO */ +#define SI_MESGQ (-3) /* sent by real time mesq state change */ +#define SI_ASYNCIO (-4) /* sent by AIO completion */ +#define SI_SIGIO (-5) /* sent by queued SIGIO */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ia64/system.h linux-2.5/include/asm-ia64/system.h --- linux-2.5.1/include/asm-ia64/system.h Fri Nov 9 22:26:17 2001 +++ linux-2.5/include/asm-ia64/system.h Thu Dec 13 16:32:37 2001 @@ -405,6 +405,10 @@ ia64_psr(ia64_task_regs(prev))->dfh = 1; \ __switch_to(prev,next,last); \ } while (0) + +/* Return true if this CPU can call the console drivers in printk() */ +#define arch_consoles_callable() (cpu_online_map & (1UL << smp_processor_id())) + #else # define switch_to(prev,next,last) do { \ ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next)); \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-m68k/semaphore.h linux-2.5/include/asm-m68k/semaphore.h --- linux-2.5.1/include/asm-m68k/semaphore.h Thu Oct 25 20:53:55 2001 +++ linux-2.5/include/asm-m68k/semaphore.h Sat Dec 29 11:10:40 2001 @@ -9,6 +9,7 @@ #include <linux/wait.h> #include <linux/spinlock.h> #include <linux/rwsem.h> +#include <linux/stringify.h> #include <asm/system.h> #include <asm/atomic.h> @@ -94,11 +95,14 @@ "subql #1,%0@\n\t" "jmi 2f\n\t" "1:\n" - ".section .text.lock,\"ax\"\n" + ".subsection 1\n" ".even\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\tpea 1b\n\t" "jbra __down_failed\n" - ".previous" + ".subsection 0\n" : /* no outputs */ : "a" (sem1) : "memory"); @@ -119,11 +123,14 @@ "jmi 2f\n\t" "clrl %0\n" "1:\n" - ".section .text.lock,\"ax\"\n" + ".subsection 1\n" ".even\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\tpea 1b\n\t" "jbra __down_failed_interruptible\n" - ".previous" + ".subsection 0\n" : "=d" (result) : "a" (sem1) : "memory"); @@ -145,11 +152,14 @@ "jmi 2f\n\t" "clrl %0\n" "1:\n" - ".section .text.lock,\"ax\"\n" + ".subsection 1\n" ".even\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\tpea 1b\n\t" "jbra __down_failed_trylock\n" - ".previous" + ".subsection 0\n" : "=d" (result) : "a" (sem1) : "memory"); @@ -175,12 +185,15 @@ "addql #1,%0@\n\t" "jle 2f\n" "1:\n" - ".section .text.lock,\"ax\"\n" + ".subsection 1\n" ".even\n" + ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" + "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" + ".endif\n" "2:\t" "pea 1b\n\t" "jbra __up_wakeup\n" - ".previous" + ".subsection 0\n" : /* no outputs */ : "a" (sem1) : "memory"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-mips/pci.h linux-2.5/include/asm-mips/pci.h --- linux-2.5.1/include/asm-mips/pci.h Fri Oct 12 22:35:54 2001 +++ linux-2.5/include/asm-mips/pci.h Thu Dec 27 16:32:31 2001 @@ -114,6 +114,14 @@ /* Nothing to do */ } +/* pci_unmap_{page,single} is a nop so... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) (0) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) do { } while (0) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) (0) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) do { } while (0) + /* * Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-mips64/pci.h linux-2.5/include/asm-mips64/pci.h --- linux-2.5.1/include/asm-mips64/pci.h Fri Oct 12 22:35:54 2001 +++ linux-2.5/include/asm-mips64/pci.h Thu Dec 27 16:32:31 2001 @@ -86,6 +86,20 @@ extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); +/* pci_unmap_{single,page} is not a nop, thus... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) + #else /* CONFIG_MAPPED_PCI_IO */ /* @@ -123,6 +137,14 @@ /* Nothing to do */ } + +/* pci_unmap_{page,single} is a nop so... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) (0) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) do { } while (0) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) (0) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) do { } while (0) /* * Map a set of buffers described by scatterlist in streaming diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-parisc/pci.h linux-2.5/include/asm-parisc/pci.h --- linux-2.5.1/include/asm-parisc/pci.h Fri Oct 12 22:35:54 2001 +++ linux-2.5/include/asm-parisc/pci.h Thu Dec 27 16:32:31 2001 @@ -172,6 +172,20 @@ #define pci_map_sg(p, sg, n, d) hppa_dma_ops->map_sg(p, sg, n, d) #define pci_unmap_sg(p, sg, n, d) hppa_dma_ops->unmap_sg(p, sg, n, d) +/* pci_unmap_{single,page} is not a nop, thus... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) + /* For U2/Astro/Ike based platforms (which are fully I/O coherent) ** dma_sync is a NOP. Let's keep the performance path short here. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-parisc/processor.h linux-2.5/include/asm-parisc/processor.h --- linux-2.5.1/include/asm-parisc/processor.h Fri Oct 5 19:11:05 2001 +++ linux-2.5/include/asm-parisc/processor.h Thu Dec 27 15:15:00 2001 @@ -90,7 +90,6 @@ 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 */ #define MCA_bus 0 #define MCA_bus__is_a_macro /* for versions in ksyms.c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-parisc/semaphore.h linux-2.5/include/asm-parisc/semaphore.h --- linux-2.5.1/include/asm-parisc/semaphore.h Wed Apr 18 00:19:31 2001 +++ linux-2.5/include/asm-parisc/semaphore.h Sat Dec 29 11:10:40 2001 @@ -12,10 +12,6 @@ * */ -/* 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 - */ - #include <linux/spinlock.h> #include <linux/rwsem.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-parisc/spinlock.h linux-2.5/include/asm-parisc/spinlock.h --- linux-2.5.1/include/asm-parisc/spinlock.h Tue Dec 5 20:29:39 2000 +++ linux-2.5/include/asm-parisc/spinlock.h Sat Dec 29 11:10:40 2001 @@ -3,10 +3,6 @@ #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 - */ - /* we seem to be the only architecture that uses 0 to mean locked - but we * have to. prumpf */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/ans-lcd.h linux-2.5/include/asm-ppc/ans-lcd.h --- linux-2.5.1/include/asm-ppc/ans-lcd.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-ppc/ans-lcd.h Thu Dec 27 16:32:31 2001 @@ -0,0 +1,11 @@ +#ifndef _PPC_ANS_LCD_H +#define _PPC_ANS_LCD_H + +#define ANSLCD_MINOR 156 + +#define ANSLCD_CLEAR 0x01 +#define ANSLCD_SENDCTRL 0x02 +#define ANSLCD_SETSHORTDELAY 0x03 +#define ANSLCD_SETLONGDELAY 0x04 + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/dbdma.h linux-2.5/include/asm-ppc/dbdma.h --- linux-2.5.1/include/asm-ppc/dbdma.h Mon May 21 22:02:06 2001 +++ linux-2.5/include/asm-ppc/dbdma.h Thu Dec 27 16:32:31 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.dbdma.h 1.5 05/17/01 18:14:24 cort + * BK Id: SCCS/s.dbdma.h 1.8 12/01/01 20:09:11 benh */ /* * Definitions for using the Apple Descriptor-Based DMA controller @@ -93,5 +93,13 @@ /* Align an address for a DBDMA command structure */ #define DBDMA_ALIGN(x) (((unsigned)(x) + sizeof(struct dbdma_cmd) - 1) \ & -sizeof(struct dbdma_cmd)) + +/* Useful macros */ +#define DBDMA_DO_STOP(regs) do { \ + out_le32(&((regs)->control), (RUN|FLUSH)<<16); \ + while(in_le32(&((regs)->status)) & (ACTIVE|FLUSH)) \ + ; \ +} while(0) + #endif /* _ASM_DBDMA_H_ */ #endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/heathrow.h linux-2.5/include/asm-ppc/heathrow.h --- linux-2.5.1/include/asm-ppc/heathrow.h Mon May 21 22:02:06 2001 +++ linux-2.5/include/asm-ppc/heathrow.h Thu Dec 27 16:32:31 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.heathrow.h 1.7 05/17/01 18:14:24 cort + * BK Id: SCCS/s.heathrow.h 1.10 12/01/01 20:09:11 benh */ /* * heathrow.h: definitions for using the "Heathrow" I/O controller chip. @@ -17,7 +17,9 @@ #define HEATHROW_CONTRAST_CNTL 0x33 /* offset from ohare base for feature control register */ -#define HEATHROW_FEATURE_REG 0x38 +#define HEATHROW_MBCR 0x34 /* Media bay control */ +#define HEATHROW_FCR 0x38 /* Feature control */ +#define HEATHROW_AUX_CNTL_REG 0x3c /* Aux control */ /* * Bits in feature control register. @@ -30,6 +32,7 @@ #define HRW_BAY_FLOPPY_ENABLE 0x00000010 #define HRW_IDE0_ENABLE 0x00000020 #define HRW_IDE0_RESET_N 0x00000040 +#define HRW_BAY_DEV_MASK 0x0000001c #define HRW_BAY_RESET_N 0x00000080 #define HRW_IOBUS_ENABLE 0x00000100 /* Internal IDE ? */ #define HRW_SCC_ENABLE 0x00000200 @@ -45,7 +48,7 @@ #define HRW_SWIM_CLONE_FLOPPY 0x00080000 /* ??? (0) */ #define HRW_AUD_RUN22 0x00100000 /* ??? (1) */ #define HRW_SCSI_LINK_MODE 0x00200000 /* Read ??? (1) */ -#define HRW_ARB_BYPASS 0x00400000 /* ??? (0 on main, 1 on gatwick) */ +#define HRW_ARB_BYPASS 0x00400000 /* Disable internal PCI arbitrer */ #define HRW_IDE1_RESET_N 0x00800000 /* Media bay */ #define HRW_SLOW_SCC_PCLK 0x01000000 /* ??? (0) */ #define HRW_MODEM_POWER_N 0x02000000 /* Used by internal modem on wallstreet */ @@ -60,3 +63,7 @@ /* Those seem to be different on paddington */ #define PADD_MODEM_POWER_N 0x00000001 /* modem power on paddington */ #define PADD_RESET_SCC 0x02000000 /* check this please */ + +/* Looks like Heathrow has some sort of GPIOs as well... */ +#define HRW_GPIO_MODEM_RESET 0x6d + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/keylargo.h linux-2.5/include/asm-ppc/keylargo.h --- linux-2.5.1/include/asm-ppc/keylargo.h Tue Aug 28 13:58:33 2001 +++ linux-2.5/include/asm-ppc/keylargo.h Thu Dec 27 16:32:31 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.keylargo.h 1.13 08/19/01 22:23:04 paulus + * BK Id: SCCS/s.keylargo.h 1.15 12/01/01 20:09:11 benh */ /* * keylargo.h: definitions for using the "KeyLargo" I/O controller chip. @@ -29,12 +29,15 @@ #define KEYLARGO_GPIO_CNT 17 #define KEYLARGO_GPIO_OUTPUT_ENABLE 0x04 #define KEYLARGO_GPIO_OUTOUT_DATA 0x01 +#define KEYLARGO_GPIO_INPUT_DATA 0x02 /* Specific GPIO regs */ -#define KL_GPIO_MODEM_RESET (KEYLARGO_GPIO_0+0x03) /* Pangea */ +#define KL_GPIO_MODEM_RESET (KEYLARGO_GPIO_0+0x03) #define KL_GPIO_MODEM_POWER (KEYLARGO_GPIO_0+0x02) /* Pangea */ +#define KL_GPIO_SOUND_POWER (KEYLARGO_GPIO_0+0x05) + /* Hrm... this one is only to be used on Pismo. It seeem to also * control the timebase enable on other machines. Still to be * experimented... --BenH. @@ -54,7 +57,9 @@ #define KL_GPIO_RESET_CPU3 (KEYLARGO_GPIO_EXTINT_0+0x10) #define KL_GPIO_PMU_MESSAGE_IRQ (KEYLARGO_GPIO_EXTINT_0+0x09) -#define KL_GPIO_PMU_MESSAGE_BIT 0x02 +#define KL_GPIO_PMU_MESSAGE_BIT KEYLARGO_GPIO_INPUT_DATA + +#define KL_GPIO_MEDIABAY_IRQ (KEYLARGO_GPIO_EXTINT_0+0x0e) #define KL_GPIO_AIRPORT_0 (KEYLARGO_GPIO_EXTINT_0+0x0a) #define KL_GPIO_AIRPORT_1 (KEYLARGO_GPIO_EXTINT_0+0x0d) @@ -65,11 +70,19 @@ /* * Bits in feature control register */ -#define KL_MBCR_MB0_DEV_ENABLE 0x00001000 +#define KL_MBCR_MB0_PCI_ENABLE 0x00000800 /* exist ? */ +#define KL_MBCR_MB0_IDE_ENABLE 0x00001000 +#define KL_MBCR_MB0_FLOPPY_ENABLE 0x00002000 /* exist ? */ +#define KL_MBCR_MB0_SOUND_ENABLE 0x00004000 /* hrm... */ +#define KL_MBCR_MB0_DEV_MASK 0x00007800 #define KL_MBCR_MB0_DEV_POWER 0x00000400 #define KL_MBCR_MB0_DEV_RESET 0x00000200 #define KL_MBCR_MB0_ENABLE 0x00000100 -#define KL_MBCR_MB1_DEV_ENABLE 0x10000000 +#define KL_MBCR_MB1_PCI_ENABLE 0x08000000 /* exist ? */ +#define KL_MBCR_MB1_IDE_ENABLE 0x10000000 +#define KL_MBCR_MB1_FLOPPY_ENABLE 0x20000000 /* exist ? */ +#define KL_MBCR_MB1_SOUND_ENABLE 0x40000000 /* hrm... */ +#define KL_MBCR_MB1_DEV_MASK 0x78000000 #define KL_MBCR_MB1_DEV_POWER 0x04000000 #define KL_MBCR_MB1_DEV_RESET 0x02000000 #define KL_MBCR_MB1_ENABLE 0x01000000 @@ -81,27 +94,23 @@ #define KL0_SCCA_ENABLE 0x00000010 #define KL0_SCCB_ENABLE 0x00000020 #define KL0_SCC_CELL_ENABLE 0x00000040 +#define KL0_IRDA_HIGH_BAND 0x00000100 +#define KL0_IRDA_SOURCE2_SEL 0x00000200 +#define KL0_IRDA_SOURCE1_SEL 0x00000400 +#define KL0_IRDA_RESET 0x00000800 +#define KL0_IRDA_DEFAULT1 0x00001000 +#define KL0_IRDA_DEFAULT0 0x00002000 +#define KL0_IRDA_FAST_CONNECT 0x00004000 +#define KL0_IRDA_ENABLE 0x00008000 +#define KL0_IRDA_CLK32_ENABLE 0x00010000 +#define KL0_IRDA_CLK19_ENABLE 0x00020000 #define KL0_USB0_PAD_SUSPEND0 0x00040000 #define KL0_USB0_PAD_SUSPEND1 0x00080000 #define KL0_USB0_CELL_ENABLE 0x00100000 #define KL0_USB1_PAD_SUSPEND0 0x00400000 #define KL0_USB1_PAD_SUSPEND1 0x00800000 #define KL0_USB1_CELL_ENABLE 0x01000000 -/* KL id 0x22 only */ #define KL0_USB_REF_SUSPEND 0x10000000 -#define KL0_IRDA_ENABLE 0x00008000 -#define KL0_IRDA_CLK32_ENABLE 0x00010000 -#define KL0_IRDA_CLK19_ENABLE 0x00020000 -/* KL id 0x25 (pangea) only */ -#define KL0_USB1_PAD_SUSPEND_SEL 0x00020000 -#define KL0_USB1_REF_SUSPEND 0x00010000 -#define KL0_USB1_REF_SUSPEND_SEL 0x00008000 -#define KL0_USB1_PMI 0x00004000 -#define KL0_USB0_PAD_SUSPEND_SEL 0x00002000 -#define KL0_USB0_REF_SUSPEND 0x00001000 -#define KL0_USB0_REF_SUSPEND_SEL 0x00000800 -#define KL0_USB0_PMI 0x00000400 - #define KL0_SERIAL_ENABLE (KL0_SCC_B_INTF_ENABLE | \ KL0_SCC_SLOWPCLK | \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/machdep.h linux-2.5/include/asm-ppc/machdep.h --- linux-2.5.1/include/asm-ppc/machdep.h Fri Nov 16 18:10:08 2001 +++ linux-2.5/include/asm-ppc/machdep.h Thu Dec 27 16:32:31 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.machdep.h 1.25 11/13/01 21:26:07 paulus + * BK Id: SCCS/s.machdep.h 1.27 12/01/01 20:09:11 benh */ #ifdef __KERNEL__ #ifndef _PPC_MACHDEP_H @@ -16,6 +16,11 @@ struct pci_dev; struct seq_file; +/* We export this macro for external modules like Alsa to know if + * ppc_md.feature_call is implemented or not + */ +#define CONFIG_PPC_HAS_FEATURE_CALLS + struct machdep_calls { void (*setup_arch)(void); /* Optional, may be NULL. */ @@ -94,6 +99,12 @@ /* this is for modules, since _machine can be a define -- Cort */ int ppc_machine; + + /* Motherboard/chipset features. This is a kind of general purpose + * hook used to control some machine specific features (like reset + * lines, chip power control, etc...). + */ + int (*feature_call)(unsigned int feature, ...); #ifdef CONFIG_SMP /* functions for dealing with other cpus */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/mediabay.h linux-2.5/include/asm-ppc/mediabay.h --- linux-2.5.1/include/asm-ppc/mediabay.h Mon May 21 22:02:06 2001 +++ linux-2.5/include/asm-ppc/mediabay.h Thu Dec 27 16:32:31 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.mediabay.h 1.5 05/17/01 18:14:25 cort + * BK Id: SCCS/s.mediabay.h 1.8 12/01/01 20:09:11 benh */ /* * mediabay.h: definitions for using the media bay @@ -12,10 +12,13 @@ #ifdef __KERNEL__ -#define MB_FD 0 /* media bay contains floppy drive */ -#define MB_FD1 1 /* media bay contains floppy drive */ -#define MB_CD 3 /* media bay contains ATA drive such as CD */ -#define MB_NO 7 /* media bay contains nothing */ +#define MB_FD 0 /* media bay contains floppy drive (automatic eject ?) */ +#define MB_FD1 1 /* media bay contains floppy drive (manual eject ?) */ +#define MB_SOUND 2 /* sound device ? */ +#define MB_CD 3 /* media bay contains ATA drive such as CD or ZIP */ +#define MB_PCI 5 /* media bay contains a PCI device */ +#define MB_POWER 6 /* media bay contains a Power device (???) */ +#define MB_NO 7 /* media bay contains nothing */ void media_bay_init(void); int check_media_bay(struct device_node *which_bay, int what); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/ohare.h linux-2.5/include/asm-ppc/ohare.h --- linux-2.5.1/include/asm-ppc/ohare.h Mon May 21 22:02:06 2001 +++ linux-2.5/include/asm-ppc/ohare.h Thu Dec 27 16:32:31 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ohare.h 1.5 05/17/01 18:14:25 cort + * BK Id: SCCS/s.ohare.h 1.8 12/01/01 20:09:11 benh */ /* * ohare.h: definitions for using the "O'Hare" I/O controller chip. @@ -11,7 +11,8 @@ */ /* offset from ohare base for feature control register */ -#define OHARE_FEATURE_REG 0x38 +#define OHARE_MBCR 0x34 +#define OHARE_FCR 0x38 /* * Bits in feature control register. @@ -25,6 +26,7 @@ #define OH_BAY_FLOPPY_ENABLE 0x10 #define OH_IDE0_ENABLE 0x20 #define OH_IDE0_RESET_N 0x40 /* a guess */ +#define OH_BAY_DEV_MASK 0x1c #define OH_BAY_RESET_N 0x80 #define OH_IOBUS_ENABLE 0x100 /* IOBUS seems to be IDE */ #define OH_SCC_ENABLE 0x200 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/pci.h linux-2.5/include/asm-ppc/pci.h --- linux-2.5.1/include/asm-ppc/pci.h Sun Oct 21 17:13:07 2001 +++ linux-2.5/include/asm-ppc/pci.h Thu Dec 27 16:32:31 2001 @@ -102,6 +102,13 @@ /* nothing to do */ } +/* pci_unmap_{page,single} is a nop so... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) (0) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) do { } while (0) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) (0) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) do { } while (0) /* * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/pmac_feature.h linux-2.5/include/asm-ppc/pmac_feature.h --- linux-2.5.1/include/asm-ppc/pmac_feature.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/asm-ppc/pmac_feature.h Thu Dec 27 16:32:31 2001 @@ -0,0 +1,251 @@ +/* + * Definition of platform feature hooks for PowerMacs + * + * 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) 1998 Paul Mackerras & + * Ben. Herrenschmidt. + * + * + * Note: I removed media-bay details from the feature stuff, I beleive it's + * not worth it, the media-bay driver can directly use the mac-io + * ASIC registers. + * + * Implementation note: Currently, none of these functions will block. + * However, they may internally protect themselves with a spinlock + * for way too long. Be prepared for at least some of these to block + * in the future. + * + * Unless specifically defined, the result code is assumed to be an + * error when negative, 0 is the default success result. Some functions + * may return additional positive result values. + * + * To keep implementation simple, all feature calls are assumed to have + * the prototype parameters (struct device_node* node, int value). + * When either is not used, pass 0. + */ + +#ifdef __KERNEL__ +#ifndef __PPC_ASM_PMAC_FEATURE_H +#define __PPC_ASM_PMAC_FEATURE_H + +/* + * Known Mac motherboard models + * + * Please, report any error here to benh@kernel.crashing.org, thanks ! + */ + +/* PowerSurge are the first generation of PCI Pmacs. This include + * all of the Grand-Central based machines + */ +#define PMAC_TYPE_PSURGE 0x10 /* PowerSurge */ + +/* Here is the infamous serie of OHare based machines + */ +#define PMAC_TYPE_COMET 0x20 /* Beleived to be PowerBook 2400 */ +#define PMAC_TYPE_HOOPER 0x21 /* Beleived to be PowerBook 3400 */ +#define PMAC_TYPE_KANGA 0x22 /* PowerBook 3500 (first G3) */ +#define PMAC_TYPE_ALCHEMY 0x23 /* Alchemy motherboard base */ +#define PMAC_TYPE_GAZELLE 0x24 /* Spartacus, some 5xxx/6xxx */ +#define PMAC_TYPE_UNKNOWN_OHARE 0x2f /* Unknown, but OHare based */ + +/* Here are the Heathrow based machines + * FIXME: Differenciate wallstreet,mainstreet,wallstreetII + */ +#define PMAC_TYPE_GOSSAMER 0x30 /* Gossamer motherboard */ +#define PMAC_TYPE_SILK 0x31 /* Desktop PowerMac G3 */ +#define PMAC_TYPE_WALLSTREET 0x32 /* Wallstreet/Mainstreet PowerBook*/ +#define PMAC_TYPE_UNKNOWN_HEATHROW 0x3f /* Unknown but heathrow based */ + +/* Here are newworld machines based on Paddington (heathrow derivative) + */ +#define PMAC_TYPE_101_PBOOK 0x40 /* 101 PowerBook (aka Lombard) */ +#define PMAC_TYPE_ORIG_IMAC 0x41 /* First generation iMac */ +#define PMAC_TYPE_YOSEMITE 0x42 /* B&W G3 */ +#define PMAC_TYPE_YIKES 0x43 /* Yikes G4 (PCI graphics) */ +#define PMAC_TYPE_UNKNOWN_PADDINGTON 0x4f /* Unknown but paddington based */ + +/* Core99 machines based on UniNorth 1.0 and 1.5 + * + * Note: A single entry here may cover several actual models according + * to the device-tree. (Sawtooth is most tower G4s, FW_IMAC is most + * FireWire based iMacs, etc...). Those machines are too similar to be + * distinguished here, when they need to be differencied, use the + * device-tree "model" or "compatible" property. + */ +#define PMAC_TYPE_ORIG_IBOOK 0x40 /* First iBook model (no firewire) */ +#define PMAC_TYPE_SAWTOOTH 0x41 /* Desktop G4s */ +#define PMAC_TYPE_FW_IMAC 0x42 /* FireWire iMacs (except Pangea based) */ +#define PMAC_TYPE_FW_IBOOK 0x43 /* FireWire iBooks (except iBook2) */ +#define PMAC_TYPE_CUBE 0x44 /* Cube PowerMac */ +#define PMAC_TYPE_QUICKSILVER 0x45 /* QuickSilver G4s */ +#define PMAC_TYPE_PISMO 0x46 /* Pismo PowerBook */ +#define PMAC_TYPE_TITANIUM 0x47 /* Titanium PowerBook */ +#define PMAC_TYPE_TITANIUM2 0x48 /* Titanium II PowerBook */ +#define PMAC_TYPE_UNKNOWN_CORE99 0x5f + +/* MacRISC2 machines based on the Pangea chipset + */ +#define PMAC_TYPE_PANGEA_IMAC 0x100 /* Flower Power iMac */ +#define PMAC_TYPE_IBOOK2 0x101 /* iBook2 (polycarbonate) */ +#define PMAC_TYPE_UNKNOWN_PANGEA 0x10f + +/* + * Motherboard flags + */ + +#define PMAC_MB_CAN_SLEEP 0x00000001 + +/* + * Feature calls supported on pmac + * + */ + +/* + * Use this inline wrapper + */ +struct device_node; + +static inline int pmac_call_feature(int selector, struct device_node* node, + int param, int value) +{ + if (!ppc_md.feature_call) + return -ENODEV; + return ppc_md.feature_call(selector, node, param, value); +} + +/* PMAC_FTR_SERIAL_ENABLE (struct device_node* node, int param, int value) + * enable/disable an SCC side. Pass the node corresponding to the + * channel side as a parameter. + * param is the type of port + * if param is ored with PMAC_SCC_FLAG_XMON, then the SCC is locked enabled + * for use by xmon. + */ +#define PMAC_FTR_SCC_ENABLE PMAC_FTR_DEF(0) + #define PMAC_SCC_ASYNC 0 + #define PMAC_SCC_IRDA 1 + #define PMAC_SCC_I2S1 2 + #define PMAC_SCC_FLAG_XMON 0x00001000 + +/* PMAC_FTR_MODEM_ENABLE (struct device_node* node, 0, int value) + * enable/disable the internal modem. + */ +#define PMAC_FTR_MODEM_ENABLE PMAC_FTR_DEF(1) + +/* PMAC_FTR_SWIM3_ENABLE (struct device_node* node, 0,int value) + * enable/disable the swim3 (floppy) cell of a mac-io ASIC + */ +#define PMAC_FTR_SWIM3_ENABLE PMAC_FTR_DEF(2) + +/* PMAC_FTR_MESH_ENABLE (struct device_node* node, 0, int value) + * enable/disable the mesh (scsi) cell of a mac-io ASIC + */ +#define PMAC_FTR_MESH_ENABLE PMAC_FTR_DEF(3) + +/* PMAC_FTR_IDE_ENABLE (struct device_node* node, int busID, int value) + * enable/disable an IDE port of a mac-io ASIC + * pass the busID parameter + */ +#define PMAC_FTR_IDE_ENABLE PMAC_FTR_DEF(4) + +/* PMAC_FTR_IDE_RESET (struct device_node* node, int busID, int value) + * assert(1)/release(0) an IDE reset line (mac-io IDE only) + */ +#define PMAC_FTR_IDE_RESET PMAC_FTR_DEF(5) + +/* PMAC_FTR_BMAC_ENABLE (struct device_node* node, 0, int value) + * enable/disable the bmac (ethernet) cell of a mac-io ASIC, also drive + * it's reset line + */ +#define PMAC_FTR_BMAC_ENABLE PMAC_FTR_DEF(6) + +/* PMAC_FTR_GMAC_ENABLE (struct device_node* node, 0, int value) + * enable/disable the gmac (ethernet) cell of an uninorth ASIC. This + * control the cell's clock. + */ +#define PMAC_FTR_GMAC_ENABLE PMAC_FTR_DEF(7) + +/* PMAC_FTR_GMAC_PHY_RESET (struct device_node* node, 0, 0) + * Perform a HW reset of the PHY connected to a gmac controller. + * Pass the gmac device node, not the PHY node. + */ +#define PMAC_FTR_GMAC_PHY_RESET PMAC_FTR_DEF(8) + +/* PMAC_FTR_SOUND_CHIP_ENABLE (struct device_node* node, 0, int value) + * enable/disable the sound chip, whatever it is and provided it can + * acually be controlled + */ +#define PMAC_FTR_SOUND_CHIP_ENABLE PMAC_FTR_DEF(9) + +/* -- add various tweaks related to sound routing -- */ + +/* PMAC_FTR_AIRPORT_ENABLE (struct device_node* node, 0, int value) + * enable/disable the airport card + */ +#define PMAC_FTR_AIRPORT_ENABLE PMAC_FTR_DEF(10) + +/* PMAC_FTR_RESET_CPU (NULL, int cpu_nr, 0) + * toggle the reset line of a CPU on an uninorth-based SMP machine + */ +#define PMAC_FTR_RESET_CPU PMAC_FTR_DEF(11) + +/* PMAC_FTR_USB_ENABLE (struct device_node* node, 0, int value) + * enable/disable an USB cell, along with the power of the USB "pad" + * on keylargo based machines + */ +#define PMAC_FTR_USB_ENABLE PMAC_FTR_DEF(12) + +/* PMAC_FTR_1394_ENABLE (struct device_node* node, 0, int value) + * enable/disable the firewire cell of an uninorth ASIC. + */ +#define PMAC_FTR_1394_ENABLE PMAC_FTR_DEF(13) + +/* PMAC_FTR_1394_CABLE_POWER (struct device_node* node, 0, int value) + * enable/disable the firewire cable power supply of the uninorth + * firewire cell + */ +#define PMAC_FTR_1394_CABLE_POWER PMAC_FTR_DEF(14) + +/* PMAC_FTR_SLEEP_STATE (struct device_node* node, 0, int value) + * set the sleep state of the motherboard. + * Pass -1 as value to query for sleep capability + */ +#define PMAC_FTR_SLEEP_STATE PMAC_FTR_DEF(15) + +/* PMAC_FTR_GET_MB_INFO (NULL, selector, 0) + * + * returns some motherboard infos. + * selector: 0 - model id + * 1 - model flags (capabilities) + * 2 - model name (cast to const char *) + */ +#define PMAC_FTR_GET_MB_INFO PMAC_FTR_DEF(16) +#define PMAC_MB_INFO_MODEL 0 +#define PMAC_MB_INFO_FLAGS 1 +#define PMAC_MB_INFO_NAME 2 + +/* PMAC_FTR_READ_GPIO (NULL, int index, 0) + * + * read a GPIO from a mac-io controller of type KeyLargo or Pangea. + * the value returned is a byte (positive), or a negative error code + */ +#define PMAC_FTR_READ_GPIO PMAC_FTR_DEF(17) + +/* PMAC_FTR_WRITE_GPIO (NULL, int index, int value) + * + * write a GPIO of a mac-io controller of type KeyLargo or Pangea. + */ +#define PMAC_FTR_WRITE_GPIO PMAC_FTR_DEF(18) + + +/* Don't use those directly, they are for the sake of pmac_setup.c */ +extern int pmac_do_feature_call(unsigned int selector, ...); +extern void pmac_feature_init(void); +extern void pmac_feature_late_init(void); + +#define PMAC_FTR_DEF(x) ((_MACH_Pmac << 16) | (x)) + +#endif /* __PPC_ASM_PMAC_FEATURE_H */ +#endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/processor.h linux-2.5/include/asm-ppc/processor.h --- linux-2.5.1/include/asm-ppc/processor.h Fri Oct 5 19:11:05 2001 +++ linux-2.5/include/asm-ppc/processor.h Thu Dec 27 16:32:31 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.processor.h 1.31 10/05/01 16:26:22 paulus + * BK Id: SCCS/s.processor.h 1.33 12/01/01 20:09:11 benh */ #ifdef __KERNEL__ #ifndef __ASM_PPC_PROCESSOR_H @@ -209,8 +209,11 @@ #define HID0_DFCA (1<<6) /* Data Cache Flush Assist */ #define HID0_BTIC (1<<5) /* Branch Target Instruction Cache Enable */ #define HID0_ABE (1<<3) /* Address Broadcast Enable */ +#define HID0_FOLD (1<<3) /* Branch Folding enable - 7450 */ #define HID0_BHTE (1<<2) /* Branch History Table Enable */ #define HID0_BTCD (1<<1) /* Branch target cache disable */ +#define HID0_NOPDST (1<<1) /* No-op dst, dstt, etc. instr. */ +#define HID0_NOPTI (1<<0) /* No-op dcbt and dcbst instr. */ #define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */ #define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ #define SPRN_IAC1 0x3F4 /* Instruction Address Compare 1 */ @@ -261,6 +264,14 @@ #define L2CR_L2DF 0x00004000 /* L2 differential clock */ #define L2CR_L2BYP 0x00002000 /* L2 DLL bypass */ #define L2CR_L2IP 0x00000001 /* L2 GI in progress */ +#define SPRN_L2CR2 0x3f8 +#define SPRN_L3CR 0x3FA /* Level 3 Cache Control Regsiter (7450) */ +#define L3CR_L3E 0x80000000 /* L3 enable */ +#define SPRN_MSSCR0 0x3f6 /* Memory Subsystem Control Register 0 */ +#define SPRN_MSSSR0 0x3f7 /* Memory Subsystem Status Register 1 */ +#define SPRN_ICTRL 0x3f3 /* Instruction Cache & Interrupt control reg */ +#define SPRN_LDSTCR 0x3f8 /* Load/Store control register */ +#define SPRN_LDSTDB 0x3f4 /* */ #define SPRN_LR 0x008 /* Link Register */ #define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */ #define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */ @@ -566,7 +577,6 @@ * Bus types */ #define EISA_bus 0 -#define EISA_bus__is_a_macro /* for versions in ksyms.c */ #define MCA_bus 0 #define MCA_bus__is_a_macro /* for versions in ksyms.c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-ppc/prom.h linux-2.5/include/asm-ppc/prom.h --- linux-2.5.1/include/asm-ppc/prom.h Tue Aug 28 13:58:33 2001 +++ linux-2.5/include/asm-ppc/prom.h Thu Dec 27 16:32:31 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prom.h 1.19 08/17/01 15:23:17 paulus + * BK Id: SCCS/s.prom.h 1.21 12/01/01 20:09:11 benh */ /* * Definitions for talking to the Open Firmware PROM on @@ -85,6 +85,10 @@ extern void prom_get_irq_senses(unsigned char *, int, int); extern int prom_n_addr_cells(struct device_node* np); extern int prom_n_size_cells(struct device_node* np); + +extern struct resource* +request_OF_resource(struct device_node* node, int index, const char* name_postfix); +extern int release_OF_resource(struct device_node* node, int index); extern void print_properties(struct device_node *node); extern int call_rtas(const char *service, int nargs, int nret, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390/idals.h linux-2.5/include/asm-s390/idals.h --- linux-2.5.1/include/asm-s390/idals.h Wed Jul 25 21:12:02 2001 +++ linux-2.5/include/asm-s390/idals.h Thu Dec 27 16:32:31 2001 @@ -10,7 +10,7 @@ #include <linux/config.h> #include <asm/irq.h> -#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */ +#define IDA_SIZE_LOG 11 /* 11 for 2k , 12 for 4k */ #define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG) static inline addr_t * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390/lowcore.h linux-2.5/include/asm-s390/lowcore.h --- linux-2.5.1/include/asm-s390/lowcore.h Thu Oct 11 16:43:38 2001 +++ linux-2.5/include/asm-s390/lowcore.h Thu Dec 27 16:32:31 2001 @@ -45,6 +45,9 @@ #define __LC_CPUID 0xC60 #define __LC_CPUADDR 0xC68 #define __LC_IPLDEV 0xC7C + +#define __LC_JIFFY_TIMER 0xC80 + #define __LC_PANIC_MAGIC 0xE00 #define __LC_PFAULT_INTPARM 0x080 @@ -161,7 +164,7 @@ /* entry.S sensitive area end */ /* SMP info area: defined by DJB */ - __u64 jiffy_timer_cc; /* 0xc80 */ + __u64 jiffy_timer; /* 0xc80 */ atomic_t ext_call_fast; /* 0xc88 */ __u8 pad11[0xe00-0xc8c]; /* 0xc8c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390/processor.h linux-2.5/include/asm-s390/processor.h --- linux-2.5.1/include/asm-s390/processor.h Fri Oct 5 19:11:05 2001 +++ linux-2.5/include/asm-s390/processor.h Thu Dec 27 16:32:31 2001 @@ -74,8 +74,6 @@ struct thread_struct { - - struct pt_regs *regs; /* the user registers can be found on*/ s390_fp_regs fp_regs; __u32 ar2; /* kernel access register 2 */ __u32 ar4; /* kernel access register 4 */ @@ -95,8 +93,7 @@ typedef struct thread_struct thread_struct; -#define INIT_THREAD { (struct pt_regs *) 0, \ - { 0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \ +#define INIT_THREAD {{0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \ {0},{0},{0},{0},{0},{0}}}, \ 0, 0, \ sizeof(init_stack) + (__u32) &init_stack, \ @@ -126,16 +123,25 @@ #define release_segments(mm) do { } while (0) /* - * Return saved PC of a blocked thread. used in kernel/sched + * Return saved PC of a blocked thread. used in kernel/sched. + * resume in entry.S does not create a new stack frame, it + * just stores the registers %r6-%r15 to the frame given by + * schedule. We want to return the address of the caller of + * schedule, so we have to walk the backchain one time to + * find the frame schedule() store its return address. */ extern inline unsigned long thread_saved_pc(struct thread_struct *t) { - return (t->regs) ? ((unsigned long)t->regs->psw.addr) : 0; + unsigned long bc; + bc = *((unsigned long *) t->ksp); + return *((unsigned long *) (bc+56)); } unsigned long get_wchan(struct task_struct *p); -#define KSTK_EIP(tsk) ((tsk)->thread.regs->psw.addr) -#define KSTK_ESP(tsk) ((tsk)->thread.ksp) +#define __KSTK_PTREGS(tsk) \ + ((struct pt_regs *)((unsigned long) tsk+THREAD_SIZE) - 1) +#define KSTK_EIP(tsk) (__KSTK_PTREGS(tsk)->psw.addr) +#define KSTK_ESP(tsk) (__KSTK_PTREGS(tsk)->gprs[15]) /* Allocation and freeing of basic task resources. */ /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390/ptrace.h linux-2.5/include/asm-s390/ptrace.h --- linux-2.5.1/include/asm-s390/ptrace.h Thu Oct 11 16:43:38 2001 +++ linux-2.5/include/asm-s390/ptrace.h Thu Dec 27 16:32:31 2001 @@ -118,7 +118,7 @@ { __u32 mask; __u32 addr; -} psw_t __attribute__ ((aligned(8))); +} __attribute__ ((aligned(8))) psw_t; #ifdef __KERNEL__ #define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL) @@ -150,8 +150,8 @@ #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 + * The first entries in pt_regs and user_regs_struct + * are common for the two structures. The s390_regs structure * covers the common parts. It simplifies copying the common part * between the three structures. */ @@ -178,30 +178,12 @@ }; /* - * The gdb_pt_regs struct is used instead of the pt_regs structure - * if kernel remote debugging is used. - */ -#if CONFIG_REMOTE_DEBUG -struct gdb_pt_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; - __u32 old_ilc; -}; -#endif - -/* * Now for the program event recording (trace) definitions. */ typedef struct { __u32 cr[3]; -} per_cr_words __attribute__((packed)); +} per_cr_words; #define PER_EM_MASK 0xE8000000 @@ -223,14 +205,14 @@ unsigned : 21; addr_t starting_addr; addr_t ending_addr; -} per_cr_bits __attribute__((packed)); +} per_cr_bits; typedef struct { __u16 perc_atmid; /* 0x096 */ __u32 address; /* 0x098 */ __u8 access_id; /* 0x0a1 */ -} per_lowcore_words __attribute__((packed)); +} per_lowcore_words; typedef struct { @@ -249,14 +231,14 @@ addr_t address; /* 0x098 */ unsigned : 4; /* 0x0a1 */ unsigned access_id : 4; -} per_lowcore_bits __attribute__((packed)); +} per_lowcore_bits; typedef struct { union { per_cr_words words; per_cr_bits bits; - } control_regs __attribute__((packed)); + } control_regs; /* * Use these flags instead of setting em_instruction_fetch * directly they are used so that single stepping can be @@ -275,7 +257,7 @@ per_lowcore_words words; per_lowcore_bits bits; } lowcore; -} per_struct __attribute__((packed)); +} per_struct; typedef struct { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390/scatterlist.h linux-2.5/include/asm-s390/scatterlist.h --- linux-2.5.1/include/asm-s390/scatterlist.h Fri Oct 12 22:35:54 2001 +++ linux-2.5/include/asm-s390/scatterlist.h Thu Dec 27 16:32:31 2001 @@ -1,8 +1,16 @@ -#ifndef _ASMS390X_SCATTERLIST_H -#define _ASMS390X_SCATTERLIST_H +#ifndef _ASMS390_SCATTERLIST_H +#define _ASMS390_SCATTERLIST_H struct scatterlist { - char * address; /* Location data is to be transferred to */ + /* This will disappear in 2.5.x */ + char *address; + + /* These two are only valid if ADDRESS member of this + * struct is NULL. + */ + struct page *page; + unsigned int offset; + unsigned int length; }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390/setup.h linux-2.5/include/asm-s390/setup.h --- linux-2.5.1/include/asm-s390/setup.h Wed Jul 25 21:12:02 2001 +++ linux-2.5/include/asm-s390/setup.h Thu Dec 27 16:32:31 2001 @@ -13,7 +13,7 @@ #define RAMDISK_ORIGIN 0x800000 #define RAMDISK_SIZE 0x800000 -#ifndef __ASSEMBLER__ +#ifndef __ASSEMBLY__ #define IPL_DEVICE (*(unsigned long *) (0x10404)) #define INITRD_START (*(unsigned long *) (0x1040C)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390/siginfo.h linux-2.5/include/asm-s390/siginfo.h --- linux-2.5.1/include/asm-s390/siginfo.h Tue Feb 13 22:13:44 2001 +++ linux-2.5/include/asm-s390/siginfo.h Thu Dec 27 16:32:31 2001 @@ -111,7 +111,7 @@ #define SI_USER 0 /* sent by kill, sigsend, raise */ #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ #define SI_QUEUE -1 /* sent by sigqueue */ -#define SI_TIMER -2 /* sent by timer expiration */ +#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ @@ -122,71 +122,71 @@ /* * SIGILL si_codes */ -#define ILL_ILLOPC 1 /* illegal opcode */ -#define ILL_ILLOPN 2 /* illegal operand */ -#define ILL_ILLADR 3 /* illegal addressing mode */ -#define ILL_ILLTRP 4 /* illegal trap */ -#define ILL_PRVOPC 5 /* privileged opcode */ -#define ILL_PRVREG 6 /* privileged register */ -#define ILL_COPROC 7 /* coprocessor error */ -#define ILL_BADSTK 8 /* internal stack error */ +#define ILL_ILLOPC (__SI_FAULT|1) /* illegal opcode */ +#define ILL_ILLOPN (__SI_FAULT|2) /* illegal operand */ +#define ILL_ILLADR (__SI_FAULT|3) /* illegal addressing mode */ +#define ILL_ILLTRP (__SI_FAULT|4) /* illegal trap */ +#define ILL_PRVOPC (__SI_FAULT|5) /* privileged opcode */ +#define ILL_PRVREG (__SI_FAULT|6) /* privileged register */ +#define ILL_COPROC (__SI_FAULT|7) /* coprocessor error */ +#define ILL_BADSTK (__SI_FAULT|8) /* internal stack error */ #define NSIGILL 8 /* * SIGFPE si_codes */ -#define FPE_INTDIV 1 /* integer divide by zero */ -#define FPE_INTOVF 2 /* integer overflow */ -#define FPE_FLTDIV 3 /* floating point divide by zero */ -#define FPE_FLTOVF 4 /* floating point overflow */ -#define FPE_FLTUND 5 /* floating point underflow */ -#define FPE_FLTRES 6 /* floating point inexact result */ -#define FPE_FLTINV 7 /* floating point invalid operation */ -#define FPE_FLTSUB 8 /* subscript out of range */ +#define FPE_INTDIV (__SI_FAULT|1) /* integer divide by zero */ +#define FPE_INTOVF (__SI_FAULT|2) /* integer overflow */ +#define FPE_FLTDIV (__SI_FAULT|3) /* floating point divide by zero */ +#define FPE_FLTOVF (__SI_FAULT|4) /* floating point overflow */ +#define FPE_FLTUND (__SI_FAULT|5) /* floating point underflow */ +#define FPE_FLTRES (__SI_FAULT|6) /* floating point inexact result */ +#define FPE_FLTINV (__SI_FAULT|7) /* floating point invalid operation */ +#define FPE_FLTSUB (__SI_FAULT|8) /* subscript out of range */ #define NSIGFPE 8 /* * SIGSEGV si_codes */ -#define SEGV_MAPERR 1 /* address not mapped to object */ -#define SEGV_ACCERR 2 /* invalid permissions for mapped object */ +#define SEGV_MAPERR (__SI_FAULT|1) /* address not mapped to object */ +#define SEGV_ACCERR (__SI_FAULT|2) /* invalid permissions for mapped object */ #define NSIGSEGV 2 /* * SIGBUS si_codes */ -#define BUS_ADRALN 1 /* invalid address alignment */ -#define BUS_ADRERR 2 /* non-existant physical address */ -#define BUS_OBJERR 3 /* object specific hardware error */ +#define BUS_ADRALN (__SI_FAULT|1) /* invalid address alignment */ +#define BUS_ADRERR (__SI_FAULT|2) /* non-existant physical address */ +#define BUS_OBJERR (__SI_FAULT|3) /* object specific hardware error */ #define NSIGBUS 3 /* * SIGTRAP si_codes */ -#define TRAP_BRKPT 1 /* process breakpoint */ -#define TRAP_TRACE 2 /* process trace trap */ +#define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */ +#define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */ #define NSIGTRAP 2 /* * SIGCHLD si_codes */ -#define CLD_EXITED 1 /* child has exited */ -#define CLD_KILLED 2 /* child was killed */ -#define CLD_DUMPED 3 /* child terminated abnormally */ -#define CLD_TRAPPED 4 /* traced child has trapped */ -#define CLD_STOPPED 5 /* child has stopped */ -#define CLD_CONTINUED 6 /* stopped child has continued */ +#define CLD_EXITED (__SI_CHLD|1) /* child has exited */ +#define CLD_KILLED (__SI_CHLD|2) /* child was killed */ +#define CLD_DUMPED (__SI_CHLD|3) /* child terminated abnormally */ +#define CLD_TRAPPED (__SI_CHLD|4) /* traced child has trapped */ +#define CLD_STOPPED (__SI_CHLD|5) /* child has stopped */ +#define CLD_CONTINUED (__SI_CHLD|6) /* stopped child has continued */ #define NSIGCHLD /* * SIGPOLL si_codes */ -#define POLL_IN 1 /* data input available */ -#define POLL_OUT 2 /* output buffers available */ -#define POLL_MSG 3 /* input message available */ -#define POLL_ERR 4 /* i/o error */ -#define POLL_PRI 5 /* high priority input available */ -#define POLL_HUP 6 /* device disconnected */ +#define POLL_IN (__SI_POLL|1) /* data input available */ +#define POLL_OUT (__SI_POLL|2) /* output buffers available */ +#define POLL_MSG (__SI_POLL|3) /* input message available */ +#define POLL_ERR (__SI_POLL|4) /* i/o error */ +#define POLL_PRI (__SI_POLL|5) /* high priority input available */ +#define POLL_HUP (__SI_POLL|6) /* device disconnected */ #define NSIGPOLL 6 /* @@ -224,7 +224,7 @@ #ifdef __KERNEL__ #include <linux/string.h> -extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from) +static inline void copy_siginfo(siginfo_t *to, siginfo_t *from) { if (from->si_code < 0) memcpy(to, from, sizeof(siginfo_t)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390/timex.h linux-2.5/include/asm-s390/timex.h --- linux-2.5.1/include/asm-s390/timex.h Fri May 12 18:41:44 2000 +++ linux-2.5/include/asm-s390/timex.h Thu Dec 27 16:32:31 2001 @@ -17,13 +17,16 @@ (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ << (SHIFT_SCALE-SHIFT_HZ)) / HZ) -typedef unsigned long cycles_t; +typedef unsigned long long cycles_t; extern cycles_t cacheflush_time; static inline cycles_t get_cycles(void) { - return 0; + cycles_t cycles; + + __asm__("stck %0" : "=m" (cycles) : : "cc"); + return cycles >> 2; } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390/uaccess.h linux-2.5/include/asm-s390/uaccess.h --- linux-2.5.1/include/asm-s390/uaccess.h Thu Oct 11 16:43:38 2001 +++ linux-2.5/include/asm-s390/uaccess.h Thu Dec 27 16:32:31 2001 @@ -379,34 +379,11 @@ * access register are set up, that 4 points to secondary (user) , 2 to primary (kernel) */ -asmlinkage void __copy_from_user_fixup(void /* special calling convention */); -asmlinkage void __copy_to_user_fixup(void /* special calling convention */); - -extern inline unsigned long -__copy_to_user_asm(void* to, const void* from, long n) -{ - - __asm__ __volatile__ ( " lr 2,%2\n" - " lr 4,%1\n" - " lr 3,%0\n" - " lr 5,3\n" - " sacf 512\n" - "0: mvcle 4,2,0\n" - " jo 0b\n" - " sacf 0\n" - " lr %0,3\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 0b,__copy_to_user_fixup\n" - ".previous" - : "+&d" (n) : "d" (to), "d" (from) - : "cc", "2", "3", "4", "5" ); - return n; -} +extern long __copy_to_user_asm(const void *from, long n, const void *to); #define __copy_to_user(to, from, n) \ ({ \ - __copy_to_user_asm(to,from,n); \ + __copy_to_user_asm(from, n, to); \ }) #define copy_to_user(to, from, n) \ @@ -414,38 +391,18 @@ long err = 0; \ __typeof__(n) __n = (n); \ if (__access_ok(to,__n)) { \ - err = __copy_to_user_asm(to,from,__n); \ + err = __copy_to_user_asm(from, __n, to); \ } \ else \ err = __n; \ err; \ }) -extern inline unsigned long -__copy_from_user_asm(void* to, const void* from, long n) -{ - __asm__ __volatile__ ( " lr 2,%1\n" - " lr 4,%2\n" - " lr 3,%0\n" - " lr 5,3\n" - " sacf 512\n" - "0: mvcle 2,4,0\n" - " jo 0b\n" - " sacf 0\n" - " lr %0,5\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 0b,__copy_from_user_fixup\n" - ".previous" - : "+&d" (n) : "d" (to), "d" (from) - : "cc", "2", "3", "4", "5" ); - return n; -} - +extern long __copy_from_user_asm(void *to, long n, const void *from); #define __copy_from_user(to, from, n) \ ({ \ - __copy_from_user_asm(to,from,n); \ + __copy_from_user_asm(to, n, from); \ }) #define copy_from_user(to, from, n) \ @@ -453,7 +410,7 @@ long err = 0; \ __typeof__(n) __n = (n); \ if (__access_ok(from,__n)) { \ - err = __copy_from_user_asm(to,from,__n); \ + err = __copy_from_user_asm(to, __n, from); \ } \ else \ err = __n; \ @@ -550,38 +507,12 @@ * Zero Userspace */ -static inline unsigned long -__clear_user(void *to, unsigned long n) -{ - __asm__ __volatile__ ( " sacf 512\n" - " lr 4,%1\n" - " lr 5,%0\n" - " sr 2,2\n" - " sr 3,3\n" - "0: mvcle 4,2,0\n" - " jo 0b\n" - " sacf 0\n" - "1: lr %0,3\n" - ".section .fixup,\"ax\"\n" - "2: lhi 5,-4096\n" - " n 5,0x90\n" - " sr 5,4\n" - " mvcle 4,2,0\n" - " sacf 0\n" - " basr 4,0\n" - " l 4,3f-.(4)\n" - " br 4\n" - "3: .long 1b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 0b,2b\n" - ".previous" - : "+&a" (n) - : "a" (to) - : "cc", "2", "3", "4", "5" ); - return n; -} +extern long __clear_user_asm(void *to, long n); + +#define __clear_user(to, n) \ +({ \ + __clear_user_asm(to, n); \ +}) static inline unsigned long clear_user(void *to, unsigned long n) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390x/lowcore.h linux-2.5/include/asm-s390x/lowcore.h --- linux-2.5.1/include/asm-s390x/lowcore.h Thu Oct 11 16:43:38 2001 +++ linux-2.5/include/asm-s390x/lowcore.h Thu Dec 27 16:32:31 2001 @@ -45,6 +45,8 @@ #define __LC_CPUADDR 0xD98 #define __LC_IPLDEV 0xDB8 +#define __LC_JIFFY_TIMER 0xDC0 + #define __LC_PANIC_MAGIC 0xE00 #define __LC_AREGS_SAVE_AREA 0x1340 @@ -158,7 +160,7 @@ /* entry.S sensitive area end */ /* SMP info area: defined by DJB */ - __u64 jiffy_timer_cc; /* 0xdc0 */ + __u64 jiffy_timer; /* 0xdc0 */ __u64 ext_call_fast; /* 0xdc8 */ __u8 pad12[0xe00-0xdd0]; /* 0xdd0 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390x/processor.h linux-2.5/include/asm-s390x/processor.h --- linux-2.5.1/include/asm-s390x/processor.h Fri Oct 5 19:11:05 2001 +++ linux-2.5/include/asm-s390x/processor.h Thu Dec 27 16:32:31 2001 @@ -80,7 +80,6 @@ struct thread_struct { - struct pt_regs *regs; /* the user registers can be found on*/ s390_fp_regs fp_regs; __u32 ar2; /* kernel access register 2 */ __u32 ar4; /* kernel access register 4 */ @@ -99,8 +98,7 @@ typedef struct thread_struct thread_struct; -#define INIT_THREAD { (struct pt_regs *) 0, \ - { 0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \ +#define INIT_THREAD {{0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \ {0},{0},{0},{0},{0},{0}}}, \ 0, 0, \ sizeof(init_stack) + (addr_t) &init_stack, \ @@ -137,15 +135,24 @@ /* * Return saved PC of a blocked thread. used in kernel/sched + * resume in entry.S does not create a new stack frame, it + * just stores the registers %r6-%r15 to the frame given by + * schedule. We want to return the address of the caller of + * schedule, so we have to walk the backchain one time to + * find the frame schedule() store its return address. */ extern inline unsigned long thread_saved_pc(struct thread_struct *t) { - return (t->regs) ? ((unsigned long)t->regs->psw.addr) : 0; + unsigned long bc; + bc = *((unsigned long *) t->ksp); + return *((unsigned long *) (bc+112)); } unsigned long get_wchan(struct task_struct *p); -#define KSTK_EIP(tsk) ((tsk)->thread.regs->psw.addr) -#define KSTK_ESP(tsk) ((tsk)->thread.ksp) +#define __KSTK_PTREGS(tsk) \ + ((struct pt_regs *)((unsigned long) tsk+THREAD_SIZE) - 1) +#define KSTK_EIP(tsk) (__KSTK_PTREGS(tsk)->psw.addr) +#define KSTK_ESP(tsk) (__KSTK_PTREGS(tsk)->gprs[15]) /* Allocation and freeing of basic task resources. */ /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390x/ptrace.h linux-2.5/include/asm-s390x/ptrace.h --- linux-2.5.1/include/asm-s390x/ptrace.h Thu Apr 12 02:02:29 2001 +++ linux-2.5/include/asm-s390x/ptrace.h Thu Dec 27 16:32:31 2001 @@ -98,7 +98,7 @@ { __u64 mask; __u64 addr; -} psw_t __attribute__ ((aligned(8))); +} __attribute__ ((aligned(8))) psw_t; #ifdef __KERNEL__ #define FIX_PSW(addr) ((unsigned long)(addr)) @@ -130,8 +130,8 @@ #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 + * The first entries in pt_regs and user_regs_struct + * are common for the two structures. The s390_regs structure * covers the common parts. It simplifies copying the common part * between the three structures. */ @@ -158,29 +158,12 @@ } __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 -struct gdb_pt_regs -{ - psw_t psw; - __u64 gprs[NUM_GPRS]; - __u32 acrs[NUM_ACRS]; - __u64 orig_gpr2; - __u32 trap; - __u32 crs[16]; - s390_fp_regs fp_regs; -}; -#endif - -/* * Now for the program event recording (trace) definitions. */ typedef struct { __u64 cr[3]; -} per_cr_words __attribute__((packed)); +} per_cr_words; #define PER_EM_MASK 0x00000000E8000000UL @@ -203,14 +186,14 @@ unsigned : 21; addr_t starting_addr; addr_t ending_addr; -} per_cr_bits __attribute__((packed)); +} per_cr_bits; typedef struct { __u16 perc_atmid; addr_t address; __u8 access_id; -} per_lowcore_words __attribute__((packed)); +} per_lowcore_words; typedef struct { @@ -230,14 +213,14 @@ addr_t address; /* 0x098 */ unsigned : 4; /* 0x0a1 */ unsigned access_id : 4; -} per_lowcore_bits __attribute__((packed)); +} per_lowcore_bits; typedef struct { union { per_cr_words words; per_cr_bits bits; - } control_regs __attribute__((packed)); + } control_regs; /* * Use these flags instead of setting em_instruction_fetch * directly they are used so that single stepping can be @@ -256,7 +239,7 @@ per_lowcore_words words; per_lowcore_bits bits; } lowcore; -} per_struct __attribute__((packed)); +} per_struct; typedef struct { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390x/scatterlist.h linux-2.5/include/asm-s390x/scatterlist.h --- linux-2.5.1/include/asm-s390x/scatterlist.h Fri Oct 12 22:35:54 2001 +++ linux-2.5/include/asm-s390x/scatterlist.h Thu Dec 27 16:32:31 2001 @@ -2,7 +2,15 @@ #define _ASMS390X_SCATTERLIST_H struct scatterlist { - char * address; /* Location data is to be transferred to */ + /* This will disappear in 2.5.x */ + char *address; + + /* These two are only valid if ADDRESS member of this + * struct is NULL. + */ + struct page *page; + unsigned int offset; + unsigned int length; }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390x/setup.h linux-2.5/include/asm-s390x/setup.h --- linux-2.5.1/include/asm-s390x/setup.h Wed Jul 25 21:12:02 2001 +++ linux-2.5/include/asm-s390x/setup.h Thu Dec 27 16:32:31 2001 @@ -13,7 +13,7 @@ #define RAMDISK_ORIGIN 0x800000 #define RAMDISK_SIZE 0x800000 -#ifndef __ASSEMBLER__ +#ifndef __ASSEMBLY__ #define IPL_DEVICE (*(unsigned long *) (0x10400)) #define INITRD_START (*(unsigned long *) (0x10408)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390x/siginfo.h linux-2.5/include/asm-s390x/siginfo.h --- linux-2.5.1/include/asm-s390x/siginfo.h Tue Feb 13 22:13:44 2001 +++ linux-2.5/include/asm-s390x/siginfo.h Thu Dec 27 16:32:31 2001 @@ -111,7 +111,7 @@ #define SI_USER 0 /* sent by kill, sigsend, raise */ #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ #define SI_QUEUE -1 /* sent by sigqueue */ -#define SI_TIMER -2 /* sent by timer expiration */ +#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ @@ -122,71 +122,71 @@ /* * SIGILL si_codes */ -#define ILL_ILLOPC 1 /* illegal opcode */ -#define ILL_ILLOPN 2 /* illegal operand */ -#define ILL_ILLADR 3 /* illegal addressing mode */ -#define ILL_ILLTRP 4 /* illegal trap */ -#define ILL_PRVOPC 5 /* privileged opcode */ -#define ILL_PRVREG 6 /* privileged register */ -#define ILL_COPROC 7 /* coprocessor error */ -#define ILL_BADSTK 8 /* internal stack error */ +#define ILL_ILLOPC (__SI_FAULT|1) /* illegal opcode */ +#define ILL_ILLOPN (__SI_FAULT|2) /* illegal operand */ +#define ILL_ILLADR (__SI_FAULT|3) /* illegal addressing mode */ +#define ILL_ILLTRP (__SI_FAULT|4) /* illegal trap */ +#define ILL_PRVOPC (__SI_FAULT|5) /* privileged opcode */ +#define ILL_PRVREG (__SI_FAULT|6) /* privileged register */ +#define ILL_COPROC (__SI_FAULT|7) /* coprocessor error */ +#define ILL_BADSTK (__SI_FAULT|8) /* internal stack error */ #define NSIGILL 8 /* * SIGFPE si_codes */ -#define FPE_INTDIV 1 /* integer divide by zero */ -#define FPE_INTOVF 2 /* integer overflow */ -#define FPE_FLTDIV 3 /* floating point divide by zero */ -#define FPE_FLTOVF 4 /* floating point overflow */ -#define FPE_FLTUND 5 /* floating point underflow */ -#define FPE_FLTRES 6 /* floating point inexact result */ -#define FPE_FLTINV 7 /* floating point invalid operation */ -#define FPE_FLTSUB 8 /* subscript out of range */ +#define FPE_INTDIV (__SI_FAULT|1) /* integer divide by zero */ +#define FPE_INTOVF (__SI_FAULT|2) /* integer overflow */ +#define FPE_FLTDIV (__SI_FAULT|3) /* floating point divide by zero */ +#define FPE_FLTOVF (__SI_FAULT|4) /* floating point overflow */ +#define FPE_FLTUND (__SI_FAULT|5) /* floating point underflow */ +#define FPE_FLTRES (__SI_FAULT|6) /* floating point inexact result */ +#define FPE_FLTINV (__SI_FAULT|7) /* floating point invalid operation */ +#define FPE_FLTSUB (__SI_FAULT|8) /* subscript out of range */ #define NSIGFPE 8 /* * SIGSEGV si_codes */ -#define SEGV_MAPERR 1 /* address not mapped to object */ -#define SEGV_ACCERR 2 /* invalid permissions for mapped object */ +#define SEGV_MAPERR (__SI_FAULT|1) /* address not mapped to object */ +#define SEGV_ACCERR (__SI_FAULT|2) /* invalid permissions for mapped object */ #define NSIGSEGV 2 /* * SIGBUS si_codes */ -#define BUS_ADRALN 1 /* invalid address alignment */ -#define BUS_ADRERR 2 /* non-existant physical address */ -#define BUS_OBJERR 3 /* object specific hardware error */ +#define BUS_ADRALN (__SI_FAULT|1) /* invalid address alignment */ +#define BUS_ADRERR (__SI_FAULT|2) /* non-existant physical address */ +#define BUS_OBJERR (__SI_FAULT|3) /* object specific hardware error */ #define NSIGBUS 3 /* * SIGTRAP si_codes */ -#define TRAP_BRKPT 1 /* process breakpoint */ -#define TRAP_TRACE 2 /* process trace trap */ +#define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */ +#define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */ #define NSIGTRAP 2 /* * SIGCHLD si_codes */ -#define CLD_EXITED 1 /* child has exited */ -#define CLD_KILLED 2 /* child was killed */ -#define CLD_DUMPED 3 /* child terminated abnormally */ -#define CLD_TRAPPED 4 /* traced child has trapped */ -#define CLD_STOPPED 5 /* child has stopped */ -#define CLD_CONTINUED 6 /* stopped child has continued */ +#define CLD_EXITED (__SI_CHLD|1) /* child has exited */ +#define CLD_KILLED (__SI_CHLD|2) /* child was killed */ +#define CLD_DUMPED (__SI_CHLD|3) /* child terminated abnormally */ +#define CLD_TRAPPED (__SI_CHLD|4) /* traced child has trapped */ +#define CLD_STOPPED (__SI_CHLD|5) /* child has stopped */ +#define CLD_CONTINUED (__SI_CHLD|6) /* stopped child has continued */ #define NSIGCHLD /* * SIGPOLL si_codes */ -#define POLL_IN 1 /* data input available */ -#define POLL_OUT 2 /* output buffers available */ -#define POLL_MSG 3 /* input message available */ -#define POLL_ERR 4 /* i/o error */ -#define POLL_PRI 5 /* high priority input available */ -#define POLL_HUP 6 /* device disconnected */ +#define POLL_IN (__SI_POLL|1) /* data input available */ +#define POLL_OUT (__SI_POLL|2) /* output buffers available */ +#define POLL_MSG (__SI_POLL|3) /* input message available */ +#define POLL_ERR (__SI_POLL|4) /* i/o error */ +#define POLL_PRI (__SI_POLL|5) /* high priority input available */ +#define POLL_HUP (__SI_POLL|6) /* device disconnected */ #define NSIGPOLL 6 /* @@ -224,7 +224,7 @@ #ifdef __KERNEL__ #include <linux/string.h> -extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from) +static inline void copy_siginfo(siginfo_t *to, siginfo_t *from) { if (from->si_code < 0) memcpy(to, from, sizeof(siginfo_t)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390x/timex.h linux-2.5/include/asm-s390x/timex.h --- linux-2.5.1/include/asm-s390x/timex.h Tue Feb 13 22:13:44 2001 +++ linux-2.5/include/asm-s390x/timex.h Thu Dec 27 16:32:31 2001 @@ -17,13 +17,16 @@ (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ << (SHIFT_SCALE-SHIFT_HZ)) / HZ) -typedef unsigned long cycles_t; +typedef unsigned long long cycles_t; extern cycles_t cacheflush_time; static inline cycles_t get_cycles(void) { - return 0; + cycles_t cycles; + + __asm__("stck %0" : "=m" (cycles) : : "cc"); + return cycles >> 2; } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-s390x/uaccess.h linux-2.5/include/asm-s390x/uaccess.h --- linux-2.5.1/include/asm-s390x/uaccess.h Wed Jul 25 21:12:03 2001 +++ linux-2.5/include/asm-s390x/uaccess.h Thu Dec 27 16:32:31 2001 @@ -336,34 +336,11 @@ * access register are set up, that 4 points to secondary (user) , 2 to primary (kernel) */ -asmlinkage void __copy_from_user_fixup(void /* special calling convention */); -asmlinkage void __copy_to_user_fixup(void /* special calling convention */); - -extern inline unsigned long -__copy_to_user_asm(void* to, const void* from, long n) -{ - - __asm__ __volatile__ ( " lgr 2,%2\n" - " lgr 4,%1\n" - " lgr 3,%0\n" - " lgr 5,3\n" - " sacf 512\n" - "0: mvcle 4,2,0\n" - " jo 0b\n" - " sacf 0\n" - " lgr %0,3\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" - " .quad 0b,__copy_to_user_fixup\n" - ".previous" - : "+&d" (n) : "d" (to), "d" (from) - : "cc", "1", "2", "3", "4", "5" ); - return n; -} +extern long __copy_to_user_asm(const void *from, long n, void *to); #define __copy_to_user(to, from, n) \ ({ \ - __copy_to_user_asm(to,from,n); \ + __copy_to_user_asm(from, n, to); \ }) #define copy_to_user(to, from, n) \ @@ -371,38 +348,18 @@ long err = 0; \ __typeof__(n) __n = (n); \ if (__access_ok(to,__n)) { \ - err = __copy_to_user_asm(to,from,__n); \ + err = __copy_to_user_asm(from, __n, to); \ } \ else \ err = __n; \ err; \ }) -extern inline unsigned long -__copy_from_user_asm(void* to, const void* from, long n) -{ - __asm__ __volatile__ ( " lgr 2,%1\n" - " lgr 4,%2\n" - " lgr 3,%0\n" - " lgr 5,3\n" - " sacf 512\n" - "0: mvcle 2,4,0\n" - " jo 0b\n" - " sacf 0\n" - " lgr %0,5\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" - " .quad 0b,__copy_from_user_fixup\n" - ".previous" - : "+&d" (n) : "d" (to), "d" (from) - : "cc", "1", "2", "3", "4", "5" ); - return n; -} - +extern long __copy_from_user_asm(void *to, long n, const void *from); #define __copy_from_user(to, from, n) \ ({ \ - __copy_from_user_asm(to,from,n); \ + __copy_from_user_asm(to, n, from); \ }) #define copy_from_user(to, from, n) \ @@ -410,7 +367,7 @@ long err = 0; \ __typeof__(n) __n = (n); \ if (__access_ok(from,__n)) { \ - err = __copy_from_user_asm(to,from,__n); \ + err = __copy_from_user_asm(to, __n, from); \ } \ else \ err = __n; \ @@ -520,27 +477,12 @@ * Zero Userspace */ -static inline unsigned long -__clear_user(void *to, unsigned long n) -{ - __asm__ __volatile__ ( " sacf 512\n" - " lgr 4,%1\n" - " lgr 5,%0\n" - " sgr 2,2\n" - " sgr 3,3\n" - "0: mvcle 4,2,0\n" - " jo 0b\n" - "1: sacf 0\n" - " lgr %0,5\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" - " .quad 0b,__copy_to_user_fixup\n" - ".previous" - : "+&a" (n) - : "a" (to) - : "cc", "1", "2", "3", "4", "5" ); - return n; -} +extern long __clear_user_asm(void *to, long n); + +#define __clear_user(to, n) \ +({ \ + __clear_user_asm(to, n); \ +}) static inline unsigned long clear_user(void *to, unsigned long n) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sh/pci.h linux-2.5/include/asm-sh/pci.h --- linux-2.5.1/include/asm-sh/pci.h Tue Dec 11 18:10:18 2001 +++ linux-2.5/include/asm-sh/pci.h Thu Dec 27 16:32:31 2001 @@ -89,6 +89,31 @@ return virt_to_bus(ptr); } +/* pci_unmap_{single,page} being a nop depends upon the + * configuration. + */ +#ifdef CONFIG_SH_PCIDMA_NONCOHERENT +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) +#else +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) (0) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) do { } while (0) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) (0) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) do { } while (0) +#endif + /* Unmap a single streaming mode DMA translation. The dma_addr and size * must match what was provided for in a previous pci_map_single call. All * other usages are undefined. @@ -195,6 +220,11 @@ { return 1; } + +/* Not supporting more than 32-bit PCI bus addresses now, but + * must satisfy references to this function. Change if needed. + */ +#define pci_dac_dma_supported(pci_dev, mask) (0) /* Not supporting more than 32-bit PCI bus addresses now, but * must satisfy references to this function. Change if needed. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sh/processor.h linux-2.5/include/asm-sh/processor.h --- linux-2.5.1/include/asm-sh/processor.h Fri Oct 5 19:11:05 2001 +++ linux-2.5/include/asm-sh/processor.h Thu Dec 27 15:15:00 2001 @@ -143,7 +143,6 @@ * Bus types */ #define EISA_bus 0 -#define EISA_bus__is_a_macro /* for versions in ksyms.c */ #define MCA_bus 0 #define MCA_bus__is_a_macro /* for versions in ksyms.c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc/bitops.h linux-2.5/include/asm-sparc/bitops.h --- linux-2.5.1/include/asm-sparc/bitops.h Tue Oct 30 23:08:11 2001 +++ linux-2.5/include/asm-sparc/bitops.h Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.65 2001/10/30 04:08:26 davem Exp $ +/* $Id: bitops.h,v 1.67 2001/11/19 18:36:34 davem Exp $ * bitops.h: Bit string operations on the Sparc. * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc/keyboard.h linux-2.5/include/asm-sparc/keyboard.h --- linux-2.5.1/include/asm-sparc/keyboard.h Tue Aug 28 14:09:44 2001 +++ linux-2.5/include/asm-sparc/keyboard.h Thu Dec 27 15:56:12 2001 @@ -40,7 +40,6 @@ #define kbd_init pcikbd_init #define compute_shiftstate pci_compute_shiftstate -#define keyboard_wait_for_keypress pci_wait_for_keypress #define getkeycode pci_getkeycode #define setkeycode pci_setkeycode #define getledstate pci_getledstate diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc/pci.h linux-2.5/include/asm-sparc/pci.h --- linux-2.5.1/include/asm-sparc/pci.h Tue Nov 13 17:16:05 2001 +++ linux-2.5/include/asm-sparc/pci.h Thu Dec 27 16:32:31 2001 @@ -63,6 +63,20 @@ */ extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction); +/* pci_unmap_{single,page} is not a nop, thus... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) + /* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the * above pci_map_single interface. Here the scatter gather list diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc/processor.h linux-2.5/include/asm-sparc/processor.h --- linux-2.5.1/include/asm-sparc/processor.h Thu Oct 11 06:42:47 2001 +++ linux-2.5/include/asm-sparc/processor.h Thu Dec 27 15:15:00 2001 @@ -28,7 +28,6 @@ * Bus types */ #define EISA_bus 0 -#define EISA_bus__is_a_macro /* for versions in ksyms.c */ #define MCA_bus 0 #define MCA_bus__is_a_macro /* for versions in ksyms.c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/bitops.h linux-2.5/include/asm-sparc64/bitops.h --- linux-2.5.1/include/asm-sparc64/bitops.h Thu Jun 21 04:00:55 2001 +++ linux-2.5/include/asm-sparc64/bitops.h Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.36 2001/06/14 12:34:49 davem Exp $ +/* $Id: bitops.h,v 1.38 2001/11/19 18:36:34 davem Exp $ * bitops.h: Bit string operations on the V9. * * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -13,9 +13,9 @@ extern long ___test_and_clear_bit(unsigned long nr, volatile void *addr); extern long ___test_and_change_bit(unsigned long nr, volatile void *addr); -#define test_and_set_bit(nr,addr) (___test_and_set_bit(nr,addr)!=0) -#define test_and_clear_bit(nr,addr) (___test_and_clear_bit(nr,addr)!=0) -#define test_and_change_bit(nr,addr) (___test_and_change_bit(nr,addr)!=0) +#define test_and_set_bit(nr,addr) ({___test_and_set_bit(nr,addr)!=0;}) +#define test_and_clear_bit(nr,addr) ({___test_and_clear_bit(nr,addr)!=0;}) +#define test_and_change_bit(nr,addr) ({___test_and_change_bit(nr,addr)!=0;}) #define set_bit(nr,addr) ((void)___test_and_set_bit(nr,addr)) #define clear_bit(nr,addr) ((void)___test_and_clear_bit(nr,addr)) #define change_bit(nr,addr) ((void)___test_and_change_bit(nr,addr)) @@ -214,8 +214,8 @@ extern long ___test_and_set_le_bit(int nr, volatile void *addr); extern long ___test_and_clear_le_bit(int nr, volatile void *addr); -#define test_and_set_le_bit(nr,addr) (___test_and_set_le_bit(nr,addr)!=0) -#define test_and_clear_le_bit(nr,addr) (___test_and_clear_le_bit(nr,addr)!=0) +#define test_and_set_le_bit(nr,addr) ({___test_and_set_le_bit(nr,addr)!=0;}) +#define test_and_clear_le_bit(nr,addr) ({___test_and_clear_le_bit(nr,addr)!=0;}) #define set_le_bit(nr,addr) ((void)___test_and_set_le_bit(nr,addr)) #define clear_le_bit(nr,addr) ((void)___test_and_clear_le_bit(nr,addr)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/keyboard.h linux-2.5/include/asm-sparc64/keyboard.h --- linux-2.5.1/include/asm-sparc64/keyboard.h Tue Aug 28 14:09:44 2001 +++ linux-2.5/include/asm-sparc64/keyboard.h Thu Dec 27 15:56:12 2001 @@ -38,7 +38,6 @@ #define kbd_init pcikbd_init #define compute_shiftstate pci_compute_shiftstate -#define keyboard_wait_for_keypress pci_wait_for_keypress #define getkeycode pci_getkeycode #define setkeycode pci_setkeycode #define getledstate pci_getledstate diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/page.h linux-2.5/include/asm-sparc64/page.h --- linux-2.5.1/include/asm-sparc64/page.h Thu Aug 10 19:43:12 2000 +++ linux-2.5/include/asm-sparc64/page.h Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.36 2000/08/10 01:04:53 davem Exp $ */ +/* $Id: page.h,v 1.38 2001/11/30 01:04:10 davem Exp $ */ #ifndef _SPARC64_PAGE_H #define _SPARC64_PAGE_H @@ -18,13 +18,20 @@ #ifndef __ASSEMBLY__ +#ifdef CONFIG_DEBUG_BUGVERBOSE +extern void do_BUG(const char *file, int line); +#define BUG() do { \ + do_BUG(__FILE__, __LINE__); \ + __builtin_trap(); \ +} while (0) +#else #define BUG() __builtin_trap() +#endif + #define PAGE_BUG(page) BUG() extern void _clear_page(void *page); -extern void _copy_page(void *to, void *from); #define clear_page(X) _clear_page((void *)(X)) -#define copy_page(X,Y) _copy_page((void *)(X), (void *)(Y)) extern void clear_user_page(void *page, unsigned long vaddr); extern void copy_user_page(void *to, void *from, unsigned long vaddr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/pci.h linux-2.5/include/asm-sparc64/pci.h --- linux-2.5.1/include/asm-sparc64/pci.h Tue Nov 13 17:16:05 2001 +++ linux-2.5/include/asm-sparc64/pci.h Thu Dec 27 16:32:31 2001 @@ -77,6 +77,20 @@ pci_map_single(dev, (page_address(page) + (off)), size, dir) #define pci_unmap_page(dev,addr,sz,dir) pci_unmap_single(dev,addr,sz,dir) +/* pci_unmap_{single,page} is not a nop, thus... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ + __u32 LEN_NAME; +#define PCI_UNMAP_ADDR(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) +#define PCI_UNMAP_ADDR_SET(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) +#define PCI_UNMAP_LEN(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) +#define PCI_UNMAP_LEN_SET(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) + /* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the * above pci_map_single interface. Here the scatter gather list diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/pgtable.h linux-2.5/include/asm-sparc64/pgtable.h --- linux-2.5.1/include/asm-sparc64/pgtable.h Tue Nov 13 17:16:05 2001 +++ linux-2.5/include/asm-sparc64/pgtable.h Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.152 2001/11/12 09:43:39 davem Exp $ +/* $Id: pgtable.h,v 1.154 2001/12/05 06:05:36 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -19,6 +19,23 @@ #include <asm/page.h> #include <asm/processor.h> +/* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 16MB). + * The page copy blockops use 0x1000000 to 0x18000000 (16MB --> 24MB). + * The PROM resides in an area spanning 0xf0000000 to 0x100000000. + * The vmalloc area spans 0x140000000 to 0x200000000. + * There is a single static kernel PMD which maps from 0x0 to address + * 0x400000000. + */ +#define TLBTEMP_BASE 0x0000000001000000 +#define MODULES_VADDR 0x0000000002000000 +#define MODULES_LEN 0x000000007e000000 +#define MODULES_END 0x0000000080000000 +#define VMALLOC_START 0x0000000140000000 +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END 0x0000000200000000 +#define LOW_OBP_ADDRESS 0x00000000f0000000 +#define HI_OBP_ADDRESS 0x0000000100000000 + /* XXX All of this needs to be rethought so we can take advantage * XXX cheetah's full 64-bit virtual address space, ie. no more hole * XXX in the middle like on spitfire. -DaveM @@ -77,13 +94,6 @@ (1) : (PTRS_PER_PGD))) #define FIRST_USER_PGD_NR 0 -/* NOTE: TLB miss handlers depend heavily upon where this is. */ -#define VMALLOC_START 0x0000000140000000UL -#define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END 0x0000000200000000UL -#define LOW_OBP_ADDRESS 0xf0000000UL -#define HI_OBP_ADDRESS 0x100000000UL - #define pte_ERROR(e) __builtin_trap() #define pmd_ERROR(e) __builtin_trap() #define pgd_ERROR(e) __builtin_trap() @@ -290,8 +300,6 @@ #define swp_entry_to_pte(x) ((pte_t) { (x).val }) extern unsigned long prom_virt_to_phys(unsigned long, int *); -#define LOW_OBP_ADDRESS 0xf0000000UL -#define HI_OBP_ADDRESS 0x100000000UL extern __inline__ unsigned long sun4u_get_pte (unsigned long addr) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/processor.h linux-2.5/include/asm-sparc64/processor.h --- linux-2.5.1/include/asm-sparc64/processor.h Thu Oct 11 06:42:47 2001 +++ linux-2.5/include/asm-sparc64/processor.h Thu Dec 27 15:15:00 2001 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.76 2001/10/08 09:32:13 davem Exp $ +/* $Id: processor.h,v 1.80 2001/11/17 00:10:48 davem Exp $ * include/asm-sparc64/processor.h * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -24,7 +24,6 @@ /* Bus types */ #define EISA_bus 0 -#define EISA_bus__is_a_macro /* for versions in ksyms.c */ #define MCA_bus 0 #define MCA_bus__is_a_macro /* for versions in ksyms.c */ @@ -66,6 +65,15 @@ unsigned long gsr[7]; unsigned long xfsr[7]; +#ifdef CONFIG_DEBUG_SPINLOCK + /* How many spinlocks held by this thread. + * Used with spin lock debugging to catch tasks + * sleeping illegally with locks held. + */ + int smp_lock_count; + unsigned int smp_lock_pc; +#endif + struct reg_window reg_window[NSWINS]; unsigned long rwbuf_stkptrs[NSWINS]; @@ -88,6 +96,7 @@ #define FAULT_CODE_ITLB 0x04 /* Miss happened in I-TLB */ #define FAULT_CODE_WINFIXUP 0x08 /* Miss happened during spill/fill */ +#ifndef CONFIG_DEBUG_SPINLOCK #define INIT_THREAD { \ /* ksp, wstate, cwp, flags, current_ds, */ \ 0, 0, 0, 0, KERNEL_DS, \ @@ -104,6 +113,24 @@ /* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \ 0, 0, 0, 0, 0, \ } +#else /* CONFIG_DEBUG_SPINLOCK */ +#define INIT_THREAD { \ +/* ksp, wstate, cwp, flags, current_ds, */ \ + 0, 0, 0, 0, KERNEL_DS, \ +/* w_saved, fpdepth, fault_code, use_blkcommit, */ \ + 0, 0, 0, 0, \ +/* fault_address, fpsaved, __pad2, kregs, */ \ + 0, { 0 }, 0, 0, \ +/* utraps, gsr, xfsr, smp_lock_count, smp_lock_pc, */\ + 0, { 0 }, { 0 }, 0, 0, \ +/* reg_window */ \ + { { { 0, }, { 0, } }, }, \ +/* rwbuf_stkptrs */ \ + { 0, 0, 0, 0, 0, 0, 0, }, \ +/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \ + 0, 0, 0, 0, 0, \ +} +#endif /* !(CONFIG_DEBUG_SPINLOCK) */ #ifdef __KERNEL__ #if PAGE_SHIFT == 13 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/rwsem.h linux-2.5/include/asm-sparc64/rwsem.h --- linux-2.5.1/include/asm-sparc64/rwsem.h Fri Apr 27 05:17:26 2001 +++ linux-2.5/include/asm-sparc64/rwsem.h Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: rwsem.h,v 1.4 2001/04/26 02:36:36 davem Exp $ +/* $Id: rwsem.h,v 1.5 2001/11/18 00:12:56 davem Exp $ * rwsem.h: R/W semaphores implemented using CAS * * Written by David S. Miller (davem@redhat.com), 2001. @@ -59,7 +59,7 @@ " add %%g7, 1, %%g7\n\t" "cmp %%g7, 0\n\t" "bl,pn %%icc, 3f\n\t" - " membar #StoreStore\n" + " membar #StoreLoad | #StoreStore\n" "2:\n\t" ".subsection 2\n" "3:\tmov %0, %%g5\n\t" @@ -92,7 +92,7 @@ "bne,pn %%icc, 1b\n\t" " cmp %%g7, 0\n\t" "bne,pn %%icc, 3f\n\t" - " membar #StoreStore\n" + " membar #StoreLoad | #StoreStore\n" "2:\n\t" ".subsection 2\n" "3:\tmov %0, %%g5\n\t" @@ -122,7 +122,7 @@ "bne,pn %%icc, 1b\n\t" " cmp %%g7, 0\n\t" "bl,pn %%icc, 3f\n\t" - " membar #StoreStore\n" + " membar #StoreLoad | #StoreStore\n" "2:\n\t" ".subsection 2\n" "3:\tsethi %%hi(%2), %%g1\n\t" @@ -160,7 +160,7 @@ " sub %%g7, %%g1, %%g7\n\t" "cmp %%g7, 0\n\t" "bl,pn %%icc, 3f\n\t" - " membar #StoreStore\n" + " membar #StoreLoad | #StoreStore\n" "2:\n\t" ".subsection 2\n" "3:\tmov %0, %%g5\n\t" @@ -189,7 +189,7 @@ "cas [%2], %%g5, %%g7\n\t" "cmp %%g5, %%g7\n\t" "bne,pn %%icc, 1b\n\t" - " nop\n\t" + " membar #StoreLoad | #StoreStore\n\t" "mov %%g7, %0\n\t" : "=&r" (tmp) : "0" (tmp), "r" (sem) @@ -208,7 +208,7 @@ again: __asm__ __volatile__("cas [%2], %3, %0\n\t" - "membar #StoreStore | #StoreLoad" + "membar #StoreLoad | #StoreStore" : "=&r" (prev) : "0" (new), "r" (sem), "r" (old) : "memory"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/semaphore.h linux-2.5/include/asm-sparc64/semaphore.h --- linux-2.5.1/include/asm-sparc64/semaphore.h Sun May 20 18:32:08 2001 +++ linux-2.5/include/asm-sparc64/semaphore.h Thu Dec 13 16:32:37 2001 @@ -75,7 +75,7 @@ " bne,pn %%icc, 1b\n" " cmp %%g7, 1\n" " bl,pn %%icc, 3f\n" -" membar #StoreStore\n" +" membar #StoreLoad | #StoreStore\n" "2:\n" " .subsection 2\n" "3: mov %0, %%g5\n" @@ -120,7 +120,7 @@ " bne,pn %%icc, 1b\n" " cmp %%g7, 1\n" " bl,pn %%icc, 3f\n" -" membar #StoreStore\n" +" membar #StoreLoad | #StoreStore\n" "2:\n" " .subsection 2\n" "3: mov %2, %%g5\n" @@ -173,7 +173,7 @@ " cmp %%g5, %%g7\n" " bne,pn %%icc, 1b\n" " mov 0, %0\n" -" membar #StoreStore\n" +" membar #StoreLoad | #StoreStore\n" "2:\n" : "=&r" (ret) : "r" (sem) @@ -207,7 +207,7 @@ " bne,pn %%icc, 1b\n" " addcc %%g7, 1, %%g0\n" " ble,pn %%icc, 3f\n" -" nop\n" +" membar #StoreLoad | #StoreStore\n" "2:\n" " .subsection 2\n" "3: mov %0, %%g5\n" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/smp.h linux-2.5/include/asm-sparc64/smp.h --- linux-2.5.1/include/asm-sparc64/smp.h Fri Apr 27 05:17:26 2001 +++ linux-2.5/include/asm-sparc64/smp.h Thu Dec 13 16:32:37 2001 @@ -8,6 +8,7 @@ #include <linux/config.h> #include <linux/threads.h> +#include <linux/cache.h> #include <asm/asi.h> #include <asm/starfire.h> #include <asm/spitfire.h> @@ -34,7 +35,7 @@ /* Per processor Sparc parameters we need. */ /* Keep this a multiple of 64-bytes for cache reasons. */ -struct cpuinfo_sparc { +typedef struct { /* Dcache line 1 */ unsigned int __pad0; /* bh_count moved to irq_stat for consistency. KAO */ unsigned int multiplier; @@ -51,9 +52,9 @@ /* Dcache lines 3 and 4 */ unsigned int irq_worklists[16]; -}; +} ____cacheline_aligned cpuinfo_sparc; -extern struct cpuinfo_sparc cpu_data[NR_CPUS]; +extern cpuinfo_sparc cpu_data[NR_CPUS]; /* * Private routines/data diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/smplock.h linux-2.5/include/asm-sparc64/smplock.h --- linux-2.5.1/include/asm-sparc64/smplock.h Thu Mar 23 20:50:09 2000 +++ linux-2.5/include/asm-sparc64/smplock.h Thu Dec 13 16:32:37 2001 @@ -9,7 +9,9 @@ extern spinlock_t kernel_flag; -#define kernel_locked() spin_is_locked(&kernel_flag) +#define kernel_locked() \ + (spin_is_locked(&kernel_flag) &&\ + (current->lock_depth >= 0)) /* * Release global kernel lock and global interrupt lock diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/spinlock.h linux-2.5/include/asm-sparc64/spinlock.h --- linux-2.5.1/include/asm-sparc64/spinlock.h Fri Apr 27 05:17:26 2001 +++ linux-2.5/include/asm-sparc64/spinlock.h Thu Dec 13 16:32:37 2001 @@ -6,11 +6,13 @@ #ifndef __SPARC64_SPINLOCK_H #define __SPARC64_SPINLOCK_H +#include <linux/config.h> + #ifndef __ASSEMBLY__ /* To get debugging spinlocks which detect and catch - * deadlock situations, set DEBUG_SPINLOCKS in the sparc64 - * specific makefile and rebuild your kernel. + * deadlock situations, set CONFIG_DEBUG_SPINLOCK + * and rebuild your kernel. */ /* All of these locking primitives are expected to work properly @@ -26,7 +28,7 @@ * must be pre-V9 branches. */ -#ifndef SPIN_LOCK_DEBUG +#ifndef CONFIG_DEBUG_SPINLOCK typedef unsigned char spinlock_t; #define SPIN_LOCK_UNLOCKED 0 @@ -75,7 +77,7 @@ : "memory"); } -#else /* !(SPIN_LOCK_DEBUG) */ +#else /* !(CONFIG_DEBUG_SPINLOCK) */ typedef struct { unsigned char lock; @@ -101,11 +103,11 @@ #define spin_lock(lock) _do_spin_lock(lock, "spin_lock") #define spin_unlock(lock) _do_spin_unlock(lock) -#endif /* SPIN_LOCK_DEBUG */ +#endif /* CONFIG_DEBUG_SPINLOCK */ /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ -#ifndef SPIN_LOCK_DEBUG +#ifndef CONFIG_DEBUG_SPINLOCK typedef unsigned int rwlock_t; #define RW_LOCK_UNLOCKED 0 @@ -121,7 +123,7 @@ #define write_lock(p) __write_lock(p) #define write_unlock(p) __write_unlock(p) -#else /* !(SPIN_LOCK_DEBUG) */ +#else /* !(CONFIG_DEBUG_SPINLOCK) */ typedef struct { unsigned long lock; @@ -164,7 +166,7 @@ __restore_flags(flags); \ } while(0) -#endif /* SPIN_LOCK_DEBUG */ +#endif /* CONFIG_DEBUG_SPINLOCK */ #endif /* !(__ASSEMBLY__) */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/spitfire.h linux-2.5/include/asm-sparc64/spitfire.h --- linux-2.5.1/include/asm-sparc64/spitfire.h Mon Oct 1 16:19:56 2001 +++ linux-2.5/include/asm-sparc64/spitfire.h Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: spitfire.h,v 1.16 2001/09/24 21:17:57 kanoj Exp $ +/* $Id: spitfire.h,v 1.18 2001/11/29 16:42:10 kanoj Exp $ * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -32,6 +32,8 @@ #define VIRT_WATCHPOINT 0x0000000000000038 #define PHYS_WATCHPOINT 0x0000000000000040 +#define SPITFIRE_HIGHEST_LOCKED_TLBENT (64 - 1) + #ifndef __ASSEMBLY__ enum ultra_tlb_layout { @@ -43,7 +45,6 @@ #define SPARC64_USE_STICK (tlb_type == cheetah) -#define SPITFIRE_HIGHEST_LOCKED_TLBENT (64 - 1) #define CHEETAH_HIGHEST_LOCKED_TLBENT (16 - 1) #define L1DCACHE_SIZE 0x4000 @@ -357,12 +358,17 @@ * 2 way assosciative, and holds 512 entries. The fourth TLB is for * instruction accesses to 8K non-locked translations, is 2 way * assosciative, and holds 128 entries. + * + * Cheetah has some bug where bogus data can be returned from + * ASI_{D,I}TLB_DATA_ACCESS loads, doing the load twice fixes + * the problem for me. -DaveM */ extern __inline__ unsigned long cheetah_get_ldtlb_data(int entry) { unsigned long data; - __asm__ __volatile__("ldxa [%1] %2, %0" + __asm__ __volatile__("ldxa [%1] %2, %%g0\n\t" + "ldxa [%1] %2, %0" : "=r" (data) : "r" ((0 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS)); @@ -374,7 +380,8 @@ { unsigned long data; - __asm__ __volatile__("ldxa [%1] %2, %0" + __asm__ __volatile__("ldxa [%1] %2, %%g0\n\t" + "ldxa [%1] %2, %0" : "=r" (data) : "r" ((0 << 16) | (entry << 3)), "i" (ASI_ITLB_DATA_ACCESS)); @@ -430,7 +437,8 @@ { unsigned long data; - __asm__ __volatile__("ldxa [%1] %2, %0" + __asm__ __volatile__("ldxa [%1] %2, %%g0\n\t" + "ldxa [%1] %2, %0" : "=r" (data) : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS)); @@ -461,7 +469,8 @@ { unsigned long data; - __asm__ __volatile__("ldxa [%1] %2, %0" + __asm__ __volatile__("ldxa [%1] %2, %%g0\n\t" + "ldxa [%1] %2, %0" : "=r" (data) : "r" ((2 << 16) | (entry << 3)), "i" (ASI_ITLB_DATA_ACCESS)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/system.h linux-2.5/include/asm-sparc64/system.h --- linux-2.5.1/include/asm-sparc64/system.h Fri Sep 7 18:01:20 2001 +++ linux-2.5/include/asm-sparc64/system.h Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.64 2001/08/30 03:22:00 kanoj Exp $ */ +/* $Id: system.h,v 1.68 2001/11/18 00:12:56 davem Exp $ */ #ifndef __SPARC64_SYSTEM_H #define __SPARC64_SYSTEM_H @@ -145,6 +145,24 @@ #define flush_register_windows flushw_all #define prepare_to_switch flushw_all +#ifndef CONFIG_DEBUG_SPINLOCk +#define CHECK_LOCKS(PREV) do { } while(0) +#else /* CONFIG_DEBUG_SPINLOCk */ +#define CHECK_LOCKS(PREV) \ +if ((PREV)->thread.smp_lock_count) { \ + unsigned long rpc; \ + __asm__ __volatile__("mov %%i7, %0" : "=r" (rpc)); \ + printk(KERN_CRIT "(%s)[%d]: Sleeping with %d locks held!\n", \ + (PREV)->comm, (PREV)->pid, \ + (PREV)->thread.smp_lock_count); \ + printk(KERN_CRIT "(%s)[%d]: Last lock at %08x\n", \ + (PREV)->comm, (PREV)->pid, \ + (PREV)->thread.smp_lock_pc); \ + printk(KERN_CRIT "(%s)[%d]: Sched caller %016lx\n", \ + (PREV)->comm, (PREV)->pid, rpc); \ +} +#endif /* !(CONFIG_DEBUG_SPINLOCk) */ + /* See what happens when you design the chip correctly? * * We tell gcc we clobber all non-fixed-usage registers except @@ -155,7 +173,8 @@ * and 2 stores in this critical code path. -DaveM */ #define switch_to(prev, next, last) \ -do { if (current->thread.flags & SPARC_FLAG_PERFCTR) { \ +do { CHECK_LOCKS(prev); \ + if (current->thread.flags & SPARC_FLAG_PERFCTR) { \ unsigned long __tmp; \ read_pcr(__tmp); \ current->thread.pcr_reg = __tmp; \ @@ -276,7 +295,7 @@ __cmpxchg_u32(volatile int *m, int old, int new) { __asm__ __volatile__("cas [%2], %3, %0\n\t" - "membar #StoreStore | #StoreLoad" + "membar #StoreLoad | #StoreStore" : "=&r" (new) : "0" (new), "r" (m), "r" (old) : "memory"); @@ -288,7 +307,7 @@ __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) { __asm__ __volatile__("casx [%2], %3, %0\n\t" - "membar #StoreStore | #StoreLoad" + "membar #StoreLoad | #StoreStore" : "=&r" (new) : "0" (new), "r" (m), "r" (old) : "memory"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/asm-sparc64/ttable.h linux-2.5/include/asm-sparc64/ttable.h --- linux-2.5.1/include/asm-sparc64/ttable.h Thu Apr 12 19:10:25 2001 +++ linux-2.5/include/asm-sparc64/ttable.h Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: ttable.h,v 1.16 2001/03/28 10:56:34 davem Exp $ */ +/* $Id: ttable.h,v 1.17 2001/11/28 23:32:16 davem Exp $ */ #ifndef _SPARC64_TTABLE_H #define _SPARC64_TTABLE_H @@ -29,6 +29,15 @@ clr %l6; \ nop; +#define TRAP_7INSNS(routine) \ + sethi %hi(109f), %g7; \ + ba,pt %xcc, etrap; \ +109: or %g7, %lo(109b), %g7; \ + call routine; \ + add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ + ba,pt %xcc, rtrap; \ + clr %l6; + #define TRAP_SAVEFPU(routine) \ sethi %hi(109f), %g7; \ ba,pt %xcc, do_fptrap; \ @@ -43,6 +52,11 @@ ba,pt %xcc, routine; \ nop; \ nop; nop; nop; nop; nop; nop; + +#define TRAP_NOSAVE_7INSNS(routine) \ + ba,pt %xcc, routine; \ + nop; \ + nop; nop; nop; nop; nop; #define TRAPTL1(routine) \ sethi %hi(109f), %g7; \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/acct.h linux-2.5/include/linux/acct.h --- linux-2.5.1/include/linux/acct.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/acct.h Mon Jan 14 14:31:05 2002 @@ -76,7 +76,7 @@ #include <linux/config.h> #ifdef CONFIG_BSD_PROCESS_ACCT -extern void acct_auto_close(kdev_t dev); +extern void acct_auto_close(struct super_block *sb); extern int acct_process(long exitcode); #else #define acct_auto_close(x) do { } while (0) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/amigaffs.h linux-2.5/include/linux/amigaffs.h --- linux-2.5.1/include/linux/amigaffs.h Sun Dec 16 20:23:05 2001 +++ linux-2.5/include/linux/amigaffs.h Thu Dec 27 15:56:12 2001 @@ -23,8 +23,7 @@ static inline void affs_set_blocksize(struct super_block *sb, int size) { - set_blocksize(sb->s_dev, size); - sb->s_blocksize = size; + sb_set_blocksize(sb, size); } static inline struct buffer_head * affs_bread(struct super_block *sb, int block) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/bio.h linux-2.5/include/linux/bio.h --- linux-2.5.1/include/linux/bio.h Sun Dec 16 23:43:49 2001 +++ linux-2.5/include/linux/bio.h Mon Jan 14 14:31:52 2002 @@ -35,6 +35,7 @@ #endif #define BIO_MAX_SECTORS 128 +#define BIO_MAX_SIZE (BIO_MAX_SECTORS << 9) /* * was unsigned short, but we might as well be ready for > 64kB I/O pages diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/blk.h linux-2.5/include/linux/blk.h --- linux-2.5.1/include/linux/blk.h Sun Dec 16 23:45:06 2001 +++ linux-2.5/include/linux/blk.h Mon Jan 14 14:33:25 2002 @@ -2,6 +2,7 @@ #define _BLK_H #include <linux/blkdev.h> +#include <linux/elevator.h> #include <linux/locks.h> #include <linux/config.h> #include <linux/spinlock.h> @@ -20,7 +21,6 @@ #define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */ extern unsigned long initrd_start,initrd_end; -extern int mount_initrd; /* zero if initrd should not be mounted */ extern int initrd_below_start_ok; /* 1 if it is not an error if initrd_start < memory_start */ extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ @@ -44,9 +44,10 @@ static inline void blkdev_dequeue_request(struct request *req) { list_del(&req->queuelist); -} -#define __elv_next_request(q) (q)->elevator.elevator_next_req_fn((q)) + if (req->q) + elv_remove_request(req->q, req); +} extern inline struct request *elv_next_request(request_queue_t *q) { @@ -55,6 +56,9 @@ while ((rq = __elv_next_request(q))) { rq->flags |= REQ_STARTED; + if (&rq->queuelist == q->last_merge) + q->last_merge = NULL; + if ((rq->flags & REQ_DONTPREP) || !q->prep_rq_fn) break; @@ -77,21 +81,21 @@ return rq; } -#define __elv_add_request_core(q, rq, where, plug) \ +#define _elv_add_request_core(q, rq, where, plug) \ do { \ if ((plug)) \ blk_plug_device((q)); \ (q)->elevator.elevator_add_req_fn((q), (rq), (where)); \ } while (0) -#define __elv_add_request(q, rq, back, p) do { \ +#define _elv_add_request(q, rq, back, p) do { \ if ((back)) \ - __elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \ + _elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \ else \ - __elv_add_request_core((q), (rq), &(q)->queue_head, 0); \ + _elv_add_request_core((q), (rq), &(q)->queue_head, 0); \ } while (0) -#define elv_add_request(q, rq, back) __elv_add_request((q), (rq), (back), 1) +#define elv_add_request(q, rq, back) _elv_add_request((q), (rq), (back), 1) #if defined(MAJOR_NR) || defined(IDE_DRIVER) @@ -104,14 +108,14 @@ #ifdef IDE_DRIVER -#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS) +#define DEVICE_NR(device) (minor(device) >> PARTN_BITS) #define DEVICE_NAME "ide" #elif (MAJOR_NR == RAMDISK_MAJOR) /* ram disk */ #define DEVICE_NAME "ramdisk" -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #define DEVICE_NO_RANDOM #elif (MAJOR_NR == Z2RAM_MAJOR) @@ -119,7 +123,7 @@ /* Zorro II Ram */ #define DEVICE_NAME "Z2RAM" #define DEVICE_REQUEST do_z2_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == FLOPPY_MAJOR) @@ -128,7 +132,7 @@ #define DEVICE_NAME "floppy" #define DEVICE_INTR do_floppy #define DEVICE_REQUEST do_fd_request -#define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 )) +#define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 )) #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) #elif (MAJOR_NR == HD_MAJOR) @@ -138,188 +142,188 @@ #define DEVICE_INTR do_hd #define TIMEOUT_VALUE (6*HZ) #define DEVICE_REQUEST do_hd_request -#define DEVICE_NR(device) (MINOR(device)>>6) +#define DEVICE_NR(device) (minor(device)>>6) #elif (SCSI_DISK_MAJOR(MAJOR_NR)) #define DEVICE_NAME "scsidisk" #define TIMEOUT_VALUE (2*HZ) -#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4)) +#define DEVICE_NR(device) (((major(device) & SD_MAJOR_MASK) << (8 - 4)) + (minor(device) >> 4)) /* Kludge to use the same number for both char and block major numbers */ #elif (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER) #define DEVICE_NAME "Multiple devices driver" #define DEVICE_REQUEST do_md_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == SCSI_TAPE_MAJOR) #define DEVICE_NAME "scsitape" #define DEVICE_INTR do_st -#define DEVICE_NR(device) (MINOR(device) & 0x7f) +#define DEVICE_NR(device) (minor(device) & 0x7f) #elif (MAJOR_NR == OSST_MAJOR) #define DEVICE_NAME "onstream" #define DEVICE_INTR do_osst -#define DEVICE_NR(device) (MINOR(device) & 0x7f) +#define DEVICE_NR(device) (minor(device) & 0x7f) #define DEVICE_ON(device) #define DEVICE_OFF(device) #elif (MAJOR_NR == SCSI_CDROM_MAJOR) #define DEVICE_NAME "CD-ROM" -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == XT_DISK_MAJOR) #define DEVICE_NAME "xt disk" #define DEVICE_REQUEST do_xd_request -#define DEVICE_NR(device) (MINOR(device) >> 6) +#define DEVICE_NR(device) (minor(device) >> 6) #elif (MAJOR_NR == PS2ESDI_MAJOR) #define DEVICE_NAME "PS/2 ESDI" #define DEVICE_REQUEST do_ps2esdi_request -#define DEVICE_NR(device) (MINOR(device) >> 6) +#define DEVICE_NR(device) (minor(device) >> 6) #elif (MAJOR_NR == CDU31A_CDROM_MAJOR) #define DEVICE_NAME "CDU31A" #define DEVICE_REQUEST do_cdu31a_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == ACSI_MAJOR) && (defined(CONFIG_ATARI_ACSI) || defined(CONFIG_ATARI_ACSI_MODULE)) #define DEVICE_NAME "ACSI" #define DEVICE_INTR do_acsi #define DEVICE_REQUEST do_acsi_request -#define DEVICE_NR(device) (MINOR(device) >> 4) +#define DEVICE_NR(device) (minor(device) >> 4) #elif (MAJOR_NR == MITSUMI_CDROM_MAJOR) #define DEVICE_NAME "Mitsumi CD-ROM" /* #define DEVICE_INTR do_mcd */ #define DEVICE_REQUEST do_mcd_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR) #define DEVICE_NAME "Mitsumi CD-ROM" /* #define DEVICE_INTR do_mcdx */ #define DEVICE_REQUEST do_mcdx_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR) #define DEVICE_NAME "Matsushita CD-ROM controller #1" #define DEVICE_REQUEST do_sbpcd_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR) #define DEVICE_NAME "Matsushita CD-ROM controller #2" #define DEVICE_REQUEST do_sbpcd2_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR) #define DEVICE_NAME "Matsushita CD-ROM controller #3" #define DEVICE_REQUEST do_sbpcd3_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR) #define DEVICE_NAME "Matsushita CD-ROM controller #4" #define DEVICE_REQUEST do_sbpcd4_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == AZTECH_CDROM_MAJOR) #define DEVICE_NAME "Aztech CD-ROM" #define DEVICE_REQUEST do_aztcd_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == CDU535_CDROM_MAJOR) #define DEVICE_NAME "SONY-CDU535" #define DEVICE_INTR do_cdu535 #define DEVICE_REQUEST do_cdu535_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR) #define DEVICE_NAME "Goldstar R420" #define DEVICE_REQUEST do_gscd_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == CM206_CDROM_MAJOR) #define DEVICE_NAME "Philips/LMS CD-ROM cm206" #define DEVICE_REQUEST do_cm206_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == OPTICS_CDROM_MAJOR) #define DEVICE_NAME "DOLPHIN 8000AT CD-ROM" #define DEVICE_REQUEST do_optcd_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == SANYO_CDROM_MAJOR) #define DEVICE_NAME "Sanyo H94A CD-ROM" #define DEVICE_REQUEST do_sjcd_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == APBLOCK_MAJOR) #define DEVICE_NAME "apblock" #define DEVICE_REQUEST ap_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == DDV_MAJOR) #define DEVICE_NAME "ddv" #define DEVICE_REQUEST ddv_request -#define DEVICE_NR(device) (MINOR(device)>>PARTN_BITS) +#define DEVICE_NR(device) (minor(device)>>PARTN_BITS) #elif (MAJOR_NR == MFM_ACORN_MAJOR) #define DEVICE_NAME "mfm disk" #define DEVICE_INTR do_mfm #define DEVICE_REQUEST do_mfm_request -#define DEVICE_NR(device) (MINOR(device) >> 6) +#define DEVICE_NR(device) (minor(device) >> 6) #elif (MAJOR_NR == NBD_MAJOR) #define DEVICE_NAME "nbd" #define DEVICE_REQUEST do_nbd_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == MDISK_MAJOR) #define DEVICE_NAME "mdisk" #define DEVICE_REQUEST mdisk_request -#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NR(device) (minor(device)) #elif (MAJOR_NR == DASD_MAJOR) #define DEVICE_NAME "dasd" #define DEVICE_REQUEST do_dasd_request -#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS) +#define DEVICE_NR(device) (minor(device) >> PARTN_BITS) #elif (MAJOR_NR == I2O_MAJOR) #define DEVICE_NAME "I2O block" #define DEVICE_REQUEST i2ob_request -#define DEVICE_NR(device) (MINOR(device)>>4) +#define DEVICE_NR(device) (minor(device)>>4) #elif (MAJOR_NR == COMPAQ_SMART2_MAJOR) #define DEVICE_NAME "ida" #define TIMEOUT_VALUE (25*HZ) #define DEVICE_REQUEST do_ida_request -#define DEVICE_NR(device) (MINOR(device) >> 4) +#define DEVICE_NR(device) (minor(device) >> 4) #endif /* MAJOR_NR == whatever */ @@ -373,7 +377,7 @@ CLEAR_INTR; \ return; \ } \ - if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \ + if (major(CURRENT->rq_dev) != MAJOR_NR) \ panic(DEVICE_NAME ": request list destroyed"); \ if (!CURRENT->bio) \ panic(DEVICE_NAME ": no bio"); \ @@ -393,7 +397,7 @@ return; #ifndef DEVICE_NO_RANDOM - add_blkdev_randomness(MAJOR(req->rq_dev)); + add_blkdev_randomness(major(req->rq_dev)); #endif DEVICE_OFF(req->rq_dev); blkdev_dequeue_request(req); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/blkdev.h linux-2.5/include/linux/blkdev.h --- linux-2.5.1/include/linux/blkdev.h Sun Dec 16 23:43:29 2001 +++ linux-2.5/include/linux/blkdev.h Mon Jan 14 14:32:30 2002 @@ -6,7 +6,7 @@ #include <linux/genhd.h> #include <linux/tqueue.h> #include <linux/list.h> -#include <linux/mm.h> +#include <linux/pagemap.h> #include <asm/scatterlist.h> @@ -25,7 +25,7 @@ struct list_head queuelist; /* looking for ->queue? you must _not_ * access it directly, use * blkdev_dequeue_request! */ - int elevator_sequence; + void *elevator_private; unsigned char cmd[16]; @@ -130,16 +130,17 @@ struct request_queue { /* - * the queue request freelist, one for reads and one for writes - */ - struct request_list rq[2]; - - /* * Together with queue_head for cacheline sharing */ struct list_head queue_head; + struct list_head *last_merge; elevator_t elevator; + /* + * the queue request freelist, one for reads and one for writes + */ + struct request_list rq[2]; + request_fn_proc *request_fn; merge_request_fn *back_merge_fn; merge_request_fn *front_merge_fn; @@ -195,8 +196,7 @@ #define RQ_SCSI_DISCONNECTING 0xffe0 #define QUEUE_FLAG_PLUGGED 0 /* queue is plugged */ -#define QUEUE_FLAG_NOSPLIT 1 /* can process bio over several goes */ -#define QUEUE_FLAG_CLUSTER 2 /* cluster several segments into 1 */ +#define QUEUE_FLAG_CLUSTER 1 /* cluster several segments into 1 */ #define blk_queue_plugged(q) test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags) #define blk_mark_plugged(q) set_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags) @@ -206,6 +206,14 @@ #define rq_data_dir(rq) ((rq)->flags & 1) /* + * mergeable request must not have _NOMERGE or _BARRIER bit set, nor may + * it already be started by driver. + */ +#define rq_mergeable(rq) \ + (!((rq)->flags & (REQ_NOMERGE | REQ_STARTED | REQ_BARRIER)) \ + && ((rq)->flags & REQ_CMD)) + +/* * noop, requests are automagically marked as active/inactive by I/O * scheduler -- see elv_next_request */ @@ -213,27 +221,25 @@ extern unsigned long blk_max_low_pfn, blk_max_pfn; -#define BLK_BOUNCE_HIGH (blk_max_low_pfn << PAGE_SHIFT) -#define BLK_BOUNCE_ANY (blk_max_pfn << PAGE_SHIFT) -#define BLK_BOUNCE_ISA (ISA_DMA_THRESHOLD) - -#ifdef CONFIG_HIGHMEM +/* + * standard bounce addresses: + * + * BLK_BOUNCE_HIGH : bounce all highmem pages + * BLK_BOUNCE_ANY : don't bounce anything + * BLK_BOUNCE_ISA : bounce pages above ISA DMA boundary + */ +#define BLK_BOUNCE_HIGH (blk_max_low_pfn << PAGE_SHIFT) +#define BLK_BOUNCE_ANY (blk_max_pfn << PAGE_SHIFT) +#define BLK_BOUNCE_ISA (ISA_DMA_THRESHOLD) +extern int init_emergency_isa_pool(void); extern void create_bounce(unsigned long pfn, int gfp, struct bio **bio_orig); -extern void init_emergency_isa_pool(void); extern inline void blk_queue_bounce(request_queue_t *q, struct bio **bio) { create_bounce(q->bounce_pfn, q->bounce_gfp, bio); } -#else /* CONFIG_HIGHMEM */ - -#define blk_queue_bounce(q, bio) do { } while (0) -#define init_emergency_isa_pool() do { } while (0) - -#endif /* CONFIG_HIGHMEM */ - #define rq_for_each_bio(bio, rq) \ if ((rq->bio)) \ for (bio = (rq)->bio; bio; bio = bio->bi_next) @@ -275,9 +281,13 @@ extern void blk_recount_segments(request_queue_t *, struct bio *); extern inline int blk_phys_contig_segment(request_queue_t *q, struct bio *, struct bio *); extern inline int blk_hw_contig_segment(request_queue_t *q, struct bio *, struct bio *); -extern void blk_queue_assign_lock(request_queue_t *q, spinlock_t *); - extern int block_ioctl(kdev_t, unsigned int, unsigned long); +extern int ll_10byte_cmd_build(request_queue_t *, struct request *); + +/* + * get ready for proper ref counting + */ +#define blk_put_queue(q) do { } while (0) /* * Access functions for manipulating queue properties @@ -292,6 +302,9 @@ extern void blk_queue_max_segment_size(request_queue_t *q, unsigned int); extern void blk_queue_hardsect_size(request_queue_t *q, unsigned short); extern void blk_queue_segment_boundary(request_queue_t *q, unsigned long); +extern void blk_queue_assign_lock(request_queue_t *q, spinlock_t *); +extern void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn); + extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *); extern void blk_dump_rq_flags(struct request *, char *); extern void generic_unplug_device(void *); @@ -358,14 +371,23 @@ extern inline unsigned int block_size(kdev_t dev) { int retval = BLOCK_SIZE; - int major = MAJOR(dev); + int major = major(dev); if (blksize_size[major]) { - int minor = MINOR(dev); + int minor = minor(dev); if (blksize_size[major][minor]) retval = blksize_size[major][minor]; } return retval; +} + +typedef struct {struct page *v;} Sector; + +unsigned char *read_dev_sector(struct block_device *, unsigned long, Sector *); + +static inline void put_dev_sector(Sector p) +{ + page_cache_release(p.v); } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/cdrom.h linux-2.5/include/linux/cdrom.h --- linux-2.5.1/include/linux/cdrom.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/cdrom.h Mon Jan 14 14:31:07 2002 @@ -792,7 +792,7 @@ sprintf (vname, "cdroms/cdrom%d", cdi->number); cdi->de = devfs_register (NULL, vname, DEVFS_FL_DEFAULT, - MAJOR (cdi->dev), MINOR (cdi->dev), + major(cdi->dev), minor(cdi->dev), S_IFBLK | S_IRUGO | S_IWUGO, ops, NULL); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/console.h linux-2.5/include/linux/console.h --- linux-2.5.1/include/linux/console.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/console.h Mon Jan 14 14:31:06 2002 @@ -97,7 +97,6 @@ void (*write)(struct console *, const char *, unsigned); int (*read)(struct console *, const char *, unsigned); kdev_t (*device)(struct console *); - int (*wait_key)(struct console *); void (*unblank)(void); int (*setup)(struct console *, char *); short flags; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/console_struct.h linux-2.5/include/linux/console_struct.h --- linux-2.5.1/include/linux/console_struct.h Thu Oct 11 18:17:22 2001 +++ linux-2.5/include/linux/console_struct.h Tue Jan 1 20:35:32 2002 @@ -33,6 +33,7 @@ unsigned int vc_top, vc_bottom; /* Scrolling region */ unsigned int vc_state; /* Escape sequence parser state */ unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */ + struct tty_struct *vc_tty; /* TTY we are attached to */ unsigned long vc_origin; /* [!] Start of real screen */ unsigned long vc_scr_end; /* [!] End of real screen */ unsigned long vc_visible_origin; /* [!] Top of visible window */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/cyclades.h linux-2.5/include/linux/cyclades.h --- linux-2.5.1/include/linux/cyclades.h Fri May 12 18:22:31 2000 +++ linux-2.5/include/linux/cyclades.h Thu Jan 10 22:24:14 2002 @@ -503,6 +503,7 @@ #endif /* Per card data structure */ +struct resource; struct cyclades_card { unsigned long base_phys; unsigned long ctl_phys; @@ -514,10 +515,13 @@ int nports; /* Number of ports in the card */ int bus_index; /* address shift - 0 for ISA, 1 for PCI */ int intr_enabled; /* FW Interrupt flag - 0 disabled, 1 enabled */ + struct resource *resource; + unsigned long res_start; + unsigned long res_len; #ifdef __KERNEL__ spinlock_t card_lock; #else - uclong filler; + unsigned long filler; #endif }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/devfs_fs.h linux-2.5/include/linux/devfs_fs.h --- linux-2.5.1/include/linux/devfs_fs.h Fri Sep 21 17:55:23 2001 +++ linux-2.5/include/linux/devfs_fs.h Thu Dec 27 21:41:29 2001 @@ -26,7 +26,7 @@ binary interface will change */ struct devfsd_notify_struct -{ +{ /* Use native C types to ensure same types in kernel and user space */ unsigned int type; /* DEVFSD_NOTIFY_* value */ unsigned int mode; /* Mode of the inode or device entry */ unsigned int major; /* Major number of device entry */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/devfs_fs_kernel.h linux-2.5/include/linux/devfs_fs_kernel.h --- linux-2.5.1/include/linux/devfs_fs_kernel.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/devfs_fs_kernel.h Mon Jan 14 14:31:06 2002 @@ -37,8 +37,7 @@ */ #define DEVFS_FL_REMOVABLE 0x010 /* This is a removable media device */ #define DEVFS_FL_WAIT 0x020 /* Wait for devfsd to finish */ -#define DEVFS_FL_NO_PERSISTENCE 0x040 /* Forget changes after unregister */ -#define DEVFS_FL_CURRENT_OWNER 0x080 /* Set initial ownership to current */ +#define DEVFS_FL_CURRENT_OWNER 0x040 /* Set initial ownership to current */ #define DEVFS_FL_DEFAULT DEVFS_FL_NONE @@ -61,6 +60,7 @@ #define UNIQUE_NUMBERSPACE_INITIALISER {SPIN_LOCK_UNLOCKED, 0, 0, 0, NULL} +extern void devfs_put (devfs_handle_t de); extern devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, unsigned int flags, unsigned int major, unsigned int minor, @@ -71,6 +71,9 @@ devfs_handle_t *handle, void *info); extern devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info); +extern devfs_handle_t devfs_get_handle (devfs_handle_t dir, const char *name, + unsigned int major,unsigned int minor, + char type, int traverse_symlinks); extern devfs_handle_t devfs_find_handle (devfs_handle_t dir, const char *name, unsigned int major,unsigned int minor, char type, int traverse_symlinks); @@ -81,6 +84,7 @@ extern devfs_handle_t devfs_get_handle_from_inode (struct inode *inode); extern int devfs_generate_path (devfs_handle_t de, char *path, int buflen); extern void *devfs_get_ops (devfs_handle_t de); +extern void devfs_put_ops (devfs_handle_t de); extern int devfs_set_file_size (devfs_handle_t de, unsigned long size); extern void *devfs_get_info (devfs_handle_t de); extern int devfs_set_info (devfs_handle_t de, void *info); @@ -112,7 +116,6 @@ int number); extern void mount_devfs_fs (void); -extern void devfs_make_root (const char *name); #else /* CONFIG_DEVFS_FS */ @@ -123,6 +126,10 @@ #define UNIQUE_NUMBERSPACE_INITIALISER {0} +static inline void devfs_put (devfs_handle_t de) +{ + return; +} static inline devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, unsigned int flags, @@ -148,6 +155,15 @@ { return NULL; } +static inline devfs_handle_t devfs_get_handle (devfs_handle_t dir, + const char *name, + unsigned int major, + unsigned int minor, + char type, + int traverse_symlinks) +{ + return NULL; +} static inline devfs_handle_t devfs_find_handle (devfs_handle_t dir, const char *name, unsigned int major, @@ -183,6 +199,10 @@ { return NULL; } +static inline void devfs_put_ops (devfs_handle_t de) +{ + return; +} static inline int devfs_set_file_size (devfs_handle_t de, unsigned long size) { return -ENOSYS; @@ -288,10 +308,6 @@ } static inline void mount_devfs_fs (void) -{ - return; -} -static inline void devfs_make_root (const char *name) { return; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/eeprom.h linux-2.5/include/linux/eeprom.h --- linux-2.5.1/include/linux/eeprom.h Thu Sep 20 21:20:14 2001 +++ linux-2.5/include/linux/eeprom.h Mon Jan 7 21:33:11 2002 @@ -1,6 +1,7 @@ /* credit winbond-840.c */ #include <asm/io.h> + struct eeprom_ops { void (*set_cs)(void *ee); void (*clear_cs)(void *ee); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/elevator.h linux-2.5/include/linux/elevator.h --- linux-2.5.1/include/linux/elevator.h Wed Nov 28 16:49:23 2001 +++ linux-2.5/include/linux/elevator.h Thu Jan 3 23:04:40 2002 @@ -1,12 +1,8 @@ #ifndef _LINUX_ELEVATOR_H #define _LINUX_ELEVATOR_H -typedef void (elevator_fn) (struct request *, elevator_t *, - struct list_head *, - struct list_head *, int); - typedef int (elevator_merge_fn) (request_queue_t *, struct request **, - struct list_head *, struct bio *); + struct bio *); typedef void (elevator_merge_cleanup_fn) (request_queue_t *, struct request *, int); @@ -15,37 +11,53 @@ typedef struct request *(elevator_next_req_fn) (request_queue_t *); typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, struct list_head *); +typedef int (elevator_queue_empty_fn) (request_queue_t *); +typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *); typedef int (elevator_init_fn) (request_queue_t *, elevator_t *); typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *); struct elevator_s { - int read_latency; - int write_latency; - elevator_merge_fn *elevator_merge_fn; elevator_merge_cleanup_fn *elevator_merge_cleanup_fn; elevator_merge_req_fn *elevator_merge_req_fn; elevator_next_req_fn *elevator_next_req_fn; elevator_add_req_fn *elevator_add_req_fn; + elevator_remove_req_fn *elevator_remove_req_fn; + + elevator_queue_empty_fn *elevator_queue_empty_fn; elevator_init_fn *elevator_init_fn; elevator_exit_fn *elevator_exit_fn; + + void *elevator_data; }; -int elevator_noop_merge(request_queue_t *, struct request **, struct list_head *, struct bio *); -void elevator_noop_merge_cleanup(request_queue_t *, struct request *, int); -void elevator_noop_merge_req(struct request *, struct request *); - -int elevator_linus_merge(request_queue_t *, struct request **, struct list_head *, struct bio *); -void elevator_linus_merge_cleanup(request_queue_t *, struct request *, int); -void elevator_linus_merge_req(struct request *, struct request *); -int elv_linus_init(request_queue_t *, elevator_t *); -void elv_linus_exit(request_queue_t *, elevator_t *); -struct request *elv_next_request_fn(request_queue_t *); -void elv_add_request_fn(request_queue_t *, struct request *,struct list_head *); +/* + * block elevator interface + */ +extern void __elv_add_request(request_queue_t *, struct request *, + struct list_head *); +extern struct request *__elv_next_request(request_queue_t *); +extern void elv_merge_cleanup(request_queue_t *, struct request *, int); +extern int elv_merge(request_queue_t *, struct request **, struct bio *); +extern void elv_merge_requests(request_queue_t *, struct request *, + struct request *); +extern void elv_remove_request(request_queue_t *, struct request *); + +/* + * noop I/O scheduler. always merges, always inserts new request at tail + */ +extern elevator_t elevator_noop; + +/* + * elevator linus. based on linus ideas of starvation control, using + * sequencing to manage inserts and merges. + */ +extern elevator_t elevator_linus; +#define elv_linus_sequence(rq) ((long)(rq)->elevator_private) /* * use the /proc/iosched interface, all the below is history -> @@ -70,76 +82,9 @@ #define ELEVATOR_BACK_MERGE 2 /* - * This is used in the elevator algorithm. We don't prioritise reads - * over writes any more --- although reads are more time-critical than - * writes, by treating them equally we increase filesystem throughput. - * This turns out to give better overall performance. -- sct - */ -#define IN_ORDER(s1,s2) \ - ((((s1)->rq_dev == (s2)->rq_dev && \ - (s1)->sector < (s2)->sector)) || \ - (s1)->rq_dev < (s2)->rq_dev) - -#define BHRQ_IN_ORDER(bh, rq) \ - ((((bh)->b_rdev == (rq)->rq_dev && \ - (bh)->b_rsector < (rq)->sector)) || \ - (bh)->b_rdev < (rq)->rq_dev) - -static inline int elevator_request_latency(elevator_t * elevator, int rw) -{ - int latency; - - latency = elevator->read_latency; - if (rw != READ) - latency = elevator->write_latency; - - return latency; -} - -/* * will change once we move to a more complex data structure than a simple * list for pending requests */ #define elv_queue_empty(q) list_empty(&(q)->queue_head) - -/* - * elevator private data - */ -struct elv_linus_data { - unsigned long flags; -}; - -#define ELV_DAT(e) ((struct elv_linus_data *)(e)->elevator_data) - -#define ELV_LINUS_BACK_MERGE 1 -#define ELV_LINUS_FRONT_MERGE 2 - -#define ELEVATOR_NOOP \ -((elevator_t) { \ - 0, /* read_latency */ \ - 0, /* write_latency */ \ - \ - elevator_noop_merge, /* elevator_merge_fn */ \ - elevator_noop_merge_cleanup, /* elevator_merge_cleanup_fn */ \ - elevator_noop_merge_req, /* elevator_merge_req_fn */ \ - elv_next_request_fn, \ - elv_add_request_fn, \ - elv_linus_init, \ - elv_linus_exit, \ - }) - -#define ELEVATOR_LINUS \ -((elevator_t) { \ - 8192, /* read passovers */ \ - 16384, /* write passovers */ \ - \ - elevator_linus_merge, /* elevator_merge_fn */ \ - elevator_linus_merge_cleanup, /* elevator_merge_cleanup_fn */ \ - elevator_linus_merge_req, /* elevator_merge_req_fn */ \ - elv_next_request_fn, \ - elv_add_request_fn, \ - elv_linus_init, \ - elv_linus_exit, \ - }) #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/ext2_fs_sb.h linux-2.5/include/linux/ext2_fs_sb.h --- linux-2.5.1/include/linux/ext2_fs_sb.h Fri Dec 29 22:36:44 2000 +++ linux-2.5/include/linux/ext2_fs_sb.h Fri Dec 28 00:06:33 2001 @@ -56,6 +56,7 @@ int s_desc_per_block_bits; int s_inode_size; int s_first_ino; + u32 s_next_generation; }; #endif /* _LINUX_EXT2_FS_SB */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/ext3_fs.h linux-2.5/include/linux/ext3_fs.h --- linux-2.5.1/include/linux/ext3_fs.h Fri Nov 9 22:25:04 2001 +++ linux-2.5/include/linux/ext3_fs.h Thu Dec 13 16:32:37 2001 @@ -36,8 +36,8 @@ /* * The second extended file system version */ -#define EXT3FS_DATE "06 Nov 2001" -#define EXT3FS_VERSION "2.4-0.9.15" +#define EXT3FS_DATE "02 Dec 2001" +#define EXT3FS_VERSION "2.4-0.9.16" /* * Debug code @@ -577,10 +577,6 @@ ~EXT3_DIR_ROUND) #ifdef __KERNEL__ - -/* Filesize hard limits for 64-bit file offsets */ -extern long long ext3_max_sizes[]; - /* * Describe an inode's exact location on disk and in memory */ @@ -603,9 +599,6 @@ # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, -/* acl.c */ -extern int ext3_permission (struct inode *, int); - /* balloc.c */ extern int ext3_bg_has_super(struct super_block *sb, int group); extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group); @@ -619,16 +612,10 @@ unsigned int block_group, struct buffer_head ** bh); -/* bitmap.c */ -extern unsigned long ext3_count_free (struct buffer_head *, unsigned); - /* dir.c */ extern int ext3_check_dir_entry(const char *, struct inode *, struct ext3_dir_entry_2 *, struct buffer_head *, unsigned long); - -/* file.c */ - /* fsync.c */ extern int ext3_sync_file (struct file *, struct dentry *, int); @@ -638,9 +625,9 @@ extern struct inode * ext3_orphan_get (struct super_block *, ino_t); extern unsigned long ext3_count_free_inodes (struct super_block *); extern void ext3_check_inodes_bitmap (struct super_block *); +extern unsigned long ext3_count_free (struct buffer_head *, unsigned); /* inode.c */ - extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *); extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *); @@ -654,13 +641,13 @@ extern void ext3_discard_prealloc (struct inode *); extern void ext3_dirty_inode(struct inode *); extern int ext3_change_inode_journal_flag(struct inode *, int); +extern void ext3_truncate (struct inode *); /* ioctl.c */ extern int ext3_ioctl (struct inode *, struct file *, unsigned int, unsigned long); /* namei.c */ -extern struct inode_operations ext3_dir_inode_operations; extern int ext3_orphan_add(handle_t *, struct inode *); extern int ext3_orphan_del(handle_t *, struct inode *); @@ -684,9 +671,6 @@ extern struct super_block * ext3_read_super (struct super_block *,void *,int); extern int ext3_statfs (struct super_block *, struct statfs *); -/* truncate.c */ -extern void ext3_truncate (struct inode *); - #define ext3_std_error(sb, errno) \ do { \ if ((errno)) \ @@ -705,10 +689,15 @@ extern struct inode_operations ext3_file_inode_operations; extern struct file_operations ext3_file_operations; +/* inode.c */ +extern struct address_space_operations ext3_aops; + +/* namei.c */ +extern struct inode_operations ext3_dir_inode_operations; + /* symlink.c */ extern struct inode_operations ext3_fast_symlink_inode_operations; -extern struct address_space_operations ext3_aops; #endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/ext3_jbd.h linux-2.5/include/linux/ext3_jbd.h --- linux-2.5.1/include/linux/ext3_jbd.h Fri Nov 9 22:25:04 2001 +++ linux-2.5/include/linux/ext3_jbd.h Thu Dec 13 16:32:37 2001 @@ -196,9 +196,22 @@ */ static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks) { + journal_t *journal; + if (inode->i_sb->s_flags & MS_RDONLY) return ERR_PTR(-EROFS); - return journal_start(EXT3_JOURNAL(inode), nblocks); + + /* Special case here: if the journal has aborted behind our + * backs (eg. EIO in the commit thread), then we still need to + * take the FS itself readonly cleanly. */ + journal = EXT3_JOURNAL(inode); + if (is_journal_aborted(journal)) { + ext3_abort(inode->i_sb, __FUNCTION__, + "Detected aborted journal"); + return ERR_PTR(-EROFS); + } + + return journal_start(journal, nblocks); } static inline handle_t * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/fb.h linux-2.5/include/linux/fb.h --- linux-2.5.1/include/linux/fb.h Mon Dec 11 21:16:53 2000 +++ linux-2.5/include/linux/fb.h Mon Jan 14 23:58:39 2002 @@ -241,19 +241,52 @@ __u32 reserved[4]; /* reserved for future compatibility */ }; +/* Internal HW accel */ +#define ROP_COPY 0 +#define ROP_XOR 1 + +struct fb_copyarea { + __u32 sx; /* screen-relative */ + __u32 sy; + __u32 width; + __u32 height; + __u32 dx; + __u32 dy; +}; + +struct fb_fillrect { + __u32 dx; /* screen-relative */ + __u32 dy; + __u32 width; + __u32 height; + __u32 color; + __u32 rop; +}; + +struct fb_image { + __u32 width; /* Size of image */ + __u32 height; + __u16 dx; /* Where to place image */ + __u16 dy; + __u32 fg_color; /* Only used when a mono bitmap */ + __u32 bg_color; + __u8 depth; /* Dpeth of the image */ + char *data; /* Pointer to image data */ +}; + #ifdef __KERNEL__ #if 1 /* to go away in 2.5.0 */ extern int GET_FB_IDX(kdev_t rdev); #else -#define GET_FB_IDX(node) (MINOR(node)) +#define GET_FB_IDX(node) (minor(node)) #endif #include <linux/fs.h> +#include <linux/poll.h> #include <linux/init.h> #include <linux/devfs_fs_kernel.h> - struct fb_info; struct fb_info_gen; struct vm_area_struct; @@ -283,9 +316,25 @@ /* set colormap */ int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); - /* pan display (optional) */ - int (*fb_pan_display)(struct fb_var_screeninfo *var, int con, - struct fb_info *info); + /* checks var and creates a par based on it */ + int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); + /* set the video mode according to par */ + int (*fb_set_par)(struct fb_info *info); + /* set color register */ + int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info); + /* blank display */ + int (*fb_blank)(int blank, struct fb_info *info); + /* pan display */ + int (*fb_pan_display)(struct fb_var_screeninfo *var, int con, struct fb_info *info); + /* draws a rectangle */ + void (*fb_fillrect)(struct fb_info *p, struct fb_fillrect *rect); + /* Copy data from area to another */ + void (*fb_copyarea)(struct fb_info *p, struct fb_copyarea *region); + /* Draws a image to the display */ + void (*fb_imageblit)(struct fb_info *p, struct fb_image *image); + /* perform polling on fb device */ + int (*fb_poll)(struct fb_info *info, poll_table *wait); /* perform fb specific ioctl (optional) */ int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int con, struct fb_info *info); @@ -309,6 +358,7 @@ char *screen_base; /* Virtual address */ struct display *disp; /* initial display variable */ struct vc_data *display_fg; /* Console visible on this display */ + int currcon; /* Current VC. */ char fontname[40]; /* default font name */ devfs_handle_t devfs_handle; /* Devfs handle for new name */ devfs_handle_t devfs_lhandle; /* Devfs handle for compat. symlink */ @@ -351,8 +401,6 @@ void (*set_par)(const void *par, struct fb_info_gen *info); int (*getcolreg)(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, unsigned *transp, struct fb_info *info); - int (*setcolreg)(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, struct fb_info *info); int (*pan_display)(const struct fb_var_screeninfo *var, struct fb_info_gen *info); int (*blank)(int blank_mode, struct fb_info_gen *info); @@ -387,6 +435,9 @@ struct fb_info *info); extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info); +extern void cfb_fillrect(struct fb_info *p, struct fb_fillrect *rect); +extern void cfb_copyarea(struct fb_info *p, struct fb_copyarea *region); +extern void cfb_imageblit(struct fb_info *p, struct fb_image *image); /* * Helper functions @@ -398,8 +449,9 @@ extern void fbgen_install_cmap(int con, struct fb_info_gen *info); extern int fbgen_update_var(int con, struct fb_info *info); extern int fbgen_switch(int con, struct fb_info *info); -extern void fbgen_blank(int blank, struct fb_info *info); +extern int fbgen_blank(int blank, struct fb_info *info); +extern void fbgen2_set_disp(int con, struct fb_info *info); /* drivers/video/fbmem.c */ extern int register_framebuffer(struct fb_info *fb_info); @@ -421,10 +473,7 @@ int (*getcolreg)(u_int, u_int *, u_int *, u_int *, u_int *, struct fb_info *), struct fb_info *fb_info); -extern int fb_set_cmap(struct fb_cmap *cmap, int kspc, - int (*setcolreg)(u_int, u_int, u_int, u_int, u_int, - struct fb_info *), - struct fb_info *fb_info); +extern int fb_set_cmap(struct fb_cmap *cmap, int kspc, struct fb_info *fb_info); extern struct fb_cmap *fb_default_cmap(int len); extern void fb_invert_cmaps(void); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/file.h linux-2.5/include/linux/file.h --- linux-2.5.1/include/linux/file.h Wed Aug 23 18:22:26 2000 +++ linux-2.5/include/linux/file.h Mon Jan 14 14:31:11 2002 @@ -5,6 +5,8 @@ #ifndef __LINUX_FILE_H #define __LINUX_FILE_H +#include <linux/sched.h> + extern void FASTCALL(fput(struct file *)); extern struct file * FASTCALL(fget(unsigned int fd)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/fs.h linux-2.5/include/linux/fs.h --- linux-2.5.1/include/linux/fs.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/fs.h Mon Jan 14 14:31:06 2002 @@ -311,7 +311,6 @@ #include <linux/udf_fs_i.h> #include <linux/ncp_fs_i.h> #include <linux/proc_fs_i.h> -#include <linux/usbdev_fs_i.h> #include <linux/jffs2_fs_i.h> #include <linux/cramfs_fs_sb.h> @@ -502,7 +501,6 @@ struct ncp_inode_info ncpfs_i; struct proc_inode_info proc_i; struct socket socket_i; - struct usbdev_inode_info usbdev_i; struct jffs2_inode_info jffs2_i; void *generic_ip; } u; @@ -686,7 +684,6 @@ #include <linux/bfs_fs_sb.h> #include <linux/udf_fs_sb.h> #include <linux/ncp_fs_sb.h> -#include <linux/usbdev_fs_sb.h> #include <linux/cramfs_fs_sb.h> #include <linux/jffs2_fs_sb.h> @@ -721,6 +718,8 @@ struct list_head s_instances; struct quota_mount_options s_dquot; /* Diskquota specific options */ + char s_id[32]; /* Informational name */ + union { struct minix_sb_info minix_sb; struct ext2_sb_info ext2_sb; @@ -744,7 +743,6 @@ struct bfs_sb_info bfs_sb; struct udf_sb_info udf_sb; struct ncp_sb_info ncpfs_sb; - struct usbdev_sb_info usbdevfs_sb; struct jffs2_sb_info jffs2_sb; struct cramfs_sb_info cramfs_sb; void *generic_sbp; @@ -982,6 +980,7 @@ extern struct vfsmount *kern_mount(struct file_system_type *); extern int may_umount(struct vfsmount *); extern long do_mount(char *, char *, char *, unsigned long, void *); +extern void umount_tree(struct vfsmount *); #define kern_umount mntput @@ -1102,7 +1101,7 @@ extern int try_to_free_buffers(struct page *, unsigned int); extern void refile_buffer(struct buffer_head * buf); -extern void create_empty_buffers(struct page *, kdev_t, unsigned long); +extern void create_empty_buffers(struct page *, unsigned long); extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate); /* reiserfs_writepage needs this */ @@ -1217,15 +1216,15 @@ extern void sync_dev(kdev_t); extern int fsync_dev(kdev_t); extern int fsync_super(struct super_block *); -extern int fsync_no_super(kdev_t); +extern int fsync_no_super(struct block_device *); extern void sync_inodes_sb(struct super_block *); extern int osync_inode_buffers(struct inode *); extern int osync_inode_data_buffers(struct inode *); extern int fsync_inode_buffers(struct inode *); extern int fsync_inode_data_buffers(struct inode *); extern int inode_has_buffers(struct inode *); -extern void filemap_fdatasync(struct address_space *); -extern void filemap_fdatawait(struct address_space *); +extern int filemap_fdatasync(struct address_space *); +extern int filemap_fdatawait(struct address_space *); extern void sync_supers(kdev_t); extern int bmap(struct inode *, int); extern int notify_change(struct dentry *, struct iattr *); @@ -1359,7 +1358,20 @@ extern struct file * get_empty_filp(void); extern void file_move(struct file *f, struct list_head *list); extern struct buffer_head * get_hash_table(kdev_t, sector_t, int); -extern struct buffer_head * getblk(kdev_t, sector_t, int); +extern struct buffer_head * __getblk(struct block_device *, sector_t, int); +static inline struct buffer_head * getblk(kdev_t dev, sector_t block, int size) +{ + struct block_device *bdev; + struct buffer_head *bh; + bdev = bdget(kdev_t_to_nr(dev)); + if (!bdev) { + printk("No block device for %s\n", bdevname(dev)); + BUG(); + } + bh = __getblk(bdev, block, size); + atomic_dec(&bdev->bd_count); + return bh; +} extern void ll_rw_block(int, int, struct buffer_head * bh[]); extern int submit_bh(int, struct buffer_head *); struct bio; @@ -1378,18 +1390,39 @@ __bforget(buf); } extern int set_blocksize(kdev_t, int); -extern struct buffer_head * bread(kdev_t, int, int); +extern int sb_set_blocksize(struct super_block *, int); +extern int sb_min_blocksize(struct super_block *, int); +extern struct buffer_head * __bread(struct block_device *, int, int); +static inline struct buffer_head * bread(kdev_t dev, int block, int size) +{ + struct block_device *bdev; + struct buffer_head *bh; + bdev = bdget(kdev_t_to_nr(dev)); + if (!bdev) { + printk("No block device for %s\n", bdevname(dev)); + BUG(); + } + bh = __bread(bdev, block, size); + atomic_dec(&bdev->bd_count); + return bh; +} static inline struct buffer_head * sb_bread(struct super_block *sb, int block) { - return bread(sb->s_dev, block, sb->s_blocksize); + return __bread(sb->s_bdev, block, sb->s_blocksize); } static inline struct buffer_head * sb_getblk(struct super_block *sb, int block) { - return getblk(sb->s_dev, block, sb->s_blocksize); + return __getblk(sb->s_bdev, block, sb->s_blocksize); } static inline struct buffer_head * sb_get_hash_table(struct super_block *sb, int block) { return get_hash_table(sb->s_dev, block, sb->s_blocksize); +} +static inline void map_bh(struct buffer_head *bh, struct super_block *sb, int block) +{ + bh->b_state |= 1 << BH_Mapped; + bh->b_dev = sb->s_dev; + bh->b_blocknr = block; } extern void wakeup_bdflush(void); extern void put_unused_buffer_head(struct buffer_head * bh); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/generic_serial.h linux-2.5/include/linux/generic_serial.h --- linux-2.5.1/include/linux/generic_serial.h Fri Sep 7 16:28:38 2001 +++ linux-2.5/include/linux/generic_serial.h Fri Dec 28 01:15:11 2001 @@ -12,9 +12,6 @@ #ifndef GENERIC_SERIAL_H #define GENERIC_SERIAL_H - - - struct real_driver { void (*disable_tx_interrupts) (void *); void (*enable_tx_interrupts) (void *); @@ -98,7 +95,7 @@ struct termios * old_termios); int gs_init_port(struct gs_port *port); int gs_setserial(struct gs_port *port, struct serial_struct *sp); -void gs_getserial(struct gs_port *port, struct serial_struct *sp); +int gs_getserial(struct gs_port *port, struct serial_struct *sp); void gs_got_break(struct gs_port *port); extern int gs_debug; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/genhd.h linux-2.5/include/linux/genhd.h --- linux-2.5.1/include/linux/genhd.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/genhd.h Mon Jan 14 14:31:07 2002 @@ -71,13 +71,11 @@ const char *major_name; /* name of major driver */ int minor_shift; /* number of times minor is shifted to get real minor */ - int max_p; /* maximum partitions per device */ struct hd_struct *part; /* [indexed by minor] */ int *sizes; /* [idem], device size in blocks */ int nr_real; /* number of real devices */ - void *real_devices; /* internal use */ struct gendisk *next; struct block_device_operations *fops; @@ -247,7 +245,7 @@ static inline unsigned int disk_index (kdev_t dev) { struct gendisk *g = get_gendisk(dev); - return g ? (MINOR(dev) >> g->minor_shift) : 0; + return g ? (minor(dev) >> g->minor_shift) : 0; } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/gfp.h linux-2.5/include/linux/gfp.h --- linux-2.5.1/include/linux/gfp.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/linux/gfp.h Mon Jan 14 14:31:06 2002 @@ -0,0 +1,81 @@ +#ifndef __LINUX_GFP_H +#define __LINUX_GFP_H + +#include <linux/mmzone.h> +#include <linux/stddef.h> +#include <linux/linkage.h> +/* + * GFP bitmasks.. + */ +/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low four bits) */ +#define __GFP_DMA 0x01 +#define __GFP_HIGHMEM 0x02 + +/* Action modifiers - doesn't change the zoning */ +#define __GFP_WAIT 0x10 /* Can wait and reschedule? */ +#define __GFP_HIGH 0x20 /* Should access emergency pools? */ +#define __GFP_IO 0x40 /* Can start low memory physical IO? */ +#define __GFP_HIGHIO 0x80 /* Can start high mem physical IO? */ +#define __GFP_FS 0x100 /* Can call down to low-level FS? */ + +#define GFP_NOHIGHIO (__GFP_HIGH | __GFP_WAIT | __GFP_IO) +#define GFP_NOIO (__GFP_HIGH | __GFP_WAIT) +#define GFP_NOFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO) +#define GFP_ATOMIC (__GFP_HIGH) +#define GFP_USER ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) +#define GFP_HIGHUSER ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS | __GFP_HIGHMEM) +#define GFP_KERNEL (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) +#define GFP_NFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) +#define GFP_KSWAPD ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) + +/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some + platforms, used as appropriate on others */ + +#define GFP_DMA __GFP_DMA + +/* + * There is only one page-allocator function, and two main namespaces to + * it. The alloc_page*() variants return 'struct page *' and as such + * can allocate highmem pages, the *get*page*() variants return + * virtual kernel addresses to the allocated page(s). + */ +extern struct page * FASTCALL(_alloc_pages(unsigned int gfp_mask, unsigned int order)); +extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist)); +extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order); + +static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order) +{ + /* + * Gets optimized away by the compiler. + */ + if (order >= MAX_ORDER) + return NULL; + return _alloc_pages(gfp_mask, order); +} + +#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) + +extern unsigned long FASTCALL(__get_free_pages(unsigned int gfp_mask, unsigned int order)); +extern unsigned long FASTCALL(get_zeroed_page(unsigned int gfp_mask)); + +#define __get_free_page(gfp_mask) \ + __get_free_pages((gfp_mask),0) + +#define __get_dma_pages(gfp_mask, order) \ + __get_free_pages((gfp_mask) | GFP_DMA,(order)) + +/* + * The old interface name will be removed in 2.5: + */ +#define get_free_page get_zeroed_page + +/* + * There is only one 'core' page-freeing function. + */ +extern void FASTCALL(__free_pages(struct page *page, unsigned int order)); +extern void FASTCALL(free_pages(unsigned long addr, unsigned int order)); + +#define __free_page(page) __free_pages((page), 0) +#define free_page(addr) free_pages((addr),0) + +#endif /* __LINUX_GFP_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/hfs_sysdep.h linux-2.5/include/linux/hfs_sysdep.h --- linux-2.5.1/include/linux/hfs_sysdep.h Tue Feb 13 22:13:44 2001 +++ linux-2.5/include/linux/hfs_sysdep.h Sat Jan 5 16:38:09 2002 @@ -122,7 +122,7 @@ } static inline const char *hfs_mdb_name(hfs_sysmdb sys_mdb) { - return kdevname(sys_mdb->s_dev); + return sys_mdb->s_id; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/highmem.h linux-2.5/include/linux/highmem.h --- linux-2.5.1/include/linux/highmem.h Sun Dec 16 23:44:04 2001 +++ linux-2.5/include/linux/highmem.h Mon Jan 14 14:32:24 2002 @@ -132,15 +132,4 @@ kunmap_atomic(vto, KM_USER1); } -static inline void copy_highpage(struct page *to, struct page *from) -{ - char *vfrom, *vto; - - vfrom = kmap(from); - vto = kmap(to); - copy_page(vto, vfrom); - kunmap(from); - kunmap(to); -} - #endif /* _LINUX_HIGHMEM_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/i8k.h linux-2.5/include/linux/i8k.h --- linux-2.5.1/include/linux/i8k.h Sat Nov 3 01:46:47 2001 +++ linux-2.5/include/linux/i8k.h Thu Dec 13 16:32:37 2001 @@ -1,5 +1,5 @@ /* - * i8k.h -- Linux driver for accessing the SMM BIOS on Dell I8000 laptops + * i8k.h -- Linux driver for accessing the SMM BIOS on Dell laptops * * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org> * @@ -36,9 +36,9 @@ #define I8K_FAN_HIGH 2 #define I8K_FAN_MAX I8K_FAN_HIGH -#define I8K_VOL_UP 0x01 -#define I8K_VOL_DOWN 0x02 -#define I8K_VOL_MUTE 0x03 +#define I8K_VOL_UP 1 +#define I8K_VOL_DOWN 2 +#define I8K_VOL_MUTE 4 #define I8K_AC 1 #define I8K_BATTERY 0 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/ide.h linux-2.5/include/linux/ide.h --- linux-2.5.1/include/linux/ide.h Sun Dec 16 23:45:06 2001 +++ linux-2.5/include/linux/ide.h Mon Jan 14 14:35:05 2002 @@ -18,13 +18,13 @@ /* * This is the multiple IDE interface driver, as evolved from hd.c. - * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15). + * It supports up to four IDE interfaces, on one or more IRQs (usually 14, 15). * There can be up to two drives per interface, as per the ATA-2 spec. * - * Primary i/f: ide0: major=3; (hda) minor=0; (hdb) minor=64 - * Secondary i/f: ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64 - * Tertiary i/f: ide2: major=33; (hde) minor=0; (hdf) minor=64 - * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64 + * Primary i/f: ide0: major=3; (hda) minor=0; (hdb) minor=64 + * Secondary i/f: ide1: major=22; (hdc) minor=0; (hdd) minor=64 + * Tertiary i/f: ide2: major=33; (hde) minor=0; (hdf) minor=64 + * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64 */ /****************************************************************************** @@ -382,12 +382,12 @@ unsigned int cyl; /* "real" number of cyls */ unsigned long capacity; /* total number of sectors */ unsigned int drive_data; /* for use by tuneproc/selectproc as needed */ - void *hwif; /* actually (ide_hwif_t *) */ + void *hwif; /* actually (ide_hwif_t *) */ wait_queue_head_t wqueue; /* used to wait for drive in open() */ struct hd_driveid *id; /* drive model identification info */ struct hd_struct *part; /* drive partition table */ char name[4]; /* drive name, such as "hda" */ - void *driver; /* (ide_driver_t *) */ + void *driver; /* (ide_driver_t *) */ void *driver_data; /* extra driver data */ devfs_handle_t de; /* directory for device */ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ @@ -915,6 +915,12 @@ * to a drive as part of a disk multwrite operation. */ int ide_multwrite (ide_drive_t *drive, unsigned int mcount); + +/* + * idedisk_input_data() is a wrapper around ide_input_data() which copes + * with byte-swapping the input data if required. + */ +inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount); /* * ide_stall_queue() can be used by a drive to give excess bandwidth back diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/init.h linux-2.5/include/linux/init.h --- linux-2.5.1/include/linux/init.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/init.h Mon Jan 14 14:31:05 2002 @@ -111,7 +111,7 @@ */ #define module_exit(x) __exitcall(x); -#else +#else /* MODULE */ #define __init #define __exit @@ -141,7 +141,7 @@ #define __setup(str,func) /* nothing */ -#endif +#endif /* !MODULE */ #ifdef CONFIG_HOTPLUG #define __devinit @@ -153,6 +153,18 @@ #define __devinitdata __initdata #define __devexit __exit #define __devexitdata __exitdata +#endif + +/* Functions marked as __devexit may be discarded at kernel link time, depending + on config options. Newer versions of binutils detect references from + retained sections to discarded sections and flag an error. Pointers to + __devexit functions must use __devexit_p(function_name), the wrapper will + insert either the function_name or NULL, depending on the config options. + */ +#if defined(MODULE) || defined(CONFIG_HOTPLUG) +#define __devexit_p(x) x +#else +#define __devexit_p(x) NULL #endif #endif /* _LINUX_INIT_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/intermezzo_fs.h linux-2.5/include/linux/intermezzo_fs.h --- linux-2.5.1/include/linux/intermezzo_fs.h Tue Nov 13 17:20:56 2001 +++ linux-2.5/include/linux/intermezzo_fs.h Tue Jan 8 01:17:10 2002 @@ -135,6 +135,7 @@ int fset_permit_count; int fset_permit_cookie; int fset_chunkbits; + int fset_data; /* replaces the dentry d_data field for fsetroots */ struct kml_fsdata *fset_kmldata; loff_t fset_file_maxio; /* writing more than this causes a close */ }; @@ -201,9 +202,6 @@ void presto_frob_dop(struct dentry *de) ; char * presto_path(struct dentry *dentry, struct dentry *root, char *buffer, int buflen); -void presto_set_dd(struct dentry *); -void presto_init_ddata_cache(void); -void presto_cleanup_ddata_cache(void); extern struct dentry_operations presto_dentry_ops; @@ -231,14 +229,6 @@ }; -struct presto_dentry_data { - int dd_count; /* how mnay dentries are using this dentry */ - struct presto_file_set *dd_fset; - loff_t dd_kml_offset; - int dd_flags; - -}; - struct presto_file_data { int fd_do_lml; loff_t fd_lml_offset; @@ -259,7 +249,6 @@ __u64 pv_ctime; __u64 pv_size; }; -inline struct presto_dentry_data *presto_d2d(struct dentry *); int presto_walk(const char *name, struct nameidata *nd); int presto_clear_fsetroot(char *path); int presto_clear_all_fsetroots(char *path); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/interrupt.h linux-2.5/include/linux/interrupt.h --- linux-2.5.1/include/linux/interrupt.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/interrupt.h Mon Jan 14 14:31:07 2002 @@ -3,12 +3,14 @@ #define _LINUX_INTERRUPT_H #include <linux/config.h> +#include <linux/sched.h> #include <linux/kernel.h> #include <linux/smp.h> #include <linux/cache.h> #include <asm/bitops.h> #include <asm/atomic.h> +#include <asm/system.h> #include <asm/ptrace.h> struct irqaction { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/isdn/tpam.h linux-2.5/include/linux/isdn/tpam.h --- linux-2.5.1/include/linux/isdn/tpam.h Mon Jul 2 21:07:55 2001 +++ linux-2.5/include/linux/isdn/tpam.h Mon Jan 7 20:58:52 2002 @@ -1,4 +1,4 @@ -/* $Id: tpam.h,v 1.1.2.1 2001/06/08 08:23:46 kai Exp $ +/* $Id: tpam.h,v 1.1.2.1 2001/11/20 14:19:38 kai Exp $ * * Turbo PAM ISDN driver for Linux. (Kernel Driver) * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/isdn.h linux-2.5/include/linux/isdn.h --- linux-2.5.1/include/linux/isdn.h Sun Sep 30 19:26:42 2001 +++ linux-2.5/include/linux/isdn.h Mon Jan 7 20:53:00 2002 @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.111.6.9 2001/09/23 22:25:05 kai Exp $ +/* $Id: isdn.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -150,7 +150,6 @@ #include <linux/errno.h> #include <linux/fs.h> #include <linux/major.h> -#include <asm/segment.h> #include <asm/io.h> #include <linux/kernel.h> #include <linux/signal.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/isdn_divertif.h linux-2.5/include/linux/isdn_divertif.h --- linux-2.5.1/include/linux/isdn_divertif.h Sun Sep 30 19:26:42 2001 +++ linux-2.5/include/linux/isdn_divertif.h Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_divertif.h,v 1.4.6.1 2001/09/23 22:25:05 kai Exp $ +/* $Id: isdn_divertif.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $ * * Header for the diversion supplementary interface for i4l. * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/isdn_lzscomp.h linux-2.5/include/linux/isdn_lzscomp.h --- linux-2.5.1/include/linux/isdn_lzscomp.h Sun Sep 30 19:26:42 2001 +++ linux-2.5/include/linux/isdn_lzscomp.h Thu Dec 13 16:32:37 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_lzscomp.h,v 1.1.10.1 2001/09/23 22:25:05 kai Exp $ +/* $Id: isdn_lzscomp.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $ * * Header for isdn_lzscomp.c * Concentrated here to not mess up half a dozen kernel headers with code diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/isdnif.h linux-2.5/include/linux/isdnif.h --- linux-2.5.1/include/linux/isdnif.h Sun Sep 30 19:26:42 2001 +++ linux-2.5/include/linux/isdnif.h Mon Jan 7 20:52:48 2002 @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.37.6.6 2001/09/23 22:25:05 kai Exp $ +/* $Id: isdnif.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $ * * Linux ISDN subsystem * Definition of the interface between the subsystem and its low-level drivers. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/jbd.h linux-2.5/include/linux/jbd.h --- linux-2.5.1/include/linux/jbd.h Fri Nov 9 22:25:04 2001 +++ linux-2.5/include/linux/jbd.h Tue Jan 8 00:44:25 2002 @@ -221,7 +221,7 @@ #endif #else -#define J_ASSERT(assert) +#define J_ASSERT(assert) do { } while (0) #endif /* JBD_ASSERTIONS */ enum jbd_state_bits { @@ -482,13 +482,13 @@ /* Device, blocksize and starting block offset for the location * where we store the journal. */ - kdev_t j_dev; + struct block_device * j_dev; int j_blocksize; unsigned int j_blk_offset; /* Device which holds the client fs. For internal journal this * will be equal to j_dev. */ - kdev_t j_fs_dev; + struct block_device * j_fs_dev; /* Total maximum capacity of the journal region on disk. */ unsigned int j_maxlen; @@ -564,7 +564,7 @@ /* Log buffer allocation */ extern struct journal_head * journal_get_descriptor_buffer(journal_t *); -extern unsigned long journal_next_log_block(journal_t *); +int journal_next_log_block(journal_t *, unsigned long *); /* Commit management */ extern void journal_commit_transaction(journal_t *); @@ -649,7 +649,8 @@ extern void journal_lock_updates (journal_t *); extern void journal_unlock_updates (journal_t *); -extern journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev, +extern journal_t * journal_init_dev(struct block_device *bdev, + struct block_device *fs_dev, int start, int len, int bsize); extern journal_t * journal_init_inode (struct inode *); extern int journal_update_format (journal_t *); @@ -664,15 +665,16 @@ extern void journal_destroy (journal_t *); extern int journal_recover (journal_t *journal); extern int journal_wipe (journal_t *, int); -extern int journal_skip_recovery (journal_t *); -extern void journal_update_superblock (journal_t *, int); -extern void __journal_abort (journal_t *); +extern int journal_skip_recovery (journal_t *); +extern void journal_update_superblock (journal_t *, int); +extern void __journal_abort_hard (journal_t *); +extern void __journal_abort_soft (journal_t *, int); extern void journal_abort (journal_t *, int); extern int journal_errno (journal_t *); extern void journal_ack_err (journal_t *); extern int journal_clear_err (journal_t *); -extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr); -extern int journal_force_commit(journal_t *journal); +extern int journal_bmap(journal_t *, unsigned long, unsigned long *); +extern int journal_force_commit(journal_t *); /* * journal_head management diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/kbd_kern.h linux-2.5/include/linux/kbd_kern.h --- linux-2.5.1/include/linux/kbd_kern.h Sun Dec 16 23:44:43 2001 +++ linux-2.5/include/linux/kbd_kern.h Mon Jan 14 14:36:34 2002 @@ -140,7 +140,6 @@ int getkeycode(unsigned int scancode); int setkeycode(unsigned int scancode, unsigned int keycode); void compute_shiftstate(void); -int keyboard_wait_for_keypress(struct console *); /* defkeymap.c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/kdev_t.h linux-2.5/include/linux/kdev_t.h --- linux-2.5.1/include/linux/kdev_t.h Sat Feb 17 00:06:17 2001 +++ linux-2.5/include/linux/kdev_t.h Tue Jan 1 23:42:42 2002 @@ -57,48 +57,84 @@ aeb - 950811 */ -/* Since MINOR(dev) is used as index in static arrays, - the kernel is not quite ready yet for larger minors. - However, everything runs fine with an arbitrary kdev_t type. */ +/* + * NOTE NOTE NOTE! + * + * The kernel-internal "kdev_t" will eventually have + * 20 bits for minor numbers, and 12 bits for majors. + * + * HOWEVER, the external representation is still 8+8 + * bits, and there is no way to generate the extended + * "kdev_t" format yet. Which is just as well, since + * we still use "minor" as an index into various + * static arrays, and they are sized for a 8-bit index. + */ +typedef struct { + unsigned short value; +} kdev_t; + +#define KDEV_MINOR_BITS 8 +#define KDEV_MAJOR_BITS 8 + +#define __mkdev(major,minor) (((major) << KDEV_MINOR_BITS) + (minor)) + +#define mk_kdev(major, minor) ((kdev_t) { __mkdev(major,minor) } ) + +/* + * The "values" are just _cookies_, usable for + * internal equality comparisons and for things + * like NFS filehandle conversion. + */ +static inline unsigned int kdev_val(kdev_t dev) +{ + return dev.value; +} + +static inline kdev_t val_to_kdev(unsigned int val) +{ + kdev_t dev; + dev.value = val; + return dev; +} + +#define HASHDEV(dev) (kdev_val(dev)) +#define NODEV (mk_kdev(0,0)) +#define B_FREE (mk_kdev(0xff,0xff)) + +extern const char * kdevname(kdev_t); /* note: returns pointer to static data! */ + +static inline int kdev_same(kdev_t dev1, kdev_t dev2) +{ + return dev1.value == dev2.value; +} + +#define kdev_none(d1) (!kdev_val(d1)) + +/* Mask off the high bits for now.. */ +#define minor(dev) ((dev).value & 0xff) +#define major(dev) (((dev).value >> KDEV_MINOR_BITS) & 0xff) + +/* These are for user-level "dev_t" */ #define MINORBITS 8 #define MINORMASK ((1U << MINORBITS) - 1) -typedef unsigned short kdev_t; - #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) -#define HASHDEV(dev) ((unsigned int) (dev)) -#define NODEV 0 #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) -#define B_FREE 0xffff /* yuk */ - -extern const char * kdevname(kdev_t); /* note: returns pointer to static data! */ /* -As long as device numbers in the outside world have 16 bits only, -we use these conversions. -*/ + * Conversion functions + */ -static inline unsigned int kdev_t_to_nr(kdev_t dev) { - return (MAJOR(dev)<<8) | MINOR(dev); +static inline int kdev_t_to_nr(kdev_t dev) +{ + return MKDEV(major(dev), minor(dev)); } static inline kdev_t to_kdev_t(int dev) { - int major, minor; -#if 0 - major = (dev >> 16); - if (!major) { - major = (dev >> 8); - minor = (dev & 0xff); - } else - minor = (dev & 0xffff); -#else - major = (dev >> 8); - minor = (dev & 0xff); -#endif - return MKDEV(major, minor); + return mk_kdev(MAJOR(dev),MINOR(dev)); } #else /* __KERNEL__ || _LVM_H_INCLUDE */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/kernel.h linux-2.5/include/linux/kernel.h --- linux-2.5.1/include/linux/kernel.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/kernel.h Mon Jan 14 14:31:06 2002 @@ -37,15 +37,12 @@ #define KERN_INFO "<6>" /* informational */ #define KERN_DEBUG "<7>" /* debug-level messages */ -# define NORET_TYPE /**/ -# define ATTRIB_NORET __attribute__((noreturn)) -# define NORET_AND noreturn, - -#ifdef __i386__ -#define FASTCALL(x) x __attribute__((regparm(3))) -#else -#define FASTCALL(x) x -#endif +extern int console_printk[]; + +#define console_loglevel (console_printk[0]) +#define default_message_loglevel (console_printk[1]) +#define minimum_console_loglevel (console_printk[2]) +#define default_console_loglevel (console_printk[3]) struct completion; @@ -83,8 +80,6 @@ asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); -extern int console_loglevel; - static inline void console_silent(void) { console_loglevel = 0; @@ -101,6 +96,9 @@ extern int tainted; extern const char *print_tainted(void); +#define TAINT_PROPRIETORY_MODULE (1<<0) +#define TAINT_FORCED_MODULE (1<<1) +#define TAINT_UNSAFE_SMP (1<<2) #if DEBUG #define pr_debug(fmt,arg...) \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/kernel_stat.h linux-2.5/include/linux/kernel_stat.h --- linux-2.5.1/include/linux/kernel_stat.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/kernel_stat.h Mon Jan 14 14:31:06 2002 @@ -32,10 +32,11 @@ unsigned int ipackets, opackets; unsigned int ierrors, oerrors; unsigned int collisions; - unsigned int context_swtch; }; extern struct kernel_stat kstat; + +extern unsigned long nr_context_switches(void); #if !defined(CONFIG_ARCH_S390) /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/keyboard.h linux-2.5/include/linux/keyboard.h --- linux-2.5.1/include/linux/keyboard.h Sun Dec 16 23:44:28 2001 +++ linux-2.5/include/linux/keyboard.h Mon Jan 14 14:36:01 2002 @@ -26,7 +26,6 @@ extern const int max_vals[]; extern unsigned short *key_maps[MAX_NR_KEYMAPS]; extern unsigned short plain_map[NR_KEYS]; -extern wait_queue_head_t keypress_wait; extern unsigned char keyboard_type; #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/limits.h linux-2.5/include/linux/limits.h --- linux-2.5.1/include/linux/limits.h Wed Jul 28 17:30:10 1999 +++ linux-2.5/include/linux/limits.h Mon Jan 14 23:55:29 2002 @@ -11,7 +11,7 @@ #define MAX_CANON 255 /* size of the canonical input queue */ #define MAX_INPUT 255 /* size of the type-ahead buffer */ #define NAME_MAX 255 /* # chars in a file name */ -#define PATH_MAX 4095 /* # chars in a path name */ +#define PATH_MAX 4096 /* # chars in a path name including nul */ #define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */ #define RTSIG_MAX 32 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/linkage.h linux-2.5/include/linux/linkage.h --- linux-2.5.1/include/linux/linkage.h Mon Dec 11 20:49:54 2000 +++ linux-2.5/include/linux/linkage.h Sun Dec 30 20:01:41 2001 @@ -60,4 +60,14 @@ #endif +# define NORET_TYPE /**/ +# define ATTRIB_NORET __attribute__((noreturn)) +# define NORET_AND noreturn, + +#ifdef __i386__ +#define FASTCALL(x) x __attribute__((regparm(3))) +#else +#define FASTCALL(x) x +#endif + #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/list.h linux-2.5/include/linux/list.h --- linux-2.5.1/include/linux/list.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/list.h Mon Jan 14 14:31:06 2002 @@ -19,6 +19,8 @@ struct list_head *next, *prev; }; +typedef struct list_head list_t; + #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ @@ -161,6 +163,16 @@ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) + +/** + * list_for_each_prev - iterate over a list in reverse order + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + #endif /* __KERNEL__ || _LVM_H_INCLUDE */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/lvm.h linux-2.5/include/linux/lvm.h --- linux-2.5.1/include/linux/lvm.h Tue Nov 27 17:23:27 2001 +++ linux-2.5/include/linux/lvm.h Sun Jan 13 22:23:13 2002 @@ -477,8 +477,16 @@ * Structure Logical Volume (LV) Version 3 */ -/* core */ -typedef struct lv_v5 { +struct kern_lv_v5; +struct user_lv_v5; +typedef struct user_lv_v5 userlv_t; +#ifdef __KERNEL__ +typedef struct kern_lv_v5 lv_t; +#else +typedef struct user_lv_v5 lv_t; +#endif + +struct user_lv_v5 { char lv_name[NAME_LEN]; char vg_name[NAME_LEN]; uint lv_access; @@ -501,15 +509,18 @@ uint lv_read_ahead; /* delta to version 1 starts here */ - struct lv_v5 *lv_snapshot_org; - struct lv_v5 *lv_snapshot_prev; - struct lv_v5 *lv_snapshot_next; + lv_t *lv_snapshot_org; + lv_t *lv_snapshot_prev; + lv_t *lv_snapshot_next; lv_block_exception_t *lv_block_exception; uint lv_remap_ptr; uint lv_remap_end; uint lv_chunk_size; uint lv_snapshot_minor; -#ifdef __KERNEL__ +}; + +struct kern_lv_v5{ + struct user_lv_v5 u; struct kiobuf *lv_iobuf; sector_t blocks[LVM_MAX_SECTORS]; struct kiobuf *lv_COW_table_iobuf; @@ -520,12 +531,8 @@ wait_queue_head_t lv_snapshot_wait; int lv_snapshot_use_rate; struct vg_v3 *vg; - uint lv_allocated_snapshot_le; -#else - char dummy[200]; -#endif -} lv_t; +}; /* disk */ typedef struct lv_disk_v3 { @@ -679,13 +686,13 @@ } static int inline LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg_t *vg, lv_t *lv) { - return vg->pe_size / lv->lv_chunk_size; + return vg->pe_size / lv->u.lv_chunk_size; } static int inline LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg_t *vg, lv_t *lv) { - ulong chunks = vg->pe_size / lv->lv_chunk_size; + ulong chunks = vg->pe_size / lv->u.lv_chunk_size; ulong entry_size = sizeof(lv_COW_table_disk_t); - ulong chunk_size = lv->lv_chunk_size * SECTOR_SIZE; + ulong chunk_size = lv->u.lv_chunk_size * SECTOR_SIZE; ulong entries = (vg->pe_size * SECTOR_SIZE) / (entry_size + chunk_size); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/mm.h linux-2.5/include/linux/mm.h --- linux-2.5.1/include/linux/mm.h Sun Dec 16 23:43:26 2001 +++ linux-2.5/include/linux/mm.h Mon Jan 14 14:31:07 2002 @@ -7,6 +7,7 @@ #ifdef __KERNEL__ #include <linux/config.h> +#include <linux/gfp.h> #include <linux/string.h> #include <linux/list.h> #include <linux/mmzone.h> @@ -344,51 +345,6 @@ /* The array of struct pages */ extern mem_map_t * mem_map; -/* - * There is only one page-allocator function, and two main namespaces to - * it. The alloc_page*() variants return 'struct page *' and as such - * can allocate highmem pages, the *get*page*() variants return - * virtual kernel addresses to the allocated page(s). - */ -extern struct page * FASTCALL(_alloc_pages(unsigned int gfp_mask, unsigned int order)); -extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist)); -extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order); - -static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order) -{ - /* - * Gets optimized away by the compiler. - */ - if (order >= MAX_ORDER) - return NULL; - return _alloc_pages(gfp_mask, order); -} - -#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) - -extern unsigned long FASTCALL(__get_free_pages(unsigned int gfp_mask, unsigned int order)); -extern unsigned long FASTCALL(get_zeroed_page(unsigned int gfp_mask)); - -#define __get_free_page(gfp_mask) \ - __get_free_pages((gfp_mask),0) - -#define __get_dma_pages(gfp_mask, order) \ - __get_free_pages((gfp_mask) | GFP_DMA,(order)) - -/* - * The old interface name will be removed in 2.5: - */ -#define get_free_page get_zeroed_page - -/* - * There is only one 'core' page-freeing function. - */ -extern void FASTCALL(__free_pages(struct page *page, unsigned int order)); -extern void FASTCALL(free_pages(unsigned long addr, unsigned int order)); - -#define __free_page(page) __free_pages((page), 0) -#define free_page(addr) free_pages((addr),0) - extern void show_free_areas(void); extern void show_free_areas_node(pg_data_t *pgdat); @@ -418,6 +374,12 @@ extern void ptrace_disable(struct task_struct *); extern int ptrace_check_attach(struct task_struct *task, int kill); +int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, + int len, int write, int force, struct page **pages, struct vm_area_struct **vmas); + +int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, + int len, int write, int force, struct page **pages, struct vm_area_struct **vmas); + /* * On a two-level page table, this ends up being trivial. Thus the * inlining and the symmetry break with pte_alloc() that does all @@ -512,35 +474,15 @@ extern int filemap_sync(struct vm_area_struct *, unsigned long, size_t, unsigned int); extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int); -/* - * GFP bitmasks.. - */ -/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low four bits) */ -#define __GFP_DMA 0x01 -#define __GFP_HIGHMEM 0x02 - -/* Action modifiers - doesn't change the zoning */ -#define __GFP_WAIT 0x10 /* Can wait and reschedule? */ -#define __GFP_HIGH 0x20 /* Should access emergency pools? */ -#define __GFP_IO 0x40 /* Can start low memory physical IO? */ -#define __GFP_HIGHIO 0x80 /* Can start high mem physical IO? */ -#define __GFP_FS 0x100 /* Can call down to low-level FS? */ - -#define GFP_NOHIGHIO (__GFP_HIGH | __GFP_WAIT | __GFP_IO) -#define GFP_NOIO (__GFP_HIGH | __GFP_WAIT) -#define GFP_NOFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO) -#define GFP_ATOMIC (__GFP_HIGH) -#define GFP_USER ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) -#define GFP_HIGHUSER ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS | __GFP_HIGHMEM) -#define GFP_KERNEL (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) -#define GFP_NFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) -#define GFP_KSWAPD ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) - -/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some - platforms, used as appropriate on others */ - -#define GFP_DMA __GFP_DMA +static inline unsigned int pf_gfp_mask(unsigned int gfp_mask) +{ + /* avoid all memory balancing I/O methods if this task cannot block on I/O */ + if (current->flags & PF_NOIO) + gfp_mask &= ~(__GFP_IO | __GFP_HIGHIO | __GFP_FS); + return gfp_mask; +} + /* vma is the first one with address < vma->vm_end, * and even address < vma->vm_start. Have to extend vma. */ static inline int expand_stack(struct vm_area_struct * vma, unsigned long address) @@ -553,11 +495,13 @@ * before relocating the vma range ourself. */ address &= PAGE_MASK; + spin_lock(&vma->vm_mm->page_table_lock); grow = (vma->vm_start - address) >> PAGE_SHIFT; if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur || - ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) + ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) { + spin_unlock(&vma->vm_mm->page_table_lock); return -ENOMEM; - spin_lock(&vma->vm_mm->page_table_lock); + } vma->vm_start = address; vma->vm_pgoff -= grow; vma->vm_mm->total_vm += grow; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/msdos_fs.h linux-2.5/include/linux/msdos_fs.h --- linux-2.5.1/include/linux/msdos_fs.h Fri Nov 30 16:30:17 2001 +++ linux-2.5/include/linux/msdos_fs.h Mon Jan 14 14:32:17 2002 @@ -200,7 +200,7 @@ #include <linux/nls.h> struct fat_cache { - kdev_t device; /* device number. 0 means unused. */ + struct super_block *sb; /* fs in question. NULL means unused */ int start_cluster; /* first cluster of the chain. */ int file_cluster; /* cluster number in the file. */ int disk_cluster; /* cluster number on disk. */ @@ -252,7 +252,7 @@ int *d_clu); extern void fat_cache_add(struct inode *inode, int f_clu, int d_clu); extern void fat_cache_inval_inode(struct inode *inode); -extern void fat_cache_inval_dev(kdev_t device); +extern void fat_cache_inval_dev(struct super_block *sb); extern int fat_get_cluster(struct inode *inode, int cluster); extern int fat_free(struct inode *inode, int skip); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/namespace.h linux-2.5/include/linux/namespace.h --- linux-2.5.1/include/linux/namespace.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/linux/namespace.h Thu Dec 27 15:56:12 2001 @@ -0,0 +1,42 @@ +#ifndef _NAMESPACE_H_ +#define _NAMESPACE_H_ +#ifdef __KERNEL__ + +struct namespace { + atomic_t count; + struct vfsmount * root; + struct list_head list; + struct rw_semaphore sem; +}; + +static inline void put_namespace(struct namespace *namespace) +{ + if (atomic_dec_and_test(&namespace->count)) { + down_write(&namespace->sem); + spin_lock(&dcache_lock); + umount_tree(namespace->root); + spin_unlock(&dcache_lock); + up_write(&namespace->sem); + kfree(namespace); + } +} + +static inline void exit_namespace(struct task_struct *p) +{ + struct namespace *namespace = p->namespace; + if (namespace) { + task_lock(p); + p->namespace = NULL; + task_unlock(p); + put_namespace(namespace); + } +} +extern int copy_namespace(int, struct task_struct *); + +static inline void get_namespace(struct namespace *namespace) +{ + atomic_inc(&namespace->count); +} + +#endif +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/netdevice.h linux-2.5/include/linux/netdevice.h --- linux-2.5.1/include/linux/netdevice.h Sun Dec 16 23:44:14 2001 +++ linux-2.5/include/linux/netdevice.h Mon Jan 14 14:32:31 2002 @@ -663,6 +663,8 @@ NETIF_MSG_TX_DONE = 0x0400, NETIF_MSG_RX_STATUS = 0x0800, NETIF_MSG_PKTDATA = 0x1000, + NETIF_MSG_HW = 0x2000, + NETIF_MSG_WOL = 0x4000, }; #define netif_msg_drv(p) ((p)->msg_enable & NETIF_MSG_DRV) @@ -678,6 +680,8 @@ #define netif_msg_tx_done(p) ((p)->msg_enable & NETIF_MSG_TX_DONE) #define netif_msg_rx_status(p) ((p)->msg_enable & NETIF_MSG_RX_STATUS) #define netif_msg_pktdata(p) ((p)->msg_enable & NETIF_MSG_PKTDATA) +#define netif_msg_hw(p) ((p)->msg_enable & NETIF_MSG_HW) +#define netif_msg_wol(p) ((p)->msg_enable & NETIF_MSG_WOL) /* These functions live elsewhere (drivers/net/net_init.c, but related) */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/netlink.h linux-2.5/include/linux/netlink.h --- linux-2.5.1/include/linux/netlink.h Thu Jul 26 21:00:17 2001 +++ linux-2.5/include/linux/netlink.h Thu Dec 13 16:32:37 2001 @@ -5,6 +5,7 @@ #define NETLINK_SKIP 1 /* Reserved for ENskip */ #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ #define NETLINK_FIREWALL 3 /* Firewalling hook */ +#define NETLINK_TCPDIAG 4 /* TCP socket monitoring */ #define NETLINK_ARPD 8 #define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */ #define NETLINK_IP6_FW 13 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/nfs_fs.h linux-2.5/include/linux/nfs_fs.h --- linux-2.5.1/include/linux/nfs_fs.h Sun Dec 16 23:44:09 2001 +++ linux-2.5/include/linux/nfs_fs.h Mon Jan 14 14:32:31 2002 @@ -16,6 +16,7 @@ #include <linux/sunrpc/debug.h> #include <linux/sunrpc/auth.h> +#include <linux/sunrpc/clnt.h> #include <linux/nfs.h> #include <linux/nfs2.h> @@ -331,6 +332,29 @@ wait_event(wq, condition); \ __retval; \ }) + +#ifdef CONFIG_NFS_V3 + +#define NFS_JUKEBOX_RETRY_TIME (5 * HZ) +static inline int +nfs_async_handle_jukebox(struct rpc_task *task) +{ + if (task->tk_status != -EJUKEBOX) + return 0; + task->tk_status = 0; + rpc_restart_call(task); + rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); + return 1; +} + +#else + +static inline int +nfs_async_handle_jukebox(struct rpc_task *task) +{ + return 0; +} +#endif /* CONFIG_NFS_V3 */ #endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/nfsd/nfsfh.h linux-2.5/include/linux/nfsd/nfsfh.h --- linux-2.5.1/include/linux/nfsd/nfsfh.h Sun Dec 16 23:44:19 2001 +++ linux-2.5/include/linux/nfsd/nfsfh.h Mon Jan 14 14:33:05 2002 @@ -119,15 +119,37 @@ /* * Conversion macros for the filehandle fields. + * + * Keep the device numbers in "backwards compatible + * format", ie the low 16 bits contain the low 8 bits + * of the 20-bit minor and the 12-bit major number. + * + * The high 16 bits contain the rest (4 bits major + * and 12 bits minor), */ static inline __u32 kdev_t_to_u32(kdev_t dev) { - return (__u32) dev; + unsigned int minor = minor(dev); + unsigned int major = major(dev); + __u32 udev; + + /* Create the low 16 bits.. */ + udev = ((major & 0xff) << 8) + (minor & 0xff); + + /* ..and then the rest. */ + major >>= 8; minor >>= 8; + udev |= (major << 28) | (minor << 16); + + return udev; } static inline kdev_t u32_to_kdev_t(__u32 udev) { - return (kdev_t) udev; + unsigned int minor, major; + + minor = (udev & 0xff) | ((udev >> 8) & 0xfff00); + major = ((udev >> 8) & 0xff) | ((udev >> 20) & 0xf00); + return mk_kdev(major, minor); } static inline __u32 ino_t_to_u32(ino_t ino) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/pagemap.h linux-2.5/include/linux/pagemap.h --- linux-2.5.1/include/linux/pagemap.h Sun Dec 16 23:44:05 2001 +++ linux-2.5/include/linux/pagemap.h Mon Jan 14 14:32:24 2002 @@ -29,7 +29,7 @@ #define PAGE_CACHE_ALIGN(addr) (((addr)+PAGE_CACHE_SIZE-1)&PAGE_CACHE_MASK) #define page_cache_get(x) get_page(x) -extern void FASTCALL(page_cache_release(struct page *)); +#define page_cache_release(x) __free_page(x) static inline struct page *page_cache_alloc(struct address_space *x) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/parport.h linux-2.5/include/linux/parport.h --- linux-2.5.1/include/linux/parport.h Wed Nov 14 22:52:47 2001 +++ linux-2.5/include/linux/parport.h Mon Jan 14 14:38:32 2002 @@ -8,6 +8,7 @@ #ifndef _PARPORT_H_ #define _PARPORT_H_ +#include <linux/sched.h> /* Start off with user-visible constants */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/pci_ids.h linux-2.5/include/linux/pci_ids.h --- linux-2.5.1/include/linux/pci_ids.h Sat Dec 8 00:26:13 2001 +++ linux-2.5/include/linux/pci_ids.h Thu Jan 10 13:32:21 2002 @@ -355,6 +355,7 @@ #define PCI_VENDOR_ID_WD 0x101c #define PCI_DEVICE_ID_WD_7197 0x3296 +#define PCI_DEVICE_ID_WD_90C 0xc24a #define PCI_VENDOR_ID_AMI 0x101e #define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960 @@ -646,6 +647,12 @@ #define PCI_DEVICE_ID_APPLE_KL_USB 0x0019 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021 +#define PCI_DEVICE_ID_APPLE_KEYLARGO 0x0022 +#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024 +#define PCI_DEVICE_ID_APPLE_KEYLARGO_P 0x0025 +#define PCI_DEVICE_ID_APPLE_KL_USB_P 0x0026 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P 0x0027 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP15 0x002d #define PCI_DEVICE_ID_APPLE_UNI_N_FW2 0x0030 #define PCI_VENDOR_ID_YAMAHA 0x1073 @@ -855,11 +862,17 @@ #define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX 0x0110 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2 0x0111 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO 0x0112 #define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR 0x0113 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS 0x0150 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2 0x0151 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152 #define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153 +#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 +#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 +#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203 #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_8849 0x8849 @@ -946,11 +959,12 @@ #define PCI_DEVICE_ID_VIA_8233_7 0x3065 #define PCI_DEVICE_ID_VIA_82C686_6 0x3068 #define PCI_DEVICE_ID_VIA_8233_0 0x3074 -#define PCI_DEVICE_ID_VIA_8622 0x3102 -#define PCI_DEVICE_ID_VIA_8233C_0 0x3109 -#define PCI_DEVICE_ID_VIA_8361 0x3112 #define PCI_DEVICE_ID_VIA_8633_0 0x3091 #define PCI_DEVICE_ID_VIA_8367_0 0x3099 +#define PCI_DEVICE_ID_VIA_8622 0x3102 +#define PCI_DEVICE_ID_VIA_8233C_0 0x3109 +#define PCI_DEVICE_ID_VIA_8361 0x3112 +#define PCI_DEVICE_ID_VIA_8233A 0x3147 #define PCI_DEVICE_ID_VIA_86C100A 0x6100 #define PCI_DEVICE_ID_VIA_8231 0x8231 #define PCI_DEVICE_ID_VIA_8231_4 0x8235 @@ -960,7 +974,7 @@ #define PCI_DEVICE_ID_VIA_82C597_1 0x8597 #define PCI_DEVICE_ID_VIA_82C598_1 0x8598 #define PCI_DEVICE_ID_VIA_8601_1 0x8601 -#define PCI_DEVICE_ID_VIA_8505_1 0X8605 +#define PCI_DEVICE_ID_VIA_8505_1 0x8605 #define PCI_DEVICE_ID_VIA_8633_1 0xB091 #define PCI_DEVICE_ID_VIA_8367_1 0xB099 @@ -1111,6 +1125,8 @@ #define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005 #define PCI_DEVICE_ID_ARTOP_ATP860 0x0006 #define PCI_DEVICE_ID_ARTOP_ATP860R 0x0007 +#define PCI_DEVICE_ID_ARTOP_ATP865 0x0008 +#define PCI_DEVICE_ID_ARTOP_ATP865R 0x0009 #define PCI_DEVICE_ID_ARTOP_AEC7610 0x8002 #define PCI_DEVICE_ID_ARTOP_AEC7612UW 0x8010 #define PCI_DEVICE_ID_ARTOP_AEC7612U 0x8020 @@ -1569,6 +1585,7 @@ #define PCI_DEVICE_ID_INTEL_82434 0x04a3 #define PCI_DEVICE_ID_INTEL_I960 0x0960 #define PCI_DEVICE_ID_INTEL_82562ET 0x1031 +#define PCI_DEVICE_ID_INTEL_82801CAM 0x1038 #define PCI_DEVICE_ID_INTEL_82559ER 0x1209 #define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 #define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/pmu.h linux-2.5/include/linux/pmu.h --- linux-2.5.1/include/linux/pmu.h Thu Aug 30 03:49:36 2001 +++ linux-2.5/include/linux/pmu.h Thu Dec 27 16:32:31 2001 @@ -168,19 +168,41 @@ /* priority levels in notifiers */ #define SLEEP_LEVEL_VIDEO 100 /* Video driver (first wake) */ -#define SLEEP_LEVEL_SOUND 90 /* Sound driver */ -#define SLEEP_LEVEL_MEDIABAY 80 /* Media bay driver */ -#define SLEEP_LEVEL_BLOCK 70 /* IDE, SCSI */ -#define SLEEP_LEVEL_NET 60 /* bmac */ -#define SLEEP_LEVEL_ADB 50 /* ADB */ -#define SLEEP_LEVEL_MISC 30 /* Anything */ -#define SLEEP_LEVEL_LAST 0 /* Reserved for apm_emu */ +#define SLEEP_LEVEL_MEDIABAY 90 /* Media bay driver */ +#define SLEEP_LEVEL_BLOCK 80 /* IDE, SCSI */ +#define SLEEP_LEVEL_NET 70 /* bmac, gmac */ +#define SLEEP_LEVEL_MISC 60 /* Anything else */ +#define SLEEP_LEVEL_USERLAND 55 /* Reserved for apm_emu */ +#define SLEEP_LEVEL_ADB 50 /* ADB (async) */ +#define SLEEP_LEVEL_SOUND 40 /* Sound driver (blocking) */ /* special register notifier functions */ int pmu_register_sleep_notifier(struct pmu_sleep_notifier* notifier); int pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* notifier); -#endif /* CONFIG_PMAC_PBOOK */ +#define PMU_MAX_BATTERIES 2 + +/* values for pmu_power_flags */ +#define PMU_PWR_AC_PRESENT 0x00000001 + +/* values for pmu_battery_info.flags */ +#define PMU_BATT_PRESENT 0x00000001 +#define PMU_BATT_CHARGING 0x00000002 +struct pmu_battery_info +{ + unsigned int flags; + unsigned int charge; /* current charge */ + unsigned int max_charge; /* maximum charge */ + signed int current; /* current, positive if charging */ + unsigned int voltage; /* voltage */ + unsigned int time_remaining; /* remaining time */ +}; + +extern int pmu_battery_count; +extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; +extern unsigned int pmu_power_flags; + +#endif /* CONFIG_PMAC_PBOOK */ #endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/pnpbios.h linux-2.5/include/linux/pnpbios.h --- linux-2.5.1/include/linux/pnpbios.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/linux/pnpbios.h Mon Jan 14 14:39:15 2002 @@ -0,0 +1,211 @@ +/* + * 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 + */ + +#ifndef _LINUX_PNPBIOS_H +#define _LINUX_PNPBIOS_H + +#ifdef __KERNEL__ + +#include <linux/types.h> +#include <linux/pci.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() + +struct pnpbios_device_id +{ + char id[8]; + unsigned long driver_data; +}; + +struct pnpbios_driver { + struct list_head node; + char *name; + const struct pnpbios_device_id *id_table; /* NULL if wants all devices */ + int (*probe) (struct pci_dev *dev, const struct pnpbios_device_id *id); /* New device inserted */ + void (*remove) (struct pci_dev *dev); /* Device removed, either due to hotplug remove or module remove */ +}; + +#ifdef CONFIG_PNPBIOS + +/* exported */ +extern int pnpbios_register_driver(struct pnpbios_driver *drv); +extern void pnpbios_unregister_driver(struct pnpbios_driver *drv); + +/* non-exported */ +#define pnpbios_for_each_dev(dev) \ + for(dev = pnpbios_dev_g(pnpbios_devices.next); dev != pnpbios_dev_g(&pnpbios_devices); dev = pnpbios_dev_g(dev->global_list.next)) + + +#define pnpbios_dev_g(n) list_entry(n, struct pci_dev, global_list) + +static __inline struct pnpbios_driver *pnpbios_dev_driver(const struct pci_dev *dev) +{ + return (struct pnpbios_driver *)dev->driver; +} + +extern int pnpbios_dont_use_current_config; +extern void *pnpbios_kmalloc(size_t size, int f); +extern void pnpbios_init (void); +extern void pnpbios_proc_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); +#if needed +extern int pnp_bios_get_event (u16 *message); +extern int pnp_bios_send_message (u16 message); +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); +#endif + +/* + * a helper function which helps ensure correct pnpbios_driver + * setup and cleanup for commonly-encountered hotplug/modular cases + * + * This MUST stay in a header, as it checks for -DMODULE + */ + +static inline int pnpbios_module_init(struct pnpbios_driver *drv) +{ + int rc = pnpbios_register_driver (drv); + + if (rc > 0) + return 0; + + /* iff CONFIG_HOTPLUG and built into kernel, we should + * leave the driver around for future hotplug events. + * For the module case, a hotplug daemon of some sort + * should load a module in response to an insert event. */ +#if defined(CONFIG_HOTPLUG) && !defined(MODULE) + if (rc == 0) + return 0; +#else + if (rc == 0) + rc = -ENODEV; +#endif + + /* if we get here, we need to clean up pci driver instance + * and return some sort of error */ + pnpbios_unregister_driver (drv); + + return rc; +} + +#else /* CONFIG_PNPBIOS */ + +static __inline__ int pnpbios_register_driver(struct pnpbios_driver *drv) +{ + return 0; +} + +static __inline__ void pnpbios_unregister_driver(struct pnpbios_driver *drv) +{ + return; +} + +#endif /* CONFIG_PNPBIOS */ +#endif /* __KERNEL__ */ + +#endif /* _LINUX_PNPBIOS_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/proc_fs.h linux-2.5/include/linux/proc_fs.h --- linux-2.5.1/include/linux/proc_fs.h Sun Dec 16 23:43:28 2001 +++ linux-2.5/include/linux/proc_fs.h Mon Jan 14 14:31:06 2002 @@ -3,6 +3,8 @@ #include <linux/config.h> #include <linux/slab.h> +#include <linux/fs.h> +#include <asm/atomic.h> /* * The proc filesystem constants/structures diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/quota.h linux-2.5/include/linux/quota.h --- linux-2.5.1/include/linux/quota.h Thu Nov 22 18:38:31 2001 +++ linux-2.5/include/linux/quota.h Thu Dec 27 22:10:28 2001 @@ -167,7 +167,6 @@ /* 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) */ - kdev_t dq_dev; /* Device this applies to */ short dq_type; /* Type of quota */ short dq_flags; /* See DQ_* */ unsigned long dq_referenced; /* Number of times this dquot was diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/quotaops.h linux-2.5/include/linux/quotaops.h --- linux-2.5.1/include/linux/quotaops.h Sun Dec 16 23:43:50 2001 +++ linux-2.5/include/linux/quotaops.h Mon Jan 14 14:31:41 2002 @@ -23,7 +23,7 @@ extern void dquot_initialize(struct inode *inode, short type); extern void dquot_drop(struct inode *inode); extern int quota_off(struct super_block *sb, short type); -extern int sync_dquots(kdev_t dev, short type); +extern int sync_dquots(struct super_block *sb, short type); extern int dquot_alloc_block(struct inode *inode, unsigned long number, char prealloc); extern int dquot_alloc_inode(const struct inode *inode, unsigned long number); @@ -159,7 +159,7 @@ return 0; } -#define DQUOT_SYNC(dev) sync_dquots(dev, -1) +#define DQUOT_SYNC(sb) sync_dquots(sb, -1) #define DQUOT_OFF(sb) quota_off(sb, -1) #else @@ -171,7 +171,7 @@ #define DQUOT_DROP(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_SYNC(sb) do { } while(0) #define DQUOT_OFF(sb) do { } while(0) #define DQUOT_TRANSFER(inode, iattr) (0) extern __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/raid/md_k.h linux-2.5/include/linux/raid/md_k.h --- linux-2.5.1/include/linux/raid/md_k.h Tue Dec 11 21:47:35 2001 +++ linux-2.5/include/linux/raid/md_k.h Tue Jan 1 23:42:42 2002 @@ -77,9 +77,9 @@ static inline mddev_t * kdev_to_mddev (kdev_t dev) { - if (MAJOR(dev) != MD_MAJOR) + if (major(dev) != MD_MAJOR) BUG(); - return mddev_map[MINOR(dev)].mddev; + return mddev_map[minor(dev)].mddev; } /* @@ -240,7 +240,7 @@ int (*stop_resync)(mddev_t *mddev); int (*restart_resync)(mddev_t *mddev); - int (*sync_request)(mddev_t *mddev, sector_t sector_nr); + int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster); }; @@ -256,7 +256,7 @@ static inline kdev_t mddev_to_kdev(mddev_t * mddev) { - return MKDEV(MD_MAJOR, mdidx(mddev)); + return mk_kdev(MD_MAJOR, mdidx(mddev)); } extern mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/raid/raid1.h linux-2.5/include/linux/raid/raid1.h --- linux-2.5.1/include/linux/raid/raid1.h Tue Dec 11 21:47:35 2001 +++ linux-2.5/include/linux/raid/raid1.h Mon Jan 7 20:59:29 2002 @@ -9,8 +9,8 @@ int number; int raid_disk; kdev_t dev; - int sect_limit; - int head_position; + sector_t head_position; + atomic_t nr_pending; /* * State bits: @@ -31,23 +31,21 @@ int raid_disks; int working_disks; int last_used; - sector_t next_sect; - int sect_count; + sector_t next_seq_sect; mdk_thread_t *thread, *resync_thread; int resync_mirrors; mirror_info_t *spare; spinlock_t device_lock; /* for use when syncing mirrors: */ - unsigned long start_active, start_ready, - start_pending, start_future; - int cnt_done, cnt_active, cnt_ready, - cnt_pending, cnt_future; - int phase; - int window; - wait_queue_head_t wait_done; - wait_queue_head_t wait_ready; - spinlock_t segment_lock; + + spinlock_t resync_lock; + int nr_pending; + int barrier; + sector_t next_resync; + + wait_queue_head_t wait_idle; + wait_queue_head_t wait_resume; mempool_t *r1bio_pool; mempool_t *r1buf_pool; @@ -62,7 +60,8 @@ #define mddev_to_conf(mddev) ((conf_t *) mddev->private) /* - * this is our 'private' 'collective' RAID1 buffer head. + * this is our 'private' RAID1 bio. + * * it contains information about what kind of IO operations were started * for this RAID1 operation, and about their status: */ @@ -83,6 +82,7 @@ * if the IO is in READ direction, then this bio is used: */ struct bio *read_bio; + int read_disk; /* * if the IO is in WRITE direction, then multiple bios are used: */ @@ -94,5 +94,5 @@ /* bits for r1bio.state */ #define R1BIO_Uptodate 1 -#define R1BIO_SyncPhase 2 + #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/reiserfs_fs.h linux-2.5/include/linux/reiserfs_fs.h --- linux-2.5.1/include/linux/reiserfs_fs.h Tue Nov 27 17:23:27 2001 +++ linux-2.5/include/linux/reiserfs_fs.h Mon Jan 14 14:35:46 2002 @@ -15,10 +15,10 @@ #include <linux/types.h> #ifdef __KERNEL__ #include <linux/slab.h> +#include <linux/interrupt.h> #include <linux/tqueue.h> #include <asm/unaligned.h> #include <linux/bitops.h> -#include <asm/hardirq.h> #include <linux/proc_fs.h> #endif @@ -52,48 +52,17 @@ */ - /* Vladimir, what is the story with - new_get_new_buffer nowadays? I - want a complete explanation written - here. */ - -/* NEW_GET_NEW_BUFFER will try to allocate new blocks better */ -/*#define NEW_GET_NEW_BUFFER*/ -#define OLD_GET_NEW_BUFFER - - /* Vladimir, what about this one too? */ -/* if this is undefined, all inode changes get into stat data immediately, if it can be found in RAM */ -#define DIRTY_LATER - -/* enable journalling */ -#define ENABLE_JOURNAL - #define USE_INODE_GENERATION_COUNTER - -#ifdef __KERNEL__ - -/* #define REISERFS_CHECK */ - #define REISERFS_PREALLOCATE -#endif #define PREALLOCATION_SIZE 8 -/* if this is undefined, all inode changes get into stat data - immediately, if it can be found in RAM */ -#define DIRTY_LATER - - -/*#define READ_LOCK_REISERFS*/ - - /* n must be power of 2 */ #define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u)) // to be ok for alpha and others we have to align structures to 8 byte // boundary. // FIXME: do not change 4 by anything else: there is code which relies on that - /* what 4? -Hans */ #define ROUND_UP(x) _ROUND_UP(x,8LL) /* debug levels. Right now, CONFIG_REISERFS_CHECK means print all debug @@ -148,22 +117,17 @@ strlen ( reiser2fs_super_magic_string))); } - /* ReiserFS leaves the first 64k unused, - so that partition labels have enough - space. If someone wants to write a - fancy bootloader that needs more than - 64k, let us know, and this will be - increased in size. This number must - be larger than than the largest block - size on any platform, or code will - break. -Hans */ +/* ReiserFS leaves the first 64k unused, so that partition labels have + enough space. If someone wants to write a fancy bootloader that + needs more than 64k, let us know, and this will be increased in size. + This number must be larger than than the largest block size on any + platform, or code will break. -Hans */ #define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) #define REISERFS_FIRST_BLOCK unused_define /* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */ #define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) - // reiserfs internal error code (used by search_by_key adn fix_nodes)) #define CARRY_ON 0 #define REPEAT_SEARCH -1 @@ -172,53 +136,54 @@ #define NO_BALANCING_NEEDED (-4) #define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5) -//#define SCHEDULE_OCCURRED 1 -//#define PATH_INCORRECT 2 - -//#define NO_DISK_SPACE (-1) - - - typedef unsigned long b_blocknr_t; typedef __u32 unp_t; - /* who is responsible for this - completely uncommented struct? */ struct unfm_nodeinfo { - /* This is what? */ unp_t unfm_nodenum; - /* now this I know what it is, and - most of the people on our project - know what it is, but I bet nobody - new I hire will have a clue. */ unsigned short unfm_freespace; }; -/* when reiserfs_file_write is called with a byte count >= MIN_PACK_ON_CLOSE, -** it sets the inode to pack on close, and when extending the file, will only -** use unformatted nodes. -** -** This is a big speed up for the journal, which is badly hurt by direct->indirect -** conversions (they must be logged). -*/ -#define MIN_PACK_ON_CLOSE 512 +/* there are two formats of keys: 3.5 and 3.6 + */ +#define KEY_FORMAT_3_5 0 +#define KEY_FORMAT_3_6 1 -// this says about version of all items (but stat data) the object -// consists of -#define inode_items_version(inode) ((inode)->u.reiserfs_i.i_version) - - - /* This is an aggressive tail suppression policy, I am hoping it - improves our benchmarks. The principle behind it is that - percentage space saving is what matters, not absolute space - saving. This is non-intuitive, but it helps to understand it if - you consider that the cost to access 4 blocks is not much more - than the cost to access 1 block, if you have to do a seek and - rotate. A tail risks a non-linear disk access that is - significant as a percentage of total time cost for a 4 block file - and saves an amount of space that is less significant as a - percentage of space, or so goes the hypothesis. -Hans */ +/* there are two stat datas */ +#define STAT_DATA_V1 0 +#define STAT_DATA_V2 1 + +/** this says about version of key of all items (but stat data) the + object consists of */ +#define get_inode_item_key_version( inode ) \ + (((inode)->u.reiserfs_i.i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5) + +#define set_inode_item_key_version( inode, version ) \ + ({ if((version)==KEY_FORMAT_3_6) \ + (inode)->u.reiserfs_i.i_flags |= i_item_key_version_mask; \ + else \ + (inode)->u.reiserfs_i.i_flags &= ~i_item_key_version_mask; }) + +#define get_inode_sd_version(inode) \ + (((inode)->u.reiserfs_i.i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1) + +#define set_inode_sd_version(inode, version) \ + ({ if((version)==STAT_DATA_V2) \ + (inode)->u.reiserfs_i.i_flags |= i_stat_data_version_mask; \ + else \ + (inode)->u.reiserfs_i.i_flags &= ~i_stat_data_version_mask; }) + +/* This is an aggressive tail suppression policy, I am hoping it + improves our benchmarks. The principle behind it is that percentage + space saving is what matters, not absolute space saving. This is + non-intuitive, but it helps to understand it if you consider that the + cost to access 4 blocks is not much more than the cost to access 1 + block, if you have to do a seek and rotate. A tail risks a + non-linear disk access that is significant as a percentage of total + time cost for a 4 block file and saves an amount of space that is + less significant as a percentage of space, or so goes the hypothesis. + -Hans */ #define STORE_TAIL_IN_UNFM(n_file_size,n_tail_size,n_block_size) \ (\ (!(n_tail_size)) || \ @@ -239,28 +204,21 @@ #define REISERFS_VALID_FS 1 #define REISERFS_ERROR_FS 2 - +// +// there are 5 item types currently +// +#define TYPE_STAT_DATA 0 +#define TYPE_INDIRECT 1 +#define TYPE_DIRECT 2 +#define TYPE_DIRENTRY 3 +#define TYPE_MAXTYPE 3 +#define TYPE_ANY 15 // FIXME: comment is required /***************************************************************************/ /* KEY & ITEM HEAD */ /***************************************************************************/ // -// we do support for old format of reiserfs: the problem is to -// distinuquish keys with 32 bit offset and keys with 60 bit ones. On -// leaf level we use ih_version of struct item_head (was -// ih_reserved). For all old items it is set to 0 -// (ITEM_VERSION_1). For new items it is ITEM_VERSION_2. On internal -// levels we have to know version of item key belongs to. -// -#define ITEM_VERSION_1 0 -#define ITEM_VERSION_2 1 - - -/* loff_t - long long */ - - -// // directories use this key as well as old files // struct offset_v1 { @@ -286,11 +244,11 @@ __u64 linear; } __attribute__ ((__packed__)) offset_v2_esafe_overlay; -static inline __u16 offset_v2_k_type( struct offset_v2 *v2 ) +static inline __u16 offset_v2_k_type( const struct offset_v2 *v2 ) { - offset_v2_esafe_overlay tmp = *(offset_v2_esafe_overlay *)v2; + offset_v2_esafe_overlay tmp = *(const constoffset_v2_esafe_overlay *)v2; tmp.linear = le64_to_cpu( tmp.linear ); - return tmp.offset_v2.k_type; + return (tmp.offset_v2.k_type <= TYPE_MAXTYPE)?tmp.offset_v2.k_type:TYPE_ANY; } static inline void set_offset_v2_k_type( struct offset_v2 *v2, int type ) @@ -301,9 +259,9 @@ tmp->linear = le64_to_cpu(tmp->linear); } -static inline loff_t offset_v2_k_offset( struct offset_v2 *v2 ) +static inline loff_t offset_v2_k_offset( const struct offset_v2 *v2 ) { - offset_v2_esafe_overlay tmp = *(offset_v2_esafe_overlay *)v2; + offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2; tmp.linear = le64_to_cpu( tmp.linear ); return tmp.offset_v2.k_offset; } @@ -341,18 +299,11 @@ indirect2direct conversion */ }; - - - - - - - /* Our function for comparing keys can compare keys of different - lengths. It takes as a parameter the length of the keys it is to - compare. These defines are used in determining what is to be - passed to it as that parameter. */ +/* Our function for comparing keys can compare keys of different + lengths. It takes as a parameter the length of the keys it is to + compare. These defines are used in determining what is to be passed + to it as that parameter. */ #define REISERFS_FULL_KEY_LEN 4 - #define REISERFS_SHORT_KEY_LEN 2 /* The result of the key compare */ @@ -362,7 +313,6 @@ #define KEY_FOUND 1 #define KEY_NOT_FOUND 0 - #define KEY_SIZE (sizeof(struct key)) #define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32)) @@ -387,8 +337,6 @@ #define GOTO_PREVIOUS_ITEM 2 #define NAME_FOUND_INVISIBLE 3 - - /* Everything in the filesystem is stored as a set of items. The item head contains the key of the item, its free space (for indirect items) and specifies the location of the item itself @@ -396,37 +344,28 @@ struct item_head { - struct key ih_key; /* Everything in the tree is found by searching for it based on its key.*/ - - /* This is bloat, this should be part - of the item not the item - header. -Hans */ - union { - __u16 ih_free_space_reserved; /* The free space in the last unformatted node of an indirect item if this - is an indirect item. This equals 0xFFFF iff this is a direct item or - stat data item. Note that the key, not this field, is used to determine - the item type, and thus which field this union contains. */ - __u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory - entries in the directory item. */ - } __attribute__ ((__packed__)) u; - __u16 ih_item_len; /* total size of the item body */ - __u16 ih_item_location; /* an offset to the item body within the block */ - /* I thought we were going to use this - for having lots of item types? Why - don't you use this for item type - not item version. That is how you - talked me into this field a year - ago, remember? I am still not - convinced it needs to be 16 bits - (for at least many years), but at - least I can sympathize with that - hope. Change the name from version - to type, and tell people not to use - FFFF in case 16 bits is someday too - small and needs to be extended:-). */ - __u16 ih_version; /* 0 for all old items, 2 for new - ones. Highest bit is set by fsck - temporary, cleaned after all done */ + /* Everything in the tree is found by searching for it based on + * its key.*/ + struct key ih_key; + union { + /* The free space in the last unformatted node of an + indirect item if this is an indirect item. This + equals 0xFFFF iff this is a direct item or stat data + item. Note that the key, not this field, is used to + determine the item type, and thus which field this + union contains. */ + __u16 ih_free_space_reserved; + /* Iff this is a directory item, this field equals the + number of directory entries in the directory item. */ + __u16 ih_entry_count; + } __attribute__ ((__packed__)) u; + __u16 ih_item_len; /* total size of the item body */ + __u16 ih_item_location; /* an offset to the item body + * within the block */ + __u16 ih_version; /* 0 for all old items, 2 for new + ones. Highest bit is set by fsck + temporary, cleaned after all + done */ } __attribute__ ((__packed__)); /* size of item header */ #define IH_SIZE (sizeof(struct item_head)) @@ -446,8 +385,8 @@ #define unreachable_item(ih) (ih_version(ih) & (1 << 15)) -#define get_ih_free_space(ih) (ih_version (ih) == ITEM_VERSION_2 ? 0 : ih_free_space (ih)) -#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == ITEM_VERSION_2) ? 0 : (val))) +#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih)) +#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == KEY_FORMAT_3_6) ? 0 : (val))) /* these operate on indirect items, where you've got an array of ints ** at a possibly unaligned location. These are a noop on ia32 @@ -459,15 +398,6 @@ #define put_block_num(p, i, v) put_unaligned(cpu_to_le32(v), (p) + (i)) // -// there are 5 item types currently -// -#define TYPE_STAT_DATA 0 -#define TYPE_INDIRECT 1 -#define TYPE_DIRECT 2 -#define TYPE_DIRENTRY 3 -#define TYPE_ANY 15 // FIXME: comment is required - -// // in old version uniqueness field shows key type // #define V1_SD_UNIQUENESS 0 @@ -476,6 +406,9 @@ #define V1_DIRENTRY_UNIQUENESS 500 #define V1_ANY_UNIQUENESS 555 // FIXME: comment is required +extern void reiserfs_warning (const char * fmt, ...); +/* __attribute__( ( format ( printf, 1, 2 ) ) ); */ + // // here are conversion routines // @@ -487,14 +420,11 @@ case V1_INDIRECT_UNIQUENESS: return TYPE_INDIRECT; case V1_DIRECT_UNIQUENESS: return TYPE_DIRECT; case V1_DIRENTRY_UNIQUENESS: return TYPE_DIRENTRY; + default: + reiserfs_warning( "vs-500: unknown uniqueness %d\n", uniqueness); + case V1_ANY_UNIQUENESS: + return TYPE_ANY; } -/* - if (uniqueness != V1_ANY_UNIQUENESS) { - printk ("uniqueness %d\n", uniqueness); - BUG (); - } -*/ - return TYPE_ANY; } static inline __u32 type2uniqueness (int type) CONSTF; @@ -505,15 +435,13 @@ case TYPE_INDIRECT: return V1_INDIRECT_UNIQUENESS; case TYPE_DIRECT: return V1_DIRECT_UNIQUENESS; case TYPE_DIRENTRY: return V1_DIRENTRY_UNIQUENESS; + default: + reiserfs_warning( "vs-501: unknown type %d\n", type); + case TYPE_ANY: + return V1_ANY_UNIQUENESS; } - /* - if (type != TYPE_ANY) - BUG (); - */ - return V1_ANY_UNIQUENESS; } - // // key is pointer to on disk key which is stored in le, result is cpu, // there is no way to get version of object from key, so, provide @@ -521,7 +449,7 @@ // static inline loff_t le_key_k_offset (int version, const struct key * key) { - return (version == ITEM_VERSION_1) ? + return (version == KEY_FORMAT_3_5) ? le32_to_cpu( key->u.k_offset_v1.k_offset ) : offset_v2_k_offset( &(key->u.k_offset_v2) ); } @@ -533,7 +461,7 @@ static inline loff_t le_key_k_type (int version, const struct key * key) { - return (version == ITEM_VERSION_1) ? + return (version == KEY_FORMAT_3_5) ? uniqueness2type( le32_to_cpu( key->u.k_offset_v1.k_uniqueness)) : offset_v2_k_type( &(key->u.k_offset_v2) ); } @@ -546,20 +474,21 @@ static inline void set_le_key_k_offset (int version, struct key * key, loff_t offset) { - (version == ITEM_VERSION_1) ? + (version == KEY_FORMAT_3_5) ? (key->u.k_offset_v1.k_offset = cpu_to_le32 (offset)) : /* jdm check */ (set_offset_v2_k_offset( &(key->u.k_offset_v2), offset )); } + + static inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset) { set_le_key_k_offset (ih_version (ih), &(ih->ih_key), offset); } - static inline void set_le_key_k_type (int version, struct key * key, int type) { - (version == ITEM_VERSION_1) ? + (version == KEY_FORMAT_3_5) ? (key->u.k_offset_v1.k_uniqueness = cpu_to_le32(type2uniqueness(type))): (set_offset_v2_k_type( &(key->u.k_offset_v2), type )); } @@ -589,21 +518,21 @@ // static inline loff_t cpu_key_k_offset (const struct cpu_key * key) { - return (key->version == ITEM_VERSION_1) ? + return (key->version == KEY_FORMAT_3_5) ? key->on_disk_key.u.k_offset_v1.k_offset : key->on_disk_key.u.k_offset_v2.k_offset; } static inline loff_t cpu_key_k_type (const struct cpu_key * key) { - return (key->version == ITEM_VERSION_1) ? + return (key->version == KEY_FORMAT_3_5) ? uniqueness2type (key->on_disk_key.u.k_offset_v1.k_uniqueness) : key->on_disk_key.u.k_offset_v2.k_type; } static inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset) { - (key->version == ITEM_VERSION_1) ? + (key->version == KEY_FORMAT_3_5) ? (key->on_disk_key.u.k_offset_v1.k_offset = offset) : (key->on_disk_key.u.k_offset_v2.k_offset = offset); } @@ -611,14 +540,15 @@ static inline void set_cpu_key_k_type (struct cpu_key * key, int type) { - (key->version == ITEM_VERSION_1) ? + (key->version == KEY_FORMAT_3_5) ? (key->on_disk_key.u.k_offset_v1.k_uniqueness = type2uniqueness (type)): (key->on_disk_key.u.k_offset_v2.k_type = type); } + static inline void cpu_key_k_offset_dec (struct cpu_key * key) { - if (key->version == ITEM_VERSION_1) + if (key->version == KEY_FORMAT_3_5) key->on_disk_key.u.k_offset_v1.k_offset --; else key->on_disk_key.u.k_offset_v2.k_offset --; @@ -761,7 +691,7 @@ } __attribute__ ((__packed__)); #define SD_V1_SIZE (sizeof(struct stat_data_v1)) -#define stat_data_v1(ih) (ih_version (ih) == ITEM_VERSION_1) +#define stat_data_v1(ih) (ih_version (ih) == KEY_FORMAT_3_5) #define sd_v1_mode(sdp) (le16_to_cpu((sdp)->sd_mode)) #define set_sd_v1_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v)) #define sd_v1_nlink(sdp) (le16_to_cpu((sdp)->sd_nlink)) @@ -815,11 +745,11 @@ } __attribute__ ((__packed__)) u; } __attribute__ ((__packed__)); // -// this is 40 bytes long +// this is 44 bytes long // #define SD_SIZE (sizeof(struct stat_data)) #define SD_V2_SIZE SD_SIZE -#define stat_data_v2(ih) (ih_version (ih) == ITEM_VERSION_2) +#define stat_data_v2(ih) (ih_version (ih) == KEY_FORMAT_3_6) #define sd_v2_mode(sdp) (le16_to_cpu((sdp)->sd_mode)) #define set_sd_v2_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v)) /* sd_reserved */ @@ -949,76 +879,10 @@ #define de_visible(deh) test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) #define de_hidden(deh) !test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) -/* compose directory item containing "." and ".." entries (entries are - not aligned to 4 byte boundary) */ -/* the last four params are LE */ -static inline void make_empty_dir_item_v1 (char * body, - __u32 dirid, __u32 objid, - __u32 par_dirid, __u32 par_objid) -{ - struct reiserfs_de_head * deh; - - memset (body, 0, EMPTY_DIR_SIZE_V1); - deh = (struct reiserfs_de_head *)body; - - /* direntry header of "." */ - put_deh_offset( &(deh[0]), DOT_OFFSET ); - /* these two are from make_le_item_head, and are are LE */ - deh[0].deh_dir_id = dirid; - deh[0].deh_objectid = objid; - deh[0].deh_state = 0; /* Endian safe if 0 */ - put_deh_location( &(deh[0]), EMPTY_DIR_SIZE_V1 - strlen( "." )); - mark_de_visible(&(deh[0])); - - /* direntry header of ".." */ - put_deh_offset( &(deh[1]), DOT_DOT_OFFSET); - /* key of ".." for the root directory */ - /* these two are from the inode, and are are LE */ - deh[1].deh_dir_id = par_dirid; - deh[1].deh_objectid = par_objid; - deh[1].deh_state = 0; /* Endian safe if 0 */ - put_deh_location( &(deh[1]), deh_location( &(deh[0]) ) - strlen( ".." ) ); - mark_de_visible(&(deh[1])); - - /* copy ".." and "." */ - memcpy (body + deh_location( &(deh[0]) ), ".", 1); - memcpy (body + deh_location( &(deh[1]) ), "..", 2); -} - -/* compose directory item containing "." and ".." entries */ -static inline void make_empty_dir_item (char * body, - __u32 dirid, __u32 objid, - __u32 par_dirid, __u32 par_objid) -{ - struct reiserfs_de_head * deh; - - memset (body, 0, EMPTY_DIR_SIZE); - deh = (struct reiserfs_de_head *)body; - - /* direntry header of "." */ - put_deh_offset( &(deh[0]), DOT_OFFSET ); - /* these two are from make_le_item_head, and are are LE */ - deh[0].deh_dir_id = dirid; - deh[0].deh_objectid = objid; - deh[0].deh_state = 0; /* Endian safe if 0 */ - put_deh_location( &(deh[0]), EMPTY_DIR_SIZE - ROUND_UP( strlen( "." ) ) ); - mark_de_visible(&(deh[0])); - - /* direntry header of ".." */ - put_deh_offset( &(deh[1]), DOT_DOT_OFFSET ); - /* key of ".." for the root directory */ - /* these two are from the inode, and are are LE */ - deh[1].deh_dir_id = par_dirid; - deh[1].deh_objectid = par_objid; - deh[1].deh_state = 0; /* Endian safe if 0 */ - put_deh_location( &(deh[1]), deh_location( &(deh[0])) - ROUND_UP( strlen( ".." ) ) ); - mark_de_visible(&(deh[1])); - - /* copy ".." and "." */ - memcpy (body + deh_location( &(deh[0]) ), ".", 1); - memcpy (body + deh_location( &(deh[1]) ), "..", 2); -} - +extern void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid, + __u32 par_dirid, __u32 par_objid); +extern void make_empty_dir_item (char * body, __u32 dirid, __u32 objid, + __u32 par_dirid, __u32 par_objid); /* array of the entry headers */ /* get item body */ @@ -1059,13 +923,9 @@ // two entries per block (at least) //#define REISERFS_MAX_NAME_LEN(block_size) //((block_size - BLKH_SIZE - IH_SIZE - DEH_SIZE * 2) / 2) - -// two entries per block (at least) #define REISERFS_MAX_NAME_LEN(block_size) 255 - - /* this structure is used for operations on directory entries. It is not a disk structure. */ /* When reiserfs_find_entry or search_by_entry_key find directory @@ -1258,23 +1118,17 @@ // in in-core inode key is stored on le form #define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key)) -//#define mark_tail_converted(inode) (atomic_set(&((inode)->u.reiserfs_i.i_converted),1)) -//#define unmark_tail_converted(inode) (atomic_set(&((inode)->u.reiserfs_i.i_converted), 0)) -//#define is_tail_converted(inode) (atomic_read(&((inode)->u.reiserfs_i.i_converted))) - - #define MAX_UL_INT 0xffffffff #define MAX_INT 0x7ffffff #define MAX_US_INT 0xffff -///#define TOO_LONG_LENGTH (~0ULL) - // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset #define U32_MAX (~(__u32)0) + static inline loff_t max_reiserfs_offset (const struct inode * inode) { - if (inode_items_version (inode) == ITEM_VERSION_1) + if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5) return (loff_t)U32_MAX; return (loff_t)((~(__u64)0) >> 4); @@ -1307,13 +1161,6 @@ /* FIXATE NODES */ /***************************************************************************/ -//#define VI_TYPE_STAT_DATA 1 -//#define VI_TYPE_DIRECT 2 -//#define VI_TYPE_INDIRECT 4 -//#define VI_TYPE_DIRECTORY 8 -//#define VI_TYPE_FIRST_DIRECTORY_ITEM 16 -//#define VI_TYPE_INSERTED_DIRECTORY_ITEM 32 - #define VI_TYPE_LEFT_MERGEABLE 1 #define VI_TYPE_RIGHT_MERGEABLE 2 @@ -1517,7 +1364,7 @@ extern struct item_operations stat_data_ops, indirect_ops, direct_ops, direntry_ops; -extern struct item_operations * item_ops [4]; +extern struct item_operations * item_ops [TYPE_ANY + 1]; #define op_bytes_number(ih,bsize) item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize) #define op_is_left_mergeable(key,bsize) item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize) @@ -1536,11 +1383,7 @@ #define COMP_KEYS comp_keys #define COMP_SHORT_KEYS comp_short_keys -#define keys_of_same_object comp_short_keys - -/*#define COMP_KEYS(p_s_key1, p_s_key2) comp_keys((unsigned long *)(p_s_key1), (unsigned long *)(p_s_key2)) -#define COMP_SHORT_KEYS(p_s_key1, p_s_key2) comp_short_keys((unsigned long *)(p_s_key1), (unsigned long *)(p_s_key2))*/ - +/*#define keys_of_same_object comp_short_keys*/ /* number of blocks pointed to by the indirect item */ #define I_UNFM_NUM(p_s_ih) ( ih_item_len(p_s_ih) / UNFM_P_SIZE ) @@ -1651,7 +1494,7 @@ #define _jhashfn(dev,block) \ ((((dev)<<(JBH_HASH_SHIFT - 6)) ^ ((dev)<<(JBH_HASH_SHIFT - 9))) ^ \ (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12)))) -#define journal_hash(t,dev,block) ((t)[_jhashfn((dev),(block)) & JBH_HASH_MASK]) +#define journal_hash(t,dev,block) ((t)[_jhashfn((kdev_t_to_nr(dev)),(block)) & JBH_HASH_MASK]) /* finds n'th buffer with 0 being the start of this commit. Needs to go away, j_ap_blocks has changed ** since I created this. One chunk of code in journal.c needs changing before deleting it @@ -1675,18 +1518,12 @@ int journal_mark_freed(struct reiserfs_transaction_handle *, struct super_block *, unsigned long blocknr) ; int push_journal_writer(char *w) ; int pop_journal_writer(int windex) ; -int journal_lock_dobalance(struct super_block *p_s_sb) ; -int journal_unlock_dobalance(struct super_block *p_s_sb) ; int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ; int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, unsigned long bl, int size, int searchall, unsigned long *next) ; int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ; -int journal_join(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ; struct super_block *reiserfs_get_super(kdev_t dev) ; void flush_async_commits(struct super_block *p_s_sb) ; -int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) ; -int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) ; - int buffer_journaled(const struct buffer_head *bh) ; int mark_buffer_journal_new(struct buffer_head *bh) ; int reiserfs_sync_all_buffers(kdev_t dev, int wait) ; @@ -1725,6 +1562,10 @@ return 0 ; } +void add_save_link (struct reiserfs_transaction_handle * th, + struct inode * inode, int truncate); +void remove_save_link (struct inode * inode, int truncate); + /* objectid.c */ __u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th); void reiserfs_release_objectid (struct reiserfs_transaction_handle *th, __u32 objectid_to_release); @@ -1762,16 +1603,16 @@ type = offset_v2_k_type( &(key->u.k_offset_v2)); if (type != TYPE_DIRECT && type != TYPE_INDIRECT && type != TYPE_DIRENTRY) - return ITEM_VERSION_1; + return KEY_FORMAT_3_5; - return ITEM_VERSION_2; + return KEY_FORMAT_3_6; } static inline void copy_key (struct key *to, const struct key *from) { - memcpy (to, from, KEY_SIZE); + memcpy (to, from, KEY_SIZE); } @@ -1815,38 +1656,32 @@ struct inode * inode, struct buffer_head * p_s_un_bh); - +void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, + struct key * key); void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * p_s_inode); void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, struct inode * p_s_inode, struct page *, int update_timestamps); -// -//void lock_inode_to_convert (struct inode * p_s_inode); -//void unlock_inode_after_convert (struct inode * p_s_inode); -//void increment_i_read_sync_counter (struct inode * p_s_inode); -//void decrement_i_read_sync_counter (struct inode * p_s_inode); - -#define block_size(inode) ((inode)->i_sb->s_blocksize) +#define i_block_size(inode) ((inode)->i_sb->s_blocksize) #define file_size(inode) ((inode)->i_size) -#define tail_size(inode) (file_size (inode) & (block_size (inode) - 1)) +#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1)) #define tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\ -!STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), block_size (inode))) - -/* -int get_buffer_by_range (struct super_block * p_s_sb, struct key * p_s_range_begin, struct key * p_s_range_end, - struct buffer_head ** pp_s_buf, unsigned long * p_n_objectid); -int get_buffers_from_range (struct super_block * p_s_sb, struct key * p_s_range_start, struct key * p_s_range_end, - struct buffer_head ** p_s_range_buffers, - int n_max_nr_buffers_to_return); -*/ +!STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), i_block_size (inode))) void padd_item (char * item, int total_length, int length); - /* inode.c */ +void reiserfs_read_inode (struct inode * inode) ; +void reiserfs_read_inode2(struct inode * inode, void *p) ; +void reiserfs_delete_inode (struct inode * inode); +void reiserfs_write_inode (struct inode * inode, int) ; +struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *data, + int len, int fhtype, int parent); +int reiserfs_dentry_to_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_parent); + int reiserfs_prepare_write(struct file *, struct page *, unsigned, unsigned) ; void reiserfs_truncate_file(struct inode *, int update_timestamps) ; void make_cpu_key (struct cpu_key * cpu_key, const struct inode * inode, loff_t offset, @@ -1854,24 +1689,9 @@ void make_le_item_head (struct item_head * ih, const struct cpu_key * key, int version, loff_t offset, int type, int length, int entry_count); -/*void store_key (struct key * key); -void forget_key (struct key * key);*/ -int reiserfs_get_block (struct inode * inode, sector_t block, - struct buffer_head * bh_result, int create); struct inode * reiserfs_iget (struct super_block * s, const struct cpu_key * key); -void reiserfs_read_inode (struct inode * inode) ; -void reiserfs_read_inode2(struct inode * inode, void *p) ; -void reiserfs_delete_inode (struct inode * inode); -extern int reiserfs_notify_change(struct dentry * dentry, struct iattr * attr); -void reiserfs_write_inode (struct inode * inode, int) ; -/* nfsd support functions */ -struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent); -int reiserfs_dentry_to_fh(struct dentry *, __u32 *fh, int *lenp, int need_parent); - -/* we don't mark inodes dirty, we just log them */ -void reiserfs_dirty_inode (struct inode * inode) ; struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th, const struct inode * dir, int mode, @@ -1879,36 +1699,12 @@ struct dentry *dentry, struct inode *inode, int * err); int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode); void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode); -int reiserfs_inode_setattr(struct dentry *, struct iattr * attr); /* namei.c */ inline void set_de_name_and_namelen (struct reiserfs_dir_entry * de); int search_by_entry_key (struct super_block * sb, const struct cpu_key * key, struct path * path, struct reiserfs_dir_entry * de); -struct dentry * reiserfs_lookup (struct inode * dir, struct dentry *dentry); -int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode); -int reiserfs_mknod (struct inode * dir_inode, struct dentry *dentry, int mode, int rdev); -int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode); -int reiserfs_rmdir (struct inode * dir, struct dentry *dentry); -int reiserfs_unlink (struct inode * dir, struct dentry *dentry); -int reiserfs_symlink (struct inode * dir, struct dentry *dentry, const char * symname); -int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct dentry *dentry); -int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir, struct dentry *new_dentry); - -/* super.c */ -inline void reiserfs_mark_buffer_dirty (struct buffer_head * bh, int flag); -inline void reiserfs_mark_buffer_clean (struct buffer_head * bh); -void reiserfs_write_super (struct super_block * s); -void reiserfs_put_super (struct super_block * s); -int reiserfs_remount (struct super_block * s, int * flags, char * data); -/*int read_super_block (struct super_block * s, int size); -int read_bitmaps (struct super_block * s); -int read_old_bitmaps (struct super_block * s); -int read_old_super_block (struct super_block * s, int size);*/ -struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent); -int reiserfs_statfs (struct super_block * s, struct statfs * buf); - /* procfs.c */ #if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO ) @@ -1989,14 +1785,19 @@ /* buffer2.c */ -struct buffer_head * reiserfs_getblk (kdev_t n_dev, int n_block, int n_size); +struct buffer_head * reiserfs_getblk (struct super_block *super, int n_block); void wait_buffer_until_released (const struct buffer_head * bh); -struct buffer_head * reiserfs_bread (struct super_block *super, int n_block, - int n_size); +struct buffer_head * reiserfs_bread (struct super_block *super, int n_block); /* fix_nodes.c */ +#ifdef CONFIG_REISERFS_CHECK void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s); void reiserfs_kfree (const void * vp, size_t size, struct super_block * s); +#else +#define reiserfs_kmalloc(x, y, z) kmalloc(x, y) +#define reiserfs_kfree(x, y, z) kfree(x) +#endif + int fix_nodes (int n_op_mode, struct tree_balance * p_s_tb, struct item_head * p_s_ins_ih, const void *); void unfix_nodes (struct tree_balance *); @@ -2006,8 +1807,6 @@ /* prints.c */ void reiserfs_panic (struct super_block * s, const char * fmt, ...) __attribute__ ( ( noreturn ) );/* __attribute__( ( format ( printf, 2, 3 ) ) ) */ -void reiserfs_warning (const char * fmt, ...); -/* __attribute__( ( format ( printf, 1, 2 ) ) ); */ void reiserfs_debug (struct super_block *s, int level, const char * fmt, ...); /* __attribute__( ( format ( printf, 3, 4 ) ) ); */ void print_virtual_node (struct virtual_node * vn); @@ -2099,83 +1898,6 @@ #define reiserfs_test_and_clear_le_bit ext2_clear_bit #define reiserfs_test_le_bit ext2_test_bit #define reiserfs_find_next_zero_le_bit ext2_find_next_zero_bit - - -// -// this was totally copied from from linux's -// find_first_zero_bit and changed a bit -// - -#ifdef __i386__ - -static __inline__ int -find_first_nonzero_bit(const void * addr, unsigned size) { - int res; - int __d0; - void *__d1; - - - if (!size) { - return (0); - } - __asm__ __volatile__ ( - "cld\n\t" - "xorl %%eax,%%eax\n\t" - "repe; scasl\n\t" - "je 1f\n\t" - "movl -4(%%edi),%%eax\n\t" - "subl $4, %%edi\n\t" - "bsfl %%eax,%%eax\n\t" - "1:\tsubl %%edx,%%edi\n\t" - "shll $3,%%edi\n\t" - "addl %%edi,%%eax" - :"=a" (res), - "=c"(__d0), "=D"(__d1) - :"1" ((size + 31) >> 5), "d" (addr), "2" (addr)); - return (res); -} - -#else /* __i386__ */ - -static __inline__ int find_next_nonzero_bit(const void * addr, unsigned size, - unsigned offset) -{ - unsigned int * p = ((unsigned int *) addr) + (offset >> 5); - unsigned int result = offset & ~31UL; - unsigned int tmp; - - if (offset >= size) - return size; - size -= result; - offset &= 31UL; - if (offset) { - tmp = *p++; - /* set to zero first offset bits */ - tmp &= ~(~0UL >> (32-offset)); - if (size < 32) - goto found_first; - if (tmp != 0U) - goto found_middle; - size -= 32; - result += 32; - } - while (size >= 32) { - if ((tmp = *p++) != 0U) - goto found_middle; - result += 32; - size -= 32; - } - if (!size) - return result; - tmp = *p; -found_first: -found_middle: - return result + ffs(tmp); -} - -#define find_first_nonzero_bit(addr,size) find_next_nonzero_bit((addr), (size), 0) - -#endif /* 0 */ /* sometimes reiserfs_truncate may require to allocate few new blocks to perform indirect2direct conversion. People probably used to diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/reiserfs_fs_i.h linux-2.5/include/linux/reiserfs_fs_i.h --- linux-2.5.1/include/linux/reiserfs_fs_i.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/reiserfs_fs_i.h Mon Jan 14 14:31:06 2002 @@ -3,50 +3,47 @@ #include <linux/list.h> +/** bitmasks for i_flags field in reiserfs-specific part of inode */ +typedef enum { + /** this says what format of key do all items (but stat data) of + an object have. If this is set, that format is 3.6 otherwise + - 3.5 */ + i_item_key_version_mask = 0x0001, + /** If this is unset, object has 3.5 stat data, otherwise, it has + 3.6 stat data with 64bit size, 32bit nlink etc. */ + i_stat_data_version_mask = 0x0002, + /** file might need tail packing on close */ + i_pack_on_close_mask = 0x0004, + /** don't pack tail of file */ + i_nopack_mask = 0x0008, + /** If those is set, "safe link" was created for this file during + truncate or unlink. Safe link is used to avoid leakage of disk + space on crash with some files open, but unlinked. */ + i_link_saved_unlink_mask = 0x0010, + i_link_saved_truncate_mask = 0x0020 +} reiserfs_inode_flags; + + struct reiserfs_inode_info { - __u32 i_key [4];/* key is still 4 32 bit integers */ + __u32 i_key [4];/* key is still 4 32 bit integers */ - /* this comment will be totally - cryptic to readers not familiar - with 3.5/3.6 format conversion, and - it does not consider that that 3.6 - might not be the last version */ - int i_version; // this says whether file is old or new - - int i_pack_on_close ; // file might need tail packing on close - - __u32 i_first_direct_byte; // offset of first byte stored in direct item. - - /* My guess is this contains the first - unused block of a sequence of - blocks plus the length of the - sequence, which I think is always - at least two at the time of the - preallocation. I really prefer - allocate on flush conceptually..... - - You know, it really annoys me when - code is this badly commented that I - have to guess what it does. - Neither I nor anyone else has time - for guessing what your - datastructures mean. -Hans */ - //For preallocation - int i_prealloc_block; - int i_prealloc_count; - struct list_head i_prealloc_list; /* per-transaction list of inodes which - * have preallocated blocks */ - /* I regret that you think the below - is a comment you should make.... -Hans */ - //nopack-attribute - int nopack; + /** transient inode flags that are never stored on disk. Bitmasks + for this field are defined above. */ + __u32 i_flags; + + __u32 i_first_direct_byte; // offset of first byte stored in direct item. + + int i_prealloc_block; /* first unused block of a sequence of unused blocks */ + int i_prealloc_count; /* length of that sequence */ + struct list_head i_prealloc_list; /* per-transaction list of inodes which + * have preallocated blocks */ - /* we use these for fsync or O_SYNC to decide which transaction needs - ** to be committed in order for this inode to be properly flushed - */ - unsigned long i_trans_id ; - unsigned long i_trans_index ; + /* we use these for fsync or O_SYNC to decide which transaction + ** needs to be committed in order for this inode to be properly + ** flushed */ + unsigned long i_trans_id ; + unsigned long i_trans_index ; }; - #endif + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/reiserfs_fs_sb.h linux-2.5/include/linux/reiserfs_fs_sb.h --- linux-2.5.1/include/linux/reiserfs_fs_sb.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/reiserfs_fs_sb.h Mon Jan 14 14:31:06 2002 @@ -201,7 +201,7 @@ struct buffer_head *bh ; /* real buffer head */ kdev_t dev ; /* dev of real buffer head */ unsigned long blocknr ; /* block number of real buffer head, == 0 when buffer on disk */ - int state ; + long state ; struct reiserfs_journal_list *jlist ; /* journal list this cnode lives in */ struct reiserfs_journal_cnode *next ; /* next in transaction list */ struct reiserfs_journal_cnode *prev ; /* prev in transaction list */ @@ -264,7 +264,7 @@ struct reiserfs_journal_cnode *j_last ; /* newest journal block */ struct reiserfs_journal_cnode *j_first ; /* oldest journal block. start here for traverse */ - int j_state ; + long j_state ; unsigned long j_trans_id ; unsigned long j_mount_id ; unsigned long j_start ; /* start of current waiting commit (index into j_ap_blocks) */ @@ -407,6 +407,8 @@ /* To be obsoleted soon by per buffer seals.. -Hans */ atomic_t s_generation_counter; // increased by one every time the // tree gets re-balanced + unsigned long s_properties; /* File system properties. Currently holds + on-disk FS format */ /* session statistics */ int s_kmallocs; @@ -420,11 +422,19 @@ int s_bmaps_without_search; int s_direct2indirect; int s_indirect2direct; + /* set up when it's ok for reiserfs_read_inode2() to read from + disk inode with nlink==0. Currently this is only used during + finish_unfinished() processing at mount time */ + int s_is_unlinked_ok; reiserfs_proc_info_data_t s_proc_info_data; struct proc_dir_entry *procdir; }; +/* Definitions of reiserfs on-disk properties: */ +#define REISERFS_3_5 0 +#define REISERFS_3_6 1 +/* Mount options */ #define NOTAIL 0 /* -o notail: no tails will be created in a session */ #define REPLAYONLY 3 /* replay journal and return 0. Use by fsck */ #define REISERFS_NOLOG 4 /* -o nolog: turn journalling off */ @@ -474,7 +484,8 @@ #define dont_have_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << NOTAIL)) #define replay_only(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REPLAYONLY)) #define reiserfs_dont_log(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NOLOG)) -#define old_format_only(s) ((SB_VERSION(s) != REISERFS_VERSION_2) && !((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_CONVERT))) +#define old_format_only(s) ((s)->u.reiserfs_sb.s_properties & (1 << REISERFS_3_5)) +#define convert_reiserfs(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_CONVERT)) void reiserfs_file_buffer (struct buffer_head * bh, int list); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/rtnetlink.h linux-2.5/include/linux/rtnetlink.h --- linux-2.5.1/include/linux/rtnetlink.h Thu Jul 26 21:01:13 2001 +++ linux-2.5/include/linux/rtnetlink.h Thu Dec 13 16:32:37 2001 @@ -546,7 +546,6 @@ extern int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len); -#ifdef CONFIG_RTNETLINK extern struct sock *rtnl; struct rtnetlink_link @@ -568,12 +567,6 @@ extern void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change); -#else - -#define rtmsg_ifinfo(a,b,c) do { } while (0) - -#endif - extern struct semaphore rtnl_sem; #define rtnl_exlock() do { } while(0) @@ -583,14 +576,10 @@ #define rtnl_shlock() down(&rtnl_sem) #define rtnl_shlock_nowait() down_trylock(&rtnl_sem) -#ifndef CONFIG_RTNETLINK -#define rtnl_shunlock() up(&rtnl_sem) -#else #define rtnl_shunlock() do { up(&rtnl_sem); \ if (rtnl && rtnl->receive_queue.qlen) \ rtnl->data_ready(rtnl, 0); \ } while(0) -#endif extern void rtnl_lock(void); extern void rtnl_unlock(void); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/sched.h linux-2.5/include/linux/sched.h --- linux-2.5.1/include/linux/sched.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/sched.h Mon Jan 14 14:31:07 2002 @@ -41,6 +41,7 @@ #define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ #define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ #define CLONE_THREAD 0x00010000 /* Same thread group? */ +#define CLONE_NEWNS 0x00020000 /* New namespace group? */ #define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD) @@ -71,10 +72,10 @@ #define CT_TO_SECS(x) ((x) / HZ) #define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ) -extern int nr_running, nr_threads; +extern int nr_threads; extern int last_pid; +extern unsigned long nr_running(void); -#include <linux/fs.h> #include <linux/time.h> #include <linux/param.h> #include <linux/resource.h> @@ -115,12 +116,6 @@ #define SCHED_FIFO 1 #define SCHED_RR 2 -/* - * This is an additional bit set when we want to - * yield the CPU for one re-schedule.. - */ -#define SCHED_YIELD 0x10 - struct sched_param { int sched_priority; }; @@ -138,7 +133,6 @@ * a separate lock). */ extern rwlock_t tasklist_lock; -extern spinlock_t runqueue_lock; extern spinlock_t mmlist_lock; extern void sched_init(void); @@ -149,6 +143,7 @@ extern void update_process_times(int user); extern void update_one_process(struct task_struct *p, unsigned long user, unsigned long system, int cpu); +extern void scheduler_tick(struct task_struct *p); #define MAX_SCHEDULE_TIMEOUT LONG_MAX extern signed long FASTCALL(schedule_timeout(signed long timeout)); @@ -165,6 +160,7 @@ */ #define NR_OPEN_DEFAULT BITS_PER_LONG +struct namespace; /* * Open file table structure */ @@ -277,6 +273,9 @@ extern struct user_struct root_user; #define INIT_USER (&root_user) +typedef struct task_struct task_t; +typedef struct prio_array prio_array_t; + struct task_struct { /* * offsets of these are hardcoded elsewhere - touch with care @@ -294,35 +293,51 @@ int lock_depth; /* Lock depth */ -/* - * offset 32 begins here on 32-bit platforms. We keep - * all fields in a single cacheline that are needed for - * the goodness() loop in schedule(). - */ - long counter; - long nice; - unsigned long policy; - struct mm_struct *mm; - int processor; /* - * cpus_runnable is ~0 if the process is not running on any - * CPU. It's (1 << cpu) if it's running on a CPU. This mask - * is updated under the runqueue lock. - * - * To determine whether a process might run on a CPU, this - * mask is AND-ed with cpus_allowed. + * offset 32 begins here on 32-bit platforms. */ - unsigned long cpus_runnable, cpus_allowed; + unsigned int cpu; + int prio; + long __nice; + list_t run_list; + prio_array_t *array; + + unsigned int time_slice; + unsigned long sleep_timestamp, run_timestamp; + /* - * (only the 'next' pointer fits into the cacheline, but - * that's just fine.) + * A task's four 'sleep history' entries. + * + * We track the last 4 seconds of time. (including the current second). + * + * A value of '0' means it has spent no time sleeping in that + * particular past second. The maximum value of 'HZ' means that + * the task spent all its time running in that particular second. + * + * 'hist_idx' points to the current second, which, unlike the other + * 3 entries, is only partially complete. This means that a value of + * '25' does not mean the task slept 25% of the time in the current + * second, it means that it spent 25 timer ticks sleeping in the + * current second. + * + * All this might look a bit complex, but it can be maintained very + * small overhead and it gives very good statistics, based on which + * the scheduler can decide whether a task is 'interactive' or a + * 'CPU hog'. See sched.c for more details. */ - struct list_head run_list; - unsigned long sleep_time; + #define SLEEP_HIST_SIZE 4 + + int hist_idx; + int hist[SLEEP_HIST_SIZE]; + + unsigned long policy; + unsigned long cpus_allowed; struct task_struct *next_task, *prev_task; - struct mm_struct *active_mm; + + struct mm_struct *mm, *active_mm; struct list_head local_pages; + unsigned int allocation_order, nr_local_pages; /* task state */ @@ -388,6 +403,8 @@ struct fs_struct *fs; /* open file information */ struct files_struct *files; +/* namespace */ + struct namespace *namespace; /* signal handlers */ spinlock_t sigmask_lock; /* Protects signal and blocked */ struct signal_struct *sig; @@ -425,6 +442,7 @@ #define PF_MEMALLOC 0x00000800 /* Allocating memory */ #define PF_MEMDIE 0x00001000 /* Killed for out-of-memory */ #define PF_FREE_PAGES 0x00002000 /* per process page freeing */ +#define PF_NOIO 0x00004000 /* avoid generating further I/O */ #define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ @@ -444,10 +462,63 @@ */ #define _STK_LIM (8*1024*1024) -#define DEF_COUNTER (10*HZ/100) /* 100 ms time slice */ -#define MAX_COUNTER (20*HZ/100) -#define DEF_NICE (0) +/* + * RT priorites go from 0 to 99, but internally we max + * them out at 128 to make it easier to search the + * scheduler bitmap. + */ +#define MAX_RT_PRIO 128 +/* + * The lower the priority of a process, the more likely it is + * to run. Priority of a process goes from 0 to 167. The 0-99 + * priority range is allocated to RT tasks, the 128-167 range + * is for SCHED_OTHER tasks. + */ +#define MAX_PRIO (MAX_RT_PRIO+40) +#define DEF_USER_NICE 0 + +/* + * Scales user-nice values [ -20 ... 0 ... 19 ] + * to static priority [ 128 ... 167 (MAX_PRIO-1) ] + * + * User-nice value of -20 == static priority 128, and + * user-nice value 19 == static priority 167. The lower + * the priority value, the higher the task's priority. + */ +#define NICE_TO_PRIO(n) (MAX_PRIO-1 + (n) - 19) + +#define DEF_PRIO NICE_TO_PRIO(DEF_USER_NICE) +/* + * Default timeslice is 90 msecs, maximum is 150 msecs. + * Minimum timeslice is 30 msecs. + */ +#define MIN_TIMESLICE ( 30 * HZ / 1000) +#define MAX_TIMESLICE (150 * HZ / 1000) + +#define USER_PRIO(p) ((p)-MAX_RT_PRIO) +#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) + +/* + * PRIO_TO_TIMESLICE scales priority values [ 128 ... 167 ] + * to initial time slice values [ MAX_TIMESLICE (150 msec) ... 2 ] + * + * The higher a process's priority, the bigger timeslices + * it gets during one round of execution. But even the lowest + * priority process gets MIN_TIMESLICE worth of execution time. + */ +#define PRIO_TO_TIMESLICE(p) \ + ((( (MAX_USER_PRIO-1-USER_PRIO(p))*(MAX_TIMESLICE-MIN_TIMESLICE) + \ + MAX_USER_PRIO-1) / MAX_USER_PRIO) + MIN_TIMESLICE) + +#define RT_PRIO_TO_TIMESLICE(p) \ + ((( (MAX_RT_PRIO-(p)-1)*(MAX_TIMESLICE-MIN_TIMESLICE) + \ + MAX_RT_PRIO-1) / MAX_RT_PRIO) + MIN_TIMESLICE) + +extern void set_cpus_allowed(task_t *p, unsigned long new_mask); +extern void set_user_nice(task_t *p, long nice); +asmlinkage long sys_sched_yield(void); +#define yield() sys_sched_yield() /* * The default (Linux) execution domain. @@ -466,14 +537,13 @@ addr_limit: KERNEL_DS, \ exec_domain: &default_exec_domain, \ lock_depth: -1, \ - counter: DEF_COUNTER, \ - nice: DEF_NICE, \ + __nice: DEF_USER_NICE, \ policy: SCHED_OTHER, \ + cpus_allowed: -1, \ mm: NULL, \ active_mm: &init_mm, \ - cpus_runnable: -1, \ - cpus_allowed: -1, \ run_list: LIST_HEAD_INIT(tsk.run_list), \ + time_slice: PRIO_TO_TIMESLICE(DEF_PRIO), \ next_task: &tsk, \ prev_task: &tsk, \ p_opptr: &tsk, \ @@ -549,19 +619,6 @@ return p; } -#define task_has_cpu(tsk) ((tsk)->cpus_runnable != ~0UL) - -static inline void task_set_cpu(struct task_struct *tsk, unsigned int cpu) -{ - tsk->processor = cpu; - tsk->cpus_runnable = 1UL << cpu; -} - -static inline void task_release_cpu(struct task_struct *tsk) -{ - tsk->cpus_runnable = ~0UL; -} - /* per-UID process charging. */ extern struct user_struct * alloc_uid(uid_t); extern void free_uid(struct user_struct *); @@ -589,6 +646,7 @@ extern long FASTCALL(interruptible_sleep_on_timeout(wait_queue_head_t *q, signed long timeout)); extern int FASTCALL(wake_up_process(struct task_struct * tsk)); +extern void FASTCALL(wake_up_forked_process(struct task_struct * tsk)); #define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1) #define wake_up_nr(x, nr) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr) @@ -783,6 +841,7 @@ extern void reparent_to_init(void); extern void daemonize(void); +extern task_t *child_reaper; extern int do_execve(char *, char **, char **, struct pt_regs *); extern int do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long); @@ -791,6 +850,9 @@ extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); +extern void wait_task_inactive(task_t * p); +extern void kick_if_running(task_t * p); + #define __wait_event(wq, condition) \ do { \ wait_queue_t __wait; \ @@ -871,22 +933,8 @@ #define next_thread(p) \ list_entry((p)->thread_group.next, struct task_struct, thread_group) -static inline void del_from_runqueue(struct task_struct * p) -{ - nr_running--; - p->sleep_time = jiffies; - list_del(&p->run_list); - p->run_list.next = NULL; -} - -static inline int task_on_runqueue(struct task_struct *p) -{ - return (p->run_list.next != NULL); -} - static inline void unhash_process(struct task_struct *p) { - if (task_on_runqueue(p)) BUG(); write_lock_irq(&tasklist_lock); nr_threads--; unhash_pid(p); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/securebits.h linux-2.5/include/linux/securebits.h --- linux-2.5.1/include/linux/securebits.h Thu Apr 2 00:26:34 1998 +++ linux-2.5/include/linux/securebits.h Mon Jan 14 13:21:58 2002 @@ -6,7 +6,7 @@ extern unsigned securebits; /* When set UID 0 has no special privileges. When unset, we support - inheritance of root-permissions and suid-root executablew under + inheritance of root-permissions and suid-root executable under compatibility mode. We raise the effective and inheritable bitmasks *of the executable file* if the effective uid of the new process is 0. If the real uid is 0, we raise the inheritable bitmask of the diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/serialP.h linux-2.5/include/linux/serialP.h --- linux-2.5.1/include/linux/serialP.h Sun Dec 16 23:44:43 2001 +++ linux-2.5/include/linux/serialP.h Mon Jan 14 22:39:49 2002 @@ -70,7 +70,7 @@ int x_char; /* xon/xoff character */ int close_delay; unsigned short closing_wait; - unsigned short closing_wait2; + unsigned short closing_wait2; /* obsolete */ int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ int LCR; /* Line control register */ @@ -83,6 +83,7 @@ long pgrp; /* pgrp of opening process */ struct circ_buf xmit; spinlock_t xmit_lock; + spinlock_t irq_spinlock; u8 *iomem_base; u16 iomem_reg_shift; int io_type; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/shm.h linux-2.5/include/linux/shm.h --- linux-2.5.1/include/linux/shm.h Sun Dec 16 23:43:31 2001 +++ linux-2.5/include/linux/shm.h Mon Jan 14 14:31:09 2002 @@ -80,7 +80,6 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr); asmlinkage long sys_shmdt (char *shmaddr); asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); -extern void shm_unuse(swp_entry_t entry, struct page *page); #endif /* __KERNEL__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/shmem_fs.h linux-2.5/include/linux/shmem_fs.h --- linux-2.5.1/include/linux/shmem_fs.h Wed Oct 10 14:53:57 2001 +++ linux-2.5/include/linux/shmem_fs.h Thu Dec 13 16:32:37 2001 @@ -11,7 +11,7 @@ * swapper address space. * * We have to move it here, since not every user of fs.h is including - * mm.h, but m.h is including fs.h via sched .h :-/ + * mm.h, but mm.h is including fs.h via sched .h :-/ */ typedef struct { unsigned long val; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/slab.h linux-2.5/include/linux/slab.h --- linux-2.5.1/include/linux/slab.h Sun Dec 16 23:43:26 2001 +++ linux-2.5/include/linux/slab.h Mon Jan 14 14:31:06 2002 @@ -11,8 +11,8 @@ typedef struct kmem_cache_s kmem_cache_t; -#include <linux/mm.h> -#include <linux/cache.h> +#include <linux/gfp.h> +#include <linux/types.h> /* flags for kmem_cache_alloc() */ #define SLAB_NOFS GFP_NOFS @@ -64,6 +64,7 @@ extern int FASTCALL(kmem_cache_reap(int)); extern int slabinfo_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); +struct file; extern int slabinfo_write_proc(struct file *file, const char *buffer, unsigned long count, void *data); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/smp.h linux-2.5/include/linux/smp.h --- linux-2.5.1/include/linux/smp.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/smp.h Mon Jan 14 14:31:06 2002 @@ -86,6 +86,8 @@ #define cpu_number_map(cpu) 0 #define smp_call_function(func,info,retry,wait) ({ 0; }) #define cpu_online_map 1 +static inline void smp_send_reschedule(int cpu) { } +static inline void smp_send_reschedule_all(void) { } #endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/socket.h linux-2.5/include/linux/socket.h --- linux-2.5.1/include/linux/socket.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/socket.h Mon Jan 14 14:31:06 2002 @@ -156,6 +156,7 @@ #define AF_IRDA 23 /* IRDA sockets */ #define AF_PPPOX 24 /* PPPoX sockets */ #define AF_WANPIPE 25 /* Wanpipe API Sockets */ +#define AF_LLC 26 /* Linux LLC */ #define AF_BLUETOOTH 31 /* Bluetooth sockets */ #define AF_MAX 32 /* For now.. */ @@ -187,6 +188,7 @@ #define PF_IRDA AF_IRDA #define PF_PPPOX AF_PPPOX #define PF_WANPIPE AF_WANPIPE +#define PF_LLC AF_LLC #define PF_BLUETOOTH AF_BLUETOOTH #define PF_MAX AF_MAX @@ -237,6 +239,8 @@ #define SOL_ATM 264 /* ATM layer (cell level) */ #define SOL_AAL 265 /* ATM Adaption Layer (packet level) */ #define SOL_IRDA 266 +#define SOL_NETBEUI 267 +#define SOL_LLC 268 /* IPX options */ #define IPX_TYPE 1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/sonypi.h linux-2.5/include/linux/sonypi.h --- linux-2.5.1/include/linux/sonypi.h Thu Oct 11 18:17:22 2001 +++ linux-2.5/include/linux/sonypi.h Tue Jan 8 01:17:10 2002 @@ -75,9 +75,21 @@ #define SONYPI_EVENT_LID_OPENED 37 -/* brightness etc. ioctls */ -#define SONYPI_IOCGBRT _IOR('v', 0, __u8) -#define SONYPI_IOCSBRT _IOW('v', 0, __u8) +/* get/set brightness */ +#define SONYPI_IOCGBRT _IOR('v', 0, __u8) +#define SONYPI_IOCSBRT _IOW('v', 0, __u8) + +/* get battery full capacity/remaining capacity */ +#define SONYPI_IOCGBAT1CAP _IOR('v', 2, __u16) +#define SONYPI_IOCGBAT1REM _IOR('v', 3, __u16) +#define SONYPI_IOCGBAT2CAP _IOR('v', 4, __u16) +#define SONYPI_IOCGBAT2REM _IOR('v', 5, __u16) + +/* get battery flags: battery1/battery2/ac adapter present */ +#define SONYPI_BFLAGS_B1 0x01 +#define SONYPI_BFLAGS_B2 0x02 +#define SONYPI_BFLAGS_AC 0x04 +#define SONYPI_IOCGBATFLAGS _IOR('v', 7, __u8) #ifdef __KERNEL__ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/stringify.h linux-2.5/include/linux/stringify.h --- linux-2.5.1/include/linux/stringify.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/linux/stringify.h Sat Dec 29 11:10:40 2001 @@ -0,0 +1,12 @@ +#ifndef __LINUX_STRINGIFY_H +#define __LINUX_STRINGIFY_H + +/* Indirect stringification. Doing two levels allows the parameter to be a + * macro itself. For example, compile with -DFOO=bar, __stringify(FOO) + * converts to "bar". + */ + +#define __stringify_1(x) #x +#define __stringify(x) __stringify_1(x) + +#endif /* !__LINUX_STRINGIFY_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/sunrpc/clnt.h linux-2.5/include/linux/sunrpc/clnt.h --- linux-2.5.1/include/linux/sunrpc/clnt.h Sun Dec 16 23:44:19 2001 +++ linux-2.5/include/linux/sunrpc/clnt.h Mon Jan 14 14:31:07 2002 @@ -15,6 +15,7 @@ #include <linux/sunrpc/auth.h> #include <linux/sunrpc/stats.h> #include <linux/sunrpc/xdr.h> +#include <asm/signal.h> /* * This defines an RPC port mapping @@ -136,7 +137,6 @@ xprt_set_timeout(&clnt->cl_timeout, retr, incr); } -extern void rpciod_tcp_dispatcher(void); extern void rpciod_wake_up(void); /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/tcp_diag.h linux-2.5/include/linux/tcp_diag.h --- linux-2.5.1/include/linux/tcp_diag.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/include/linux/tcp_diag.h Thu Dec 13 16:32:37 2001 @@ -0,0 +1,116 @@ +#ifndef _TCP_DIAG_H_ +#define _TCP_DIAG_H_ 1 + +/* Just some random number */ +#define TCPDIAG_GETSOCK 18 + +/* Socket identity */ +struct tcpdiag_sockid +{ + __u16 tcpdiag_sport; + __u16 tcpdiag_dport; + __u32 tcpdiag_src[4]; + __u32 tcpdiag_dst[4]; + __u32 tcpdiag_if; + __u32 tcpdiag_cookie[2]; +#define TCPDIAG_NOCOOKIE (~0U) +}; + +/* Request structure */ + +struct tcpdiagreq +{ + __u8 tcpdiag_family; /* Family of addresses. */ + __u8 tcpdiag_src_len; + __u8 tcpdiag_dst_len; + __u8 tcpdiag_ext; /* Query extended information */ + + struct tcpdiag_sockid id; + + __u32 tcpdiag_states; /* States to dump */ + __u32 tcpdiag_dbs; /* Tables to dump (NI) */ +}; + +enum +{ + TCPDIAG_REQ_NONE, + TCPDIAG_REQ_BYTECODE, +}; + +#define TCPDIAG_REQ_MAX TCPDIAG_REQ_BYTECODE + +/* Bytecode is sequence of 4 byte commands followed by variable arguments. + * All the commands identified by "code" are conditional jumps forward: + * to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be + * length of the command and its arguments. + */ + +struct tcpdiag_bc_op +{ + unsigned char code; + unsigned char yes; + unsigned short no; +}; + +enum +{ + TCPDIAG_BC_NOP, + TCPDIAG_BC_JMP, + TCPDIAG_BC_S_GE, + TCPDIAG_BC_S_LE, + TCPDIAG_BC_D_GE, + TCPDIAG_BC_D_LE, + TCPDIAG_BC_AUTO, + TCPDIAG_BC_S_COND, + TCPDIAG_BC_D_COND, +}; + +struct tcpdiag_hostcond +{ + __u8 family; + __u8 prefix_len; + int port; + __u32 addr[0]; +}; + +/* Base info structure. It contains socket identity (addrs/ports/cookie) + * and, alas, the information shown by netstat. */ +struct tcpdiagmsg +{ + __u8 tcpdiag_family; + __u8 tcpdiag_state; + __u8 tcpdiag_timer; + __u8 tcpdiag_retrans; + + struct tcpdiag_sockid id; + + __u32 tcpdiag_expires; + __u32 tcpdiag_rqueue; + __u32 tcpdiag_wqueue; + __u32 tcpdiag_uid; + __u32 tcpdiag_inode; +}; + +/* Extensions */ + +enum +{ + TCPDIAG_NONE, + TCPDIAG_MEMINFO, + TCPDIAG_INFO, +}; + +#define TCPDIAG_MAX TCPDIAG_INFO + + +/* TCPDIAG_MEM */ + +struct tcpdiag_meminfo +{ + __u32 tcpdiag_rmem; + __u32 tcpdiag_wmem; + __u32 tcpdiag_fmem; + __u32 tcpdiag_tmem; +}; + +#endif /* _TCP_DIAG_H_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/threads.h linux-2.5/include/linux/threads.h --- linux-2.5.1/include/linux/threads.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/threads.h Mon Jan 14 14:31:05 2002 @@ -5,7 +5,7 @@ /* * The default limit for the nr of threads is now in - * /proc/sys/kernel/max-threads. + * /proc/sys/kernel/threads-max. */ #ifdef CONFIG_SMP diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/tpqic02.h linux-2.5/include/linux/tpqic02.h --- linux-2.5.1/include/linux/tpqic02.h Sun Dec 16 23:44:43 2001 +++ linux-2.5/include/linux/tpqic02.h Mon Jan 14 14:36:34 2002 @@ -587,10 +587,10 @@ * |___________________ Reserved for diagnostics during debugging. */ -#define TP_REWCLOSE(d) ((MINOR(d)&0x01) == 1) /* rewind bit */ +#define TP_REWCLOSE(d) ((minor(d)&0x01) == 1) /* rewind bit */ /* 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 */ +#define TP_DENS(dev) ((minor(dev) >> 1) & 0x07) /* tape density */ +#define TP_UNIT(dev) ((minor(dev) >> 4) & 0x07) /* unit number */ /* print excessive diagnostics */ #define TP_DIAGS(dev) (QIC02_TAPE_DEBUG & TPQD_DIAGS) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/tty_driver.h linux-2.5/include/linux/tty_driver.h --- linux-2.5.1/include/linux/tty_driver.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/tty_driver.h Mon Jan 14 14:31:06 2002 @@ -130,6 +130,7 @@ struct termios init_termios; /* Initial termios */ int flags; /* tty driver flags */ int *refcount; /* for loadable tty drivers */ + struct console *console;/* console attached to this tty hardware */ struct proc_dir_entry *proc_entry; /* /proc fs entry */ struct tty_driver *other; /* only used for the PTY driver */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/usb.h linux-2.5/include/linux/usb.h --- linux-2.5.1/include/linux/usb.h Sun Dec 16 23:46:59 2001 +++ linux-2.5/include/linux/usb.h Mon Jan 14 14:39:23 2002 @@ -117,13 +117,26 @@ mdelay(ms); } -typedef struct { - __u8 requesttype; - __u8 request; - __u16 value; - __u16 index; - __u16 length; -} devrequest __attribute__ ((packed)); +/** + * struct usb_ctrlrequest - structure used to make USB device control requests easier to create and decode + * @bRequestType: matches the USB bmRequestType field + * @bRequest: matches the USB bRequest field + * @wValue: matches the USB wValue field + * @wIndex: matches the USB wIndex field + * @wLength: matches the USB wLength field + * + * This structure is used to send control requests to a USB device. It matches + * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the + * USB spec for a fuller description of the different fields, and what they are + * used for. + */ +struct usb_ctrlrequest { + __u8 bRequestType; + __u8 bRequest; + __u16 wValue; + __u16 wIndex; + __u16 wLength; +} __attribute__ ((packed)); /* * USB device number allocation bitmap. There's one bitmap @@ -460,6 +473,7 @@ /** * struct usb_driver - identifies USB driver to usbcore + * @owner: pointer to the module owner of this driver * @name: The driver name should be unique among USB drivers * @probe: Called to see if the driver is willing to manage a particular * interface on a device. The probe routine returns a handle that @@ -502,6 +516,7 @@ * well as cancel any I/O requests that are still pending. */ struct usb_driver { + struct module *owner; const char *name; void *(*probe)( @@ -521,7 +536,7 @@ struct semaphore serialize; - /* ioctl -- userspace apps can talk to drivers through usbdevfs */ + /* ioctl -- userspace apps can talk to drivers through usbfs */ int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf); /* support for "new-style" USB hotplugging */ @@ -567,7 +582,7 @@ unsigned int length; /* expected length */ unsigned int actual_length; unsigned int status; -} iso_packet_descriptor_t, *piso_packet_descriptor_t; +} iso_packet_descriptor_t; struct urb; @@ -629,7 +644,7 @@ * * This structure identifies USB transfer requests. URBs may be allocated * in any way, although usb_alloc_urb() is often convenient. Initialization - * may be done using various FILL_*_URB() macros. URBs are submitted + * may be done using various usb_fill_*_urb() functions. URBs are submitted * using usb_submit_urb(), and pending requests may be canceled using * usb_unlink_urb(). * @@ -729,87 +744,7 @@ iso_packet_descriptor_t iso_frame_desc[0]; /* (in) ISO ONLY */ }; -typedef struct urb urb_t, *purb_t; - -/** - * FILL_CONTROL_URB - macro to help initialize a control urb - * @URB: pointer to the urb to initialize. - * @DEV: pointer to the struct usb_device for this urb. - * @PIPE: the endpoint pipe - * @SETUP_PACKET: pointer to the setup_packet buffer - * @TRANSFER_BUFFER: pointer to the transfer buffer - * @BUFFER_LENGTH: length of the transfer buffer - * @COMPLETE: pointer to the usb_complete_t function - * @CONTEXT: what to set the urb context to. - * - * Initializes a control urb with the proper information needed to submit - * it to a device. This macro is depreciated, the usb_fill_control_urb() - * function should be used instead. - */ -#define FILL_CONTROL_URB(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \ - do {\ - spin_lock_init(&(URB)->lock);\ - (URB)->dev=DEV;\ - (URB)->pipe=PIPE;\ - (URB)->setup_packet=SETUP_PACKET;\ - (URB)->transfer_buffer=TRANSFER_BUFFER;\ - (URB)->transfer_buffer_length=BUFFER_LENGTH;\ - (URB)->complete=COMPLETE;\ - (URB)->context=CONTEXT;\ - } while (0) - -/** - * FILL_BULK_URB - macro to help initialize a bulk urb - * @URB: pointer to the urb to initialize. - * @DEV: pointer to the struct usb_device for this urb. - * @PIPE: the endpoint pipe - * @TRANSFER_BUFFER: pointer to the transfer buffer - * @BUFFER_LENGTH: length of the transfer buffer - * @COMPLETE: pointer to the usb_complete_t function - * @CONTEXT: what to set the urb context to. - * - * Initializes a bulk urb with the proper information needed to submit it - * to a device. This macro is depreciated, the usb_fill_bulk_urb() - * function should be used instead. - */ -#define FILL_BULK_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \ - do {\ - spin_lock_init(&(URB)->lock);\ - (URB)->dev=DEV;\ - (URB)->pipe=PIPE;\ - (URB)->transfer_buffer=TRANSFER_BUFFER;\ - (URB)->transfer_buffer_length=BUFFER_LENGTH;\ - (URB)->complete=COMPLETE;\ - (URB)->context=CONTEXT;\ - } while (0) - -/** - * FILL_INT_URB - macro to help initialize a interrupt urb - * @URB: pointer to the urb to initialize. - * @DEV: pointer to the struct usb_device for this urb. - * @PIPE: the endpoint pipe - * @TRANSFER_BUFFER: pointer to the transfer buffer - * @BUFFER_LENGTH: length of the transfer buffer - * @COMPLETE: pointer to the usb_complete_t function - * @CONTEXT: what to set the urb context to. - * @INTERVAL: what to set the urb interval to. - * - * Initializes a interrupt urb with the proper information needed to submit - * it to a device. This macro is depreciated, the usb_fill_int_urb() - * function should be used instead. - */ -#define FILL_INT_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL) \ - do {\ - spin_lock_init(&(URB)->lock);\ - (URB)->dev=DEV;\ - (URB)->pipe=PIPE;\ - (URB)->transfer_buffer=TRANSFER_BUFFER;\ - (URB)->transfer_buffer_length=BUFFER_LENGTH;\ - (URB)->complete=COMPLETE;\ - (URB)->context=CONTEXT;\ - (URB)->interval=INTERVAL;\ - (URB)->start_frame=-1;\ - } while (0) +typedef struct urb urb_t; /** * usb_fill_control_urb - initializes a control urb @@ -908,11 +843,22 @@ urb->interval = interval; urb->start_frame = -1; } - + +/* + * old style macros to enable 2.4 and 2.2 drivers to build + * properly. Please do not use these for new USB drivers. + */ +#define FILL_CONTROL_URB(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \ + usb_fill_control_urb(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) +#define FILL_BULK_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \ + usb_fill_bulk_urb(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) +#define FILL_INT_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL) \ + usb_fill_int_urb(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL) + extern struct urb *usb_alloc_urb(int iso_packets); -extern void usb_free_urb(struct urb *purb); -extern int usb_submit_urb(struct urb *purb); -extern int usb_unlink_urb(struct urb *purb); +extern void usb_free_urb(struct urb *urb); +extern int usb_submit_urb(struct urb *urb); +extern int usb_unlink_urb(struct urb *urb); /*-------------------------------------------------------------------* * SYNCHRONOUS CALL SUPPORT * @@ -959,8 +905,8 @@ int (*allocate)(struct usb_device *); int (*deallocate)(struct usb_device *); int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb* purb); - int (*unlink_urb) (struct urb* purb); + int (*submit_urb) (struct urb *urb); + int (*unlink_urb) (struct urb *urb); }; #define DEVNUM_ROUND_ROBIN /***** OPTION *****/ @@ -989,8 +935,7 @@ int bandwidth_int_reqs; /* number of Interrupt requesters */ int bandwidth_isoc_reqs; /* number of Isoc. requesters */ - /* usbdevfs inode list */ - struct list_head inodes; + struct dentry *dentry; /* usbfs dentry entry for the bus */ atomic_t refcnt; }; @@ -1028,6 +973,21 @@ #define NS_TO_US(ns) ((ns + 500L) / 1000L) /* convert & round nanoseconds to microseconds */ +/* + * As of USB 2.0, full/low speed devices are segregated into trees. + * One type grows from USB 1.1 host controllers (OHCI, UHCI etc). + * The other type grows from high speed hubs when they connect to + * full/low speed devices using "Transaction Translators" (TTs). + * + * TTs should only be known to the hub driver, and high speed bus + * drivers (only EHCI for now). They affect periodic scheduling and + * sometimes control/bulk error recovery. + */ +struct usb_tt { + struct usb_device *hub; /* upstream highspeed hub */ + int multi; /* true means one TT per port */ +}; + /* -------------------------------------------------------------------------- */ @@ -1056,7 +1016,8 @@ #define USB_MAXCHILDREN (16) struct usb_device { - int devnum; /* Device number on USB bus */ + int devnum; /* Address on USB bus */ + char devpath [16]; /* Use in messages: /port/port/... */ enum { USB_SPEED_UNKNOWN = 0, /* enumerating */ @@ -1064,8 +1025,8 @@ 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 */ + struct usb_tt *tt; /* low/full speed dev, highspeed hub */ + int ttport; /* device port on that tt hub */ atomic_t refcnt; /* Reference count */ struct semaphore serialize; @@ -1090,9 +1051,8 @@ void *hcpriv; /* Host Controller private data */ - /* usbdevfs inode list */ - struct list_head inodes; struct list_head filelist; + struct dentry *dentry; /* usbfs dentry entry for the device */ /* * Child devices - these can be either new devices @@ -1254,7 +1214,7 @@ /* * bus and driver list - * exported only for usbdevfs (not visible outside usbcore) + * exported only for usbfs (not visible outside usbcore) */ extern struct list_head usb_driver_list; @@ -1271,23 +1231,25 @@ * these are expected to be called from the USB core/hub thread * with the kernel lock held */ -extern void usbdevfs_add_bus(struct usb_bus *bus); -extern void usbdevfs_remove_bus(struct usb_bus *bus); -extern void usbdevfs_add_device(struct usb_device *dev); -extern void usbdevfs_remove_device(struct usb_device *dev); +extern void usbfs_add_bus(struct usb_bus *bus); +extern void usbfs_remove_bus(struct usb_bus *bus); +extern void usbfs_add_device(struct usb_device *dev); +extern void usbfs_remove_device(struct usb_device *dev); +extern void usbfs_update_special (void); -extern int usbdevfs_init(void); -extern void usbdevfs_cleanup(void); +extern int usbfs_init(void); +extern void usbfs_cleanup(void); #else /* CONFIG_USB_DEVICEFS */ -static inline void usbdevfs_add_bus(struct usb_bus *bus) {} -static inline void usbdevfs_remove_bus(struct usb_bus *bus) {} -static inline void usbdevfs_add_device(struct usb_device *dev) {} -static inline void usbdevfs_remove_device(struct usb_device *dev) {} +static inline void usbfs_add_bus(struct usb_bus *bus) {} +static inline void usbfs_remove_bus(struct usb_bus *bus) {} +static inline void usbfs_add_device(struct usb_device *dev) {} +static inline void usbfs_remove_device(struct usb_device *dev) {} +static inline void usbfs_update_special (void) {} -static inline int usbdevfs_init(void) { return 0; } -static inline void usbdevfs_cleanup(void) { } +static inline int usbfs_init(void) { return 0; } +static inline void usbfs_cleanup(void) { } #endif /* CONFIG_USB_DEVICEFS */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/usbdevice_fs.h linux-2.5/include/linux/usbdevice_fs.h --- linux-2.5.1/include/linux/usbdevice_fs.h Sun Dec 16 23:47:13 2001 +++ linux-2.5/include/linux/usbdevice_fs.h Mon Jan 14 14:39:23 2002 @@ -40,11 +40,11 @@ /* usbdevfs ioctl codes */ struct usbdevfs_ctrltransfer { - __u8 requesttype; - __u8 request; - __u16 value; - __u16 index; - __u16 length; + __u8 bRequestType; + __u8 bRequest; + __u16 wValue; + __u16 wIndex; + __u16 wLength; __u32 timeout; /* in milliseconds */ void *data; }; @@ -150,17 +150,6 @@ #include <linux/list.h> #include <asm/semaphore.h> -/* - * inode number macros - */ -#define ITYPE(x) ((x)&(0xf<<28)) -#define ISPECIAL (0<<28) -#define IBUS (1<<28) -#define IDEVICE (2<<28) -#define IBUSNR(x) (((x)>>8)&0xff) -#define IDEVNR(x) ((x)&0xff) - -#define IROOT 1 struct dev_state { struct list_head list; /* state list */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/vt_kern.h linux-2.5/include/linux/vt_kern.h --- linux-2.5.1/include/linux/vt_kern.h Sun Dec 16 23:44:28 2001 +++ linux-2.5/include/linux/vt_kern.h Mon Jan 14 14:33:06 2002 @@ -9,6 +9,7 @@ #include <linux/config.h> #include <linux/vt.h> #include <linux/kd.h> +#include <linux/tty.h> /* * Presently, a lot of graphics programs do not restore the contents of diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/linux/wait.h linux-2.5/include/linux/wait.h --- linux-2.5.1/include/linux/wait.h Sun Dec 16 23:43:25 2001 +++ linux-2.5/include/linux/wait.h Mon Jan 14 14:31:06 2002 @@ -19,24 +19,11 @@ #include <asm/page.h> #include <asm/processor.h> -/* - * 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 struct task_struct * task; struct list_head task_list; -#if WAITQUEUE_DEBUG - long __magic; - long __waker; -#endif }; typedef struct __wait_queue wait_queue_t; @@ -77,129 +64,47 @@ struct __wait_queue_head { wq_lock_t lock; struct list_head task_list; -#if WAITQUEUE_DEBUG - long __magic; - long __creator; -#endif }; typedef struct __wait_queue_head wait_queue_head_t; /* - * Debugging macros. We eschew `do { } while (0)' because gcc can generate - * spurious .aligns. - */ -#if WAITQUEUE_DEBUG -#define WQ_BUG() BUG() -#define CHECK_MAGIC(x) \ - do { \ - if ((x) != (long)&(x)) { \ - printk("bad magic %lx (should be %lx), ", \ - (long)x, (long)&(x)); \ - WQ_BUG(); \ - } \ - } while (0) -#define CHECK_MAGIC_WQHEAD(x) \ - do { \ - if ((x)->__magic != (long)&((x)->__magic)) { \ - printk("bad magic %lx (should be %lx, creator %lx), ", \ - (x)->__magic, (long)&((x)->__magic), (x)->__creator); \ - WQ_BUG(); \ - } \ - } while (0) -#define WQ_CHECK_LIST_HEAD(list) \ - do { \ - if (!(list)->next || !(list)->prev) \ - WQ_BUG(); \ - } while(0) -#define WQ_NOTE_WAKER(tsk) \ - do { \ - (tsk)->__waker = (long)__builtin_return_address(0); \ - } while (0) -#else -#define WQ_BUG() -#define CHECK_MAGIC(x) -#define CHECK_MAGIC_WQHEAD(x) -#define WQ_CHECK_LIST_HEAD(list) -#define WQ_NOTE_WAKER(tsk) -#endif - -/* * Macros for declaration and initialisaton of the datatypes */ -#if WAITQUEUE_DEBUG -# define __WAITQUEUE_DEBUG_INIT(name) (long)&(name).__magic, 0 -# define __WAITQUEUE_HEAD_DEBUG_INIT(name) (long)&(name).__magic, (long)&(name).__magic -#else -# define __WAITQUEUE_DEBUG_INIT(name) -# define __WAITQUEUE_HEAD_DEBUG_INIT(name) -#endif - #define __WAITQUEUE_INITIALIZER(name, tsk) { \ task: tsk, \ - task_list: { NULL, NULL }, \ - __WAITQUEUE_DEBUG_INIT(name)} + task_list: { NULL, NULL } } #define DECLARE_WAITQUEUE(name, tsk) \ wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk) #define __WAIT_QUEUE_HEAD_INITIALIZER(name) { \ lock: WAITQUEUE_RW_LOCK_UNLOCKED, \ - task_list: { &(name).task_list, &(name).task_list }, \ - __WAITQUEUE_HEAD_DEBUG_INIT(name)} + task_list: { &(name).task_list, &(name).task_list } } #define DECLARE_WAIT_QUEUE_HEAD(name) \ wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name) static inline void init_waitqueue_head(wait_queue_head_t *q) { -#if WAITQUEUE_DEBUG - if (!q) - WQ_BUG(); -#endif q->lock = WAITQUEUE_RW_LOCK_UNLOCKED; INIT_LIST_HEAD(&q->task_list); -#if WAITQUEUE_DEBUG - q->__magic = (long)&q->__magic; - q->__creator = (long)current_text_addr(); -#endif } static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p) { -#if WAITQUEUE_DEBUG - if (!q || !p) - WQ_BUG(); -#endif q->flags = 0; q->task = p; -#if WAITQUEUE_DEBUG - q->__magic = (long)&q->__magic; -#endif } static inline int waitqueue_active(wait_queue_head_t *q) { -#if WAITQUEUE_DEBUG - if (!q) - WQ_BUG(); - CHECK_MAGIC_WQHEAD(q); -#endif - return !list_empty(&q->task_list); } static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) { -#if WAITQUEUE_DEBUG - if (!head || !new) - WQ_BUG(); - CHECK_MAGIC_WQHEAD(head); - CHECK_MAGIC(new->__magic); - if (!head->task_list.next || !head->task_list.prev) - WQ_BUG(); -#endif list_add(&new->task_list, &head->task_list); } @@ -209,25 +114,12 @@ static inline void __add_wait_queue_tail(wait_queue_head_t *head, wait_queue_t *new) { -#if WAITQUEUE_DEBUG - if (!head || !new) - WQ_BUG(); - CHECK_MAGIC_WQHEAD(head); - CHECK_MAGIC(new->__magic); - if (!head->task_list.next || !head->task_list.prev) - WQ_BUG(); -#endif list_add_tail(&new->task_list, &head->task_list); } static inline void __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old) { -#if WAITQUEUE_DEBUG - if (!old) - WQ_BUG(); - CHECK_MAGIC(old->__magic); -#endif list_del(&old->task_list); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/net/bluetooth/hci_usb.h linux-2.5/include/net/bluetooth/hci_usb.h --- linux-2.5.1/include/net/bluetooth/hci_usb.h Fri Sep 7 16:28:38 2001 +++ linux-2.5/include/net/bluetooth/hci_usb.h Tue Jan 8 00:44:25 2002 @@ -38,7 +38,7 @@ struct hci_usb { struct usb_device *udev; - devrequest dev_req; + struct usb_ctrlrequest dev_req; struct urb *ctrl_urb; struct urb *intr_urb; struct urb *read_urb; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/net/dn_fib.h linux-2.5/include/net/dn_fib.h --- linux-2.5.1/include/net/dn_fib.h Mon Dec 11 21:33:56 2000 +++ linux-2.5/include/net/dn_fib.h Thu Dec 13 16:32:37 2001 @@ -113,9 +113,7 @@ int (*get_info)(struct dn_fib_table *table, char *buf, int first, int count); #endif /* CONFIG_PROC_FS */ -#ifdef CONFIG_RTNETLINK int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb); -#endif /* CONFIG_RTNETLINK */ unsigned char data[0]; }; @@ -163,7 +161,6 @@ /* * rtnetlink interface */ -#ifdef CONFIG_RTNETLINK extern int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); extern int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); extern int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb); @@ -171,7 +168,6 @@ extern int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); extern int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); extern int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb); -#endif /* CONFIG_RTNETLINK */ #define DN_NUM_TABLES 255 #define DN_MIN_TABLE 1 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/net/sock.h linux-2.5/include/net/sock.h --- linux-2.5.1/include/net/sock.h Sun Dec 16 23:44:19 2001 +++ linux-2.5/include/net/sock.h Mon Jan 14 14:32:43 2002 @@ -643,9 +643,7 @@ #if defined(CONFIG_PPPOE) || defined(CONFIG_PPPOE_MODULE) struct pppox_opt *pppox; #endif -#ifdef CONFIG_NETLINK struct netlink_opt *af_netlink; -#endif #if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE) struct econet_opt *af_econet; #endif @@ -828,6 +826,11 @@ unsigned long size, int noblock, int *errcode); +extern struct sk_buff *sock_alloc_send_pskb(struct sock *sk, + unsigned long header_len, + unsigned long data_len, + 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); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/pcmcia/ciscode.h linux-2.5/include/pcmcia/ciscode.h --- linux-2.5.1/include/pcmcia/ciscode.h Fri Mar 2 19:02:15 2001 +++ linux-2.5/include/pcmcia/ciscode.h Thu Dec 13 16:32:37 2001 @@ -1,5 +1,5 @@ /* - * ciscode.h 1.45 2000/08/12 02:08:23 + * ciscode.h 1.48 2001/08/24 12:16:12 * * 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 @@ -16,8 +16,8 @@ * 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 + * 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 @@ -104,6 +104,8 @@ #define PRODID_QUATECH_DUAL_RS232 0x0012 #define PRODID_QUATECH_DUAL_RS232_D1 0x0007 #define PRODID_QUATECH_QUAD_RS232 0x001b +#define PRODID_QUATECH_DUAL_RS422 0x000e +#define PRODID_QUATECH_QUAD_RS422 0x0045 #define MANFID_SMC 0x0108 #define PRODID_SMC_ETHER 0x0105 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/pcmcia/cs.h linux-2.5/include/pcmcia/cs.h --- linux-2.5.1/include/pcmcia/cs.h Sat Feb 17 00:02:37 2001 +++ linux-2.5/include/pcmcia/cs.h Thu Dec 13 16:32:37 2001 @@ -1,5 +1,5 @@ /* - * cs.h 1.71 2000/08/29 00:54:20 + * cs.h 1.74 2001/10/04 03:15:22 * * 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 @@ -16,8 +16,8 @@ * 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 + * 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 @@ -181,6 +181,7 @@ #define INT_MEMORY 0x01 #define INT_MEMORY_AND_IO 0x02 #define INT_CARDBUS 0x04 +#define INT_ZOOMED_VIDEO 0x08 /* For RequestIO and ReleaseIO */ typedef struct io_req_t { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/scsi/scsi.h linux-2.5/include/scsi/scsi.h --- linux-2.5.1/include/scsi/scsi.h Fri Apr 27 20:59:19 2001 +++ linux-2.5/include/scsi/scsi.h Mon Jan 14 22:39:49 2002 @@ -130,6 +130,7 @@ #define TYPE_DISK 0x00 #define TYPE_TAPE 0x01 +#define TYPE_PRINTER 0x02 #define TYPE_PROCESSOR 0x03 /* HP scanners use this */ #define TYPE_WORM 0x04 /* Treated as ROM by our system */ #define TYPE_ROM 0x05 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/scsi/scsicam.h linux-2.5/include/scsi/scsicam.h --- linux-2.5.1/include/scsi/scsicam.h Tue Feb 20 01:14:38 2001 +++ linux-2.5/include/scsi/scsicam.h Thu Jan 3 01:27:27 2002 @@ -14,6 +14,7 @@ #define SCSICAM_H #include <linux/kdev_t.h> extern int scsicam_bios_param (Disk *disk, kdev_t dev, int *ip); -extern int scsi_partsize(struct buffer_head *bh, unsigned long capacity, +extern int scsi_partsize(unsigned char *buf, unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs); +extern unsigned char *scsi_bios_ptable(kdev_t dev); #endif /* def SCSICAM_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/scsi/sg.h linux-2.5/include/scsi/sg.h --- linux-2.5.1/include/scsi/sg.h Fri Sep 7 16:28:37 2001 +++ linux-2.5/include/scsi/sg.h Fri Jan 4 16:27:30 2002 @@ -11,78 +11,71 @@ Version 2 and 3 extensions to driver: * Copyright (C) 1998 - 2001 Douglas Gilbert - Version: 3.1.20 (20010814) - This version is for 2.4 series kernels. + Version: 3.5.23 (20011231) + This version is for 2.5 series kernels. - Changes since 3.1.19 (20010623) - - add SG_GET_ACCESS_COUNT ioctl - - make open() increment and close() decrement access_count - - only register first 256 devices, reject subsequent devices - Changes since 3.1.18 (20010505) - - fix bug that caused long wait when large buffer requested - - fix leak in error case of sg_new_read() [report: Eric Barton] - - add 'online' column to /proc/scsi/sg/devices - Changes since 3.1.17 (20000921) - - add CAP_SYS_RAWIO capability for sensitive stuff - - compile in dio stuff, procfs 'allow_dio' defaulted off (0) - - make premature close and detach more robust - - lun masked into commands <= SCSI_2 - - poll() and async notification now yield POLL_HUP on detach - - various 3rd party tweaks tracking lk 2.4 internal changes + Changes since 3.1.22 (20011208) + - branch sg driver for lk 2.5 series + - remove lock_kernel() from sg_close() + - remove code based on scsi mid level dma pool + - change scatterlist 'address' to use page + offset + - add SG_INTERFACE_ID_ORIG Map of SG verions to the Linux kernels in which they appear: ---------- ---------------------------------- original all kernels < 2.2.6 - 2.1.38 2.2.16 - 2.1.39 2.2.17 - 2.2.19 + 2.1.40 2.2.20 3.0.x optional version 3 sg driver for 2.2 series - 3.1.17 2.4.0 ++ + 3.1.17++ 2.4.0++ + 3.5.23++ 2.5.0++ Major new features in SG 3.x driver (cf SG 2.x drivers) - SG_IO ioctl() combines function if write() and read() - new interface (sg_io_hdr_t) but still supports old interface - - scatter/gather in user space and direct IO supported + - scatter/gather in user space, direct IO, and mmap supported - The term "indirect IO" refers a method by which data is DMAed into kernel - buffers from the hardware and afterwards is transferred into the user - space (or vice versa if you are writing). Transfer speeds of up to 20 to - 30MBytes/sec have been measured using indirect IO. For faster throughputs - "direct IO" which cuts out the double handling of data is required. - Direct IO is supported by the SG 3.x drivers on 2.4 series Linux kernels - and requires the use of the new interface. - - Requests for direct IO with the new interface will automatically fall back - to indirect IO mode if they cannot be fulfilled. An example of such a case - is an ISA SCSI adapter which is only capable of DMAing to the lower 16MB of - memory due to the architecture of ISA. The 'info' field in the new - interface indicates whether a direct or indirect data transfer took place. - - Obtaining memory for the kernel buffers used in indirect IO is done by - first checking if the "reserved buffer" for the current file descriptor - is available and large enough. If these conditions are _not_ met then - kernel memory is obtained on a per SCSI command basis. This corresponds - to a write(), read() sequence or a SG_IO ioctl() call. Further, the - kernel memory that is suitable for DMA may be constrained by the - architecture of the SCSI adapter (e.g. ISA adapters). + The normal action of this driver is to use the adapter (HBA) driver to DMA + data into kernel buffers and then use the CPU to copy the data into the + user space (vice versa for writes). That is called "indirect" IO due to + the double handling of data. There are two methods offered to remove the + redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and + 2) using the mmap() system call to map the reserve buffer (this driver has + one reserve buffer per fd) into the user space. Both have their advantages. + In terms of absolute speed mmap() is faster. If speed is not a concern, + indirect IO should be fine. Read the documentation for more information. ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be needed. That pseudo file's content is defaulted to 0. ** + + Historical note: this SCSI pass-through driver has been known as "sg" for + a decade. In broader kernel discussions "sg" is used to refer to scatter + gather techniques. The context should clarify which "sg" is referred to. Documentation ============= - A web site for SG device drivers can be found at: + A web site for the SG device driver can be found at: http://www.torque.net/sg [alternatively check the MAINTAINERS file] - The main documents are still based on 2.x versions: + The documentation for the sg version 3 driver can be found at: + http://www.torque.net/sg/p/sg_v3_ho.html + This is a rendering from DocBook source [change the extension to "sgml" + or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon). + + The older, version 2 documents discuss the original sg interface in detail: http://www.torque.net/sg/p/scsi-generic.txt http://www.torque.net/sg/p/scsi-generic_long.txt - Documentation on the changes and additions in 3.x version of the sg driver - can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt A version of this document (potentially out of date) may also be found in the kernel source tree, probably at: /usr/src/linux/Documentation/scsi-generic.txt . - Utility and test programs are available at the sg web site. + + Utility and test programs are available at the sg web site. They are + bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the + lk 2.4 series). + + There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at: + http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO */ + /* New interface introduced in the 3.x SG drivers follows */ typedef struct sg_iovec /* same structure as used by readv() Linux system */ @@ -119,20 +112,23 @@ unsigned int info; /* [o] auxiliary information */ } sg_io_hdr_t; /* 64 bytes long (on i386) */ +#define SG_INTERFACE_ID_ORIG 'S' + /* Use negative values to flag difference from original sg_header structure */ -#define SG_DXFER_NONE -1 /* e.g. a SCSI Test Unit Ready command */ -#define SG_DXFER_TO_DEV -2 /* e.g. a SCSI WRITE command */ -#define SG_DXFER_FROM_DEV -3 /* e.g. a SCSI READ command */ -#define SG_DXFER_TO_FROM_DEV -4 /* treated like SG_DXFER_FROM_DEV with the +#define SG_DXFER_NONE (-1) /* e.g. a SCSI Test Unit Ready command */ +#define SG_DXFER_TO_DEV (-2) /* e.g. a SCSI WRITE command */ +#define SG_DXFER_FROM_DEV (-3) /* e.g. a SCSI READ command */ +#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the additional property than during indirect IO the user buffer is copied into the kernel buffers before the transfer */ -#define SG_DXFER_UNKNOWN -5 /* Unknown data direction */ +#define SG_DXFER_UNKNOWN (-5) /* Unknown data direction */ /* following flag values can be "or"-ed together */ #define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */ -#define SG_FLAG_LUN_INHIBIT 2 /* default is to put device's lun into */ - /* the 2nd byte of SCSI command */ +#define SG_FLAG_LUN_INHIBIT 2 /* default is overwrite lun in SCSI */ + /* command block (when <= SCSI_2) */ +#define SG_FLAG_MMAP_IO 4 /* request memory mapped IO */ #define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */ /* user space (debug indirect IO) */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/include/video/sbusfb.h linux-2.5/include/video/sbusfb.h --- linux-2.5.1/include/video/sbusfb.h Tue Dec 21 06:06:42 1999 +++ linux-2.5/include/video/sbusfb.h Fri Jan 11 11:07:03 2002 @@ -123,8 +123,8 @@ void (*setcurshape)(struct fb_info_sbusfb *); void (*setcursormap)(struct fb_info_sbusfb *, unsigned char *, unsigned char *, unsigned char *); void (*loadcmap)(struct fb_info_sbusfb *, struct display *, int, int); - void (*blank)(struct fb_info_sbusfb *); - void (*unblank)(struct fb_info_sbusfb *); + int (*blank)(struct fb_info_sbusfb *); + int (*unblank)(struct fb_info_sbusfb *); void (*margins)(struct fb_info_sbusfb *, struct display *, int, int); void (*reset)(struct fb_info_sbusfb *); void (*fill)(struct fb_info_sbusfb *, struct display *, int, int, unsigned short *); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/init/do_mounts.c linux-2.5/init/do_mounts.c --- linux-2.5.1/init/do_mounts.c Sun Dec 16 20:27:48 2001 +++ linux-2.5/init/do_mounts.c Tue Jan 8 00:44:25 2002 @@ -1,15 +1,15 @@ #define __KERNEL_SYSCALLS__ #include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/devfs_fs_kernel.h> #include <linux/unistd.h> -#include <linux/string.h> #include <linux/ctype.h> -#include <linux/init.h> -#include <linux/smp_lock.h> #include <linux/blk.h> -#include <linux/tty.h> #include <linux/fd.h> +#include <linux/tty.h> +#include <linux/init.h> #include <linux/nfs_fs.h> #include <linux/nfs_fs_sb.h> @@ -18,12 +18,9 @@ #include <linux/ext2_fs.h> #include <linux/romfs_fs.h> -#include <asm/uaccess.h> - #define BUILD_CRAMDISK extern int get_filesystem_list(char * buf); -extern void wait_for_keypress(void); asmlinkage long sys_mount(char *dev_name, char *dir_name, char *type, unsigned long flags, void *data); @@ -38,12 +35,21 @@ #ifdef CONFIG_BLK_DEV_INITRD unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ -#endif -#ifdef CONFIG_BLK_DEV_RAM -extern int rd_doload; +static int __initdata mount_initrd = 1; + +static int __init no_initrd(char *str) +{ + mount_initrd = 0; + return 1; +} + +__setup("noinitrd", no_initrd); #else -static int rd_doload = 0; +static int __initdata mount_initrd = 0; #endif + +int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */ + int root_mountflags = MS_RDONLY | MS_VERBOSE; static char root_device_name[64]; @@ -52,6 +58,13 @@ static int do_devfs = 0; +static int __init load_ramdisk(char *str) +{ + rd_doload = simple_strtol(str,NULL,0) & 3; + return 1; +} +__setup("load_ramdisk=", load_ramdisk); + static int __init readonly(char *str) { if (*str) @@ -341,8 +354,8 @@ if (!do_devfs) return sys_mknod(name, S_IFBLK|0600, kdev_t_to_nr(dev)); - handle = devfs_find_handle(NULL, dev ? NULL : devfs_name, - MAJOR(dev), MINOR(dev), DEVFS_SPECIAL_BLK, 1); + handle = devfs_find_handle(NULL, kdev_none(dev) ? devfs_name : NULL, + major(dev), minor(dev), DEVFS_SPECIAL_BLK, 1); if (!handle) return -1; n = devfs_generate_path(handle, path + 5, sizeof (path) - 5); @@ -353,8 +366,9 @@ static void __init change_floppy(char *fmt, ...) { - extern void wait_for_keypress(void); + struct termios termios; char buf[80]; + char c; int fd; va_list args; va_start(args, fmt); @@ -366,11 +380,38 @@ close(fd); } printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf); - wait_for_keypress(); + fd = open("/dev/console", O_RDWR, 0); + if (fd >= 0) { + sys_ioctl(fd, TCGETS, (long)&termios); + termios.c_lflag &= ~ICANON; + sys_ioctl(fd, TCSETSF, (long)&termios); + read(fd, &c, 1); + termios.c_lflag |= ICANON; + sys_ioctl(fd, TCSETSF, (long)&termios); + close(fd); + } } #ifdef CONFIG_BLK_DEV_RAM +int __initdata rd_prompt = 1; /* 1 = prompt for RAM disk, 0 = don't prompt */ + +static int __init prompt_ramdisk(char *str) +{ + rd_prompt = simple_strtol(str,NULL,0) & 1; + return 1; +} +__setup("prompt_ramdisk=", prompt_ramdisk); + +int __initdata rd_image_start; /* starting block # of image */ + +static int __init ramdisk_start_setup(char *str) +{ + rd_image_start = simple_strtol(str,NULL,0); + return 1; +} +__setup("ramdisk_start=", ramdisk_start_setup); + static int __init crd_load(int in_fd, int out_fd); /* @@ -588,18 +629,74 @@ static int __init rd_load_disk(int n) { #ifdef CONFIG_BLK_DEV_RAM - extern int rd_prompt; if (rd_prompt) change_floppy("root floppy disk to be loaded into RAM disk"); - create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n), NULL); + create_dev("/dev/ram", mk_kdev(RAMDISK_MAJOR, n), NULL); #endif return rd_load_image("/dev/root"); } +#ifdef CONFIG_DEVFS_FS + +static void __init convert_name(char *prefix, char *name, char *p, int part) +{ + int host, bus, target, lun; + char dest[64]; + char src[64]; + char *base = p - 1; + + /* Decode "c#b#t#u#" */ + if (*p++ != 'c') + return; + host = simple_strtol(p, &p, 10); + if (*p++ != 'b') + return; + bus = simple_strtol(p, &p, 10); + if (*p++ != 't') + return; + target = simple_strtol(p, &p, 10); + if (*p++ != 'u') + return; + lun = simple_strtol(p, &p, 10); + if (!part) + sprintf(dest, "%s/host%d/bus%d/target%d/lun%d", + prefix, host, bus, target, lun); + else if (*p++ == 'p') + sprintf(dest, "%s/host%d/bus%d/target%d/lun%d/part%s", + prefix, host, bus, target, lun, p); + else + sprintf(dest, "%s/host%d/bus%d/target%d/lun%d/disc", + prefix, host, bus, target, lun); + *base = '\0'; + sprintf(src, "/dev/%s", name); + sys_mkdir(src, 0755); + *base = '/'; + sprintf(src, "/dev/%s", name); + sys_symlink(dest, src); +} + +static void __init devfs_make_root(char *name) +{ + + if (!strncmp(name, "sd/", 3)) + convert_name("../scsi", name, name+3, 1); + else if (!strncmp(name, "sr/", 3)) + convert_name("../scsi", name, name+3, 0); + else if (!strncmp(name, "ide/hd/", 7)) + convert_name("..", name, name + 7, 1); + else if (!strncmp(name, "ide/cd/", 7)) + convert_name("..", name, name + 7, 0); +} +#else +static void __init devfs_make_root(char *name) +{ +} +#endif + static void __init mount_root(void) { #ifdef CONFIG_ROOT_NFS - if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { + if (major(ROOT_DEV) == UNNAMED_MAJOR) { if (mount_nfs_root()) { sys_chdir("/root"); ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; @@ -607,17 +704,17 @@ return; } printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); - ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0); + ROOT_DEV = mk_kdev(FLOPPY_MAJOR, 0); } #endif devfs_make_root(root_device_name); create_dev("/dev/root", ROOT_DEV, root_device_name); #ifdef CONFIG_BLK_DEV_FD - if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { + if (major(ROOT_DEV) == FLOPPY_MAJOR) { /* rd_doload is 2 for a dual initrd/ramload setup */ if (rd_doload==2) { if (rd_load_disk(1)) { - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 1); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 1); create_dev("/dev/root", ROOT_DEV, NULL); } } else @@ -652,7 +749,7 @@ static void __init handle_initrd(void) { #ifdef CONFIG_BLK_DEV_INITRD - int ram0 = kdev_t_to_nr(MKDEV(RAMDISK_MAJOR,0)); + kdev_t ram0 = mk_kdev(RAMDISK_MAJOR,0); int error; int i, pid; @@ -663,21 +760,19 @@ pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid > 0) { - while (pid != wait(&i)) { - current->policy |= SCHED_YIELD; - schedule(); - } + while (pid != wait(&i)) + yield(); } sys_mount("..", ".", NULL, MS_MOVE, NULL); sys_umount("/old/dev", 0); - if (real_root_dev == ram0) { + if (real_root_dev == kdev_t_to_nr(ram0)) { sys_chdir("/old"); return; } - ROOT_DEV = real_root_dev; + ROOT_DEV = to_kdev_t(real_root_dev); mount_root(); printk(KERN_NOTICE "Trying to move old root to /initrd ... "); @@ -704,8 +799,8 @@ static int __init initrd_load(void) { #ifdef CONFIG_BLK_DEV_INITRD - create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL); - create_dev("/dev/initrd", MKDEV(RAMDISK_MAJOR, INITRD_MINOR), NULL); + create_dev("/dev/ram", mk_kdev(RAMDISK_MAJOR, 0), NULL); + create_dev("/dev/initrd", mk_kdev(RAMDISK_MAJOR, INITRD_MINOR), NULL); #endif return rd_load_image("/dev/initrd"); } @@ -715,30 +810,28 @@ */ void prepare_namespace(void) { - int do_initrd = 0; - int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; + int is_floppy = major(ROOT_DEV) == FLOPPY_MAJOR; #ifdef CONFIG_BLK_DEV_INITRD if (!initrd_start) mount_initrd = 0; - if (mount_initrd) - do_initrd = 1; - real_root_dev = ROOT_DEV; + real_root_dev = kdev_t_to_nr(ROOT_DEV); #endif sys_mkdir("/dev", 0700); sys_mkdir("/root", 0700); + sys_mknod("/dev/console", S_IFCHR|0600, MKDEV(TTYAUX_MAJOR, 1)); #ifdef CONFIG_DEVFS_FS sys_mount("devfs", "/dev", "devfs", 0, NULL); do_devfs = 1; #endif create_dev("/dev/root", ROOT_DEV, NULL); - if (do_initrd) { - if (initrd_load() && ROOT_DEV != MKDEV(RAMDISK_MAJOR, 0)) { + if (mount_initrd) { + if (initrd_load() && kdev_same(ROOT_DEV, mk_kdev(RAMDISK_MAJOR, 0))) { handle_initrd(); goto out; } } else if (is_floppy && rd_doload && rd_load_disk(0)) - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0); mount_root(); out: sys_umount("/dev", 0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/init/main.c linux-2.5/init/main.c --- linux-2.5.1/init/main.c Sat Dec 8 00:24:52 2001 +++ linux-2.5/init/main.c Thu Jan 10 13:32:21 2002 @@ -62,6 +62,10 @@ #include <linux/isapnp.h> #endif +#ifdef CONFIG_PNPBIOS +#include <linux/pnpbios.h> +#endif + #ifdef CONFIG_IRDA extern int irda_proto_init(void); extern int irda_device_init(void); @@ -312,18 +316,9 @@ /* Get other processors into their bootup holding patterns. */ smp_boot_cpus(); wait_init_idle = cpu_online_map; - clear_bit(current->processor, &wait_init_idle); /* Don't wait on me! */ smp_threads_ready=1; smp_commence(); - - /* Wait for the other cpus to set up their idle processes */ - printk("Waiting on wait_init_idle (map = 0x%lx)\n", wait_init_idle); - while (wait_init_idle) { - cpu_relax(); - barrier(); - } - printk("All processors have done init_idle\n"); } #endif @@ -339,7 +334,6 @@ { kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); unlock_kernel(); - current->need_resched = 1; cpu_idle(); } @@ -427,6 +421,16 @@ * make syscalls (and thus be locked). */ smp_init(); + + /* + * Finally, we wait for all other CPU's, and initialize this + * thread that will become the idle thread for the boot CPU. + * After this, the scheduler is fully initialized, and we can + * start creating and running new threads. + */ + init_idle(); + + /* Do the rest non-__init'ed, we're now alive */ rest_init(); } @@ -516,6 +520,9 @@ #endif #ifdef CONFIG_ISAPNP isapnp_init(); +#endif +#ifdef CONFIG_PNPBIOS + pnpbios_init(); #endif #ifdef CONFIG_TC tc_init(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/ipc/shm.c linux-2.5/ipc/shm.c --- linux-2.5.1/ipc/shm.c Sun Dec 9 04:31:51 2001 +++ linux-2.5/ipc/shm.c Sun Dec 30 20:01:41 2001 @@ -17,6 +17,7 @@ #include <linux/config.h> #include <linux/slab.h> +#include <linux/mm.h> #include <linux/shm.h> #include <linux/init.h> #include <linux/file.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/acct.c linux-2.5/kernel/acct.c --- linux-2.5.1/kernel/acct.c Mon Mar 19 20:35:08 2001 +++ linux-2.5/kernel/acct.c Thu Dec 27 22:10:28 2001 @@ -213,10 +213,10 @@ goto out; } -void acct_auto_close(kdev_t dev) +void acct_auto_close(struct super_block *sb) { lock_kernel(); - if (acct_file && acct_file->f_dentry->d_inode->i_dev == dev) + if (acct_file && acct_file->f_dentry->d_inode->i_sb == sb) sys_acct(NULL); unlock_kernel(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/capability.c linux-2.5/kernel/capability.c --- linux-2.5.1/kernel/capability.c Sat Jun 24 04:06:37 2000 +++ linux-2.5/kernel/capability.c Tue Jan 8 00:44:25 2002 @@ -8,6 +8,8 @@ #include <linux/mm.h> #include <asm/uaccess.h> +unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ + kernel_cap_t cap_bset = CAP_INIT_EFF_SET; /* Note: never hold tasklist_lock while spinning for this one */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/device.c linux-2.5/kernel/device.c --- linux-2.5.1/kernel/device.c Mon Dec 10 22:15:12 2001 +++ linux-2.5/kernel/device.c Thu Jan 3 23:04:40 2002 @@ -732,15 +732,10 @@ error = -EINVAL; - if (!num_args) { - printk("have no arguments\n"); + if (!num_args) goto done; - } if (!strnicmp(str_command,"suspend",7)) { - - printk("%s: we know it's a suspend action\n",__FUNCTION__); - if (num_args != 3) goto done; if (!strnicmp(str_stage,"notify",6)) @@ -775,8 +770,7 @@ error = dev->driver->resume(dev,int_stage); else error = 0; - } else - printk("%s: couldn't find any thing to do\n",__FUNCTION__); + } done: put_device(dev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/exit.c linux-2.5/kernel/exit.c --- linux-2.5.1/kernel/exit.c Fri Nov 30 18:02:34 2001 +++ linux-2.5/kernel/exit.c Sun Jan 13 18:08:45 2002 @@ -5,6 +5,7 @@ */ #include <linux/config.h> +#include <linux/mm.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/smp_lock.h> @@ -12,13 +13,14 @@ #include <linux/completion.h> #include <linux/personality.h> #include <linux/tty.h> +#include <linux/namespace.h> #ifdef CONFIG_BSD_PROCESS_ACCT #include <linux/acct.h> #endif #include <asm/uaccess.h> #include <asm/pgtable.h> -#include <asm/mmu_context.h> +#include <asm/sched.h> extern void sem_exit (void); extern struct task_struct *child_reaper; @@ -27,49 +29,39 @@ static void release_task(struct task_struct * p) { - if (p != current) { + unsigned long flags; + + if (p == current) + BUG(); #ifdef CONFIG_SMP - /* - * Wait to make sure the process isn't on the - * runqueue (active on some other CPU still) - */ - for (;;) { - task_lock(p); - if (!task_has_cpu(p)) - break; - task_unlock(p); - do { - cpu_relax(); - barrier(); - } while (task_has_cpu(p)); - } - task_unlock(p); + wait_task_inactive(p); #endif - atomic_dec(&p->user->processes); - free_uid(p->user); - unhash_process(p); - - release_thread(p); - current->cmin_flt += p->min_flt + p->cmin_flt; - current->cmaj_flt += p->maj_flt + p->cmaj_flt; - current->cnswap += p->nswap + p->cnswap; - /* - * Potentially available timeslices are retrieved - * here - this way the parent does not get penalized - * for creating too many processes. - * - * (this cannot be used to artificially 'generate' - * timeslices, because any timeslice recovered here - * was given away by the parent in the first place.) - */ - current->counter += p->counter; - if (current->counter >= MAX_COUNTER) - current->counter = MAX_COUNTER; - p->pid = 0; - free_task_struct(p); - } else { - printk("task releasing itself\n"); - } + atomic_dec(&p->user->processes); + free_uid(p->user); + unhash_process(p); + + release_thread(p); + current->cmin_flt += p->min_flt + p->cmin_flt; + current->cmaj_flt += p->maj_flt + p->cmaj_flt; + current->cnswap += p->nswap + p->cnswap; + /* + * Potentially available timeslices are retrieved + * here - this way the parent does not get penalized + * for creating too many processes. + * + * (this cannot be used to artificially 'generate' + * timeslices, because any timeslice recovered here + * was given away by the parent in the first place.) + */ + __save_flags(flags); + __cli(); + current->time_slice += p->time_slice; + if (current->time_slice > MAX_TIMESLICE) + current->time_slice = MAX_TIMESLICE; + __restore_flags(flags); + + p->pid = 0; + free_task_struct(p); } /* @@ -149,6 +141,80 @@ return retval; } +/** + * reparent_to_init() - Reparent the calling kernel thread to the init task. + * + * If a kernel thread is launched as a result of a system call, or if + * it ever exits, it should generally reparent itself to init so that + * it is correctly cleaned up on exit. + * + * The various task state such as scheduling policy and priority may have + * been inherited from a user process, so we reset them to sane values here. + * + * NOTE that reparent_to_init() gives the caller full capabilities. + */ +void reparent_to_init(void) +{ + write_lock_irq(&tasklist_lock); + + /* Reparent to init */ + REMOVE_LINKS(current); + current->p_pptr = child_reaper; + current->p_opptr = child_reaper; + SET_LINKS(current); + + /* Set the exit signal to SIGCHLD so we signal init on exit */ + current->exit_signal = SIGCHLD; + + current->ptrace = 0; + if ((current->policy == SCHED_OTHER) && + (current->__nice < DEF_USER_NICE)) + set_user_nice(current, DEF_USER_NICE); + /* cpus_allowed? */ + /* rt_priority? */ + /* signals? */ + current->cap_effective = CAP_INIT_EFF_SET; + current->cap_inheritable = CAP_INIT_INH_SET; + current->cap_permitted = CAP_FULL_SET; + current->keep_capabilities = 0; + memcpy(current->rlim, init_task.rlim, sizeof(*(current->rlim))); + current->user = INIT_USER; + + write_unlock_irq(&tasklist_lock); +} + +/* + * Put all the gunge required to become a kernel thread without + * attached user resources in one place where it belongs. + */ + +void daemonize(void) +{ + struct fs_struct *fs; + + + /* + * If we were started as result of loading a module, close all of the + * user space pages. We don't need them, and if we didn't close them + * they would be locked into memory. + */ + exit_mm(current); + + current->session = 1; + current->pgrp = 1; + current->tty = NULL; + + /* Become as one with the init task */ + + exit_fs(current); /* current->fs->count--; */ + fs = init_task.fs; + current->fs = fs; + atomic_inc(&fs->count); + exit_files(current); + current->files = init_task.files; + atomic_inc(¤t->files->count); +} + /* * When we die, we re-parent all our children. * Try to give them to another thread in our process @@ -452,6 +518,7 @@ sem_exit(); __exit_files(tsk); __exit_fs(tsk); + exit_namespace(tsk); exit_sighand(tsk); exit_thread(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/fork.c linux-2.5/kernel/fork.c --- linux-2.5.1/kernel/fork.c Fri Nov 30 23:53:28 2001 +++ linux-2.5/kernel/fork.c Sun Jan 13 19:02:53 2002 @@ -19,16 +19,16 @@ #include <linux/module.h> #include <linux/vmalloc.h> #include <linux/completion.h> +#include <linux/namespace.h> #include <linux/personality.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> #include <asm/uaccess.h> -#include <asm/mmu_context.h> +#include <asm/sched.h> /* The idle threads do not count.. */ int nr_threads; -int nr_running; int max_threads; unsigned long total_forks; /* Handle normal Linux uptimes. */ @@ -36,6 +36,8 @@ struct task_struct *pidhash[PIDHASH_SZ]; +rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ + void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -219,6 +221,7 @@ init_rwsem(&mm->mmap_sem); mm->page_table_lock = SPIN_LOCK_UNLOCKED; mm->pgd = pgd_alloc(mm); + mm->def_flags = 0; if (mm->pgd) return mm; free_mm(mm); @@ -563,9 +566,13 @@ struct pt_regs *regs, unsigned long stack_size) { int retval; + unsigned long flags; struct task_struct *p; struct completion vfork; + if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) + return -EINVAL; + retval = -EPERM; /* @@ -585,8 +592,10 @@ *p = *current; retval = -EAGAIN; - if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) - goto bad_fork_free; + if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) { + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE)) + goto bad_fork_free; + } atomic_inc(&p->user->__count); atomic_inc(&p->user->processes); @@ -611,8 +620,7 @@ copy_flags(clone_flags, p); p->pid = get_pid(clone_flags); - p->run_list.next = NULL; - p->run_list.prev = NULL; + INIT_LIST_HEAD(&p->run_list); p->p_cptr = NULL; init_waitqueue_head(&p->wait_chldexit); @@ -638,14 +646,16 @@ #ifdef CONFIG_SMP { int i; - p->cpus_runnable = ~0UL; - p->processor = current->processor; + + p->cpu = smp_processor_id(); + /* ?? should we just memset this ?? */ for(i = 0; i < smp_num_cpus; i++) p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; spin_lock_init(&p->sigmask_lock); } #endif + p->array = NULL; p->lock_depth = -1; /* -1 = no lock */ p->start_time = jiffies; @@ -661,9 +671,11 @@ goto bad_fork_cleanup_fs; if (copy_mm(clone_flags, p)) goto bad_fork_cleanup_sighand; + if (copy_namespace(clone_flags, p)) + goto bad_fork_cleanup_mm; retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); if (retval) - goto bad_fork_cleanup_mm; + goto bad_fork_cleanup_namespace; p->semundo = NULL; /* Our parent execution domain becomes current domain @@ -677,15 +689,26 @@ 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. + * Share the timeslice between parent and child, thus the + * total amount of pending timeslices in the system doesnt change, + * resulting in more scheduling fairness. */ - p->counter = (current->counter + 1) >> 1; - current->counter >>= 1; - if (!current->counter) - current->need_resched = 1; + __save_flags(flags); + __cli(); + p->time_slice = (current->time_slice + 1) >> 1; + current->time_slice >>= 1; + if (!current->time_slice) { + /* + * This case is rare, it happens when the parent has only + * a single jiffy left from its timeslice. Taking the + * runqueue lock is not a problem. + */ + current->time_slice = 1; + scheduler_tick(current); + } + p->sleep_timestamp = p->run_timestamp = jiffies; + p->hist[0] = p->hist[1] = p->hist[2] = p->hist[3] = 0; + __restore_flags(flags); /* * Ok, add it to the run-queues and make it @@ -722,14 +745,29 @@ if (p->ptrace & PT_PTRACED) send_sig(SIGSTOP, p, 1); - wake_up_process(p); /* do this last */ +#define RUN_CHILD_FIRST 1 +#if RUN_CHILD_FIRST + wake_up_forked_process(p); /* do this last */ +#else + wake_up_process(p); /* do this last */ +#endif ++total_forks; if (clone_flags & CLONE_VFORK) wait_for_completion(&vfork); +#if RUN_CHILD_FIRST + else + /* + * Let the child process run first, to avoid most of the + * COW overhead when the child exec()s afterwards. + */ + current->need_resched = 1; +#endif fork_out: return retval; +bad_fork_cleanup_namespace: + exit_namespace(p); bad_fork_cleanup_mm: exit_mm(p); bad_fork_cleanup_sighand: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/kmod.c linux-2.5/kernel/kmod.c --- linux-2.5.1/kernel/kmod.c Wed Jul 18 01:23:50 2001 +++ linux-2.5/kernel/kmod.c Thu Dec 27 15:56:12 2001 @@ -24,6 +24,8 @@ #include <linux/unistd.h> #include <linux/kmod.h> #include <linux/smp_lock.h> +#include <linux/slab.h> +#include <linux/namespace.h> #include <linux/completion.h> #include <asm/uaccess.h> @@ -36,6 +38,7 @@ struct fs_struct *our_fs, *init_fs; struct dentry *root, *pwd; struct vfsmount *rootmnt, *pwdmnt; + struct namespace *our_ns, *init_ns; /* * Make modprobe's fs context be a copy of init's. @@ -55,6 +58,11 @@ */ init_fs = init_task.fs; + init_ns = init_task.namespace; + get_namespace(init_ns); + our_ns = current->namespace; + current->namespace = init_ns; + put_namespace(our_ns); read_lock(&init_fs->lock); rootmnt = mntget(init_fs->rootmnt); root = dget(init_fs->root); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/ksyms.c linux-2.5/kernel/ksyms.c --- linux-2.5.1/kernel/ksyms.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/kernel/ksyms.c Thu Jan 10 22:41:07 2002 @@ -46,6 +46,7 @@ #include <linux/tty.h> #include <linux/in6.h> #include <linux/completion.h> +#include <linux/seq_file.h> #include <asm/checksum.h> #if defined(CONFIG_PROC_FS) @@ -94,7 +95,6 @@ EXPORT_SYMBOL(alloc_pages_node); EXPORT_SYMBOL(__get_free_pages); EXPORT_SYMBOL(get_zeroed_page); -EXPORT_SYMBOL(page_cache_release); EXPORT_SYMBOL(__free_pages); EXPORT_SYMBOL(free_pages); EXPORT_SYMBOL(num_physpages); @@ -116,11 +116,11 @@ EXPORT_SYMBOL(find_vma); EXPORT_SYMBOL(get_unmapped_area); EXPORT_SYMBOL(init_mm); +EXPORT_SYMBOL(create_bounce); #ifdef CONFIG_HIGHMEM EXPORT_SYMBOL(kmap_high); EXPORT_SYMBOL(kunmap_high); EXPORT_SYMBOL(highmem_start_page); -EXPORT_SYMBOL(create_bounce); EXPORT_SYMBOL(kmap_prot); EXPORT_SYMBOL(kmap_pte); #endif @@ -188,12 +188,14 @@ EXPORT_SYMBOL(write_inode_now); EXPORT_SYMBOL(notify_change); EXPORT_SYMBOL(set_blocksize); -EXPORT_SYMBOL(getblk); +EXPORT_SYMBOL(sb_set_blocksize); +EXPORT_SYMBOL(sb_min_blocksize); +EXPORT_SYMBOL(__getblk); EXPORT_SYMBOL(cdget); EXPORT_SYMBOL(cdput); EXPORT_SYMBOL(bdget); EXPORT_SYMBOL(bdput); -EXPORT_SYMBOL(bread); +EXPORT_SYMBOL(__bread); EXPORT_SYMBOL(__brelse); EXPORT_SYMBOL(__bforget); EXPORT_SYMBOL(ll_rw_block); @@ -305,6 +307,7 @@ EXPORT_SYMBOL(ioctl_by_bdev); EXPORT_SYMBOL(grok_partitions); EXPORT_SYMBOL(register_disk); +EXPORT_SYMBOL(read_dev_sector); EXPORT_SYMBOL(tq_disk); EXPORT_SYMBOL(init_buffer); EXPORT_SYMBOL(refile_buffer); @@ -354,9 +357,7 @@ EXPORT_SYMBOL(del_timer); EXPORT_SYMBOL(request_irq); EXPORT_SYMBOL(free_irq); -#if !defined(CONFIG_ARCH_S390) -EXPORT_SYMBOL(irq_stat); /* No separate irq_stat for s390, it is part of PSA */ -#endif +EXPORT_SYMBOL(irq_stat); /* waitqueue handling */ EXPORT_SYMBOL(add_wait_queue); @@ -437,6 +438,8 @@ EXPORT_SYMBOL(interruptible_sleep_on_timeout); EXPORT_SYMBOL(schedule); EXPORT_SYMBOL(schedule_timeout); +EXPORT_SYMBOL(sys_sched_yield); +EXPORT_SYMBOL(set_user_nice); EXPORT_SYMBOL(jiffies); EXPORT_SYMBOL(xtime); EXPORT_SYMBOL(do_gettimeofday); @@ -448,6 +451,7 @@ EXPORT_SYMBOL(kstat); EXPORT_SYMBOL(nr_running); +EXPORT_SYMBOL(nr_context_switches); /* misc */ EXPORT_SYMBOL(panic); @@ -461,6 +465,7 @@ 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__ @@ -477,6 +482,12 @@ EXPORT_SYMBOL(reparent_to_init); EXPORT_SYMBOL(daemonize); EXPORT_SYMBOL(csum_partial); /* for networking and md */ +EXPORT_SYMBOL(seq_escape); +EXPORT_SYMBOL(seq_printf); +EXPORT_SYMBOL(seq_open); +EXPORT_SYMBOL(seq_release); +EXPORT_SYMBOL(seq_read); +EXPORT_SYMBOL(seq_lseek); /* Program loader interfaces */ EXPORT_SYMBOL(setup_arg_pages); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/panic.c linux-2.5/kernel/panic.c --- linux-2.5.1/kernel/panic.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/kernel/panic.c Tue Jan 1 03:24:58 2002 @@ -96,6 +96,10 @@ #endif sti(); for(;;) { +#if defined(__i386__) && defined(CONFIG_VT) + extern void panic_blink(void); + panic_blink(); +#endif CHECK_EMERGENCY_SYNC } } @@ -103,6 +107,10 @@ /** * print_tainted - return a string to represent the kernel taint state. * + * 'P' - Proprietory module has been loaded. + * 'F' - Module has been forcibly loaded. + * 'S' - SMP with CPUs not designed for SMP. + * * The string is overwritten by the next call to print_taint(). */ @@ -110,9 +118,10 @@ { static char buf[20]; if (tainted) { - snprintf(buf, sizeof(buf), "Tainted: %c%c", - tainted & 1 ? 'P' : 'G', - tainted & 2 ? 'F' : ' '); + snprintf(buf, sizeof(buf), "Tainted: %c%c%c", + tainted & TAINT_PROPRIETORY_MODULE ? 'P' : 'G', + tainted & TAINT_FORCED_MODULE ? 'F' : ' ', + tainted & TAINT_UNSAFE_SMP ? 'S' : ' '); } else snprintf(buf, sizeof(buf), "Not tainted"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/pm.c linux-2.5/kernel/pm.c --- linux-2.5.1/kernel/pm.c Fri Apr 6 17:51:19 2001 +++ linux-2.5/kernel/pm.c Sun Dec 30 20:01:41 2001 @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/mm.h> #include <linux/slab.h> #include <linux/pm.h> #include <linux/interrupt.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/printk.c linux-2.5/kernel/printk.c --- linux-2.5.1/kernel/printk.c Sun Nov 11 18:20:21 2001 +++ linux-2.5/kernel/printk.c Sun Jan 13 23:48:01 2002 @@ -16,6 +16,7 @@ * 01Mar01 Andrew Morton <andrewm@uow.edu.au> */ +#include <linux/kernel.h> #include <linux/mm.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -24,12 +25,14 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/interrupt.h> /* For in_interrupt() */ -#include <linux/config.h> +#include <linux/delay.h> #include <asm/uaccess.h> #ifdef CONFIG_MULTIQUAD #define LOG_BUF_LEN (65536) +#elif defined(CONFIG_ARCH_S390) +#define LOG_BUF_LEN (131072) #elif defined(CONFIG_SMP) #define LOG_BUF_LEN (32768) #else @@ -38,6 +41,10 @@ #define LOG_BUF_MASK (LOG_BUF_LEN-1) +#ifndef arch_consoles_callable +#define arch_consoles_callable() (1) +#endif + /* printk's without a loglevel use this.. */ #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ @@ -47,11 +54,12 @@ DECLARE_WAIT_QUEUE_HEAD(log_wait); -/* Keep together for sysctl support */ -int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; -int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL; -int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL; -int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; +int console_printk[4] = { + DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */ + DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */ + MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */ + DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ +}; int oops_in_progress; @@ -438,6 +446,14 @@ log_level_unknown = 1; } + if (!arch_consoles_callable()) { + /* + * On some architectures, the consoles are not usable + * on secondary CPUs early in the boot process. + */ + spin_unlock_irqrestore(&logbuf_lock, flags); + goto out; + } if (!down_trylock(&console_sem)) { /* * We own the drivers. We can drop the spinlock and let @@ -454,6 +470,7 @@ */ spin_unlock_irqrestore(&logbuf_lock, flags); } +out: return printed_len; } EXPORT_SYMBOL(printk); @@ -512,6 +529,7 @@ if (must_wake_klogd && !oops_in_progress) wake_up_interruptible(&log_wait); } +EXPORT_SYMBOL(release_console_sem); /** console_conditional_schedule - yield the CPU if required * diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/ptrace.c linux-2.5/kernel/ptrace.c --- linux-2.5.1/kernel/ptrace.c Wed Nov 21 22:43:01 2001 +++ linux-2.5/kernel/ptrace.c Tue Jan 8 00:44:25 2002 @@ -31,20 +31,7 @@ if (child->state != TASK_STOPPED) return -ESRCH; #ifdef CONFIG_SMP - /* Make sure the child gets off its CPU.. */ - for (;;) { - task_lock(child); - if (!task_has_cpu(child)) - break; - task_unlock(child); - do { - if (child->state != TASK_STOPPED) - return -ESRCH; - barrier(); - cpu_relax(); - } while (task_has_cpu(child)); - } - task_unlock(child); + wait_task_inactive(child); #endif } @@ -121,119 +108,17 @@ } /* - * Access another process' address space, one page at a time. + * Access another process' address space. + * Source/target buffer must be kernel space, + * Do not walk the page table directly, use get_user_pages */ -static int access_one_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write) -{ - pgd_t * pgdir; - pmd_t * pgmiddle; - pte_t * pgtable; - char *maddr; - struct page *page; - -repeat: - spin_lock(&mm->page_table_lock); - pgdir = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgdir)) - goto fault_in_page; - if (pgd_bad(*pgdir)) - goto bad_pgd; - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) - goto fault_in_page; - if (pmd_bad(*pgmiddle)) - goto bad_pmd; - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) - goto fault_in_page; - if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable))) - goto fault_in_page; - page = pte_page(*pgtable); - - /* ZERO_PAGE is special: reads from it are ok even though it's marked reserved */ - if (page != ZERO_PAGE(addr) || write) { - if ((!VALID_PAGE(page)) || PageReserved(page)) { - spin_unlock(&mm->page_table_lock); - return 0; - } - } - get_page(page); - spin_unlock(&mm->page_table_lock); - flush_cache_page(vma, addr); - - if (write) { - maddr = kmap(page); - memcpy(maddr + (addr & ~PAGE_MASK), buf, len); - flush_page_to_ram(page); - flush_icache_page(vma, page); - kunmap(page); - } else { - maddr = kmap(page); - memcpy(buf, maddr + (addr & ~PAGE_MASK), len); - flush_page_to_ram(page); - kunmap(page); - } - put_page(page); - return len; - -fault_in_page: - spin_unlock(&mm->page_table_lock); - /* -1: out of memory. 0 - unmapped page */ - if (handle_mm_fault(mm, vma, addr, write) > 0) - goto repeat; - return 0; - -bad_pgd: - spin_unlock(&mm->page_table_lock); - pgd_ERROR(*pgdir); - return 0; - -bad_pmd: - spin_unlock(&mm->page_table_lock); - pmd_ERROR(*pgmiddle); - return 0; -} - -static int access_mm(struct mm_struct *mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write) -{ - int copied = 0; - - for (;;) { - unsigned long offset = addr & ~PAGE_MASK; - int this_len = PAGE_SIZE - offset; - int retval; - - if (this_len > len) - this_len = len; - retval = access_one_page(mm, vma, addr, buf, this_len, write); - copied += retval; - if (retval != this_len) - break; - - len -= retval; - if (!len) - break; - - addr += retval; - buf += retval; - - if (addr < vma->vm_end) - continue; - if (!vma->vm_next) - break; - if (vma->vm_next->vm_start != vma->vm_end) - break; - - vma = vma->vm_next; - } - return copied; -} int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) { - int copied; struct mm_struct *mm; - struct vm_area_struct * vma; + struct vm_area_struct *vma; + struct page *page; + void *old_buf = buf; /* Worry about races with exit() */ task_lock(tsk); @@ -245,14 +130,41 @@ return 0; down_read(&mm->mmap_sem); - vma = find_extend_vma(mm, addr); - copied = 0; - if (vma) - copied = access_mm(mm, vma, addr, buf, len, write); + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + int bytes, ret, offset; + void *maddr; + + ret = get_user_pages(current, mm, addr, 1, + write, 1, &page, &vma); + if (ret <= 0) + break; + + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + flush_cache_page(vma, addr); + maddr = kmap(page); + if (write) { + memcpy(maddr + offset, buf, bytes); + flush_page_to_ram(page); + flush_icache_page(vma, page); + } else { + memcpy(buf, maddr + offset, bytes); + flush_page_to_ram(page); + } + kunmap(page); + put_page(page); + len -= bytes; + buf += bytes; + } up_read(&mm->mmap_sem); mmput(mm); - return copied; + + return buf - old_buf; } int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/sched.c linux-2.5/kernel/sched.c --- linux-2.5.1/kernel/sched.c Thu Nov 22 00:25:48 2001 +++ linux-2.5/kernel/sched.c Sun Jan 13 18:08:45 2002 @@ -12,318 +12,359 @@ * 1998-12-28 Implemented better SMP scheduling by Ingo Molnar */ -/* - * 'sched.c' is the main kernel file. It contains scheduling primitives - * (sleep_on, wakeup, schedule etc) as well as a number of simple system - * call functions (type getpid()), which just extract a field from - * current-task - */ - -#include <linux/config.h> #include <linux/mm.h> +#include <linux/nmi.h> #include <linux/init.h> +#include <asm/uaccess.h> #include <linux/smp_lock.h> -#include <linux/nmi.h> #include <linux/interrupt.h> -#include <linux/kernel_stat.h> -#include <linux/completion.h> -#include <linux/prefetch.h> -#include <linux/compiler.h> +#include <asm/sched.h> -#include <asm/uaccess.h> -#include <asm/mmu_context.h> +#define BITMAP_SIZE ((((MAX_PRIO+7)/8)+sizeof(long)-1)/sizeof(long)) -extern void timer_bh(void); -extern void tqueue_bh(void); -extern void immediate_bh(void); +typedef struct runqueue runqueue_t; -/* - * scheduler variables - */ - -unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ - -extern void mem_use(void); +struct prio_array { + int nr_active; + spinlock_t *lock; + runqueue_t *rq; + unsigned long bitmap[BITMAP_SIZE]; + list_t queue[MAX_PRIO]; +}; /* - * Scheduling quanta. + * This is the main, per-CPU runqueue data structure. * - * NOTE! The unix "nice" value influences how long a process - * gets. The nice value ranges from -20 to +19, where a -20 - * is a "high-priority" task, and a "+10" is a low-priority - * task. + * Locking rule: those places that want to lock multiple runqueues + * (such as the load balancing or the process migration code), lock + * acquire operations must be ordered by the runqueue's cpu id. * - * We want the time-slice to be around 50ms or so, so this - * calculation depends on the value of HZ. + * The RT event id is used to avoid calling into the the RT scheduler + * if there is a RT task active in an SMP system but there is no + * RT scheduling activity otherwise. */ -#if HZ < 200 -#define TICK_SCALE(x) ((x) >> 2) -#elif HZ < 400 -#define TICK_SCALE(x) ((x) >> 1) -#elif HZ < 800 -#define TICK_SCALE(x) (x) -#elif HZ < 1600 -#define TICK_SCALE(x) ((x) << 1) -#else -#define TICK_SCALE(x) ((x) << 2) -#endif - -#define NICE_TO_TICKS(nice) (TICK_SCALE(20-(nice))+1) +struct runqueue { + spinlock_t lock; + unsigned long nr_running, nr_switches; + task_t *curr, *idle; + prio_array_t *active, *expired, arrays[2]; + int prev_nr_running[NR_CPUS]; +} ____cacheline_aligned; + +static struct runqueue runqueues[NR_CPUS] __cacheline_aligned; + +#define cpu_rq(cpu) (runqueues + (cpu)) +#define this_rq() cpu_rq(smp_processor_id()) +#define task_rq(p) cpu_rq((p)->cpu) +#define cpu_curr(cpu) (cpu_rq(cpu)->curr) +#define rq_cpu(rq) ((rq) - runqueues) +#define rt_task(p) ((p)->policy != SCHED_OTHER) + + +#define lock_task_rq(rq,p,flags) \ +do { \ +repeat_lock_task: \ + rq = task_rq(p); \ + spin_lock_irqsave(&rq->lock, flags); \ + if (unlikely(rq_cpu(rq) != (p)->cpu)) { \ + spin_unlock_irqrestore(&rq->lock, flags); \ + goto repeat_lock_task; \ + } \ +} while (0) +#define unlock_task_rq(rq,p,flags) \ + spin_unlock_irqrestore(&rq->lock, flags) /* - * Init task must be ok at boot for the ix86 as we will check its signals - * via the SMP irq return path. + * Adding/removing a task to/from a priority array: */ - -struct task_struct * init_tasks[NR_CPUS] = {&init_task, }; +static inline void dequeue_task(struct task_struct *p, prio_array_t *array) +{ + array->nr_active--; + list_del_init(&p->run_list); + if (list_empty(array->queue + p->prio)) + __set_bit(p->prio, array->bitmap); +} + +static inline void enqueue_task(struct task_struct *p, prio_array_t *array) +{ + list_add_tail(&p->run_list, array->queue + p->prio); + __clear_bit(p->prio, array->bitmap); + array->nr_active++; + p->array = array; +} /* - * The tasklist_lock protects the linked list of processes. + * This is the per-process load estimator. Processes that generate + * more load than the system can handle get a priority penalty. + * + * The estimator uses a 4-entry load-history ringbuffer which is + * updated whenever a task is moved to/from the runqueue. The load + * estimate is also updated from the timer tick to get an accurate + * estimation of currently executing tasks as well. * - * The runqueue_lock locks the parts that actually access - * and change the run-queues, and have to be interrupt-safe. + * The 4-entry p->hist[4] array holds the 'sleep history' of + * every task. Every entry holds the number of time ticks spent + * sleeping in the past 4 seconds. Three of the entries belong to + * one-one second in the past, the fourth entry belongs to the current + * second. (the p->hist_idx index is used in fact as a rotating index + * to reduce overhead.) * - * If both locks are to be concurrently held, the runqueue_lock - * nests inside the tasklist_lock. + * The array elements are integers in the range of 0-HZ. If HZ is 100, + * then '100' means a process has spent 100% of it's time sleeping, in + * that particular second of time. '0' means the process has spent all + * its time on the runqueue - ie. it was a CPU hog in that second. * - * task->alloc_lock nests inside tasklist_lock. + * For RAM usage and algorithmic overhead reasons we do not want a too + * big history buffer. It's also usually not interesting to the scheduler + * to know whether a task was idle or not 10 minutes ago. 'Recent behavior' + * is what matters, if a task was mostly sleeping recently then it's a + * 'good' interactive task. If it has spent most (or all) of its time + * running then it's a 'bad' CPU-hog that gets a priority penalty. + * + * The load estimator itself was written to be fast as well in every + * circumstance. Eg. if a task is context switching heavily then we do + * not call into the estimator, only about once per timer tick, on average. */ -spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; /* inner */ -rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ - -static LIST_HEAD(runqueue_head); /* - * We align per-CPU scheduling data on cacheline boundaries, - * to prevent cacheline ping-pong. + * The 'history index' goes forward in time, if one second passes then + * the index is increased by 1 via this function. We wrap around the + * index if it reaches 4. (The modulo is fast with the current + * SLEEP_HIST_SIZE of 4.) */ -static union { - struct schedule_data { - struct task_struct * curr; - cycles_t last_schedule; - } schedule_data; - char __pad [SMP_CACHE_BYTES]; -} aligned_data [NR_CPUS] __cacheline_aligned = { {{&init_task,0}}}; - -#define cpu_curr(cpu) aligned_data[(cpu)].schedule_data.curr -#define last_schedule(cpu) aligned_data[(cpu)].schedule_data.last_schedule - -struct kernel_stat kstat; -extern struct task_struct *child_reaper; - -#ifdef CONFIG_SMP - -#define idle_task(cpu) (init_tasks[cpu_number_map(cpu)]) -#define can_schedule(p,cpu) \ - ((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu)) - -#else - -#define idle_task(cpu) (&init_task) -#define can_schedule(p,cpu) (1) +static inline void new_second(task_t *p) +{ + p->hist_idx = (p->hist_idx + 1) % SLEEP_HIST_SIZE; +} -#endif +/* + * process load-history tick length. Right now it's 1 second: + */ +#define HHZ (HZ) -void scheduling_functions_start_here(void) { } +/* + * This function clears the load-history entries when a task has spent + * more than 4 seconds running. + */ +static inline void clear_hist(task_t *p) +{ + p->hist[0] = p->hist[1] = p->hist[2] = p->hist[3] = 0; +} /* - * This is the function that decides how desirable a process is.. - * You can weigh different processes against each other depending - * on what CPU they've run on lately etc to try to handle cache - * and TLB miss penalties. - * - * Return values: - * -1000: never select this - * 0: out of time, recalculate counters (but it might still be - * selected) - * +ve: "goodness" value (the larger, the better) - * +1000: realtime process, select this. + * This function fills in the load-history entries with the maximum + * values when a task has spent more than 4 seconds sleeping. */ +static inline void fill_hist(task_t *p) +{ + p->hist[0] = p->hist[1] = p->hist[2] = p->hist[3] = HHZ; +} -static inline int goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm) +/* + * This function is called when a task goes sleeping, ie. when the task + * has potentially spent alot of time on the runqueue. p->run_timestamp + * is the time the task has started running, 'now' is the time when the + * task goes to sleep. + */ +static inline void update_sleep_avg_deactivate(task_t *p) { - int weight; + int idx; + unsigned long now = jiffies, + seconds_passed = now/HHZ - p->run_timestamp/HHZ; /* - * select the current process after every other - * runnable process, but before the idle thread. - * Also, dont trigger a counter recalculation. + * Do we have to update the history entries becase a + * 'new second' has been started? If a new second has + * been started then we have to clear all the 'full' + * seconds that have been passed during the time the + * task was running, and the new current entry has + * to be cleared as well. + * + * Otherwise we only have to update the sleep timestamp. */ - weight = -1; - if (p->policy & SCHED_YIELD) - goto out; + if (unlikely(seconds_passed)) { + if (seconds_passed < SLEEP_HIST_SIZE) + for (idx = 0; idx < seconds_passed; idx++) { + new_second(p); + p->hist[p->hist_idx] = 0; + } + else + clear_hist(p); + } + p->sleep_timestamp = now; +} - /* - * Non-RT process - normal case first. +/* + * This is called when a task gets runnable and gets moved to the runqueue. + * ie. when the task has potentially spent alot of time sleeping. + * p->sleep_timestamp is the time the task has started sleeping, 'now' is + * the time when we go to the runqueue. + */ +static inline void update_sleep_avg_activate(task_t *p, unsigned long now) +{ + int idx; + unsigned long sleep_ticks, + seconds_passed = now/HHZ - p->sleep_timestamp/HHZ; + + /* + * Do we have to update the history entries becase a + * 'new second' has been started? This is slightly more + * complex than the deactivate path, because in the deactivate + * path history entries are simply cleared, but here we have + * to add any potential time spent sleeping in the current + * second. This value is 'sleep_ticks' - it can be anywhere + * between 0 and HZ-1. (it cannot be HZ because that would mean + * that the current second is over and we'd have to go to the + * next history entry.) Another detail is that we might + * have gone sleeping in this second, or in any previous second. + * + * Otherwise we only have to update the run timestamp and the + * current history entry. */ - if (p->policy == SCHED_OTHER) { - /* - * Give the process a first-approximation goodness value - * according to the number of clock-ticks it has left. - * - * Don't do any other calculations if the time slice is - * over.. - */ - weight = p->counter; - if (!weight) - goto out; - -#ifdef CONFIG_SMP - /* Give a largish advantage to the same processor... */ - /* (this is equivalent to penalizing other processors) */ - if (p->processor == this_cpu) - weight += PROC_CHANGE_PENALTY; -#endif + if (unlikely(seconds_passed)) { + if (seconds_passed < SLEEP_HIST_SIZE) { + /* + * Update the "last partially-slept" second's entry: + */ + p->hist[p->hist_idx] += HHZ - (p->sleep_timestamp % HHZ); + new_second(p); - /* .. and a slight advantage to the current MM */ - if (p->mm == this_mm || !p->mm) - weight += 1; - weight += 20 - p->nice; - goto out; - } + /* + * Clear any (optional) interim seconds that were + * spent fully sleeping: + */ + for (idx = 1; idx < seconds_passed; idx++) { + new_second(p); + p->hist[p->hist_idx] = HHZ; + } + } else + /* + * We slept more than 4 seconds, fill in the + * history: + */ + fill_hist(p); + /* Clear the new current entry: */ + p->hist[p->hist_idx] = 0; + sleep_ticks = now % HHZ; + } else + sleep_ticks = now - p->sleep_timestamp; /* - * Realtime process, select the first one on the - * runqueue (taking priorities within processes - * into account). + * Update the current entry with the amount of + * ticks the task spent sleeping: */ - weight = 1000 + p->rt_priority; -out: - return weight; + p->hist[p->hist_idx] += sleep_ticks; + p->run_timestamp = now; } /* - * the 'goodness value' of replacing a process on a given CPU. - * positive value means 'replace', zero or negative means 'dont'. + * Get the current 'load average' of the task. + * + * Naively one would divide the sum by 4. But in fact the current entry + * is just a partial history, so we have to divide by the actual portion + * we recorded, which is somewhere between 3.0 and 4.0 seconds. */ -static inline int preemption_goodness(struct task_struct * prev, struct task_struct * p, int cpu) +static inline unsigned int get_run_avg(task_t *p, unsigned long new) { - return goodness(p, cpu, prev->active_mm) - goodness(prev, cpu, prev->active_mm); + return HHZ - (p->hist[0] + p->hist[1] + p->hist[2] + + p->hist[3]) * HHZ / ((SLEEP_HIST_SIZE-1)*HHZ + (new % HHZ)); } -/* - * This is ugly, but reschedule_idle() is very timing-critical. - * We are called with the runqueue spinlock held and we must - * not claim the tasklist_lock. - */ -static FASTCALL(void reschedule_idle(struct task_struct * p)); - -static void reschedule_idle(struct task_struct * p) +static inline void activate_task(task_t *p, runqueue_t *rq) { -#ifdef CONFIG_SMP - int this_cpu = smp_processor_id(); - struct task_struct *tsk, *target_tsk; - int cpu, best_cpu, i, max_prio; - cycles_t oldest_idle; + prio_array_t *array = rq->active; + unsigned long now = jiffies; + unsigned int penalty; - /* - * shortcut if the woken up task's last CPU is - * idle now. - */ - best_cpu = p->processor; - if (can_schedule(p, best_cpu)) { - tsk = idle_task(best_cpu); - if (cpu_curr(best_cpu) == tsk) { - int need_resched; -send_now_idle: - /* - * If need_resched == -1 then we can skip sending - * the IPI altogether, tsk->need_resched is - * actively watched by the idle thread. - */ - need_resched = tsk->need_resched; - tsk->need_resched = 1; - if ((best_cpu != this_cpu) && !need_resched) - smp_send_reschedule(best_cpu); - return; - } - } + if (likely(p->run_timestamp == now)) + goto enqueue; + update_sleep_avg_activate(p, now); /* - * We know that the preferred CPU has a cache-affine current - * process, lets try to find a new idle CPU for the woken-up - * process. Select the least recently active idle CPU. (that - * one will have the least active cache context.) Also find - * the executing process which has the least priority. - */ - oldest_idle = (cycles_t) -1; - target_tsk = NULL; - max_prio = 0; + * Give the process a priority penalty if it has not slept often + * enough in the past. We scale the priority penalty according + * to the current load of the runqueue, and the 'load history' + * this process has. Eg. if the CPU has 3 processes running + * right now then a process that has slept more than two-thirds + * of the time is considered to be 'interactive'. The higher + * the load of the CPUs is, the easier it is for a process to + * get an non-interactivity penalty. + * + * the return value of get_run_avg() is an integer between 0 and HZ. + * We scale this 'load value' to between 0 and MAX_USER_PRIO/3. + * A task that generates 100% load gets the maximum penalty. + */ + penalty = MAX_USER_PRIO * get_run_avg(p, now) / (3 * HHZ); + if (!rt_task(p)) { + p->prio = NICE_TO_PRIO(p->__nice) + penalty; + if (p->prio > MAX_PRIO-1) + p->prio = MAX_PRIO-1; + } +enqueue: + enqueue_task(p, array); + rq->nr_running++; +} - for (i = 0; i < smp_num_cpus; i++) { - cpu = cpu_logical_map(i); - if (!can_schedule(p, cpu)) - continue; - tsk = cpu_curr(cpu); - /* - * We use the first available idle CPU. This creates - * a priority list between idle CPUs, but this is not - * a problem. - */ - if (tsk == idle_task(cpu)) { - if (last_schedule(cpu) < oldest_idle) { - oldest_idle = last_schedule(cpu); - target_tsk = tsk; - } - } else { - if (oldest_idle == -1ULL) { - int prio = preemption_goodness(tsk, p, cpu); +static inline void deactivate_task(struct task_struct *p, runqueue_t *rq) +{ + rq->nr_running--; + dequeue_task(p, p->array); + p->array = NULL; + update_sleep_avg_deactivate(p); +} - if (prio > max_prio) { - max_prio = prio; - target_tsk = tsk; - } - } - } - } - tsk = target_tsk; - if (tsk) { - if (oldest_idle != -1ULL) { - best_cpu = tsk->processor; - goto send_now_idle; - } - tsk->need_resched = 1; - if (tsk->processor != this_cpu) - smp_send_reschedule(tsk->processor); - } - return; - +static inline void resched_task(task_t *p) +{ + int need_resched; -#else /* UP */ - int this_cpu = smp_processor_id(); - struct task_struct *tsk; - - tsk = cpu_curr(this_cpu); - if (preemption_goodness(tsk, p, this_cpu) > 0) - tsk->need_resched = 1; -#endif + need_resched = p->need_resched; + wmb(); + p->need_resched = 1; + if (!need_resched && (p->cpu != smp_processor_id())) + smp_send_reschedule(p->cpu); } +#ifdef CONFIG_SMP + /* - * Careful! - * - * This has to add the process to the _beginning_ of the - * run-queue, not the end. See the comment about "This is - * subtle" in the scheduler proper.. + * Wait for a process to unschedule. This is used by the exit() and + * ptrace() code. */ -static inline void add_to_runqueue(struct task_struct * p) +void wait_task_inactive(task_t * p) { - list_add(&p->run_list, &runqueue_head); - nr_running++; -} + unsigned long flags; + runqueue_t *rq; -static inline void move_last_runqueue(struct task_struct * p) -{ - list_del(&p->run_list); - list_add_tail(&p->run_list, &runqueue_head); +repeat: + rq = task_rq(p); + while (unlikely(rq->curr == p)) { + cpu_relax(); + barrier(); + } + lock_task_rq(rq, p, flags); + if (unlikely(rq->curr == p)) { + unlock_task_rq(rq, p, flags); + goto repeat; + } + unlock_task_rq(rq, p, flags); } -static inline void move_first_runqueue(struct task_struct * p) +/* + * Kick the remote CPU if the task is running currently, + * this code is used by the signal code to signal tasks + * which are in user-mode as quickly as possible. + * + * (Note that we do this lockless - if the task does anything + * while the message is in flight then it will notice the + * sigpending condition anyway.) + */ +void kick_if_running(task_t * p) { - list_del(&p->run_list); - list_add(&p->run_list, &runqueue_head); + if (p == task_rq(p)->curr) + resched_task(p); } +#endif /* * Wake up a process. Put it on the run-queue if it's not @@ -333,392 +374,468 @@ * "current->state = TASK_RUNNING" to mark yourself runnable * without the overhead of this. */ -static inline int try_to_wake_up(struct task_struct * p, int synchronous) +static int try_to_wake_up(task_t * p, int synchronous) { unsigned long flags; int success = 0; + runqueue_t *rq; - /* - * We want the common case fall through straight, thus the goto. - */ - spin_lock_irqsave(&runqueue_lock, flags); + lock_task_rq(rq, p, flags); p->state = TASK_RUNNING; - if (task_on_runqueue(p)) - goto out; - add_to_runqueue(p); - if (!synchronous || !(p->cpus_allowed & (1 << smp_processor_id()))) - reschedule_idle(p); - success = 1; -out: - spin_unlock_irqrestore(&runqueue_lock, flags); + if (!p->array) { + activate_task(p, rq); + if ((rq->curr == rq->idle) || (p->prio < rq->curr->prio)) + resched_task(rq->curr); + success = 1; + } + unlock_task_rq(rq, p, flags); return success; } -inline int wake_up_process(struct task_struct * p) +inline int wake_up_process(task_t * p) { return try_to_wake_up(p, 0); } -static void process_timeout(unsigned long __data) +void wake_up_forked_process(task_t * p) { - struct task_struct * p = (struct task_struct *) __data; + runqueue_t *rq = this_rq(); - wake_up_process(p); + spin_lock_irq(&rq->lock); + p->state = TASK_RUNNING; + if (!rt_task(p)) { + p->prio += MAX_USER_PRIO/10; + if (p->prio > MAX_PRIO-1) + p->prio = MAX_PRIO-1; + } + activate_task(p, rq); + spin_unlock_irq(&rq->lock); } -/** - * schedule_timeout - sleep until timeout - * @timeout: timeout value in jiffies - * - * Make the current task sleep until @timeout jiffies have - * elapsed. The routine will return immediately unless - * the current task state has been set (see set_current_state()). - * - * You can set the task state as follows - - * - * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to - * pass before the routine returns. The routine will return 0 - * - * %TASK_INTERRUPTIBLE - the routine may return early if a signal is - * delivered to the current task. In this case the remaining time - * in jiffies will be returned, or 0 if the timer expired in time - * - * The current task state is guaranteed to be TASK_RUNNING when this - * routine returns. - * - * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule - * the CPU away without a bound on the timeout. In this case the return - * value will be %MAX_SCHEDULE_TIMEOUT. - * - * In all cases the return value is guaranteed to be non-negative. - */ -signed long schedule_timeout(signed long timeout) +asmlinkage void schedule_tail(task_t *prev) { - struct timer_list timer; - unsigned long expire; + spin_unlock_irq(&this_rq()->lock); +} - switch (timeout) - { - case MAX_SCHEDULE_TIMEOUT: - /* - * These two special cases are useful to be comfortable - * in the caller. Nothing more. We could take - * MAX_SCHEDULE_TIMEOUT from one of the negative value - * but I' d like to return a valid offset (>=0) to allow - * the caller to do everything it want with the retval. - */ - schedule(); - goto out; - default: - /* - * Another bit of PARANOID. Note that the retval will be - * 0 since no piece of kernel is supposed to do a check - * for a negative retval of schedule_timeout() (since it - * should never happens anyway). You just have the printk() - * that will tell you if something is gone wrong and where. - */ - if (timeout < 0) - { - printk(KERN_ERR "schedule_timeout: wrong timeout " - "value %lx from %p\n", timeout, - __builtin_return_address(0)); - current->state = TASK_RUNNING; - goto out; - } +static inline void context_switch(task_t *prev, task_t *next) +{ + struct mm_struct *mm = next->mm; + struct mm_struct *oldmm = prev->active_mm; + + prepare_to_switch(); + + if (!mm) { + next->active_mm = oldmm; + atomic_inc(&oldmm->mm_count); + enter_lazy_tlb(oldmm, next, smp_processor_id()); + } else + switch_mm(oldmm, mm, next, smp_processor_id()); + + if (!prev->mm) { + prev->active_mm = NULL; + mmdrop(oldmm); } - expire = timeout + jiffies; + /* + * Here we just switch the register state and the stack. There are + * 3 processes affected by a context switch: + * + * prev ==> .... ==> (last => next) + * + * It's the 'much more previous' 'prev' that is on next's stack, + * but prev is set to (the just run) 'last' process by switch_to(). + * This might sound slightly confusing but makes tons of sense. + */ + switch_to(prev, next, prev); +} + +unsigned long nr_running(void) +{ + unsigned long i, sum = 0; - init_timer(&timer); - timer.expires = expire; - timer.data = (unsigned long) current; - timer.function = process_timeout; + for (i = 0; i < smp_num_cpus; i++) + sum += cpu_rq(i)->nr_running; - add_timer(&timer); - schedule(); - del_timer_sync(&timer); + return sum; +} + +unsigned long nr_context_switches(void) +{ + unsigned long i, sum = 0; - timeout = expire - jiffies; + for (i = 0; i < smp_num_cpus; i++) + sum += cpu_rq(i)->nr_switches; - out: - return timeout < 0 ? 0 : timeout; + return sum; +} + +static inline unsigned long max_rq_len(void) +{ + unsigned long i, curr, max = 0; + + for (i = 0; i < smp_num_cpus; i++) { + curr = cpu_rq(i)->nr_running; + if (curr > max) + max = curr; + } + return max; } /* - * schedule_tail() is getting called from the fork return path. This - * cleans up all remaining scheduler things, without impacting the - * common case. + * Current runqueue is empty, or rebalance tick: if there is an + * inbalance (current runqueue is too short) then pull from + * busiest runqueue(s). + * + * We call this with the current runqueue locked, + * irqs disabled. */ -static inline void __schedule_tail(struct task_struct *prev) +static void load_balance(runqueue_t *this_rq, int idle) { -#ifdef CONFIG_SMP - int policy; + int imbalance, nr_running, load, prev_max_load, + max_load, idx, i, this_cpu = smp_processor_id(); + task_t *next = this_rq->idle, *tmp; + runqueue_t *busiest, *rq_src; + prio_array_t *array; + list_t *head, *curr; /* - * prev->policy can be written from here only before `prev' - * can be scheduled (before setting prev->cpus_runnable to ~0UL). - * Of course it must also be read before allowing prev - * to be rescheduled, but since the write depends on the read - * to complete, wmb() is enough. (the spin_lock() acquired - * before setting cpus_runnable is not enough because the spin_lock() - * common code semantics allows code outside the critical section - * to enter inside the critical section) + * We search all runqueues to find the most busy one. + * We do this lockless to reduce cache-bouncing overhead, + * we re-check the 'best' source CPU later on again, with + * the lock held. + * + * We fend off statistical fluctuations in runqueue lengths by + * saving the runqueue length during the previous load-balancing + * operation and using the smaller one the current and saved lengths. + * If a runqueue is long enough for a longer amount of time then + * we recognize it and pull tasks from it. + * + * The 'current runqueue length' is a statistical maximum variable, + * for that one we take the longer one - to avoid fluctuations in + * the other direction. So for a load-balance to happen it needs + * stable long runqueue on the target CPU and stable short runqueue + * on the local runqueue. + * + * We make an exception if this CPU is about to become idle - in + * that case we are less picky about moving a task across CPUs and + * take what can be taken. */ - policy = prev->policy; - prev->policy = policy & ~SCHED_YIELD; - wmb(); + if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu])) + nr_running = this_rq->nr_running; + else + nr_running = this_rq->prev_nr_running[this_cpu]; + prev_max_load = 1000000000; + + busiest = NULL; + max_load = 0; + for (i = 0; i < smp_num_cpus; i++) { + rq_src = cpu_rq(i); + if (idle || (rq_src->nr_running < this_rq->prev_nr_running[i])) + load = rq_src->nr_running; + else + load = this_rq->prev_nr_running[i]; + this_rq->prev_nr_running[i] = rq_src->nr_running; + + if ((load > max_load) && (load < prev_max_load) && + (rq_src != this_rq)) { + busiest = rq_src; + max_load = load; + } + } + + if (likely(!busiest)) + return; + + imbalance = (max_load - nr_running) / 2; /* - * fast path falls through. We have to clear cpus_runnable before - * checking prev->state to avoid a wakeup race. Protect against - * the task exiting early. - */ - task_lock(prev); - task_release_cpu(prev); - mb(); - if (prev->state == TASK_RUNNING) - goto needs_resched; + * It needs an at least ~25% imbalance to trigger balancing. + * + * prev_max_load makes sure that we do not try to balance + * ad infinitum - certain tasks might be impossible to be + * pulled into this runqueue. + */ + if (!idle && (imbalance < (max_load + 3)/4)) + return; + prev_max_load = max_load; -out_unlock: - task_unlock(prev); /* Synchronise here with release_task() if prev is TASK_ZOMBIE */ - return; + /* + * Ok, lets do some actual balancing: + */ + if (rq_cpu(busiest) < this_cpu) { + spin_unlock(&this_rq->lock); + spin_lock(&busiest->lock); + spin_lock(&this_rq->lock); + } else + spin_lock(&busiest->lock); /* - * Slow path - we 'push' the previous process and - * reschedule_idle() will attempt to find a new - * processor for it. (but it might preempt the - * current process as well.) We must take the runqueue - * lock and re-check prev->state to be correct. It might - * still happen that this process has a preemption - * 'in progress' already - but this is not a problem and - * might happen in other circumstances as well. + * Make sure nothing changed since we checked the + * runqueue length. */ -needs_resched: - { - unsigned long flags; + if (busiest->nr_running <= nr_running + 1) + goto out_unlock; - /* - * Avoid taking the runqueue lock in cases where - * no preemption-check is necessery: - */ - if ((prev == idle_task(smp_processor_id())) || - (policy & SCHED_YIELD)) - goto out_unlock; + /* + * We first consider expired tasks. Those will likely not run + * in the near future, thus switching CPUs has the least effect + * on them. + */ + if (busiest->expired->nr_active) + array = busiest->expired; + else + array = busiest->active; - spin_lock_irqsave(&runqueue_lock, flags); - if ((prev->state == TASK_RUNNING) && !task_has_cpu(prev)) - reschedule_idle(prev); - spin_unlock_irqrestore(&runqueue_lock, flags); +new_array: + /* + * Load-balancing does not affect RT tasks, so we start the + * searching at priority 128. + */ + idx = MAX_RT_PRIO; +skip_bitmap: + idx = find_next_zero_bit(array->bitmap, MAX_PRIO, idx); + if (idx == MAX_PRIO) { + if (array == busiest->expired) { + array = busiest->active; + goto new_array; + } goto out_unlock; } -#else - prev->policy &= ~SCHED_YIELD; -#endif /* CONFIG_SMP */ + + head = array->queue + idx; + curr = head->next; +skip_queue: + tmp = list_entry(curr, task_t, run_list); + if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << this_cpu))) { + curr = curr->next; + if (curr != head) + goto skip_queue; + idx++; + goto skip_bitmap; + } + next = tmp; + /* + * take the task out of the other runqueue and + * put it into this one: + */ + dequeue_task(next, array); + busiest->nr_running--; + next->cpu = this_cpu; + this_rq->nr_running++; + enqueue_task(next, this_rq->active); + if (next->prio < current->prio) + current->need_resched = 1; + if (!idle && --imbalance) { + if (array == busiest->expired) { + array = busiest->active; + goto new_array; + } + } +out_unlock: + spin_unlock(&busiest->lock); } -asmlinkage void schedule_tail(struct task_struct *prev) +/* + * One of the idle_cpu_tick() or the busy_cpu_tick() function will + * gets called every timer tick, on every CPU. Our balancing action + * frequency and balancing agressivity depends on whether the CPU is + * idle or not. + * + * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on + * systems with HZ=100, every 10 msecs.) + */ +#define BUSY_REBALANCE_TICK (HZ/4 ?: 1) +#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1) + +static inline void idle_tick(void) { - __schedule_tail(prev); + if ((jiffies % IDLE_REBALANCE_TICK) || + likely(this_rq()->curr == NULL)) + return; + spin_lock(&this_rq()->lock); + load_balance(this_rq(), 1); + spin_unlock(&this_rq()->lock); } /* - * 'schedule()' is the scheduler function. It's a very simple and nice - * scheduler: it's not perfect, but certainly works for most things. - * - * The goto is "interesting". - * - * NOTE!! Task 0 is the 'idle' task, which gets called when no other - * tasks can run. It can not be killed, and it cannot sleep. The 'state' - * information in task[0] is never used. + * Should we treat the task as interactive or not. + * A task is interactive if it has not exceeded 50% + * of the max CPU-hog penalty yet. */ -asmlinkage void schedule(void) +static int task_interactive(task_t *p, unsigned long now) { - struct schedule_data * sched_data; - struct task_struct *prev, *next, *p; - struct list_head *tmp; - int this_cpu, c; + int penalty; + if (rt_task(p)) + return 1; + penalty = MAX_USER_PRIO * get_run_avg(p, jiffies) / (3 * HHZ); + if (penalty <= MAX_USER_PRIO/6) + return 1; + return 0; +} - spin_lock_prefetch(&runqueue_lock); +/* + * This function gets called by the timer code, with HZ frequency. + * We call it with interrupts disabled. + */ +void scheduler_tick(task_t *p) +{ + unsigned long now = jiffies; + runqueue_t *rq = this_rq(); - if (!current->active_mm) BUG(); -need_resched_back: - prev = current; - this_cpu = prev->processor; + if (p == rq->idle || !rq->idle) + return idle_tick(); + /* Task might have expired already, but not scheduled off yet */ + if (p->array != rq->active) { + p->need_resched = 1; + return; + } + /* + * The task cannot change CPUs because it's the current task. + */ + spin_lock(&rq->lock); + if ((p->policy != SCHED_FIFO) && !--p->time_slice) { + p->need_resched = 1; + if (rt_task(p)) + p->time_slice = RT_PRIO_TO_TIMESLICE(p->prio); + else + p->time_slice = PRIO_TO_TIMESLICE(p->prio); - if (unlikely(in_interrupt())) { - printk("Scheduling in interrupt\n"); - BUG(); + /* + * Timeslice used up - discard any possible + * priority penalty: + */ + dequeue_task(p, rq->active); + /* + * Tasks that have nice values of -20 ... -15 are put + * back into the active array. If they use up too much + * CPU time then they'll get a priority penalty anyway + * so this can not starve other processes accidentally. + * Otherwise this is pretty handy for sysadmins ... + */ + if (task_interactive(p, now)) + enqueue_task(p, rq->active); + else + enqueue_task(p, rq->expired); + } else { + /* + * Deactivate + activate the task so that the + * load estimator gets updated properly: + */ + if (!rt_task(p)) { + deactivate_task(p, rq); + activate_task(p, rq); + } } + if (!(now % BUSY_REBALANCE_TICK)) + load_balance(rq, 0); + spin_unlock(&rq->lock); +} - release_kernel_lock(prev, this_cpu); - - /* - * 'sched_data' is protected by the fact that we can run - * only one process per CPU. - */ - sched_data = & aligned_data[this_cpu].schedule_data; +void scheduling_functions_start_here(void) { } - spin_lock_irq(&runqueue_lock); +/* + * 'schedule()' is the main scheduler function. + */ +asmlinkage void schedule(void) +{ + task_t *prev, *next; + prio_array_t *array; + runqueue_t *rq; + list_t *queue; + int idx; - /* move an exhausted RR process to be last.. */ - if (unlikely(prev->policy == SCHED_RR)) - if (!prev->counter) { - prev->counter = NICE_TO_TICKS(prev->nice); - move_last_runqueue(prev); - } + if (unlikely(in_interrupt())) + BUG(); +need_resched_back: + prev = current; + release_kernel_lock(prev, smp_processor_id()); + rq = this_rq(); + spin_lock_irq(&rq->lock); switch (prev->state) { case TASK_INTERRUPTIBLE: - if (signal_pending(prev)) { + if (unlikely(signal_pending(prev))) { prev->state = TASK_RUNNING; break; } default: - del_from_runqueue(prev); - case TASK_RUNNING:; - } - prev->need_resched = 0; - - /* - * this is the scheduler proper: - */ - -repeat_schedule: - /* - * Default process to select.. - */ - next = idle_task(this_cpu); - c = -1000; - list_for_each(tmp, &runqueue_head) { - p = list_entry(tmp, struct task_struct, run_list); - if (can_schedule(p, this_cpu)) { - int weight = goodness(p, this_cpu, prev->active_mm); - if (weight > c) - c = weight, next = p; - } + deactivate_task(prev, rq); + case TASK_RUNNING: } - - /* Do we need to re-calculate counters? */ - if (unlikely(!c)) { - struct task_struct *p; - - spin_unlock_irq(&runqueue_lock); - read_lock(&tasklist_lock); - for_each_task(p) - p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice); - read_unlock(&tasklist_lock); - spin_lock_irq(&runqueue_lock); - goto repeat_schedule; +pick_next_task: + if (unlikely(!rq->nr_running)) { + load_balance(rq, 1); + if (rq->nr_running) + goto pick_next_task; + next = rq->idle; + goto switch_tasks; } - /* - * from this point on nothing can prevent us from - * switching to the next task, save this fact in - * sched_data. - */ - sched_data->curr = next; - task_set_cpu(next, this_cpu); - spin_unlock_irq(&runqueue_lock); - - if (unlikely(prev == next)) { - /* We won't go through the normal tail, so do this by hand */ - prev->policy &= ~SCHED_YIELD; - goto same_process; + array = rq->active; + if (unlikely(!array->nr_active)) { + /* + * Switch the active and expired arrays. + */ + rq->active = rq->expired; + rq->expired = array; + array = rq->active; } -#ifdef CONFIG_SMP - /* - * maintain the per-process 'last schedule' value. - * (this has to be recalculated even if we reschedule to - * the same process) Currently this is only used on SMP, - * and it's approximate, so we do not have to maintain - * it while holding the runqueue spinlock. - */ - sched_data->last_schedule = get_cycles(); - - /* - * We drop the scheduler lock early (it's a global spinlock), - * thus we have to lock the previous process from getting - * rescheduled during switch_to(). - */ - -#endif /* CONFIG_SMP */ + idx = sched_find_first_zero_bit(array->bitmap); + queue = array->queue + idx; + next = list_entry(queue->next, task_t, run_list); - kstat.context_swtch++; - /* - * there are 3 processes which are affected by a context switch: - * - * prev == .... ==> (last => next) - * - * It's the 'much more previous' 'prev' that is on next's stack, - * but prev is set to (the just run) 'last' process by switch_to(). - * This might sound slightly confusing but makes tons of sense. - */ - prepare_to_switch(); - { - struct mm_struct *mm = next->mm; - struct mm_struct *oldmm = prev->active_mm; - if (!mm) { - if (next->active_mm) BUG(); - next->active_mm = oldmm; - atomic_inc(&oldmm->mm_count); - enter_lazy_tlb(oldmm, next, this_cpu); - } else { - if (next->active_mm != mm) BUG(); - switch_mm(oldmm, mm, next, this_cpu); - } +switch_tasks: + prev->need_resched = 0; - if (!prev->mm) { - prev->active_mm = NULL; - mmdrop(oldmm); - } + if (likely(prev != next)) { + rq->nr_switches++; + rq->curr = next; + next->cpu = prev->cpu; + context_switch(prev, next); + /* + * The runqueue pointer might be from another CPU + * if the new task was last running on a different + * CPU - thus re-load it. + */ + barrier(); + rq = this_rq(); } + spin_unlock_irq(&rq->lock); - /* - * This just switches the register state and the - * stack. - */ - switch_to(prev, next, prev); - __schedule_tail(prev); - -same_process: reacquire_kernel_lock(current); - if (current->need_resched) + if (unlikely(current->need_resched)) goto need_resched_back; return; } /* - * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just wake everything - * up. If it's an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the - * non-exclusive tasks and one exclusive task. + * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just + * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve + * number) then we wake all the non-exclusive tasks and one exclusive task. * * There are circumstances in which we can try to wake a task which has already - * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns zero - * in this (rare) case, and we handle it by contonuing to scan the queue. + * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns + * zero in this (rare) case, and we handle it by continuing to scan the queue. */ static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode, int nr_exclusive, const int sync) { struct list_head *tmp; - struct task_struct *p; + task_t *p; - CHECK_MAGIC_WQHEAD(q); - WQ_CHECK_LIST_HEAD(&q->task_list); - list_for_each(tmp,&q->task_list) { unsigned int state; - wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list); + wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list); - CHECK_MAGIC(curr->__magic); p = curr->task; state = p->state; - if (state & mode) { - WQ_NOTE_WAKER(curr); - if (try_to_wake_up(p, sync) && (curr->flags&WQ_FLAG_EXCLUSIVE) && !--nr_exclusive) - break; - } + if ((state & mode) && + try_to_wake_up(p, sync) && + ((curr->flags & WQ_FLAG_EXCLUSIVE) && + !--nr_exclusive)) + break; } } @@ -835,8 +952,95 @@ return timeout; } +/* + * Change the current task's CPU affinity. Migrate the process to a + * proper CPU and schedule away if the current CPU is removed from + * the allowed bitmask. + */ +void set_cpus_allowed(task_t *p, unsigned long new_mask) +{ + runqueue_t *this_rq = this_rq(), *target_rq; + unsigned long this_mask = 1UL << smp_processor_id(); + int target_cpu; + + new_mask &= cpu_online_map; + if (!new_mask) + BUG(); + p->cpus_allowed = new_mask; + /* + * Can the task run on the current CPU? If not then + * migrate the process off to a proper CPU. + */ + if (new_mask & this_mask) + return; + target_cpu = ffz(~new_mask); + target_rq = cpu_rq(target_cpu); + if (target_cpu < smp_processor_id()) { + spin_lock_irq(&target_rq->lock); + spin_lock(&this_rq->lock); + } else { + spin_lock_irq(&this_rq->lock); + spin_lock(&target_rq->lock); + } + dequeue_task(p, p->array); + this_rq->nr_running--; + target_rq->nr_running++; + enqueue_task(p, target_rq->active); + target_rq->curr->need_resched = 1; + spin_unlock(&target_rq->lock); + + /* + * The easiest solution is to context switch into + * the idle thread - which will pick the best task + * afterwards: + */ + this_rq->nr_switches++; + this_rq->curr = this_rq->idle; + this_rq->idle->need_resched = 1; + context_switch(current, this_rq->idle); + barrier(); + spin_unlock_irq(&this_rq()->lock); +} + void scheduling_functions_end_here(void) { } +void set_user_nice(task_t *p, long nice) +{ + unsigned long flags; + prio_array_t *array; + runqueue_t *rq; + + if (p->__nice == nice) + return; + /* + * We have to be careful, if called from sys_setpriority(), + * the task might be in the middle of scheduling on another CPU. + */ + lock_task_rq(rq, p, flags); + if (rt_task(p)) { + p->__nice = nice; + goto out_unlock; + } + array = p->array; + if (array) { + dequeue_task(p, array); + } + p->__nice = nice; + p->prio = NICE_TO_PRIO(nice); + if (array) { + enqueue_task(p, array); + /* + * If the task is runnable and lowered its priority, + * or increased its priority then reschedule its CPU: + */ + if ((nice < p->__nice) || + ((p->__nice < nice) && (p == rq->curr))) + resched_task(rq->curr); + } +out_unlock: + unlock_task_rq(rq, p, flags); +} + #ifndef __alpha__ /* @@ -847,7 +1051,7 @@ asmlinkage long sys_nice(int increment) { - long newprio; + long nice; /* * Setpriority might change our priority at the same moment. @@ -863,32 +1067,30 @@ if (increment > 40) increment = 40; - newprio = current->nice + increment; - if (newprio < -20) - newprio = -20; - if (newprio > 19) - newprio = 19; - current->nice = newprio; + nice = current->__nice + increment; + if (nice < -20) + nice = -20; + if (nice > 19) + nice = 19; + set_user_nice(current, nice); return 0; } #endif -static inline struct task_struct *find_process_by_pid(pid_t pid) +static inline task_t *find_process_by_pid(pid_t pid) { - struct task_struct *tsk = current; - - if (pid) - tsk = find_task_by_pid(pid); - return tsk; + return pid ? find_task_by_pid(pid) : current; } -static int setscheduler(pid_t pid, int policy, - struct sched_param *param) +static int setscheduler(pid_t pid, int policy, struct sched_param *param) { struct sched_param lp; - struct task_struct *p; + prio_array_t *array; + unsigned long flags; + runqueue_t *rq; int retval; + task_t *p; retval = -EINVAL; if (!param || pid < 0) @@ -902,14 +1104,19 @@ * We play safe to avoid deadlocks. */ read_lock_irq(&tasklist_lock); - spin_lock(&runqueue_lock); p = find_process_by_pid(pid); retval = -ESRCH; if (!p) - goto out_unlock; - + goto out_unlock_tasklist; + + /* + * To be able to change p->policy safely, the apropriate + * runqueue lock must be held. + */ + lock_task_rq(rq,p,flags); + if (policy < 0) policy = p->policy; else { @@ -930,30 +1137,36 @@ goto out_unlock; retval = -EPERM; - if ((policy == SCHED_FIFO || policy == SCHED_RR) && + if ((policy == SCHED_FIFO || policy == SCHED_RR) && !capable(CAP_SYS_NICE)) goto out_unlock; if ((current->euid != p->euid) && (current->euid != p->uid) && !capable(CAP_SYS_NICE)) goto out_unlock; + array = p->array; + if (array) + deactivate_task(p, task_rq(p)); retval = 0; p->policy = policy; p->rt_priority = lp.sched_priority; - if (task_on_runqueue(p)) - move_first_runqueue(p); - - current->need_resched = 1; + if (rt_task(p)) + p->prio = 99-p->rt_priority; + else + p->prio = NICE_TO_PRIO(p->__nice); + if (array) + activate_task(p, task_rq(p)); out_unlock: - spin_unlock(&runqueue_lock); + unlock_task_rq(rq,p,flags); +out_unlock_tasklist: read_unlock_irq(&tasklist_lock); out_nounlock: return retval; } -asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, +asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param) { return setscheduler(pid, policy, param); @@ -966,7 +1179,7 @@ asmlinkage long sys_sched_getscheduler(pid_t pid) { - struct task_struct *p; + task_t *p; int retval; retval = -EINVAL; @@ -977,7 +1190,7 @@ read_lock(&tasklist_lock); p = find_process_by_pid(pid); if (p) - retval = p->policy & ~SCHED_YIELD; + retval = p->policy; read_unlock(&tasklist_lock); out_nounlock: @@ -986,7 +1199,7 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param) { - struct task_struct *p; + task_t *p; struct sched_param lp; int retval; @@ -1017,42 +1230,28 @@ asmlinkage long sys_sched_yield(void) { + runqueue_t *rq = this_rq(); + prio_array_t *array; + /* - * Trick. sched_yield() first counts the number of truly - * 'pending' runnable processes, then returns if it's - * only the current processes. (This test does not have - * to be atomic.) In threaded applications this optimization - * gets triggered quite often. + * Decrease the yielding task's priority by one, to avoid + * livelocks. This priority loss is temporary, it's recovered + * once the current timeslice expires. + * + * If priority is already MAX_PRIO-1 then we still + * roundrobin the task within the runlist. */ + spin_lock_irq(&rq->lock); + array = current->array; + dequeue_task(current, array); + if (likely(!rt_task(current))) + if (current->prio < MAX_PRIO-1) + current->prio++; + enqueue_task(current, array); + spin_unlock_irq(&rq->lock); - int nr_pending = nr_running; - -#if CONFIG_SMP - int i; - - // Subtract non-idle processes running on other CPUs. - 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--; -#endif - if (nr_pending) { - /* - * This process can only be rescheduled by us, - * so this is safe without any locking. - */ - if (current->policy == SCHED_OTHER) - current->policy |= SCHED_YIELD; - current->need_resched = 1; + schedule(); - spin_lock_irq(&runqueue_lock); - move_last_runqueue(current); - spin_unlock_irq(&runqueue_lock); - } return 0; } @@ -1090,7 +1289,7 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval) { struct timespec t; - struct task_struct *p; + task_t *p; int retval = -EINVAL; if (pid < 0) @@ -1100,8 +1299,8 @@ read_lock(&tasklist_lock); p = find_process_by_pid(pid); if (p) - jiffies_to_timespec(p->policy & SCHED_FIFO ? 0 : NICE_TO_TICKS(p->nice), - &t); + jiffies_to_timespec(p->policy & SCHED_FIFO ? + 0 : RT_PRIO_TO_TIMESLICE(p->prio), &t); read_unlock(&tasklist_lock); if (p) retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0; @@ -1109,7 +1308,7 @@ return retval; } -static void show_task(struct task_struct * p) +static void show_task(task_t * p) { unsigned long free = 0; int state; @@ -1157,7 +1356,7 @@ printk(" (NOTLB)\n"); { - extern void show_trace_task(struct task_struct *tsk); + extern void show_trace_task(task_t *tsk); show_trace_task(p); } } @@ -1179,7 +1378,7 @@ void show_state(void) { - struct task_struct *p; + task_t *p; #if (BITS_PER_LONG == 32) printk("\n" @@ -1202,121 +1401,98 @@ read_unlock(&tasklist_lock); } -/** - * reparent_to_init() - Reparent the calling kernel thread to the init task. - * - * If a kernel thread is launched as a result of a system call, or if - * it ever exits, it should generally reparent itself to init so that - * it is correctly cleaned up on exit. - * - * The various task state such as scheduling policy and priority may have - * been inherited fro a user process, so we reset them to sane values here. - * - * NOTE that reparent_to_init() gives the caller full capabilities. - */ -void reparent_to_init(void) -{ - struct task_struct *this_task = current; - - write_lock_irq(&tasklist_lock); - - /* Reparent to init */ - REMOVE_LINKS(this_task); - this_task->p_pptr = child_reaper; - this_task->p_opptr = child_reaper; - SET_LINKS(this_task); - - /* Set the exit signal to SIGCHLD so we signal init on exit */ - this_task->exit_signal = SIGCHLD; - - /* We also take the runqueue_lock while altering task fields - * which affect scheduling decisions */ - spin_lock(&runqueue_lock); - - this_task->ptrace = 0; - this_task->nice = DEF_NICE; - this_task->policy = SCHED_OTHER; - /* cpus_allowed? */ - /* rt_priority? */ - /* signals? */ - this_task->cap_effective = CAP_INIT_EFF_SET; - this_task->cap_inheritable = CAP_INIT_INH_SET; - this_task->cap_permitted = CAP_FULL_SET; - this_task->keep_capabilities = 0; - memcpy(this_task->rlim, init_task.rlim, sizeof(*(this_task->rlim))); - this_task->user = INIT_USER; +extern unsigned long wait_init_idle; - spin_unlock(&runqueue_lock); - write_unlock_irq(&tasklist_lock); +static inline void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2) +{ + if (rq1 == rq2) + spin_lock(&rq1->lock); + else { + if (rq_cpu(rq1) < rq_cpu(rq2)) { + spin_lock(&rq1->lock); + spin_lock(&rq2->lock); + } else { + spin_lock(&rq2->lock); + spin_lock(&rq1->lock); + } + } } -/* - * Put all the gunge required to become a kernel thread without - * attached user resources in one place where it belongs. - */ - -void daemonize(void) +static inline void double_rq_unlock(runqueue_t *rq1, runqueue_t *rq2) { - struct fs_struct *fs; - - - /* - * If we were started as result of loading a module, close all of the - * user space pages. We don't need them, and if we didn't close them - * they would be locked into memory. - */ - exit_mm(current); - - current->session = 1; - current->pgrp = 1; - current->tty = NULL; - - /* Become as one with the init task */ - - exit_fs(current); /* current->fs->count--; */ - fs = init_task.fs; - current->fs = fs; - atomic_inc(&fs->count); - exit_files(current); - current->files = init_task.files; - atomic_inc(¤t->files->count); + spin_unlock(&rq1->lock); + if (rq1 != rq2) + spin_unlock(&rq2->lock); } -extern unsigned long wait_init_idle; - void __init init_idle(void) { - struct schedule_data * sched_data; - sched_data = &aligned_data[smp_processor_id()].schedule_data; + runqueue_t *this_rq = this_rq(), *rq = current->array->rq; + unsigned long flags; - if (current != &init_task && task_on_runqueue(current)) { - printk("UGH! (%d:%d) was on the runqueue, removing.\n", - smp_processor_id(), current->pid); - del_from_runqueue(current); + __save_flags(flags); + __cli(); + double_rq_lock(this_rq, rq); + + this_rq->curr = this_rq->idle = current; + deactivate_task(current, rq); + current->array = NULL; + current->prio = MAX_PRIO; + current->state = TASK_RUNNING; + clear_bit(smp_processor_id(), &wait_init_idle); + double_rq_unlock(this_rq, rq); + while (wait_init_idle) { + cpu_relax(); + barrier(); } - sched_data->curr = current; - sched_data->last_schedule = get_cycles(); - clear_bit(current->processor, &wait_init_idle); + current->need_resched = 1; + __sti(); } -extern void init_timervecs (void); +extern void init_timervecs(void); +extern void timer_bh(void); +extern void tqueue_bh(void); +extern void immediate_bh(void); void __init sched_init(void) { + runqueue_t *rq; + int i, j, k; + + for (i = 0; i < NR_CPUS; i++) { + runqueue_t *rq = cpu_rq(i); + prio_array_t *array; + + rq->active = rq->arrays + 0; + rq->expired = rq->arrays + 1; + spin_lock_init(&rq->lock); + + for (j = 0; j < 2; j++) { + array = rq->arrays + j; + array->rq = rq; + array->lock = &rq->lock; + for (k = 0; k < MAX_PRIO; k++) { + INIT_LIST_HEAD(array->queue + k); + __set_bit(k, array->bitmap); + } + // zero delimiter for bitsearch + __clear_bit(MAX_PRIO, array->bitmap); + } + } /* * We have to do a little magic to get the first * process right in SMP mode. */ - int cpu = smp_processor_id(); - int nr; - - init_task.processor = cpu; - - for(nr = 0; nr < PIDHASH_SZ; nr++) - pidhash[nr] = NULL; + rq = this_rq(); + rq->curr = current; + rq->idle = NULL; + wake_up_process(current); + + /* used to clear pidhash[] to NULL here -- but being + * declared in bss does that automatically, + * so don't do it here. */ init_timervecs(); - init_bh(TIMER_BH, timer_bh); init_bh(TQUEUE_BH, tqueue_bh); init_bh(IMMEDIATE_BH, immediate_bh); @@ -1325,5 +1501,5 @@ * The boot idle thread does lazy MMU switching as well: */ atomic_inc(&init_mm.mm_count); - enter_lazy_tlb(&init_mm, current, cpu); + enter_lazy_tlb(&init_mm, current, smp_processor_id()); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/signal.c linux-2.5/kernel/signal.c --- linux-2.5.1/kernel/signal.c Fri Dec 14 20:25:24 2001 +++ linux-2.5/kernel/signal.c Tue Jan 8 00:44:25 2002 @@ -478,12 +478,9 @@ * process of changing - but no harm is done by that * other than doing an extra (lightweight) IPI interrupt. */ - spin_lock(&runqueue_lock); - if (task_has_cpu(t) && t->processor != smp_processor_id()) - smp_send_reschedule(t->processor); - spin_unlock(&runqueue_lock); -#endif /* CONFIG_SMP */ - + if ((t->state == TASK_RUNNING) && (t->cpu != smp_processor_id())) + kick_if_running(t); +#endif if (t->state & TASK_INTERRUPTIBLE) { wake_up_process(t); return; @@ -649,10 +646,8 @@ /* * kill_something_info() interprets pid in interesting ways just like kill(2). * - * POSIX (2001) specifies "If pid is -1, sig shall be sent to all processes - * (excluding an unspecified set of system processes) for which the process - * has permission to send that signal." - * So, probably the process should also signal itself. + * POSIX specifies that kill(-1,sig) is unspecified, but what we have + * is probably wrong. Should make it like BSD or SYSV. */ static int kill_something_info(int sig, struct siginfo *info, int pid) @@ -665,7 +660,7 @@ read_lock(&tasklist_lock); for_each_task(p) { - if (p->pid > 1) { + if (p->pid > 1 && p != current) { int err = send_sig_info(sig, info, p); ++count; if (err != -EPERM) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/softirq.c linux-2.5/kernel/softirq.c --- linux-2.5.1/kernel/softirq.c Fri Nov 30 23:53:28 2001 +++ linux-2.5/kernel/softirq.c Tue Jan 8 00:44:25 2002 @@ -259,10 +259,9 @@ while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { current->state = TASK_RUNNING; - do { - current->policy |= SCHED_YIELD; - schedule(); - } while (test_bit(TASKLET_STATE_SCHED, &t->state)); + do + yield(); + while (test_bit(TASKLET_STATE_SCHED, &t->state)); } tasklet_unlock_wait(t); clear_bit(TASKLET_STATE_SCHED, &t->state); @@ -365,13 +364,13 @@ int cpu = cpu_logical_map(bind_cpu); daemonize(); - current->nice = 19; + set_user_nice(current, 19); sigfillset(¤t->blocked); /* Migrate to the right CPU */ - current->cpus_allowed = 1UL << cpu; - while (smp_processor_id() != cpu) - schedule(); + set_cpus_allowed(current, 1UL << cpu); + if (smp_processor_id() != cpu) + BUG(); sprintf(current->comm, "ksoftirqd_CPU%d", bind_cpu); @@ -400,18 +399,13 @@ { int cpu; - for (cpu = 0; cpu < smp_num_cpus; cpu++) { + for (cpu = 0; cpu < smp_num_cpus; cpu++) if (kernel_thread(ksoftirqd, (void *) (long) cpu, CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) printk("spawn_ksoftirqd() failed for cpu %d\n", cpu); - else { - while (!ksoftirqd_task(cpu_logical_map(cpu))) { - current->policy |= SCHED_YIELD; - schedule(); - } - } - } - + else + while (!ksoftirqd_task(cpu_logical_map(cpu))) + yield(); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/sys.c linux-2.5/kernel/sys.c --- linux-2.5.1/kernel/sys.c Tue Sep 18 21:10:43 2001 +++ linux-2.5/kernel/sys.c Tue Jan 8 00:44:25 2002 @@ -220,10 +220,10 @@ } if (error == -ESRCH) error = 0; - if (niceval < p->nice && !capable(CAP_SYS_NICE)) + if (niceval < p->__nice && !capable(CAP_SYS_NICE)) error = -EACCES; else - p->nice = niceval; + set_user_nice(p, niceval); } read_unlock(&tasklist_lock); @@ -249,7 +249,7 @@ long niceval; if (!proc_sel(p, which, who)) continue; - niceval = 20 - p->nice; + niceval = 20 - p->__nice; if (niceval > retval) retval = niceval; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/sysctl.c linux-2.5/kernel/sysctl.c --- linux-2.5.1/kernel/sysctl.c Mon Dec 10 18:39:20 2001 +++ linux-2.5/kernel/sysctl.c Sun Dec 30 20:01:41 2001 @@ -19,6 +19,7 @@ */ #include <linux/config.h> +#include <linux/mm.h> #include <linux/slab.h> #include <linux/sysctl.h> #include <linux/swapctl.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/time.c linux-2.5/kernel/time.c --- linux-2.5.1/kernel/time.c Mon Oct 16 19:58:51 2000 +++ linux-2.5/kernel/time.c Thu Dec 13 16:32:37 2001 @@ -70,11 +70,11 @@ */ asmlinkage long sys_time(int * tloc) { - int i; + struct timeval now; + int i; - /* SMP: This is fairly trivial. We grab CURRENT_TIME and - stuff it to user space. No side effects */ - i = CURRENT_TIME; + do_gettimeofday(&now); + i = now.tv_sec; if (tloc) { if (put_user(i,tloc)) i = -EFAULT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/kernel/timer.c linux-2.5/kernel/timer.c --- linux-2.5.1/kernel/timer.c Mon Oct 8 17:41:41 2001 +++ linux-2.5/kernel/timer.c Sun Jan 13 18:08:45 2002 @@ -25,6 +25,8 @@ #include <asm/uaccess.h> +struct kernel_stat kstat; + /* * Timekeeping variables */ @@ -583,17 +585,16 @@ update_one_process(p, user_tick, system, cpu); if (p->pid) { - if (--p->counter <= 0) { - p->counter = 0; - p->need_resched = 1; - } - if (p->nice > 0) + if (p->__nice > 0) kstat.per_cpu_nice[cpu] += user_tick; else kstat.per_cpu_user[cpu] += user_tick; kstat.per_cpu_system[cpu] += system; - } else if (local_bh_count(cpu) || local_irq_count(cpu) > 1) - kstat.per_cpu_system[cpu] += system; + } else { + if (local_bh_count(cpu) || local_irq_count(cpu) > 1) + kstat.per_cpu_system[cpu] += system; + } + scheduler_tick(p); } /* @@ -793,6 +794,89 @@ } #endif + +static void process_timeout(unsigned long __data) +{ + wake_up_process((task_t *)__data); +} + +/** + * schedule_timeout - sleep until timeout + * @timeout: timeout value in jiffies + * + * Make the current task sleep until @timeout jiffies have + * elapsed. The routine will return immediately unless + * the current task state has been set (see set_current_state()). + * + * You can set the task state as follows - + * + * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to + * pass before the routine returns. The routine will return 0 + * + * %TASK_INTERRUPTIBLE - the routine may return early if a signal is + * delivered to the current task. In this case the remaining time + * in jiffies will be returned, or 0 if the timer expired in time + * + * The current task state is guaranteed to be TASK_RUNNING when this + * routine returns. + * + * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule + * the CPU away without a bound on the timeout. In this case the return + * value will be %MAX_SCHEDULE_TIMEOUT. + * + * In all cases the return value is guaranteed to be non-negative. + */ +signed long schedule_timeout(signed long timeout) +{ + struct timer_list timer; + unsigned long expire; + + switch (timeout) + { + case MAX_SCHEDULE_TIMEOUT: + /* + * These two special cases are useful to be comfortable + * in the caller. Nothing more. We could take + * MAX_SCHEDULE_TIMEOUT from one of the negative value + * but I' d like to return a valid offset (>=0) to allow + * the caller to do everything it want with the retval. + */ + schedule(); + goto out; + default: + /* + * Another bit of PARANOID. Note that the retval will be + * 0 since no piece of kernel is supposed to do a check + * for a negative retval of schedule_timeout() (since it + * should never happens anyway). You just have the printk() + * that will tell you if something is gone wrong and where. + */ + if (timeout < 0) + { + printk(KERN_ERR "schedule_timeout: wrong timeout " + "value %lx from %p\n", timeout, + __builtin_return_address(0)); + current->state = TASK_RUNNING; + goto out; + } + } + + expire = timeout + jiffies; + + init_timer(&timer); + timer.expires = expire; + timer.data = (unsigned long) current; + timer.function = process_timeout; + + add_timer(&timer); + schedule(); + del_timer_sync(&timer); + + timeout = expire - jiffies; + + out: + return timeout < 0 ? 0 : timeout; +} /* Thread ID - the internal kernel "pid" */ asmlinkage long sys_gettid(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/Makefile linux-2.5/mm/Makefile --- linux-2.5.1/mm/Makefile Tue Dec 11 17:49:40 2001 +++ linux-2.5/mm/Makefile Thu Dec 20 19:14:29 2001 @@ -14,8 +14,6 @@ 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 \ - shmem.o mempool.o - -obj-$(CONFIG_HIGHMEM) += highmem.o + shmem.o highmem.o mempool.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/bootmem.c linux-2.5/mm/bootmem.c --- linux-2.5.1/mm/bootmem.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/mm/bootmem.c Thu Dec 13 16:32:37 2001 @@ -155,6 +155,12 @@ if (align & (align-1)) BUG(); + offset = 0; + if (align && + (bdata->node_boot_start & (align - 1UL)) != 0) + offset = (align - (bdata->node_boot_start & (align - 1UL))); + offset >>= PAGE_SHIFT; + /* * We try to allocate bootmem pages above 'goal' * first, then we try to allocate lower pages. @@ -166,6 +172,7 @@ preferred = 0; preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT; + preferred += offset; areasize = (size+PAGE_SIZE-1)/PAGE_SIZE; incr = align >> PAGE_SHIFT ? : 1; @@ -185,7 +192,7 @@ fail_block:; } if (preferred) { - preferred = 0; + preferred = offset; goto restart_scan; } return NULL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/filemap.c linux-2.5/mm/filemap.c --- linux-2.5.1/mm/filemap.c Sun Dec 16 23:21:24 2001 +++ linux-2.5/mm/filemap.c Sun Jan 13 23:00:07 2002 @@ -576,8 +576,9 @@ * @mapping: address space structure to write * */ -void filemap_fdatasync(struct address_space * mapping) +int filemap_fdatasync(struct address_space * mapping) { + int ret = 0; int (*writepage)(struct page *) = mapping->a_ops->writepage; spin_lock(&pagecache_lock); @@ -597,8 +598,11 @@ lock_page(page); if (PageDirty(page)) { + int err; ClearPageDirty(page); - writepage(page); + err = writepage(page); + if (err && !ret) + ret = err; } else UnlockPage(page); @@ -606,6 +610,7 @@ spin_lock(&pagecache_lock); } spin_unlock(&pagecache_lock); + return ret; } /** @@ -615,8 +620,10 @@ * @mapping: address space structure to wait for * */ -void filemap_fdatawait(struct address_space * mapping) +int filemap_fdatawait(struct address_space * mapping) { + int ret = 0; + spin_lock(&pagecache_lock); while (!list_empty(&mapping->locked_pages)) { @@ -632,11 +639,14 @@ spin_unlock(&pagecache_lock); ___wait_on_page(page); + if (PageError(page)) + ret = -EIO; page_cache_release(page); spin_lock(&pagecache_lock); } spin_unlock(&pagecache_lock); + return ret; } /* @@ -1132,9 +1142,9 @@ static inline int get_max_readahead(struct inode * inode) { - if (!inode->i_dev || !max_readahead[MAJOR(inode->i_dev)]) + if (kdev_none(inode->i_dev) || !max_readahead[major(inode->i_dev)]) return MAX_READAHEAD; - return max_readahead[MAJOR(inode->i_dev)][MINOR(inode->i_dev)]; + return max_readahead[major(inode->i_dev)][minor(inode->i_dev)]; } static void generic_file_readahead(int reada_ok, @@ -1513,12 +1523,14 @@ goto out_free; /* - * Flush to disk exlusively the _data_, metadata must remains + * Flush to disk exclusively the _data_, metadata must remain * completly asynchronous or performance will go to /dev/null. */ - filemap_fdatasync(mapping); - retval = fsync_inode_data_buffers(inode); - filemap_fdatawait(mapping); + retval = filemap_fdatasync(mapping); + if (retval == 0) + retval = fsync_inode_data_buffers(inode); + if (retval == 0) + retval = filemap_fdatawait(mapping); if (retval < 0) goto out_free; @@ -1570,7 +1582,12 @@ size = count; kaddr = kmap(page); +// Barf. Make this alias to __copy_to_user() on archs with no prefetch. +#if defined(CONFIG_MPENTIUMIII) || defined (CONFIG_MK7) + left = __copy_to_user_prefetch(desc->buf, kaddr + offset, size); +#else left = __copy_to_user(desc->buf, kaddr + offset, size); +#endif kunmap(page); if (left) { @@ -2135,26 +2152,45 @@ * The msync() system call. */ +/* + * MS_SYNC syncs the entire file - including mappings. + * + * MS_ASYNC initiates writeout of just the dirty mapped data. + * This provides no guarantee of file integrity - things like indirect + * blocks may not have started writeout. MS_ASYNC is primarily useful + * where the application knows that it has finished with the data and + * wishes to intelligently schedule its own I/O traffic. + */ static int msync_interval(struct vm_area_struct * vma, unsigned long start, unsigned long end, int flags) { + int ret = 0; struct file * file = vma->vm_file; + if (file && (vma->vm_flags & VM_SHARED)) { - int error; - error = filemap_sync(vma, start, end-start, flags); + ret = filemap_sync(vma, start, end-start, flags); - if (!error && (flags & MS_SYNC)) { + if (!ret && (flags & (MS_SYNC|MS_ASYNC))) { struct inode * inode = file->f_dentry->d_inode; + down(&inode->i_sem); - filemap_fdatasync(inode->i_mapping); - if (file->f_op && file->f_op->fsync) - error = file->f_op->fsync(file, file->f_dentry, 1); - filemap_fdatawait(inode->i_mapping); + ret = filemap_fdatasync(inode->i_mapping); + if (flags & MS_SYNC) { + int err; + + if (file->f_op && file->f_op->fsync) { + err = file->f_op->fsync(file, file->f_dentry, 1); + if (err && !ret) + ret = err; + } + err = filemap_fdatawait(inode->i_mapping); + if (err && !ret) + ret = err; + } up(&inode->i_sem); } - return error; } - return 0; + return ret; } asmlinkage long sys_msync(unsigned long start, size_t len, int flags) @@ -2998,7 +3034,7 @@ kaddr = kmap(page); status = mapping->a_ops->prepare_write(file, page, offset, offset+bytes); if (status) - goto unlock; + goto sync_failure; page_fault = __copy_from_user(kaddr+offset, buf, bytes); flush_dcache_page(page); status = mapping->a_ops->commit_write(file, page, offset, offset+bytes); @@ -3023,6 +3059,7 @@ if (status < 0) break; } while (count); +done: *ppos = pos; if (cached_page) @@ -3044,6 +3081,18 @@ fail_write: status = -EFAULT; goto unlock; + +sync_failure: + /* + * If blocksize < pagesize, prepare_write() may have instantiated a + * few blocks outside i_size. Trim these off again. + */ + kunmap(page); + UnlockPage(page); + page_cache_release(page); + if (pos + bytes > inode->i_size) + vmtruncate(inode, inode->i_size); + goto done; o_direct: written = generic_file_direct_IO(WRITE, file, (char *) buf, count, pos); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/highmem.c linux-2.5/mm/highmem.c --- linux-2.5.1/mm/highmem.c Sun Dec 16 20:20:21 2001 +++ linux-2.5/mm/highmem.c Mon Jan 14 23:52:46 2002 @@ -19,6 +19,21 @@ #include <linux/mm.h> #include <linux/pagemap.h> #include <linux/mempool.h> +#include <linux/blkdev.h> + +static mempool_t *page_pool, *isa_page_pool; + +static void *page_pool_alloc(int gfp_mask, void *data) +{ + int gfp = gfp_mask | (int) data; + + return alloc_page(gfp); +} + +static void page_pool_free(void *page, void *data) +{ + __free_page(page); +} /* * Virtual_count is not a pure "count". @@ -28,9 +43,10 @@ * since the last TLB flush - so we can't use it. * n means that there are (n-1) current users of it. */ +#ifdef CONFIG_HIGHMEM static int pkmap_count[LAST_PKMAP]; static unsigned int last_pkmap_nr; -static spinlock_t kmap_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t kmap_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; pte_t * pkmap_page_table; @@ -185,19 +201,6 @@ } #define POOL_SIZE 64 -#define ISA_POOL_SIZE 16 - -static mempool_t *page_pool, *isa_page_pool; - -static void *page_pool_alloc(int gfp_mask, void *data) -{ - return alloc_page(gfp_mask); -} - -static void page_pool_free(void *page, void *data) -{ - __free_page(page); -} static __init int init_emergency_pool(void) { @@ -211,11 +214,37 @@ page_pool = mempool_create(POOL_SIZE, page_pool_alloc, page_pool_free, NULL); if (!page_pool) BUG(); - printk("highmem bounce pool size: %d pages and bhs.\n", POOL_SIZE); + printk("highmem bounce pool size: %d pages\n", POOL_SIZE); return 0; } +__initcall(init_emergency_pool); + +/* + * highmem version, map in to vec + */ +static inline void bounce_copy_vec(struct bio_vec *to, unsigned char *vfrom) +{ + unsigned long flags; + unsigned char *vto; + + local_irq_save(flags); + vto = kmap_atomic(to->bv_page, KM_BOUNCE_READ); + memcpy(vto + to->bv_offset, vfrom, to->bv_len); + kunmap_atomic(vto, KM_BOUNCE_READ); + local_irq_restore(flags); +} + +#else /* CONFIG_HIGHMEM */ + +#define bounce_copy_vec(to, vfrom) \ + memcpy(page_address((to)->bv_page) + (to)->bv_offset, vfrom, (to)->bv_len) + +#endif + +#define ISA_POOL_SIZE 16 + /* * gets called "every" time someone init's a queue with BLK_BOUNCE_ISA * as the max address, so check if the pool has already been created. @@ -225,7 +254,7 @@ if (isa_page_pool) return 0; - isa_page_pool = mempool_create(ISA_POOL_SIZE, page_pool_alloc, page_pool_free, NULL); + isa_page_pool = mempool_create(ISA_POOL_SIZE, page_pool_alloc, page_pool_free, (void *) __GFP_DMA); if (!isa_page_pool) BUG(); @@ -233,8 +262,6 @@ return 0; } -__initcall(init_emergency_pool); - /* * Simple bounce buffer support for highmem pages. Depending on the * queue gfp mask set, *to may or may not be a highmem page. kmap it @@ -242,13 +269,12 @@ */ static inline void copy_to_high_bio_irq(struct bio *to, struct bio *from) { - unsigned char *vto, *vfrom; - unsigned long flags; + unsigned char *vfrom; struct bio_vec *tovec, *fromvec; int i; __bio_for_each_segment(tovec, to, i, 0) { - fromvec = &from->bi_io_vec[i]; + fromvec = from->bi_io_vec + i; /* * not bounced @@ -258,11 +284,7 @@ vfrom = page_address(fromvec->bv_page) + fromvec->bv_offset; - local_irq_save(flags); - vto = kmap_atomic(tovec->bv_page, KM_BOUNCE_READ); - memcpy(vto + tovec->bv_offset, vfrom, tovec->bv_len); - kunmap_atomic(vto, KM_BOUNCE_READ); - local_irq_restore(flags); + bounce_copy_vec(tovec, vfrom); } } @@ -281,7 +303,7 @@ * free up bounce indirect pages used */ __bio_for_each_segment(bvec, bio, i, 0) { - org_vec = &bio_orig->bi_io_vec[i]; + org_vec = bio_orig->bi_io_vec + i; if (bvec->bv_page == org_vec->bv_page) continue; @@ -336,10 +358,19 @@ BUG_ON((*bio_orig)->bi_idx); + /* + * for non-isa bounce case, just check if the bounce pfn is equal + * to or bigger than the highest pfn in the system -- in that case, + * don't waste time iterating over bio segments + */ if (!(gfp & GFP_DMA)) { + if (pfn >= blk_max_pfn) + return; + bio_gfp = GFP_NOHIGHIO; pool = page_pool; } else { + BUG_ON(!isa_page_pool); bio_gfp = GFP_NOIO; pool = isa_page_pool; } @@ -359,7 +390,7 @@ if (!bio) bio = bio_alloc(bio_gfp, (*bio_orig)->bi_vcnt); - to = &bio->bi_io_vec[i]; + to = bio->bi_io_vec + i; to->bv_page = mempool_alloc(pool, gfp); to->bv_len = from->bv_len; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/memory.c linux-2.5/mm/memory.c --- linux-2.5.1/mm/memory.c Wed Dec 12 17:14:21 2001 +++ linux-2.5/mm/memory.c Thu Dec 13 22:09:30 2001 @@ -397,17 +397,16 @@ spin_unlock(&mm->page_table_lock); } - /* * Do a quick page-table lookup for a single page. */ -static struct page * follow_page(unsigned long address, int write) +static struct page * follow_page(struct mm_struct *mm, unsigned long address, int write) { pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte; - pgd = pgd_offset(current->mm, address); + pgd = pgd_offset(mm, address); if (pgd_none(*pgd) || pgd_bad(*pgd)) goto out; @@ -443,21 +442,74 @@ return page; } +int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, + int len, int write, int force, struct page **pages, struct vm_area_struct **vmas) +{ + int i = 0; + + do { + struct vm_area_struct * vma; + + vma = find_extend_vma(mm, start); + + if ( !vma || + (!force && + ((write && (!(vma->vm_flags & VM_WRITE))) || + (!write && (!(vma->vm_flags & VM_READ))) ) )) { + if (i) return i; + return -EFAULT; + } + + spin_lock(&mm->page_table_lock); + do { + struct page *map; + while (!(map = follow_page(mm, start, write))) { + spin_unlock(&mm->page_table_lock); + switch (handle_mm_fault(mm, vma, start, write)) { + case 1: + tsk->min_flt++; + break; + case 2: + tsk->maj_flt++; + break; + case 0: + if (i) return i; + return -EFAULT; + default: + if (i) return i; + return -ENOMEM; + } + spin_lock(&mm->page_table_lock); + } + if (pages) { + pages[i] = get_page_map(map); + /* FIXME: call the correct function, + * depending on the type of the found page + */ + if (pages[i]) + page_cache_get(pages[i]); + } + if (vmas) + vmas[i] = vma; + i++; + start += PAGE_SIZE; + len--; + } while(len && start < vma->vm_end); + spin_unlock(&mm->page_table_lock); + } while(len); + return i; +} + /* * Force in an entire range of pages from the current process's user VA, * and pin them in physical memory. */ - #define dprintk(x...) + int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len) { - unsigned long ptr, end; - int err; + int pgcount, err; struct mm_struct * mm; - struct vm_area_struct * vma = 0; - struct page * map; - int i; - int datain = (rw == READ); /* Make sure the iobuf is not already mapped somewhere. */ if (iobuf->nr_pages) @@ -466,79 +518,37 @@ mm = current->mm; dprintk ("map_user_kiobuf: begin\n"); - ptr = va & PAGE_MASK; - end = (va + len + PAGE_SIZE - 1) & PAGE_MASK; - err = expand_kiobuf(iobuf, (end - ptr) >> PAGE_SHIFT); + pgcount = (va + len + PAGE_SIZE - 1)/PAGE_SIZE - va/PAGE_SIZE; + /* mapping 0 bytes is not permitted */ + if (!pgcount) BUG(); + err = expand_kiobuf(iobuf, pgcount); if (err) return err; - down_read(&mm->mmap_sem); - - err = -EFAULT; iobuf->locked = 0; - iobuf->offset = va & ~PAGE_MASK; + iobuf->offset = va & (PAGE_SIZE-1); iobuf->length = len; - i = 0; - - /* - * First of all, try to fault in all of the necessary pages - */ - while (ptr < end) { - if (!vma || ptr >= vma->vm_end) { - vma = find_vma(current->mm, ptr); - if (!vma) - goto out_unlock; - if (vma->vm_start > ptr) { - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto out_unlock; - if (expand_stack(vma, ptr)) - goto out_unlock; - } - if (((datain) && (!(vma->vm_flags & VM_WRITE))) || - (!(vma->vm_flags & VM_READ))) { - err = -EACCES; - goto out_unlock; - } - } - spin_lock(&mm->page_table_lock); - while (!(map = follow_page(ptr, datain))) { - int ret; - - spin_unlock(&mm->page_table_lock); - ret = handle_mm_fault(current->mm, vma, ptr, datain); - if (ret <= 0) { - if (!ret) - goto out_unlock; - else { - err = -ENOMEM; - goto out_unlock; - } - } - spin_lock(&mm->page_table_lock); - } - map = get_page_map(map); - if (map) { - flush_dcache_page(map); - page_cache_get(map); - } 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; - } - + /* Try to fault in all of the necessary pages */ + down_read(&mm->mmap_sem); + /* rw==READ means read from disk, write into memory area */ + err = get_user_pages(current, mm, va, pgcount, + (rw==READ), 0, iobuf->maplist, NULL); up_read(&mm->mmap_sem); + if (err < 0) { + unmap_kiobuf(iobuf); + dprintk ("map_user_kiobuf: end %d\n", err); + return err; + } + iobuf->nr_pages = err; + while (pgcount--) { + /* FIXME: flush superflous for rw==READ, + * probably wrong function for rw==WRITE + */ + flush_dcache_page(iobuf->maplist[pgcount]); + } dprintk ("map_user_kiobuf: end OK\n"); return 0; - - out_unlock: - up_read(&mm->mmap_sem); - unmap_kiobuf(iobuf); - dprintk ("map_user_kiobuf: end %d\n", err); - return err; } /* @@ -588,6 +598,9 @@ if (map) { if (iobuf->locked) UnlockPage(map); + /* FIXME: cache flush missing for rw==READ + * FIXME: call the correct reference counting function + */ page_cache_release(map); } } @@ -1022,16 +1035,10 @@ do_expand: limit = current->rlim[RLIMIT_FSIZE].rlim_cur; - if (limit != RLIM_INFINITY) { - if (inode->i_size >= limit) { - send_sig(SIGXFSZ, current, 0); - goto out; - } - if (offset > limit) { - send_sig(SIGXFSZ, current, 0); - offset = limit; - } - } + if (limit != RLIM_INFINITY && offset > limit) + goto out_sig; + if (offset > inode->i_sb->s_maxbytes) + goto out; inode->i_size = offset; out_truncate: @@ -1040,8 +1047,11 @@ inode->i_op->truncate(inode); unlock_kernel(); } -out: return 0; +out_sig: + send_sig(SIGXFSZ, current, 0); +out: + return -EFBIG; } /* @@ -1104,6 +1114,8 @@ ret = 2; } + mark_page_accessed(page); + lock_page(page); /* @@ -1174,6 +1186,7 @@ flush_page_to_ram(page); entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); lru_cache_add(page); + mark_page_accessed(page); } set_pte(page_table, entry); @@ -1225,7 +1238,7 @@ page_cache_release(new_page); return -1; } - copy_highpage(page, new_page); + copy_user_highpage(page, new_page, address); page_cache_release(new_page); lru_cache_add(page); new_page = page; @@ -1414,23 +1427,19 @@ return pte_offset(pmd, address); } -/* - * Simplistic page force-in.. - */ int make_pages_present(unsigned long addr, unsigned long end) { - int write; - struct mm_struct *mm = current->mm; + int ret, len, write; struct vm_area_struct * vma; - vma = find_vma(mm, addr); + vma = find_vma(current->mm, addr); write = (vma->vm_flags & VM_WRITE) != 0; if (addr >= end) BUG(); - do { - if (handle_mm_fault(mm, vma, addr, write) < 0) - return -1; - addr += PAGE_SIZE; - } while (addr < end); - return 0; + if (end > vma->vm_end) + BUG(); + len = (end+PAGE_SIZE-1)/PAGE_SIZE-addr/PAGE_SIZE; + ret = get_user_pages(current, current->mm, addr, + len, write, 0, NULL, NULL); + return ret == len ? 0 : -1; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/mempool.c linux-2.5/mm/mempool.c --- linux-2.5.1/mm/mempool.c Sun Dec 16 20:25:28 2001 +++ linux-2.5/mm/mempool.c Sun Dec 30 20:01:41 2001 @@ -8,6 +8,7 @@ * started by Ingo Molnar, Copyright (C) 2001 */ +#include <linux/mm.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/mempool.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/mprotect.c linux-2.5/mm/mprotect.c --- linux-2.5.1/mm/mprotect.c Mon Sep 17 22:30:23 2001 +++ linux-2.5/mm/mprotect.c Sun Dec 30 20:01:41 2001 @@ -3,6 +3,7 @@ * * (C) Copyright 1994 Linus Torvalds */ +#include <linux/mm.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/shm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/mremap.c linux-2.5/mm/mremap.c --- linux-2.5.1/mm/mremap.c Fri Sep 21 03:31:26 2001 +++ linux-2.5/mm/mremap.c Sun Dec 30 20:01:41 2001 @@ -4,6 +4,7 @@ * (C) Copyright 1996 Linus Torvalds */ +#include <linux/mm.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/shm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/oom_kill.c linux-2.5/mm/oom_kill.c --- linux-2.5.1/mm/oom_kill.c Sun Nov 4 01:05:25 2001 +++ linux-2.5/mm/oom_kill.c Mon Jan 14 23:49:29 2002 @@ -82,7 +82,7 @@ * Niced processes are most likely less important, so double * their badness points. */ - if (p->nice > 0) + if (p->__nice > 0) points *= 2; /* @@ -110,8 +110,7 @@ /* * Simple selection loop. We chose the process with the highest - * number of 'points'. We need the locks to make sure that the - * list of task structs doesn't change while we look the other way. + * number of 'points'. We expect the caller will lock the tasklist. * * (not docbooked, we don't want this one cluttering up the manual) */ @@ -121,7 +120,6 @@ struct task_struct *p = NULL; struct task_struct *chosen = NULL; - read_lock(&tasklist_lock); for_each_task(p) { if (p->pid) { int points = badness(p); @@ -131,7 +129,6 @@ } } } - read_unlock(&tasklist_lock); return chosen; } @@ -149,7 +146,7 @@ * all the memory it needs. That way it should be able to * exit() and clear out its resources quickly... */ - p->counter = 5 * HZ; + p->time_slice = 2 * MAX_TIMESLICE; p->flags |= PF_MEMALLOC | PF_MEMDIE; /* This process has hardware access, be more careful. */ @@ -170,14 +167,16 @@ */ static void oom_kill(void) { - struct task_struct *p = select_bad_process(), *q; + struct task_struct *p, *q; + + read_lock(&tasklist_lock); + p = select_bad_process(); /* Found nothing?!?! Either we hang forever, or we panic. */ if (p == NULL) panic("Out of memory and no killable processes...\n"); /* kill all processes that share the ->mm (i.e. all threads) */ - read_lock(&tasklist_lock); for_each_task(q) { if(q->mm == p->mm) oom_kill_task(q); } @@ -188,8 +187,7 @@ * killing itself before someone else gets the chance to ask * for more memory. */ - current->policy |= SCHED_YIELD; - schedule(); + yield(); return; } @@ -198,7 +196,7 @@ */ void out_of_memory(void) { - static unsigned long first, last, count; + static unsigned long first, last, count, lastkill; unsigned long now, since; /* @@ -235,8 +233,18 @@ return; /* + * If we just killed a process, wait a while + * to give that task a chance to exit. This + * avoids killing multiple processes needlessly. + */ + since = now - lastkill; + if (since < HZ*5) + return; + + /* * Ok, really out of memory. Kill something. */ + lastkill = now; oom_kill(); reset: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/page_alloc.c linux-2.5/mm/page_alloc.c --- linux-2.5.1/mm/page_alloc.c Tue Nov 20 00:35:40 2001 +++ linux-2.5/mm/page_alloc.c Thu Jan 10 22:41:07 2002 @@ -70,6 +70,12 @@ struct page *base; zone_t *zone; + /* Yes, think what happens when other parts of the kernel take + * a reference to a page in order to pin it for io. -ben + */ + if (PageLRU(page)) + lru_cache_del(page); + if (page->buffers) BUG(); if (page->mapping) @@ -394,9 +400,7 @@ return NULL; /* Yield for kswapd, and try again */ - current->policy |= SCHED_YIELD; - __set_current_state(TASK_RUNNING); - schedule(); + yield(); goto rebalance; } @@ -424,15 +428,6 @@ return (unsigned long) address; } return 0; -} - -void page_cache_release(struct page *page) -{ - if (!PageReserved(page) && put_page_testzero(page)) { - if (PageLRU(page)) - lru_cache_del(page); - __free_pages_ok(page, 0); - } } void __free_pages(struct page *page, unsigned int order) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/page_io.c linux-2.5/mm/page_io.c --- linux-2.5.1/mm/page_io.c Tue Nov 27 17:23:27 2001 +++ linux-2.5/mm/page_io.c Tue Jan 1 23:42:42 2002 @@ -38,7 +38,7 @@ unsigned long offset; sector_t zones[PAGE_SIZE/512]; int zones_used; - kdev_t dev = 0; + kdev_t dev = NODEV; int block_size; struct inode *swapf = 0; @@ -49,7 +49,7 @@ kstat.pswpout++; get_swaphandle_info(entry, &offset, &dev, &swapf); - if (dev) { + if (!kdev_none(dev)) { zones[0] = offset; zones_used = 1; block_size = PAGE_SIZE; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/shmem.c linux-2.5/mm/shmem.c --- linux-2.5.1/mm/shmem.c Wed Nov 21 17:57:57 2001 +++ linux-2.5/mm/shmem.c Thu Dec 13 16:32:37 2001 @@ -1193,7 +1193,7 @@ follow_link: shmem_follow_link, }; -static int shmem_parse_options(char *options, int *mode, unsigned long * blocks, unsigned long *inodes) +static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long * blocks, unsigned long *inodes) { char *this_char, *value, *rest; @@ -1205,7 +1205,7 @@ *value++ = 0; } else { printk(KERN_ERR - "shmem_parse_options: No value for option '%s'\n", + "tmpfs: No value for mount option '%s'\n", this_char); return 1; } @@ -1230,8 +1230,20 @@ *mode = simple_strtoul(value,&rest,8); if (*rest) goto bad_val; + } else if (!strcmp(this_char,"uid")) { + if (!uid) + continue; + *uid = simple_strtoul(value,&rest,0); + if (*rest) + goto bad_val; + } else if (!strcmp(this_char,"gid")) { + if (!gid) + continue; + *gid = simple_strtoul(value,&rest,0); + if (*rest) + goto bad_val; } else { - printk(KERN_ERR "shmem_parse_options: Bad option %s\n", + printk(KERN_ERR "tmpfs: Bad mount option %s\n", this_char); return 1; } @@ -1239,7 +1251,7 @@ return 0; bad_val: - printk(KERN_ERR "shmem_parse_options: Bad value '%s' for option '%s'\n", + printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'\n", value, this_char); return 1; @@ -1251,7 +1263,7 @@ unsigned long max_blocks = sbinfo->max_blocks; unsigned long max_inodes = sbinfo->max_inodes; - if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes)) + if (shmem_parse_options (data, NULL, NULL, NULL, &max_blocks, &max_inodes)) return -EINVAL; return shmem_set_size(sbinfo, max_blocks, max_inodes); } @@ -1268,6 +1280,8 @@ struct dentry * root; unsigned long blocks, inodes; int mode = S_IRWXUGO | S_ISVTX; + uid_t uid = current->fsuid; + gid_t gid = current->fsgid; struct shmem_sb_info *sbinfo = SHMEM_SB(sb); struct sysinfo si; @@ -1279,10 +1293,8 @@ blocks = inodes = si.totalram / 2; #ifdef CONFIG_TMPFS - if (shmem_parse_options (data, &mode, &blocks, &inodes)) { - printk(KERN_ERR "tmpfs invalid option\n"); + if (shmem_parse_options (data, &mode, &uid, &gid, &blocks, &inodes)) return NULL; - } #endif spin_lock_init (&sbinfo->stat_lock); @@ -1299,6 +1311,8 @@ if (!inode) return NULL; + inode->i_uid = uid; + inode->i_gid = gid; root = d_alloc_root(inode); if (!root) { iput(inode); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/slab.c linux-2.5/mm/slab.c --- linux-2.5.1/mm/slab.c Tue Nov 27 17:31:22 2001 +++ linux-2.5/mm/slab.c Sun Dec 30 20:01:41 2001 @@ -70,6 +70,8 @@ #include <linux/config.h> #include <linux/slab.h> +#include <linux/mm.h> +#include <linux/cache.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/compiler.h> @@ -1282,10 +1284,9 @@ }) #ifdef CONFIG_SMP -void* kmem_cache_alloc_batch(kmem_cache_t* cachep, int flags) +void* kmem_cache_alloc_batch(kmem_cache_t* cachep, cpucache_t* cc, int flags) { int batchcount = cachep->batchcount; - cpucache_t* cc = cc_data(cachep); spin_lock(&cachep->spinlock); while (batchcount--) { @@ -1334,7 +1335,7 @@ objp = cc_entry(cc)[--cc->avail]; } else { STATS_INC_ALLOCMISS(cachep); - objp = kmem_cache_alloc_batch(cachep,flags); + objp = kmem_cache_alloc_batch(cachep,cc,flags); if (!objp) goto alloc_new_slab_nolock; } @@ -1922,12 +1923,13 @@ #endif #ifdef CONFIG_SMP { + cpucache_t *cc = cc_data(cachep); unsigned int batchcount = cachep->batchcount; unsigned int limit; - if (cc_data(cachep)) - limit = cc_data(cachep)->limit; - else + if (cc) + limit = cc->limit; + else limit = 0; len += sprintf(page+len, " : %4u %4u", limit, batchcount); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/swapfile.c linux-2.5/mm/swapfile.c --- linux-2.5.1/mm/swapfile.c Fri Nov 30 21:33:44 2001 +++ linux-2.5/mm/swapfile.c Tue Jan 1 23:42:42 2002 @@ -5,6 +5,7 @@ * Swap reorganised 29.12.95, Stephen Tweedie */ +#include <linux/mm.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/kernel_stat.h> @@ -773,7 +774,7 @@ swap_list_unlock(); goto out_dput; } - if (p->swap_device) + if (!kdev_none(p->swap_device)) blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP); path_release(&nd); @@ -783,7 +784,7 @@ nd.dentry = p->swap_file; p->swap_vfsmnt = NULL; p->swap_file = NULL; - p->swap_device = 0; + p->swap_device = NODEV; p->max = 0; swap_map = p->swap_map; p->swap_map = NULL; @@ -825,7 +826,7 @@ } len += sprintf(buf + len, "%-39s %s\t%d\t%d\t%d\n", path, - ptr->swap_device ? "partition" : "file\t", + kdev_none(ptr->swap_device) ? "file\t" : "partition", ptr->pages << (PAGE_SHIFT - 10), usedswap << (PAGE_SHIFT - 10), ptr->prio); @@ -841,7 +842,7 @@ for (i = 0 ; i < nr_swapfiles ; i++, ptr++) { if (ptr->flags & SWP_USED) - if (ptr->swap_device == dev) + if (kdev_same(ptr->swap_device, dev)) return 1; } return 0; @@ -887,7 +888,7 @@ p->flags = SWP_USED; p->swap_file = NULL; p->swap_vfsmnt = NULL; - p->swap_device = 0; + p->swap_device = NODEV; p->swap_map = NULL; p->lowest_bit = 0; p->highest_bit = 0; @@ -913,26 +914,29 @@ if (S_ISBLK(swap_inode->i_mode)) { kdev_t dev = swap_inode->i_rdev; struct block_device_operations *bdops; + devfs_handle_t de; p->swap_device = dev; set_blocksize(dev, PAGE_SIZE); bd_acquire(swap_inode); bdev = swap_inode->i_bdev; - bdops = devfs_get_ops(devfs_get_handle_from_inode(swap_inode)); + de = devfs_get_handle_from_inode(swap_inode); + bdops = devfs_get_ops(de); /* Increments module use count */ if (bdops) bdev->bd_op = bdops; error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP); + devfs_put_ops(de);/*Decrement module use count now we're safe*/ if (error) goto bad_swap_2; set_blocksize(dev, PAGE_SIZE); error = -ENODEV; - if (!dev || (blk_size[MAJOR(dev)] && - !blk_size[MAJOR(dev)][MINOR(dev)])) + if (kdev_none(dev) || (blk_size[major(dev)] && + !blk_size[major(dev)][minor(dev)])) goto bad_swap; swapfilesize = 0; - if (blk_size[MAJOR(dev)]) - swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)] + if (blk_size[major(dev)]) + swapfilesize = blk_size[major(dev)][minor(dev)] >> (PAGE_SHIFT - 10); } else if (S_ISREG(swap_inode->i_mode)) swapfilesize = swap_inode->i_size >> PAGE_SHIFT; @@ -1088,7 +1092,7 @@ swap_map = p->swap_map; nd.mnt = p->swap_vfsmnt; nd.dentry = p->swap_file; - p->swap_device = 0; + p->swap_device = NODEV; p->swap_file = NULL; p->swap_vfsmnt = NULL; p->swap_map = NULL; @@ -1241,7 +1245,7 @@ return; } - if (p->swap_device) { + if (!kdev_none(p->swap_device)) { *dev = p->swap_device; } else if (p->swap_file) { *swapf = p->swap_file->d_inode; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/vmalloc.c linux-2.5/mm/vmalloc.c --- linux-2.5.1/mm/vmalloc.c Mon Sep 17 20:16:31 2001 +++ linux-2.5/mm/vmalloc.c Thu Jan 10 22:41:07 2002 @@ -6,6 +6,7 @@ * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000 */ +#include <linux/config.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/spinlock.h> @@ -163,6 +164,7 @@ ret = 0; } while (address && (address < end)); spin_unlock(&init_mm.page_table_lock); + flush_cache_all(); return ret; } @@ -273,6 +275,43 @@ if (count == 0) goto finished; *buf = *addr; + buf++; + addr++; + count--; + } while (--n > 0); + } +finished: + read_unlock(&vmlist_lock); + return buf - buf_start; +} + +long vwrite(char *buf, char *addr, unsigned long count) +{ + struct vm_struct *tmp; + char *vaddr, *buf_start = buf; + unsigned long n; + + /* Don't allow overflow */ + if ((unsigned long) addr + count < count) + count = -(unsigned long) addr; + + read_lock(&vmlist_lock); + for (tmp = vmlist; tmp; tmp = tmp->next) { + vaddr = (char *) tmp->addr; + if (addr >= vaddr + tmp->size - PAGE_SIZE) + continue; + while (addr < vaddr) { + if (count == 0) + goto finished; + buf++; + addr++; + count--; + } + n = vaddr + tmp->size - PAGE_SIZE - addr; + do { + if (count == 0) + goto finished; + *addr = *buf; buf++; addr++; count--; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/mm/vmscan.c linux-2.5/mm/vmscan.c --- linux-2.5.1/mm/vmscan.c Sun Nov 18 03:18:17 2001 +++ linux-2.5/mm/vmscan.c Tue Jan 8 01:17:10 2002 @@ -11,6 +11,7 @@ * Multiqueue VM started 5.8.00, Rik van Riel. */ +#include <linux/mm.h> #include <linux/slab.h> #include <linux/kernel_stat.h> #include <linux/swap.h> @@ -338,7 +339,7 @@ { struct list_head * entry; int max_scan = nr_inactive_pages / priority; - int max_mapped = nr_pages << (9 - priority); + int max_mapped = min((nr_pages << (10 - priority)), max_scan / 10); spin_lock(&pagemap_lru_lock); while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) { @@ -537,7 +538,7 @@ spin_lock(&pagemap_lru_lock); entry = active_list.prev; - while (nr_pages-- && entry != &active_list) { + while (nr_pages && entry != &active_list) { struct page * page; page = list_entry(entry, struct page, lru); @@ -548,6 +549,8 @@ continue; } + nr_pages--; + del_page_from_active_list(page); add_page_to_inactive_list(page); SetPageReferenced(page); @@ -588,6 +591,7 @@ int priority = DEF_PRIORITY; int nr_pages = SWAP_CLUSTER_MAX; + gfp_mask = pf_gfp_mask(gfp_mask); do { nr_pages = shrink_caches(classzone, priority, gfp_mask, nr_pages); if (nr_pages <= 0) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/802/fddi.c linux-2.5/net/802/fddi.c --- linux-2.5.1/net/802/fddi.c Wed Nov 29 05:53:45 2000 +++ linux-2.5/net/802/fddi.c Sun Dec 30 21:17:30 2001 @@ -27,7 +27,6 @@ */ #include <linux/config.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/types.h> #include <linux/kernel.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/802/hippi.c linux-2.5/net/802/hippi.c --- linux-2.5.1/net/802/hippi.c Thu Jun 21 04:00:55 2001 +++ linux-2.5/net/802/hippi.c Sun Dec 30 21:17:30 2001 @@ -36,7 +36,6 @@ #include <net/sock.h> #include <asm/uaccess.h> #include <asm/checksum.h> -#include <asm/segment.h> #include <asm/system.h> /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/8021q/vlan.c linux-2.5/net/8021q/vlan.c --- linux-2.5.1/net/8021q/vlan.c Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/8021q/vlan.c Thu Dec 13 16:32:37 2001 @@ -1,11 +1,10 @@ /* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * + * INET 802.1Q VLAN * Ethernet-type device handling. * - * Authors: Ben Greear <greearb@candelatech.com>, <greearb@agcs.com> + * Authors: Ben Greear <greearb@candelatech.com> + * Please send support related email to: vlan@scry.wanfear.com + * VLAN Home Page: http://www.candelatech.com/~greear/vlan.html * * Fixes: * Fix for packet capture - Nick Eggleston <nick@dccinc.com>; @@ -42,7 +41,7 @@ static char vlan_fullname[] = "802.1Q VLAN Support"; static unsigned int vlan_version = 1; -static unsigned int vlan_release = 5; +static unsigned int vlan_release = 6; static char vlan_copyright[] = " Ben Greear <greearb@candelatech.com>"; static int vlan_device_event(struct notifier_block *, unsigned long, void *); @@ -106,6 +105,23 @@ } /* + * Cleanup of groups before exit + */ + +static void vlan_group_cleanup(void) +{ + struct vlan_group *grp = NULL; + struct vlan_group *nextgroup; + + for (grp = p802_1Q_vlan_list; (grp != NULL);) { + nextgroup = grp->next; + kfree(grp); + grp = nextgroup; + } + p802_1Q_vlan_list = NULL; +} + +/* * Module 'remove' entry point. * o delete /proc/net/router directory and static entries. */ @@ -116,7 +132,7 @@ dev_remove_pack(&vlan_packet_type); vlan_proc_cleanup(); - + vlan_group_cleanup(); vlan_ioctl_hook = NULL; } @@ -328,6 +344,7 @@ /* set up method calls */ new_dev->init = vlan_dev_init; new_dev->destructor = vlan_dev_destruct; + new_dev->features |= NETIF_F_DYNALLOC ; /* new_dev->ifindex = 0; it will be set when added to * the global list. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/8021q/vlan_dev.c linux-2.5/net/8021q/vlan_dev.c --- linux-2.5.1/net/8021q/vlan_dev.c Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/8021q/vlan_dev.c Thu Dec 13 16:32:37 2001 @@ -1,11 +1,10 @@ /* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * + * INET 802.1Q VLAN * Ethernet-type device handling. * - * Authors: Ben Greear <greearb@candelatech.com>, <greearb@agcs.com> + * Authors: Ben Greear <greearb@candelatech.com> + * Please send support related email to: vlan@scry.wanfear.com + * VLAN Home Page: http://www.candelatech.com/~greear/vlan.html * * Fixes: Mar 22 2001: Martin Bokaemper <mbokaemper@unispherenetworks.com> * - reset skb->pkt_type on incoming packets when MAC was changed @@ -512,10 +511,6 @@ VLAN_FMEM_DBG("dev->priv free, addr: %p\n", dev->priv); dev->priv = NULL; } - - kfree(dev); - VLAN_FMEM_DBG("net_device free, addr: %p\n", dev); - dev = NULL; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/8021q/vlanproc.c linux-2.5/net/8021q/vlanproc.c --- linux-2.5.1/net/8021q/vlanproc.c Tue Nov 13 17:19:41 2001 +++ linux-2.5/net/8021q/vlanproc.c Sun Dec 30 21:17:30 2001 @@ -25,7 +25,6 @@ #include <linux/mm.h> /* verify_area(), etc. */ #include <linux/string.h> /* inline mem*, str* functions */ #include <linux/init.h> /* __initfunc 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> @@ -116,7 +115,7 @@ * Clean up /proc/net/vlan entries */ -void __exit vlan_proc_cleanup(void) +void vlan_proc_cleanup(void) { if (proc_vlan_conf) remove_proc_entry(name_conf, proc_vlan_dir); @@ -462,7 +461,7 @@ return 0; } -void __exit vlan_proc_cleanup(void) +void vlan_proc_cleanup(void) { return; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/Config.in linux-2.5/net/Config.in --- linux-2.5.1/net/Config.in Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/Config.in Mon Dec 31 18:21:26 2001 @@ -7,11 +7,9 @@ if [ "$CONFIG_PACKET" != "n" ]; then bool ' Packet socket: mmapped IO' CONFIG_PACKET_MMAP fi -bool 'Kernel/User netlink socket' CONFIG_NETLINK -if [ "$CONFIG_NETLINK" = "y" ]; then - bool ' Routing messages' CONFIG_RTNETLINK - tristate ' Netlink device emulation' CONFIG_NETLINK_DEV -fi + +tristate 'Netlink device emulation' CONFIG_NETLINK_DEV + bool 'Network packet filtering (replaces ipchains)' CONFIG_NETFILTER if [ "$CONFIG_NETFILTER" = "y" ]; then bool ' Network packet filtering debugging' CONFIG_NETFILTER_DEBUG @@ -61,7 +59,7 @@ if [ "$CONFIG_DECNET" != "n" ]; then source net/decnet/Config.in fi -tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE +dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25 tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/Makefile linux-2.5/net/Makefile --- linux-2.5.1/net/Makefile Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/Makefile Thu Dec 13 16:32:37 2001 @@ -14,7 +14,7 @@ subdir-m := ipv4 # hum? -subdir-$(CONFIG_NET) += 802 sched +subdir-$(CONFIG_NET) += 802 sched netlink subdir-$(CONFIG_INET) += ipv4 subdir-$(CONFIG_NETFILTER) += ipv4/netfilter subdir-$(CONFIG_UNIX) += unix @@ -27,7 +27,6 @@ endif subdir-$(CONFIG_KHTTPD) += khttpd -subdir-$(CONFIG_NETLINK) += netlink subdir-$(CONFIG_PACKET) += packet subdir-$(CONFIG_NET_SCHED) += sched subdir-$(CONFIG_BRIDGE) += bridge diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/README linux-2.5/net/README --- linux-2.5.1/net/README Tue Jun 12 02:15:27 2001 +++ linux-2.5/net/README Thu Dec 13 16:32:37 2001 @@ -23,4 +23,4 @@ unix alan@lxorguk.ukuu.org.uk x25 g4klx@g4klx.demon.co.uk bluetooth maxk@qualcomm.com - +8021q greearb@candelatech.com, vlan@scry.wanfear.com diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/atm/resources.c linux-2.5/net/atm/resources.c --- linux-2.5.1/net/atm/resources.c Fri Nov 9 22:11:15 2001 +++ linux-2.5/net/atm/resources.c Sun Dec 30 21:17:30 2001 @@ -11,7 +11,6 @@ #include <linux/module.h> #include <linux/bitops.h> #include <net/sock.h> /* for struct sock */ -#include <asm/segment.h> /* for get_fs_long and put_fs_long */ #include "common.h" #include "resources.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/bridge/br.c linux-2.5/net/bridge/br.c --- linux-2.5.1/net/bridge/br.c Wed Oct 17 21:16:39 2001 +++ linux-2.5/net/bridge/br.c Mon Dec 31 18:21:26 2001 @@ -43,9 +43,7 @@ printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n"); br_handle_frame_hook = br_handle_frame; -#ifdef CONFIG_INET br_ioctl_hook = br_ioctl_deviceless_stub; -#endif #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) br_fdb_get_hook = br_fdb_get; br_fdb_put_hook = br_fdb_put; @@ -62,9 +60,7 @@ static void __br_clear_ioctl_hook(void) { -#ifdef CONFIG_INET br_ioctl_hook = NULL; -#endif } static void __exit br_deinit(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/bridge/br_device.c linux-2.5/net/bridge/br_device.c --- linux-2.5.1/net/bridge/br_device.c Wed Aug 15 08:54:30 2001 +++ linux-2.5/net/bridge/br_device.c Mon Dec 31 18:21:26 2001 @@ -71,7 +71,7 @@ return 0; } -static int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) +int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_bridge *br; int ret; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/bridge/br_fdb.c linux-2.5/net/bridge/br_fdb.c --- linux-2.5.1/net/bridge/br_fdb.c Thu Nov 9 23:57:53 2000 +++ linux-2.5/net/bridge/br_fdb.c Thu Jan 10 20:29:36 2002 @@ -292,7 +292,8 @@ write_lock_bh(&br->hash_lock); fdb = br->hash[hash]; while (fdb != NULL) { - if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) { + if (!fdb->is_local && + !memcmp(fdb->addr.addr, addr, ETH_ALEN)) { __fdb_possibly_replace(fdb, source, is_local); write_unlock_bh(&br->hash_lock); return; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/bridge/br_if.c linux-2.5/net/bridge/br_if.c --- linux-2.5.1/net/bridge/br_if.c Thu Nov 9 23:57:53 2000 +++ linux-2.5/net/bridge/br_if.c Mon Dec 31 18:21:26 2001 @@ -5,7 +5,7 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_if.c,v 1.5 2000/11/08 05:16:40 davem Exp $ + * $Id: br_if.c,v 1.6 2001/11/24 17:51:03 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -226,6 +226,9 @@ if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER) return -EINVAL; + if (dev->hard_start_xmit == br_dev_xmit) + return -ELOOP; + dev_hold(dev); write_lock_bh(&br->lock); if ((p = new_nbp(br, dev)) == NULL) { @@ -261,8 +264,6 @@ { struct net_bridge *br; int i; - - i = 0; br = bridge_list; for (i=0;i<num;i++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/bridge/br_input.c linux-2.5/net/bridge/br_input.c --- linux-2.5.1/net/bridge/br_input.c Wed Aug 15 08:54:39 2001 +++ linux-2.5/net/bridge/br_input.c Mon Dec 31 18:21:26 2001 @@ -46,7 +46,7 @@ br_pass_frame_up_finish); } -static void __br_handle_frame(struct sk_buff *skb) +static int br_handle_frame_finish(struct sk_buff *skb) { struct net_bridge *br; unsigned char *dest; @@ -57,103 +57,112 @@ dest = skb->mac.ethernet->h_dest; p = skb->dev->br_port; - br = p->br; - passedup = 0; + if (p == NULL) + goto err_nolock; - if (!(br->dev.flags & IFF_UP) || - p->state == BR_STATE_DISABLED) - goto freeandout; + br = p->br; + read_lock(&br->lock); + if (skb->dev->br_port == NULL) + goto err; + passedup = 0; if (br->dev.flags & IFF_PROMISC) { struct sk_buff *skb2; skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) { + if (skb2 != NULL) { passedup = 1; br_pass_frame_up(br, skb2); } } - if (skb->mac.ethernet->h_source[0] & 1) - goto freeandout; - - if (!passedup && - (dest[0] & 1) && - (br->dev.flags & IFF_ALLMULTI || br->dev.mc_list != NULL)) { - struct sk_buff *skb2; - - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) { - passedup = 1; - br_pass_frame_up(br, skb2); - } - } - - if (br->stp_enabled && - !memcmp(dest, bridge_ula, 5) && - !(dest[5] & 0xF0)) - goto handle_special_frame; - - if (p->state == BR_STATE_LEARNING || - p->state == BR_STATE_FORWARDING) - br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0); - - if (p->state != BR_STATE_FORWARDING) - goto freeandout; - if (dest[0] & 1) { - br_flood_forward(br, skb, 1); + br_flood_forward(br, skb, !passedup); if (!passedup) br_pass_frame_up(br, skb); - else - kfree_skb(skb); - return; + goto out; } dst = br_fdb_get(br, dest); - if (dst != NULL && dst->is_local) { if (!passedup) br_pass_frame_up(br, skb); else kfree_skb(skb); br_fdb_put(dst); - return; + goto out; } if (dst != NULL) { br_forward(dst->dst, skb); br_fdb_put(dst); - return; + goto out; } br_flood_forward(br, skb, 0); - return; - handle_special_frame: - if (!dest[5]) { - br_stp_handle_bpdu(skb); - return; - } +out: + read_unlock(&br->lock); + return 0; - freeandout: +err: + read_unlock(&br->lock); +err_nolock: kfree_skb(skb); + return 0; } -static int br_handle_frame_finish(struct sk_buff *skb) +void br_handle_frame(struct sk_buff *skb) { struct net_bridge *br; + unsigned char *dest; + struct net_bridge_port *p; - br = skb->dev->br_port->br; + dest = skb->mac.ethernet->h_dest; + + p = skb->dev->br_port; + if (p == NULL) + goto err_nolock; + + br = p->br; read_lock(&br->lock); - __br_handle_frame(skb); - read_unlock(&br->lock); + if (skb->dev->br_port == NULL) + goto err; - return 0; -} + if (!(br->dev.flags & IFF_UP) || + p->state == BR_STATE_DISABLED) + goto err; -void br_handle_frame(struct sk_buff *skb) -{ - NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, + if (skb->mac.ethernet->h_source[0] & 1) + goto err; + + if (p->state == BR_STATE_LEARNING || + p->state == BR_STATE_FORWARDING) + br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0); + + if (br->stp_enabled && + !memcmp(dest, bridge_ula, 5) && + !(dest[5] & 0xF0)) + goto handle_special_frame; + + if (p->state == BR_STATE_FORWARDING) { + NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, br_handle_frame_finish); + read_unlock(&br->lock); + return; + } + +err: + read_unlock(&br->lock); +err_nolock: + kfree_skb(skb); + return; + +handle_special_frame: + if (!dest[5]) { + br_stp_handle_bpdu(skb); + return; + } + + kfree_skb(skb); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/bridge/br_private.h linux-2.5/net/bridge/br_private.h --- linux-2.5.1/net/bridge/br_private.h Tue Jun 12 02:15:27 2001 +++ linux-2.5/net/bridge/br_private.h Mon Dec 31 18:21:26 2001 @@ -120,6 +120,7 @@ extern void br_inc_use_count(void); /* br_device.c */ +extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev); extern void br_dev_setup(struct net_device *dev); /* br_fdb.c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/core/datagram.c linux-2.5/net/core/datagram.c --- linux-2.5.1/net/core/datagram.c Thu Apr 12 19:11:39 2001 +++ linux-2.5/net/core/datagram.c Thu Dec 13 16:32:37 2001 @@ -30,21 +30,18 @@ #include <asm/system.h> #include <linux/mm.h> #include <linux/interrupt.h> -#include <linux/in.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/inet.h> #include <linux/netdevice.h> +#include <linux/rtnetlink.h> #include <linux/poll.h> #include <linux/highmem.h> -#include <net/ip.h> #include <net/protocol.h> -#include <net/route.h> -#include <net/tcp.h> -#include <net/udp.h> #include <linux/skbuff.h> #include <net/sock.h> +#include <net/checksum.h> /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/core/neighbour.c linux-2.5/net/core/neighbour.c --- linux-2.5.1/net/core/neighbour.c Mon Oct 1 16:19:56 2001 +++ linux-2.5/net/core/neighbour.c Thu Dec 13 16:32:37 2001 @@ -1172,9 +1172,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK - - int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { struct ndmsg *ndm = NLMSG_DATA(nlh); @@ -1438,12 +1435,7 @@ netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC); } - - -#endif - - -#endif +#endif /* CONFIG_ARPD */ #ifdef CONFIG_SYSCTL diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/core/rtnetlink.c linux-2.5/net/core/rtnetlink.c --- linux-2.5.1/net/core/rtnetlink.c Sun Aug 5 20:12:41 2001 +++ linux-2.5/net/core/rtnetlink.c Thu Dec 13 16:32:37 2001 @@ -77,15 +77,10 @@ return 0; } -#ifdef CONFIG_RTNETLINK struct sock *rtnl; struct rtnetlink_link * rtnetlink_links[NPROTO]; -#define _S 1 /* superuser privileges required */ -#define _X 2 /* exclusive access to tables required */ -#define _G 4 /* GET request */ - static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] = { NLMSG_LENGTH(sizeof(struct ifinfomsg)), @@ -533,7 +528,3 @@ rtnetlink_links[PF_UNSPEC] = link_rtnetlink_table; rtnetlink_links[PF_PACKET] = link_rtnetlink_table; } - - - -#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/core/scm.c linux-2.5/net/core/scm.c --- linux-2.5.1/net/core/scm.c Thu Nov 9 23:57:53 2000 +++ linux-2.5/net/core/scm.c Thu Dec 13 16:32:37 2001 @@ -26,11 +26,7 @@ #include <asm/system.h> #include <asm/uaccess.h> -#include <linux/inet.h> -#include <net/ip.h> #include <net/protocol.h> -#include <net/tcp.h> -#include <net/udp.h> #include <linux/skbuff.h> #include <net/sock.h> #include <net/scm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/core/skbuff.c linux-2.5/net/core/skbuff.c --- linux-2.5.1/net/core/skbuff.c Tue Aug 7 15:30:50 2001 +++ linux-2.5/net/core/skbuff.c Thu Dec 13 16:32:37 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.89 2001/08/06 13:25:02 davem Exp $ + * Version: $Id: skbuff.c,v 1.90 2001/11/07 05:56:19 davem Exp $ * * Fixes: * Alan Cox : Fixed the worst of the load balancer bugs. @@ -49,15 +49,14 @@ #include <linux/string.h> #include <linux/skbuff.h> #include <linux/cache.h> +#include <linux/rtnetlink.h> #include <linux/init.h> #include <linux/highmem.h> -#include <net/ip.h> #include <net/protocol.h> #include <net/dst.h> -#include <net/tcp.h> -#include <net/udp.h> #include <net/sock.h> +#include <net/checksum.h> #include <asm/uaccess.h> #include <asm/system.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/core/sock.c linux-2.5/net/core/sock.c --- linux-2.5.1/net/core/sock.c Sat Jul 28 19:12:38 2001 +++ linux-2.5/net/core/sock.c Thu Dec 13 16:32:37 2001 @@ -7,7 +7,7 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.112 2001/07/27 09:54:48 davem Exp $ + * Version: $Id: sock.c,v 1.116 2001/11/08 04:20:06 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -113,24 +113,20 @@ #include <asm/uaccess.h> #include <asm/system.h> -#include <linux/inet.h> #include <linux/netdevice.h> -#include <net/ip.h> #include <net/protocol.h> -#include <net/arp.h> -#include <net/route.h> -#include <net/tcp.h> -#include <net/udp.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <net/raw.h> -#include <net/icmp.h> #include <linux/ipsec.h> #ifdef CONFIG_FILTER #include <linux/filter.h> #endif +#ifdef CONFIG_INET +#include <net/tcp.h> +#endif + /* Run time adjustable parameters. */ __u32 sysctl_wmem_max = SK_WMEM_MAX; __u32 sysctl_rmem_max = SK_RMEM_MAX; @@ -759,48 +755,62 @@ * Generic send/receive buffer handlers */ -struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, - int noblock, int *errcode) +struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len, + unsigned long data_len, int noblock, int *errcode) { - int err; struct sk_buff *skb; long timeo; + int err; timeo = sock_sndtimeo(sk, noblock); - while (1) { - unsigned long try_size = size; - err = sock_error(sk); if (err != 0) goto failure; - /* - * We should send SIGPIPE in these cases according to - * 1003.1g draft 6.4. If we (the user) did a shutdown() - * call however we should not. - * - * Note: This routine isnt just used for datagrams and - * anyway some datagram protocols have a notion of - * close down. - */ - err = -EPIPE; - if (sk->shutdown&SEND_SHUTDOWN) + if (sk->shutdown & SEND_SHUTDOWN) goto failure; if (atomic_read(&sk->wmem_alloc) < sk->sndbuf) { - skb = alloc_skb(try_size, sk->allocation); - if (skb) + skb = alloc_skb(header_len, sk->allocation); + if (skb) { + int npages; + int i; + + /* No pages, we're done... */ + if (!data_len) + break; + + npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + skb->truesize += data_len; + skb_shinfo(skb)->nr_frags = npages; + for (i = 0; i < npages; i++) { + struct page *page; + skb_frag_t *frag; + + page = alloc_pages(sk->allocation, 0); + if (!page) { + err = -ENOBUFS; + kfree_skb(skb); + goto failure; + } + + frag = &skb_shinfo(skb)->frags[i]; + frag->page = page; + frag->page_offset = 0; + frag->size = (data_len >= PAGE_SIZE ? + PAGE_SIZE : + data_len); + data_len -= PAGE_SIZE; + } + + /* Full success... */ break; + } err = -ENOBUFS; goto failure; } - - /* - * This means we have too many buffers for this socket already. - */ - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); set_bit(SOCK_NOSPACE, &sk->socket->flags); err = -EAGAIN; @@ -819,6 +829,12 @@ failure: *errcode = err; return NULL; +} + +struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, + int noblock, int *errcode) +{ + return sock_alloc_send_pskb(sk, size, 0, noblock, errcode); } void __lock_sock(struct sock *sk) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/decnet/README linux-2.5/net/decnet/README --- linux-2.5.1/net/decnet/README Wed May 26 16:36:36 1999 +++ linux-2.5/net/decnet/README Thu Dec 13 16:32:37 2001 @@ -3,6 +3,6 @@ The documentation for this kernel subsystem is available in the Documentation/networking subdirctory of this distribution and also -on line at http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html. +on line at http://www.chygwyn.com/DECnet/ Steve Whitehouse <SteveW@ACM.org> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/decnet/af_decnet.c linux-2.5/net/decnet/af_decnet.c --- linux-2.5.1/net/decnet/af_decnet.c Fri Nov 9 22:12:54 2001 +++ linux-2.5/net/decnet/af_decnet.c Sun Dec 30 21:17:30 2001 @@ -36,6 +36,7 @@ * Steve Whitehouse: Removed unused code. Fix to use sk->allocation * when required. * Patrick Caulfield: /proc/net/decnet now has object name/number + * Steve Whitehouse: Fixed local port allocation, hashed sk list */ @@ -112,7 +113,6 @@ #include <linux/route.h> #include <linux/netfilter.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/ioctls.h> #include <linux/mm.h> @@ -139,9 +139,13 @@ dn_address decnet_address = 0; unsigned char decnet_ether_address[ETH_ALEN] = { 0xAA, 0x00, 0x04, 0x00, 0x00, 0x00 }; +#define DN_SK_HASH_SHIFT 8 +#define DN_SK_HASH_SIZE (1 << DN_SK_HASH_SHIFT) +#define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1) + static struct proto_ops dn_proto_ops; rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED; -static struct sock *dn_sklist; +static struct sock *dn_sk_hash[DN_SK_HASH_SIZE]; static struct sock *dn_wild_sk; static int __dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen, int flags); @@ -154,18 +158,38 @@ if (scp->addr.sdn_flags & SDF_WILD) return dn_wild_sk ? NULL : &dn_wild_sk; - return &dn_sklist; + return &dn_sk_hash[scp->addrloc & DN_SK_HASH_MASK]; +} + +/* + * Valid ports are those greater than zero and not already in use. + */ +static int check_port(unsigned short port) +{ + struct sock *sk = dn_sk_hash[port & DN_SK_HASH_MASK]; + if (port == 0) + return -1; + while(sk) { + struct dn_scp *scp = DN_SK(sk); + if (scp->addrloc == port) + return -1; + sk = sk->next; + } + return 0; } static unsigned short port_alloc(struct sock *sk) { struct dn_scp *scp = DN_SK(sk); static unsigned short port = 0x2000; + unsigned short i_port = port; - if (port == 0) - port++; + while(check_port(++port) != 0) { + if (port == i_port) + return 0; + } - scp->addrloc = port++; + scp->addrloc = port; return 1; } @@ -238,6 +262,48 @@ sk->pprev = NULL; } +struct sock **listen_hash(struct sockaddr_dn *addr) +{ + int i; + unsigned hash = addr->sdn_objnum; + + if (hash == 0) { + hash = addr->sdn_objnamel; + for(i = 0; i < addr->sdn_objnamel; i++) { + hash ^= addr->sdn_objname[i]; + hash ^= (hash << 3); + } + } + + return &dn_sk_hash[hash & DN_SK_HASH_MASK]; +} + +/* + * Called to transform a socket from bound (i.e. with a local address) + * into a listening socket (doesn't need a local port number) and rehashes + * based upon the object name/number. + */ +static void dn_rehash_sock(struct sock *sk) +{ + struct sock **skp = sk->pprev; + struct dn_scp *scp = DN_SK(sk); + + if (scp->addr.sdn_flags & SDF_WILD) + return; + + write_lock_bh(&dn_hash_lock); + while(*skp != sk) + skp = &((*skp)->next); + *skp = sk->next; + + DN_SK(sk)->addrloc = 0; + skp = listen_hash(&DN_SK(sk)->addr); + + sk->next = *skp; + sk->pprev = skp; + *skp = sk; + write_unlock_bh(&dn_hash_lock); +} int dn_sockaddr2username(struct sockaddr_dn *sdn, unsigned char *buf, unsigned char type) { @@ -328,10 +394,11 @@ struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr) { + struct sock **skp = listen_hash(addr); struct sock *sk; read_lock(&dn_hash_lock); - for(sk = dn_sklist; sk != NULL; sk = sk->next) { + for(sk = *skp; sk != NULL; sk = sk->next) { struct dn_scp *scp = DN_SK(sk); if (sk->state != TCP_LISTEN) continue; @@ -365,7 +432,8 @@ struct dn_scp *scp; read_lock(&dn_hash_lock); - for(sk = dn_sklist; sk != NULL; sk = sk->next) { + sk = dn_sk_hash[cb->dst_port & DN_SK_HASH_MASK]; + for (; sk != NULL; sk = sk->next) { scp = DN_SK(sk); if (cb->src != dn_saddr2dn(&scp->peer)) continue; @@ -1045,6 +1113,9 @@ sizeof(struct optdata_dn)); lock_sock(newsk); + /* + * FIXME: This can fail if we've run out of local ports.... + */ dn_hash_sock(newsk); dn_send_conn_ack(newsk); @@ -1200,6 +1271,7 @@ sk->ack_backlog = 0; sk->state = TCP_LISTEN; err = 0; + dn_rehash_sock(sk); out: release_sock(sk); @@ -2063,44 +2135,47 @@ char buf2[DN_ASCBUF_LEN]; char local_object[DN_MAXOBJL+3]; char remote_object[DN_MAXOBJL+3]; + int i; len += sprintf(buffer + len, "Local Remote\n"); read_lock(&dn_hash_lock); - for(sk = dn_sklist; sk != NULL; sk = sk->next) { - scp = DN_SK(sk); - - dn_printable_object(&scp->addr, local_object); - dn_printable_object(&scp->peer, remote_object); - - len += sprintf(buffer + len, - "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n", - dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1), - scp->addrloc, - scp->numdat, - scp->numoth, - scp->ackxmt_dat, - scp->ackxmt_oth, - scp->flowloc_sw, - local_object, - dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2), - scp->addrrem, - scp->numdat_rcv, - scp->numoth_rcv, - scp->ackrcv_dat, - scp->ackrcv_oth, - scp->flowrem_sw, - remote_object, - dn_state2asc(scp->state), - ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER")); - - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; + for(i = 0; i < DN_SK_HASH_SIZE; i++) { + for(sk = dn_sk_hash[i]; sk != NULL; sk = sk->next) { + scp = DN_SK(sk); + + dn_printable_object(&scp->addr, local_object); + dn_printable_object(&scp->peer, remote_object); + + len += sprintf(buffer + len, + "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n", + dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1), + scp->addrloc, + scp->numdat, + scp->numoth, + scp->ackxmt_dat, + scp->ackxmt_oth, + scp->flowloc_sw, + local_object, + dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2), + scp->addrrem, + scp->numdat_rcv, + scp->numoth_rcv, + scp->ackrcv_dat, + scp->ackrcv_oth, + scp->flowrem_sw, + remote_object, + dn_state2asc(scp->state), + ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER")); + + pos = begin + len; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > (offset + length)) + break; } - if (pos > (offset + length)) - break; } read_unlock(&dn_hash_lock); @@ -2158,7 +2233,7 @@ MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node"); #endif -static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.9s (C) 1995-2001 Linux DECnet Project Team\n"; +static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.15-pre5s (C) 1995-2001 Linux DECnet Project Team\n"; static int __init decnet_init(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/decnet/dn_dev.c linux-2.5/net/decnet/dn_dev.c --- linux-2.5.1/net/decnet/dn_dev.c Fri Jul 6 23:46:22 2001 +++ linux-2.5/net/decnet/dn_dev.c Thu Dec 13 16:32:37 2001 @@ -56,9 +56,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err); static void dn_dev_delete(struct net_device *dev); -#ifdef CONFIG_RTNETLINK static void rtmsg_ifa(int event, struct dn_ifaddr *ifa); -#endif static int dn_eth_up(struct net_device *); static void dn_send_brd_hello(struct net_device *dev); @@ -369,9 +367,7 @@ *ifap = ifa1->ifa_next; -#ifdef CONFIG_RTNETLINK rtmsg_ifa(RTM_DELADDR, ifa1); -#endif /* CONFIG_RTNETLINK */ if (destroy) { dn_dev_free_ifa(ifa1); @@ -390,9 +386,7 @@ ifa->ifa_next = dn_db->ifa_list; dn_db->ifa_list = ifa; -#ifdef CONFIG_RTNETLINK rtmsg_ifa(RTM_NEWADDR, ifa); -#endif /* CONFIG_RTNETLINK */ return 0; } @@ -501,7 +495,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK static struct dn_dev *dn_dev_by_index(int ifindex) { struct net_device *dev; @@ -658,8 +651,6 @@ return skb->len; } -#endif /* CONFIG_RTNETLINK */ - static void dn_send_endnode_hello(struct net_device *dev) { struct endnode_hello_message *msg; @@ -1172,7 +1163,6 @@ #endif /* CONFIG_PROC_FS */ -#ifdef CONFIG_RTNETLINK static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = { { NULL, NULL, }, @@ -1213,7 +1203,6 @@ { NULL, NULL, } #endif }; -#endif /* CONFIG_RTNETLINK */ void __init dn_dev_init(void) { @@ -1223,9 +1212,7 @@ register_gifconf(PF_DECnet, dnet_gifconf); #endif /* CONFIG_DECNET_SIOCGIFCONF */ -#ifdef CONFIG_RTNETLINK rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table; -#endif /* CONFIG_RTNETLINK */ #ifdef CONFIG_PROC_FS proc_net_create("decnet_dev", 0, decnet_dev_get_info); @@ -1242,9 +1229,7 @@ void __exit dn_dev_cleanup(void) { -#ifdef CONFIG_RTNETLINK rtnetlink_links[PF_DECnet] = NULL; -#endif /* CONFIG_RTNETLINK */ #ifdef CONFIG_DECNET_SIOCGIFCONF unregister_gifconf(PF_DECnet); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/decnet/dn_fib.c linux-2.5/net/decnet/dn_fib.c --- linux-2.5.1/net/decnet/dn_fib.c Mon Jan 22 21:32:10 2001 +++ linux-2.5/net/decnet/dn_fib.c Thu Dec 13 16:32:37 2001 @@ -50,9 +50,7 @@ #define endfor_nexthops(fi) } -#ifdef CONFIG_RTNETLINK extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb); -#endif /* CONFIG_RTNETLINK */ static struct dn_fib_info *dn_fib_info_list; @@ -415,8 +413,6 @@ } -#ifdef CONFIG_RTNETLINK - static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta) { int i; @@ -497,7 +493,6 @@ return skb->len; } -#endif /* CONFIG_RTNETLINK */ int dn_fib_sync_down(dn_address local, struct net_device *dev, int force) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/decnet/dn_nsp_in.c linux-2.5/net/decnet/dn_nsp_in.c --- linux-2.5.1/net/decnet/dn_nsp_in.c Fri Nov 9 22:12:54 2001 +++ linux-2.5/net/decnet/dn_nsp_in.c Sun Dec 30 21:17:30 2001 @@ -59,7 +59,6 @@ #include <linux/inet.h> #include <linux/route.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/decnet/dn_nsp_out.c linux-2.5/net/decnet/dn_nsp_out.c --- linux-2.5.1/net/decnet/dn_nsp_out.c Mon Jan 22 21:32:10 2001 +++ linux-2.5/net/decnet/dn_nsp_out.c Sun Dec 30 21:17:30 2001 @@ -51,7 +51,6 @@ #include <linux/inet.h> #include <linux/route.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/decnet/dn_route.c linux-2.5/net/decnet/dn_route.c --- linux-2.5.1/net/decnet/dn_route.c Fri Nov 9 22:12:54 2001 +++ linux-2.5/net/decnet/dn_route.c Thu Dec 13 16:32:37 2001 @@ -1020,7 +1020,6 @@ return dn_route_input_slow(skb); } -#ifdef CONFIG_RTNETLINK static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait) { struct dn_route *rt = (struct dn_route *)skb->dst; @@ -1181,7 +1180,6 @@ cb->args[1] = idx; return skb->len; } -#endif /* CONFIG_RTNETLINK */ #ifdef CONFIG_PROC_FS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/decnet/dn_rules.c linux-2.5/net/decnet/dn_rules.c --- linux-2.5.1/net/decnet/dn_rules.c Mon Jan 22 21:32:10 2001 +++ linux-2.5/net/decnet/dn_rules.c Thu Dec 13 16:32:37 2001 @@ -299,8 +299,6 @@ notifier_call: dn_fib_rules_event, }; -#ifdef CONFIG_RTNETLINK - static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r, struct netlink_callback *cb) { struct rtmsg *rtm; @@ -359,8 +357,6 @@ return skb->len; } - -#endif /* CONFIG_RTNETLINK */ void __init dn_fib_rules_init(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/decnet/dn_table.c linux-2.5/net/decnet/dn_table.c --- linux-2.5.1/net/decnet/dn_table.c Mon Jan 22 21:32:10 2001 +++ linux-2.5/net/decnet/dn_table.c Thu Dec 13 16:32:37 2001 @@ -267,7 +267,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, struct dn_fib_info *fi) @@ -435,12 +434,6 @@ return skb->len; } -#else /* no CONFIG_RTNETLINK */ - -#define dn_rtmsg_fib(event,f,z,tb_id,nlh,req) - -#endif /* CONFIG_RTNETLINK */ - static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) { struct dn_hash *table = (struct dn_hash *)tb->data; @@ -860,9 +853,7 @@ #ifdef CONFIG_PROC_FS t->get_info = dn_fib_table_get_info; #endif -#ifdef CONFIG_RTNETLINK t->dump = dn_fib_table_dump; -#endif dn_fib_tables[n] = t; return t; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/Config.in linux-2.5/net/ipv4/Config.in --- linux-2.5.1/net/ipv4/Config.in Wed May 2 03:59:24 2001 +++ linux-2.5/net/ipv4/Config.in Thu Dec 13 16:32:37 2001 @@ -4,8 +4,6 @@ bool ' IP: multicasting' CONFIG_IP_MULTICAST bool ' IP: advanced router' CONFIG_IP_ADVANCED_ROUTER if [ "$CONFIG_IP_ADVANCED_ROUTER" = "y" ]; then - define_bool CONFIG_RTNETLINK y - define_bool CONFIG_NETLINK y bool ' IP: policy routing' CONFIG_IP_MULTIPLE_TABLES if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then if [ "$CONFIG_NETFILTER" = "y" ]; then @@ -39,9 +37,7 @@ fi fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_RTNETLINK" = "y" ]; then - bool ' IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD - fi + bool ' IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD fi bool ' IP: TCP Explicit Congestion Notification support' CONFIG_INET_ECN bool ' IP: TCP syncookie support (disabled per default)' CONFIG_SYN_COOKIES diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/Makefile linux-2.5/net/ipv4/Makefile --- linux-2.5.1/net/ipv4/Makefile Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/ipv4/Makefile Thu Dec 13 16:32:37 2001 @@ -15,7 +15,7 @@ ip_input.o ip_fragment.o ip_forward.o ip_options.o \ ip_output.o ip_sockglue.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o tcp_minisocks.o \ - raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ + tcp_diag.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/af_inet.c linux-2.5/net/ipv4/af_inet.c --- linux-2.5.1/net/ipv4/af_inet.c Mon Nov 5 17:46:12 2001 +++ linux-2.5/net/ipv4/af_inet.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.135 2001/10/27 03:27:13 davem Exp $ + * Version: $Id: af_inet.c,v 1.136 2001/11/06 22:21:08 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/devinet.c linux-2.5/net/ipv4/devinet.c --- linux-2.5.1/net/ipv4/devinet.c Mon Oct 1 16:19:57 2001 +++ linux-2.5/net/ipv4/devinet.c Thu Dec 13 16:32:37 2001 @@ -1,7 +1,7 @@ /* * NET3 IP device support routines. * - * Version: $Id: devinet.c,v 1.43 2001/09/26 22:52:58 davem Exp $ + * Version: $Id: devinet.c,v 1.44 2001/10/31 21:55:54 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -63,11 +63,7 @@ struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 0, }; static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, }; -#ifdef CONFIG_RTNETLINK static void rtmsg_ifa(int event, struct in_ifaddr *); -#else -#define rtmsg_ifa(a,b) do { } while(0) -#endif static struct notifier_block *inetaddr_chain; static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy); @@ -359,8 +355,6 @@ return NULL; } -#ifdef CONFIG_RTNETLINK - int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { @@ -437,8 +431,6 @@ return inet_insert_ifa(ifa); } -#endif - /* * Determine a default network mask, based on the IP address. */ @@ -859,8 +851,6 @@ notifier_call: inetdev_event, }; -#ifdef CONFIG_RTNETLINK - static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, u32 pid, u32 seq, int event) { @@ -994,8 +984,6 @@ #endif }; -#endif /* CONFIG_RTNETLINK */ - #ifdef CONFIG_SYSCTL @@ -1150,9 +1138,7 @@ { register_gifconf(PF_INET, inet_gifconf); register_netdevice_notifier(&ip_netdev_notifier); -#ifdef CONFIG_RTNETLINK rtnetlink_links[PF_INET] = inet_rtnetlink_table; -#endif #ifdef CONFIG_SYSCTL devinet_sysctl.sysctl_header = register_sysctl_table(devinet_sysctl.devinet_root_dir, 0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/fib_frontend.c linux-2.5/net/ipv4/fib_frontend.c --- linux-2.5.1/net/ipv4/fib_frontend.c Tue Jun 12 02:15:27 2001 +++ linux-2.5/net/ipv4/fib_frontend.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: FIB frontend. * - * Version: $Id: fib_frontend.c,v 1.25 2001/05/29 22:16:25 davem Exp $ + * Version: $Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $ * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * @@ -332,8 +332,6 @@ #endif -#ifdef CONFIG_RTNETLINK - static int inet_check_attr(struct rtmsg *r, struct rtattr **rta) { int i; @@ -408,8 +406,6 @@ return skb->len; } - -#endif /* Prepare and feed intra-kernel routing request. Really, it should be netlink message, but :-( netlink diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/fib_hash.c linux-2.5/net/ipv4/fib_hash.c --- linux-2.5.1/net/ipv4/fib_hash.c Tue Aug 31 18:23:03 1999 +++ linux-2.5/net/ipv4/fib_hash.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * * IPv4 FIB: lookup engine and maintenance routines. * - * Version: $Id: fib_hash.c,v 1.12 1999/08/31 07:03:27 davem Exp $ + * Version: $Id: fib_hash.c,v 1.13 2001/10/31 21:55:54 davem Exp $ * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * @@ -425,14 +425,9 @@ #endif -#ifdef CONFIG_RTNETLINK static void rtmsg_fib(int, struct fib_node*, int, int, struct nlmsghdr *n, struct netlink_skb_parms *); -#else -#define rtmsg_fib(a, b, c, d, e, f) -#endif - static int fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, @@ -796,9 +791,7 @@ #endif -#ifdef CONFIG_RTNETLINK - -extern __inline__ int +static __inline__ int fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb, struct fib_table *tb, struct fn_zone *fz, @@ -823,7 +816,7 @@ return skb->len; } -extern __inline__ int +static __inline__ int fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb, struct fib_table *tb, struct fn_zone *fz) @@ -894,8 +887,6 @@ netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); } -#endif /* CONFIG_RTNETLINK */ - #ifdef CONFIG_IP_MULTIPLE_TABLES struct fib_table * fib_hash_init(int id) #else @@ -920,9 +911,7 @@ tb->tb_delete = fn_hash_delete; tb->tb_flush = fn_hash_flush; tb->tb_select_default = fn_hash_select_default; -#ifdef CONFIG_RTNETLINK tb->tb_dump = fn_hash_dump; -#endif #ifdef CONFIG_PROC_FS tb->tb_get_info = fn_hash_get_info; #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/fib_rules.c linux-2.5/net/ipv4/fib_rules.c --- linux-2.5.1/net/ipv4/fib_rules.c Wed May 2 03:59:24 2001 +++ linux-2.5/net/ipv4/fib_rules.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: policy rules. * - * Version: $Id: fib_rules.c,v 1.16 2001/04/30 04:39:14 davem Exp $ + * Version: $Id: fib_rules.c,v 1.17 2001/10/31 21:55:54 davem Exp $ * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * @@ -395,9 +395,7 @@ notifier_call: fib_rules_event, }; -#ifdef CONFIG_RTNETLINK - -extern __inline__ int inet_fill_rule(struct sk_buff *skb, +static __inline__ int inet_fill_rule(struct sk_buff *skb, struct fib_rule *r, struct netlink_callback *cb) { @@ -462,8 +460,6 @@ return skb->len; } - -#endif /* CONFIG_RTNETLINK */ void __init fib_rules_init(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/fib_semantics.c linux-2.5/net/ipv4/fib_semantics.c --- linux-2.5.1/net/ipv4/fib_semantics.c Tue Aug 22 15:59:00 2000 +++ linux-2.5/net/ipv4/fib_semantics.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: semantics. * - * Version: $Id: fib_semantics.c,v 1.17 2000/08/19 23:22:56 davem Exp $ + * Version: $Id: fib_semantics.c,v 1.18 2001/10/31 21:55:54 davem Exp $ * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * @@ -626,8 +626,6 @@ return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope); } -#ifdef CONFIG_RTNETLINK - int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos, @@ -697,8 +695,6 @@ skb_trim(skb, b - skb->data); return -1; } - -#endif /* CONFIG_RTNETLINK */ #ifndef CONFIG_IP_NOSIOCRT diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/icmp.c linux-2.5/net/ipv4/icmp.c --- linux-2.5.1/net/ipv4/icmp.c Wed Nov 7 22:39:36 2001 +++ linux-2.5/net/ipv4/icmp.c Mon Jan 14 22:39:50 2002 @@ -154,8 +154,8 @@ * it's bit position. * * default: - * dest unreachable (0x03), source quench (0x04), - * time exceeded (0x11), parameter problem (0x12) + * dest unreachable (3), source quench (4), + * time exceeded (11), parameter problem (12) */ int sysctl_icmp_ratelimit = 1*HZ; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/ipconfig.c linux-2.5/net/ipv4/ipconfig.c --- linux-2.5.1/net/ipv4/ipconfig.c Thu Nov 29 15:49:10 2001 +++ linux-2.5/net/ipv4/ipconfig.c Sat Jan 5 16:38:09 2002 @@ -1,5 +1,5 @@ /* - * $Id: ipconfig.c,v 1.42 2001/11/10 07:23:12 davem Exp $ + * $Id: ipconfig.c,v 1.43 2001/11/21 20:27:34 davem Exp $ * * Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or * user-supplied information to configure own IP address and routes. @@ -1145,7 +1145,7 @@ */ if (ic_myaddr == INADDR_NONE || #ifdef CONFIG_ROOT_NFS - (MAJOR(ROOT_DEV) == UNNAMED_MAJOR + (major(ROOT_DEV) == UNNAMED_MAJOR && root_server_addr == INADDR_NONE && ic_servaddr == INADDR_NONE) || #endif @@ -1170,7 +1170,7 @@ * -- Chip */ #ifdef CONFIG_ROOT_NFS - if (ROOT_DEV == MKDEV(UNNAMED_MAJOR, 255)) { + if (kdev_same(ROOT_DEV, mk_kdev(UNNAMED_MAJOR, 255))) { printk(KERN_ERR "IP-Config: Retrying forever (NFS root)...\n"); goto try_try_again; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/ipmr.c linux-2.5/net/ipv4/ipmr.c --- linux-2.5.1/net/ipv4/ipmr.c Thu Sep 20 21:12:56 2001 +++ linux-2.5/net/ipv4/ipmr.c Thu Dec 13 16:32:37 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.64 2001/09/18 22:29:09 davem Exp $ + * Version: $Id: ipmr.c,v 1.65 2001/10/31 21:55:54 davem Exp $ * * Fixes: * Michael Chastain : Incorrect size of copying. @@ -294,7 +294,6 @@ atomic_dec(&cache_resolve_queue_len); while((skb=skb_dequeue(&c->mfc_un.unres.unresolved))) { -#ifdef CONFIG_RTNETLINK if (skb->nh.iph->version == 0) { struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); nlh->nlmsg_type = NLMSG_ERROR; @@ -303,7 +302,6 @@ ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT; netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); } else -#endif kfree_skb(skb); } @@ -501,7 +499,6 @@ */ while((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) { -#ifdef CONFIG_RTNETLINK if (skb->nh.iph->version == 0) { int err; struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); @@ -516,7 +513,6 @@ } err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); } else -#endif ip_mr_forward(skb, c, 0); } } @@ -1522,8 +1518,6 @@ } #endif -#ifdef CONFIG_RTNETLINK - static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm) { @@ -1598,7 +1592,6 @@ read_unlock(&mrt_lock); return err; } -#endif #ifdef CONFIG_PROC_FS /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/Config.in linux-2.5/net/ipv4/netfilter/Config.in --- linux-2.5.1/net/ipv4/netfilter/Config.in Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/ipv4/netfilter/Config.in Thu Dec 13 16:32:37 2001 @@ -10,7 +10,7 @@ dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK fi -if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NETLINK" = "y" ]; then +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP_NF_QUEUE fi tristate 'IP tables support (required for filtering/masq/NAT)' CONFIG_IP_NF_IPTABLES diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.5/net/ipv4/netfilter/ip_conntrack_irc.c --- linux-2.5.1/net/ipv4/netfilter/ip_conntrack_irc.c Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/ipv4/netfilter/ip_conntrack_irc.c Thu Dec 13 16:32:37 2001 @@ -1,8 +1,8 @@ -/* IRC extension for IP connection tracking, Version 1.19 - * (C) 2000 by Harald Welte <laforge@gnumonks.org> +/* IRC extension for IP connection tracking, Version 1.20 + * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org> * based on RR's ip_conntrack_ftp.c * - * ip_conntrack_irc.c,v 1.19 2001/10/25 14:34:21 laforge Exp + * ip_conntrack_irc.c,v 1.20 2001/12/06 07:42:10 laforge Exp * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. ** * Module load syntax: - * insmod ip_nat_irc.o ports=port1,port2,...port<MAX_PORTS> + * insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS> * * please give the ports of all IRC servers You wish to connect to. * If You don't specify ports, the default will be port 6667 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ip_fw_compat.c linux-2.5/net/ipv4/netfilter/ip_fw_compat.c --- linux-2.5.1/net/ipv4/netfilter/ip_fw_compat.c Sat Nov 10 23:36:38 2001 +++ linux-2.5/net/ipv4/netfilter/ip_fw_compat.c Thu Dec 13 16:32:37 2001 @@ -84,6 +84,16 @@ if ((*pskb)->ip_summed == CHECKSUM_HW) (*pskb)->ip_summed = CHECKSUM_NONE; + /* Firewall rules can alter TOS: raw socket (tcpdump) may have + clone of incoming skb: don't disturb it --RR */ + if (skb_cloned(*pskb) && !(*pskb)->sk) { + struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC); + if (!nskb) + return NF_DROP; + kfree_skb(*pskb); + *pskb = nskb; + } + switch (hooknum) { case NF_IP_PRE_ROUTING: if (fwops->fw_acct_in) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ip_fw_compat_redir.c linux-2.5/net/ipv4/netfilter/ip_fw_compat_redir.c --- linux-2.5.1/net/ipv4/netfilter/ip_fw_compat_redir.c Fri Aug 4 20:07:24 2000 +++ linux-2.5/net/ipv4/netfilter/ip_fw_compat_redir.c Thu Dec 13 16:32:37 2001 @@ -206,6 +206,8 @@ } list_prepend(&redirs, redir); init_timer(&redir->destroyme); + redir->destroyme.expires = jiffies + 75*HZ; + add_timer(&redir->destroyme); } /* In case mangling has changed, rewrite this part. */ redir->core = ((struct redir_core) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ip_nat_core.c linux-2.5/net/ipv4/netfilter/ip_nat_core.c --- linux-2.5.1/net/ipv4/netfilter/ip_nat_core.c Sat Nov 10 23:36:38 2001 +++ linux-2.5/net/ipv4/netfilter/ip_nat_core.c Thu Dec 13 16:32:37 2001 @@ -734,6 +734,18 @@ synchronize_bh()) can vanish. */ READ_LOCK(&ip_nat_lock); for (i = 0; i < info->num_manips; i++) { + /* raw socket (tcpdump) may have clone of incoming + skb: don't disturb it --RR */ + if (skb_cloned(*pskb) && !(*pskb)->sk) { + struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC); + if (!nskb) { + READ_UNLOCK(&ip_nat_lock); + return NF_DROP; + } + kfree_skb(*pskb); + *pskb = nskb; + } + if (info->manips[i].direction == dir && info->manips[i].hooknum == hooknum) { DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ip_nat_helper.c linux-2.5/net/ipv4/netfilter/ip_nat_helper.c --- linux-2.5.1/net/ipv4/netfilter/ip_nat_helper.c Tue Aug 28 14:09:44 2001 +++ linux-2.5/net/ipv4/netfilter/ip_nat_helper.c Thu Dec 13 16:32:37 2001 @@ -143,6 +143,23 @@ } } + /* Alexey says: if a hook changes _data_ ... it can break + original packet sitting in tcp queue and this is fatal */ + if (skb_cloned(*skb)) { + struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC); + if (!nskb) { + if (net_ratelimit()) + printk("Out of memory cloning TCP packet\n"); + return 0; + } + /* Rest of kernel will get very unhappy if we pass it + a suddenly-orphaned skbuff */ + if ((*skb)->sk) + skb_set_owner_w(nskb, (*skb)->sk); + kfree_skb(*skb); + *skb = nskb; + } + /* skb may be copied !! */ iph = (*skb)->nh.iph; tcph = (void *)iph + iph->ihl*4; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ip_nat_irc.c linux-2.5/net/ipv4/netfilter/ip_nat_irc.c --- linux-2.5.1/net/ipv4/netfilter/ip_nat_irc.c Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/ipv4/netfilter/ip_nat_irc.c Thu Dec 13 16:32:37 2001 @@ -1,8 +1,8 @@ /* IRC extension for TCP NAT alteration. - * (C) 2000 by Harald Welte <laforge@gnumonks.org> + * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org> * based on a copy of RR's ip_nat_ftp.c * - * ip_nat_irc.c,v 1.15 2001/10/22 10:43:53 laforge Exp + * ip_nat_irc.c,v 1.16 2001/12/06 07:42:10 laforge Exp * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -81,7 +81,7 @@ } newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; - newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n", NIPQUAD(newsrcip), NIPQUAD(newdstip)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ip_nat_standalone.c linux-2.5/net/ipv4/netfilter/ip_nat_standalone.c --- linux-2.5.1/net/ipv4/netfilter/ip_nat_standalone.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/net/ipv4/netfilter/ip_nat_standalone.c Mon Jan 14 22:39:50 2002 @@ -166,19 +166,16 @@ return ip_nat_fn(hooknum, pskb, in, out, okfn); } -/* FIXME: change in oif may mean change in hh_len. Check and realloc - --RR */ -static int -route_me_harder(struct sk_buff *skb) +static int route_me_harder(struct sk_buff **pskb) { - struct iphdr *iph = skb->nh.iph; + struct iphdr *iph = (*pskb)->nh.iph; struct rtable *rt; struct rt_key key = { dst:iph->daddr, src:iph->saddr, - oif:skb->sk ? skb->sk->bound_dev_if : 0, + oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, tos:RT_TOS(iph->tos)|RTO_CONN, #ifdef CONFIG_IP_ROUTE_FWMARK - fwmark:skb->nfmark + fwmark:(*pskb)->nfmark #endif }; @@ -188,9 +185,24 @@ } /* Drop old route. */ - dst_release(skb->dst); + dst_release((*pskb)->dst); - skb->dst = &rt->u.dst; + (*pskb)->dst = &rt->u.dst; + + /* Change in oif may mean change in hh_len. */ + if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) { + struct sk_buff *nskb; + + nskb = skb_realloc_headroom(*pskb, + (*pskb)->dst->dev + ->hard_header_len); + if (!nskb) + return -ENOMEM; + if ((*pskb)->sk) + skb_set_owner_w(nskb, (*pskb)->sk); + kfree_skb(*pskb); + *pskb = nskb; + } return 0; } @@ -216,7 +228,7 @@ if (ret != NF_DROP && ret != NF_STOLEN && ((*pskb)->nh.iph->saddr != saddr || (*pskb)->nh.iph->daddr != daddr)) - return route_me_harder(*pskb) == 0 ? ret : NF_DROP; + return route_me_harder(pskb) == 0 ? ret : NF_DROP; return ret; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ipt_MIRROR.c linux-2.5/net/ipv4/netfilter/ipt_MIRROR.c --- linux-2.5.1/net/ipv4/netfilter/ipt_MIRROR.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/net/ipv4/netfilter/ipt_MIRROR.c Thu Dec 13 16:32:37 2001 @@ -6,6 +6,10 @@ Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be> + Changes: + 25 Aug 2001 Harald Welte <laforge@gnumonks.org> + - decrement and check TTL if not called from FORWARD hook + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your @@ -24,6 +28,7 @@ #include <linux/skbuff.h> #include <linux/ip.h> #include <net/ip.h> +#include <net/icmp.h> #include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netdevice.h> #include <linux/route.h> @@ -100,15 +105,31 @@ const void *targinfo, void *userinfo) { - if ((*pskb)->dst != NULL) { - if (route_mirror(*pskb)) { - ip_rewrite(*pskb); - /* Don't let conntrack code see this packet: - it will think we are starting a new - connection! --RR */ - ip_direct_send(*pskb); - return NF_STOLEN; + if (((*pskb)->dst != NULL) && + route_mirror(*pskb)) { + + ip_rewrite(*pskb); + + /* If we are not at FORWARD hook (INPUT/PREROUTING), + * the TTL isn't decreased by the IP stack */ + if (hooknum != NF_IP_FORWARD) { + struct iphdr *iph = (*pskb)->nh.iph; + if (iph->ttl <= 1) { + /* this will traverse normal stack, and + * thus call conntrack on the icmp packet */ + icmp_send(*pskb, ICMP_TIME_EXCEEDED, + ICMP_EXC_TTL, 0); + return NF_DROP; + } + ip_decrease_ttl(iph); } + + /* Don't let conntrack code see this packet: + it will think we are starting a new + connection! --RR */ + ip_direct_send(*pskb); + + return NF_STOLEN; } return NF_DROP; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ipt_TCPMSS.c linux-2.5/net/ipv4/netfilter/ipt_TCPMSS.c --- linux-2.5.1/net/ipv4/netfilter/ipt_TCPMSS.c Sat Nov 10 23:36:38 2001 +++ linux-2.5/net/ipv4/netfilter/ipt_TCPMSS.c Thu Dec 13 16:32:37 2001 @@ -44,11 +44,22 @@ { const struct ipt_tcpmss_info *tcpmssinfo = targinfo; struct tcphdr *tcph; - struct iphdr *iph = (*pskb)->nh.iph; + struct iphdr *iph; u_int16_t tcplen, newtotlen, oldval, newmss; unsigned int i; u_int8_t *opt; + /* raw socket (tcpdump) may have clone of incoming skb: don't + disturb it --RR */ + if (skb_cloned(*pskb) && !(*pskb)->sk) { + struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC); + if (!nskb) + return NF_DROP; + kfree_skb(*pskb); + *pskb = nskb; + } + + iph = (*pskb)->nh.iph; tcplen = (*pskb)->len - iph->ihl*4; tcph = (void *)iph + iph->ihl*4; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ipt_TOS.c linux-2.5/net/ipv4/netfilter/ipt_TOS.c --- linux-2.5.1/net/ipv4/netfilter/ipt_TOS.c Sat Nov 10 23:36:38 2001 +++ linux-2.5/net/ipv4/netfilter/ipt_TOS.c Wed Dec 19 01:08:32 2001 @@ -21,6 +21,17 @@ if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { u_int16_t diffs[2]; + /* raw socket (tcpdump) may have clone of incoming + skb: don't disturb it --RR */ + if (skb_cloned(*pskb) && !(*pskb)->sk) { + struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC); + if (!nskb) + return NF_DROP; + kfree_skb(*pskb); + *pskb = nskb; + iph = (*pskb)->nh.iph; + } + diffs[0] = htons(iph->tos) ^ 0xFFFF; iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; diffs[1] = htons(iph->tos); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/netfilter/ipt_unclean.c linux-2.5/net/ipv4/netfilter/ipt_unclean.c --- linux-2.5.1/net/ipv4/netfilter/ipt_unclean.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/net/ipv4/netfilter/ipt_unclean.c Thu Dec 13 16:32:37 2001 @@ -257,6 +257,8 @@ #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 +#define TH_ECE 0x40 +#define TH_CWR 0x80 /* TCP-specific checks. */ static int @@ -328,9 +330,10 @@ } /* CHECK: TCP flags. */ - tcpflags = ((u_int8_t *)tcph)[13]; + tcpflags = (((u_int8_t *)tcph)[13] & ~(TH_ECE|TH_CWR)); if (tcpflags != TH_SYN && tcpflags != (TH_SYN|TH_ACK) + && tcpflags != TH_RST && tcpflags != (TH_RST|TH_ACK) && tcpflags != (TH_RST|TH_ACK|TH_PUSH) && tcpflags != (TH_FIN|TH_ACK) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/route.c linux-2.5/net/ipv4/route.c --- linux-2.5.1/net/ipv4/route.c Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/ipv4/route.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.101 2001/10/20 00:00:11 davem Exp $ + * Version: $Id: route.c,v 1.102 2001/10/31 21:55:54 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -2013,7 +2013,6 @@ return ip_route_output_slow(rp, key); } -#ifdef CONFIG_RTNETLINK static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait) { @@ -2218,8 +2217,6 @@ cb->args[1] = idx; return skb->len; } - -#endif /* CONFIG_RTNETLINK */ void ip_rt_multicast_event(struct in_device *in_dev) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/tcp.c linux-2.5/net/ipv4/tcp.c --- linux-2.5.1/net/ipv4/tcp.c Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/ipv4/tcp.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.214 2001/10/20 00:00:11 davem Exp $ + * Version: $Id: tcp.c,v 1.215 2001/10/31 08:17:58 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -2442,6 +2442,7 @@ extern void __skb_cb_too_small_for_tcp(int, int); +extern void tcpdiag_init(void); void __init tcp_init(void) { @@ -2553,4 +2554,6 @@ printk("TCP: Hash tables configured (established %d bind %d)\n", tcp_ehash_size<<1, tcp_bhash_size); + + tcpdiag_init(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/tcp_diag.c linux-2.5/net/ipv4/tcp_diag.c --- linux-2.5.1/net/ipv4/tcp_diag.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/net/ipv4/tcp_diag.c Thu Dec 13 16:45:01 2001 @@ -0,0 +1,609 @@ +/* + * tcp_diag.c Module for monitoring TCP sockets. + * + * Version: $Id: tcp_diag.c,v 1.1 2001/12/13 16:45:01 davej Exp $ + * + * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the 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/module.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/random.h> +#include <linux/cache.h> +#include <linux/init.h> + +#include <net/icmp.h> +#include <net/tcp.h> +#include <net/ipv6.h> +#include <net/inet_common.h> + +#include <linux/inet.h> +#include <linux/stddef.h> + +#include <linux/tcp_diag.h> + +static struct sock *tcpnl; + + +#define TCPDIAG_PUT(skb, attrtype, attrlen) \ +({ int rtalen = RTA_LENGTH(attrlen); \ + struct rtattr *rta; \ + if (skb_tailroom(skb) < RTA_ALIGN(rtalen)) goto nlmsg_failure; \ + rta = (void*)__skb_put(skb, RTA_ALIGN(rtalen)); \ + rta->rta_type = attrtype; \ + rta->rta_len = rtalen; \ + RTA_DATA(rta); }) + +static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, + int ext, u32 pid, u32 seq) +{ + struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; + struct tcpdiagmsg *r; + struct nlmsghdr *nlh; + struct tcp_info *info = NULL; + struct tcpdiag_meminfo *minfo = NULL; + unsigned char *b = skb->tail; + + nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r)); + r = NLMSG_DATA(nlh); + if (sk->state != TCP_TIME_WAIT) { + if (ext & (1<<(TCPDIAG_MEMINFO-1))) + minfo = TCPDIAG_PUT(skb, TCPDIAG_MEMINFO, sizeof(*minfo)); + if (ext & (1<<(TCPDIAG_INFO-1))) + info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info)); + } + r->tcpdiag_family = sk->family; + r->tcpdiag_state = sk->state; + r->tcpdiag_timer = 0; + r->tcpdiag_retrans = 0; + + r->id.tcpdiag_sport = sk->sport; + r->id.tcpdiag_dport = sk->dport; + r->id.tcpdiag_src[0] = sk->rcv_saddr; + r->id.tcpdiag_dst[0] = sk->daddr; + r->id.tcpdiag_if = sk->bound_dev_if; + *((struct sock **)&r->id.tcpdiag_cookie) = sk; + + if (r->tcpdiag_state == TCP_TIME_WAIT) { + struct tcp_tw_bucket *tw = (struct tcp_tw_bucket*)sk; + long tmo = tw->ttd - jiffies; + if (tmo < 0) + tmo = 0; + + r->tcpdiag_state = tw->substate; + r->tcpdiag_timer = 3; + r->tcpdiag_expires = (tmo*1000+HZ-1)/HZ; + r->tcpdiag_rqueue = 0; + r->tcpdiag_wqueue = 0; + r->tcpdiag_uid = 0; + r->tcpdiag_inode = 0; +#ifdef CONFIG_IPV6 + if (r->tcpdiag_family == AF_INET6) { + memcpy(r->id.tcpdiag_src, &tw->v6_rcv_saddr, 16); + memcpy(r->id.tcpdiag_dst, &tw->v6_daddr, 16); + } +#endif + nlh->nlmsg_len = skb->tail - b; + return skb->len; + } + +#ifdef CONFIG_IPV6 + if (r->tcpdiag_family == AF_INET6) { + memcpy(r->id.tcpdiag_src, &sk->net_pinfo.af_inet6.rcv_saddr, 16); + memcpy(r->id.tcpdiag_dst, &sk->net_pinfo.af_inet6.daddr, 16); + } +#endif + +#define EXPIRES_IN_MS(tmo) ((tmo-jiffies)*1000+HZ-1)/HZ + + if (tp->pending == TCP_TIME_RETRANS) { + r->tcpdiag_timer = 1; + r->tcpdiag_retrans = tp->retransmits; + r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout); + } else if (tp->pending == TCP_TIME_PROBE0) { + r->tcpdiag_timer = 4; + r->tcpdiag_retrans = tp->probes_out; + r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout); + } else if (timer_pending(&sk->timer)) { + r->tcpdiag_timer = 2; + r->tcpdiag_retrans = tp->probes_out; + r->tcpdiag_expires = EXPIRES_IN_MS(sk->timer.expires); + } else { + r->tcpdiag_timer = 0; + r->tcpdiag_expires = 0; + } +#undef EXPIRES_IN_MS + + r->tcpdiag_rqueue = tp->rcv_nxt - tp->copied_seq; + r->tcpdiag_wqueue = tp->write_seq - tp->snd_una; + r->tcpdiag_uid = sock_i_uid(sk); + r->tcpdiag_inode = sock_i_ino(sk); + + if (minfo) { + minfo->tcpdiag_rmem = atomic_read(&sk->rmem_alloc); + minfo->tcpdiag_wmem = sk->wmem_queued; + minfo->tcpdiag_fmem = sk->forward_alloc; + minfo->tcpdiag_tmem = atomic_read(&sk->wmem_alloc); + } + + if (info) { + u32 now = tcp_time_stamp; + + info->tcpi_state = sk->state; + info->tcpi_ca_state = tp->ca_state; + info->tcpi_retransmits = tp->retransmits; + info->tcpi_probes = tp->probes_out; + info->tcpi_backoff = tp->backoff; + info->tcpi_options = 0; + if (tp->tstamp_ok) + info->tcpi_options |= TCPI_OPT_TIMESTAMPS; + if (tp->sack_ok) + info->tcpi_options |= TCPI_OPT_SACK; + if (tp->wscale_ok) { + info->tcpi_options |= TCPI_OPT_WSCALE; + info->tcpi_snd_wscale = tp->snd_wscale; + info->tcpi_rcv_wscale = tp->rcv_wscale; + } else { + info->tcpi_snd_wscale = 0; + info->tcpi_rcv_wscale = 0; + } +#ifdef CONFIG_INET_ECN + if (tp->ecn_flags&TCP_ECN_OK) + info->tcpi_options |= TCPI_OPT_ECN; +#endif + + info->tcpi_rto = (1000000*tp->rto)/HZ; + info->tcpi_ato = (1000000*tp->ack.ato)/HZ; + info->tcpi_snd_mss = tp->mss_cache; + info->tcpi_rcv_mss = tp->ack.rcv_mss; + + info->tcpi_unacked = tp->packets_out; + info->tcpi_sacked = tp->sacked_out; + info->tcpi_lost = tp->lost_out; + info->tcpi_retrans = tp->retrans_out; + info->tcpi_fackets = tp->fackets_out; + + info->tcpi_last_data_sent = ((now - tp->lsndtime)*1000)/HZ; + info->tcpi_last_ack_sent = 0; + info->tcpi_last_data_recv = ((now - tp->ack.lrcvtime)*1000)/HZ; + info->tcpi_last_ack_recv = ((now - tp->rcv_tstamp)*1000)/HZ; + + info->tcpi_pmtu = tp->pmtu_cookie; + info->tcpi_rcv_ssthresh = tp->rcv_ssthresh; + info->tcpi_rtt = ((1000000*tp->srtt)/HZ)>>3; + info->tcpi_rttvar = ((1000000*tp->mdev)/HZ)>>2; + info->tcpi_snd_ssthresh = tp->snd_ssthresh; + info->tcpi_snd_cwnd = tp->snd_cwnd; + info->tcpi_advmss = tp->advmss; + info->tcpi_reordering = tp->reordering; + } + + nlh->nlmsg_len = skb->tail - b; + return skb->len; + +nlmsg_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif); +#ifdef CONFIG_IPV6 +extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport, + struct in6_addr *daddr, u16 dport, + int dif); +#endif + +static int tcpdiag_get_exact(struct sk_buff *in_skb, struct nlmsghdr *nlh) +{ + int err; + struct sock *sk; + struct tcpdiagreq *req = NLMSG_DATA(nlh); + struct sk_buff *rep; + + if (req->tcpdiag_family == AF_INET) { + sk = tcp_v4_lookup(req->id.tcpdiag_dst[0], req->id.tcpdiag_dport, + req->id.tcpdiag_src[0], req->id.tcpdiag_sport, + req->id.tcpdiag_if); + } +#ifdef CONFIG_IPV6 + else if (req->tcpdiag_family == AF_INET6) { + sk = tcp_v6_lookup((struct in6_addr*)req->id.tcpdiag_dst, req->id.tcpdiag_dport, + (struct in6_addr*)req->id.tcpdiag_src, req->id.tcpdiag_sport, + req->id.tcpdiag_if); + } +#endif + else { + return -EINVAL; + } + + if (sk == NULL) + return -ENOENT; + + err = -ESTALE; + if ((req->id.tcpdiag_cookie[0] != TCPDIAG_NOCOOKIE || + req->id.tcpdiag_cookie[1] != TCPDIAG_NOCOOKIE) && + sk != *((struct sock **)&req->id.tcpdiag_cookie[0])) + goto out; + + err = -ENOMEM; + rep = alloc_skb(NLMSG_SPACE(sizeof(struct tcpdiagmsg)+ + sizeof(struct tcpdiag_meminfo)+ + sizeof(struct tcp_info)+64), GFP_KERNEL); + if (!rep) + goto out; + + if (tcpdiag_fill(rep, sk, req->tcpdiag_ext, + NETLINK_CB(in_skb).pid, + nlh->nlmsg_seq) <= 0) + BUG(); + + err = netlink_unicast(tcpnl, rep, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); + if (err > 0) + err = 0; + +out: + if (sk) { + if (sk->state == TCP_TIME_WAIT) + tcp_tw_put((struct tcp_tw_bucket*)sk); + else + sock_put(sk); + } + return err; +} + +int bitstring_match(u32 *a1, u32 *a2, int bits) +{ + int words = bits >> 5; + + bits &= 0x1f; + + if (words) { + if (memcmp(a1, a2, words << 2)) + return 0; + } + if (bits) { + __u32 w1, w2; + __u32 mask; + + w1 = a1[words]; + w2 = a2[words]; + + mask = htonl((0xffffffff) << (32 - bits)); + + if ((w1 ^ w2) & mask) + return 0; + } + + return 1; +} + + +int tcpdiag_bc_run(char *bc, int len, struct sock *sk) +{ + while (len > 0) { + int yes = 1; + struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc; + + switch (op->code) { + case TCPDIAG_BC_NOP: + break; + case TCPDIAG_BC_JMP: + yes = 0; + break; + case TCPDIAG_BC_S_GE: + yes = (sk->num >= op[1].no); + break; + case TCPDIAG_BC_S_LE: + yes = (sk->num <= op[1].no); + break; + case TCPDIAG_BC_D_GE: + yes = (ntohs(sk->dport) >= op[1].no); + break; + case TCPDIAG_BC_D_LE: + yes = (ntohs(sk->dport) <= op[1].no); + break; + case TCPDIAG_BC_AUTO: + yes = !(sk->userlocks&SOCK_BINDPORT_LOCK); + break; + case TCPDIAG_BC_S_COND: + case TCPDIAG_BC_D_COND: + { + struct tcpdiag_hostcond *cond = (struct tcpdiag_hostcond*)(op+1); + u32 *addr; + + if (cond->port != -1 && + cond->port != (op->code == TCPDIAG_BC_S_COND ? sk->num : ntohs(sk->dport))) { + yes = 0; + break; + } + + if (cond->prefix_len == 0) + break; + +#ifdef CONFIG_IPV6 + if (sk->family == AF_INET6) { + if (op->code == TCPDIAG_BC_S_COND) + addr = (u32*)&sk->net_pinfo.af_inet6.rcv_saddr; + else + addr = (u32*)&sk->net_pinfo.af_inet6.daddr; + } else +#endif + { + if (op->code == TCPDIAG_BC_S_COND) + addr = &sk->rcv_saddr; + else + addr = &sk->daddr; + } + + if (bitstring_match(addr, cond->addr, cond->prefix_len)) + break; + if (sk->family == AF_INET6 && cond->family == AF_INET) { + if (addr[0] == 0 && addr[1] == 0 && + addr[2] == __constant_htonl(0xffff) && + bitstring_match(addr+3, cond->addr, cond->prefix_len)) + break; + } + yes = 0; + break; + } + } + + if (yes) { + len -= op->yes; + bc += op->yes; + } else { + len -= op->no; + bc += op->no; + } + } + return (len == 0); +} + +int valid_cc(char *bc, int len, int cc) +{ + while (len >= 0) { + struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc; + + if (cc > len) + return 0; + if (cc == len) + return 1; + if (op->yes < 4) + return 0; + len -= op->yes; + bc += op->yes; + } + return 0; +} + +int tcpdiag_bc_audit(char *bytecode, int bytecode_len) +{ + char *bc = bytecode; + int len = bytecode_len; + + while (len > 0) { + struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc; + +//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len); + switch (op->code) { + case TCPDIAG_BC_AUTO: + case TCPDIAG_BC_S_COND: + case TCPDIAG_BC_D_COND: + case TCPDIAG_BC_S_GE: + case TCPDIAG_BC_S_LE: + case TCPDIAG_BC_D_GE: + case TCPDIAG_BC_D_LE: + if (op->yes < 4 || op->yes > len+4) + return -EINVAL; + case TCPDIAG_BC_JMP: + if (op->no < 4 || op->no > len+4) + return -EINVAL; + if (op->no < len && + !valid_cc(bytecode, bytecode_len, len-op->no)) + return -EINVAL; + break; + case TCPDIAG_BC_NOP: + if (op->yes < 4 || op->yes > len+4) + return -EINVAL; + break; + default: + return -EINVAL; + } + bc += op->yes; + len -= op->yes; + } + return len == 0 ? 0 : -EINVAL; +} + + +int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb) +{ + int i, num; + int s_i, s_num; + struct tcpdiagreq *r = NLMSG_DATA(cb->nlh); + struct rtattr *bc = NULL; + + if (cb->nlh->nlmsg_len > 4+NLMSG_SPACE(sizeof(struct tcpdiagreq))) + bc = (struct rtattr*)(r+1); + + s_i = cb->args[1]; + s_num = num = cb->args[2]; + + if (cb->args[0] == 0) { + if (!(r->tcpdiag_states&(TCPF_LISTEN|TCPF_SYN_RECV))) + goto skip_listen_ht; + tcp_listen_lock(); + for (i = s_i; i < TCP_LHTABLE_SIZE; i++) { + struct sock *sk = tcp_listening_hash[i]; + + if (i > s_i) + s_num = 0; + + for (sk = tcp_listening_hash[i], num = 0; + sk != NULL; + sk = sk->next, num++) { + if (num < s_num) + continue; + if (!(r->tcpdiag_states&TCPF_LISTEN) || + r->id.tcpdiag_dport) + continue; + if (r->id.tcpdiag_sport != sk->sport && r->id.tcpdiag_sport) + continue; + if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk)) + continue; + if (tcpdiag_fill(skb, sk, r->tcpdiag_ext, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq) <= 0) { + tcp_listen_unlock(); + goto done; + } + } + } + tcp_listen_unlock(); +skip_listen_ht: + cb->args[0] = 1; + s_i = num = s_num = 0; + } + + if (!(r->tcpdiag_states&~(TCPF_LISTEN|TCPF_SYN_RECV))) + return skb->len; + + for (i = s_i; i < tcp_ehash_size; i++) { + struct tcp_ehash_bucket *head = &tcp_ehash[i]; + struct sock *sk; + + if (i > s_i) + s_num = 0; + + read_lock_bh(&head->lock); + + for (sk = head->chain, num = 0; + sk != NULL; + sk = sk->next, num++) { + if (num < s_num) + continue; + if (!(r->tcpdiag_states&(1<<sk->state))) + continue; + if (r->id.tcpdiag_sport != sk->sport && r->id.tcpdiag_sport) + continue; + if (r->id.tcpdiag_dport != sk->dport && r->id.tcpdiag_dport) + continue; + if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk)) + continue; + if (tcpdiag_fill(skb, sk, r->tcpdiag_ext, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq) <= 0) { + read_unlock_bh(&head->lock); + goto done; + } + } + + if (r->tcpdiag_states&TCPF_TIME_WAIT) { + for (sk = tcp_ehash[i+tcp_ehash_size].chain; + sk != NULL; + sk = sk->next, num++) { + if (num < s_num) + continue; + if (!(r->tcpdiag_states&(1<<sk->zapped))) + continue; + if (r->id.tcpdiag_sport != sk->sport && r->id.tcpdiag_sport) + continue; + if (r->id.tcpdiag_dport != sk->dport && r->id.tcpdiag_dport) + continue; + if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk)) + continue; + if (tcpdiag_fill(skb, sk, r->tcpdiag_ext, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq) <= 0) { + read_unlock_bh(&head->lock); + goto done; + } + } + } + read_unlock_bh(&head->lock); + } + +done: + cb->args[1] = i; + cb->args[2] = num; + return skb->len; +} + +static int tcpdiag_dump_done(struct netlink_callback *cb) +{ + return 0; +} + + +static __inline__ int +tcpdiag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) +{ + if (!(nlh->nlmsg_flags&NLM_F_REQUEST)) + return 0; + + if (nlh->nlmsg_type != TCPDIAG_GETSOCK) + goto err_inval; + + if (NLMSG_LENGTH(sizeof(struct tcpdiagreq)) > skb->len) + goto err_inval; + + if (nlh->nlmsg_flags&NLM_F_DUMP) { + if (nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(struct tcpdiagreq))) { + struct rtattr *rta = (struct rtattr*)(NLMSG_DATA(nlh) + sizeof(struct tcpdiagreq)); + if (rta->rta_type != TCPDIAG_REQ_BYTECODE || + rta->rta_len < 8 || + rta->rta_len > nlh->nlmsg_len - NLMSG_SPACE(sizeof(struct tcpdiagreq))) + goto err_inval; + if (tcpdiag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta))) + goto err_inval; + } + return netlink_dump_start(tcpnl, skb, nlh, + tcpdiag_dump, + tcpdiag_dump_done); + } else { + return tcpdiag_get_exact(skb, nlh); + } + +err_inval: + return -EINVAL; +} + + +extern __inline__ void tcpdiag_rcv_skb(struct sk_buff *skb) +{ + int err; + struct nlmsghdr * nlh; + + if (skb->len >= NLMSG_SPACE(0)) { + nlh = (struct nlmsghdr *)skb->data; + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) + return; + err = tcpdiag_rcv_msg(skb, nlh); + if (err) + netlink_ack(skb, nlh, err); + } +} + +static void tcpdiag_rcv(struct sock *sk, int len) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { + tcpdiag_rcv_skb(skb); + kfree_skb(skb); + } +} + +void __init tcpdiag_init(void) +{ + tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv); + if (tcpnl == NULL) + panic("tcpdiag_init: Cannot create netlink socket."); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/tcp_input.c linux-2.5/net/ipv4/tcp_input.c --- linux-2.5.1/net/ipv4/tcp_input.c Mon Dec 10 19:19:42 2001 +++ linux-2.5/net/ipv4/tcp_input.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.238 2001/10/20 00:00:11 davem Exp $ + * Version: $Id: tcp_input.c,v 1.241 2001/11/14 02:48:51 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/tcp_ipv4.c linux-2.5/net/ipv4/tcp_ipv4.c --- linux-2.5.1/net/ipv4/tcp_ipv4.c Mon Nov 5 17:46:12 2001 +++ linux-2.5/net/ipv4/tcp_ipv4.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.235 2001/10/26 14:51:13 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.237 2001/12/05 08:54:10 davem Exp $ * * IPv4 specific functions * @@ -754,21 +754,19 @@ } static struct open_request *tcp_v4_search_req(struct tcp_opt *tp, - struct iphdr *iph, - struct tcphdr *th, - struct open_request ***prevp) + struct open_request ***prevp, + __u16 rport, + __u32 raddr, __u32 laddr) { struct tcp_listen_opt *lopt = tp->listen_opt; struct open_request *req, **prev; - __u16 rport = th->source; - __u32 raddr = iph->saddr; for (prev = &lopt->syn_table[tcp_v4_synq_hash(raddr, rport)]; (req = *prev) != NULL; prev = &req->dl_next) { if (req->rmt_port == rport && req->af.v4_req.rmt_addr == raddr && - req->af.v4_req.loc_addr == iph->daddr && + req->af.v4_req.loc_addr == laddr && TCP_INET_FAMILY(req->class->family)) { BUG_TRAP(req->sk == NULL); *prevp = prev; @@ -939,7 +937,9 @@ if (sk->lock.users != 0) goto out; - req = tcp_v4_search_req(tp, iph, th, &prev); + req = tcp_v4_search_req(tp, &prev, + th->dest, + iph->daddr, iph->saddr); if (!req) goto out; @@ -1473,11 +1473,14 @@ { struct open_request *req, **prev; struct tcphdr *th = skb->h.th; + struct iphdr *iph = skb->nh.iph; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct sock *nsk; /* Find possible connection requests. */ - req = tcp_v4_search_req(tp, skb->nh.iph, th, &prev); + req = tcp_v4_search_req(tp, &prev, + th->source, + iph->saddr, iph->daddr); if (req) return tcp_check_req(sk, skb, req, prev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv4/tcp_output.c linux-2.5/net/ipv4/tcp_output.c --- linux-2.5.1/net/ipv4/tcp_output.c Mon Nov 5 17:46:12 2001 +++ linux-2.5/net/ipv4/tcp_output.c Tue Jan 8 00:44:25 2002 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.143 2001/10/26 14:51:13 davem Exp $ + * Version: $Id: tcp_output.c,v 1.144 2001/11/06 22:21:08 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -1009,8 +1009,7 @@ skb = alloc_skb(MAX_TCP_HEADER, GFP_KERNEL); if (skb) break; - current->policy |= SCHED_YIELD; - schedule(); + yield(); } /* Reserve space for headers and prepare control bits. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv6/Config.in linux-2.5/net/ipv6/Config.in --- linux-2.5.1/net/ipv6/Config.in Wed May 16 17:31:27 2001 +++ linux-2.5/net/ipv6/Config.in Thu Dec 13 16:32:37 2001 @@ -1,11 +1,7 @@ # # IPv6 configuration # -if [ "$CONFIG_NETLINK" = "y" ]; then - if [ "$CONFIG_RTNETLINK" = "n" ]; then - bool ' IPv6: routing messages via old netlink' CONFIG_IPV6_NETLINK - fi -fi + #bool ' IPv6: flow policy support' CONFIG_RT6_POLICY #bool ' IPv6: firewall support' CONFIG_IPV6_FIREWALL diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv6/addrconf.c linux-2.5/net/ipv6/addrconf.c --- linux-2.5.1/net/ipv6/addrconf.c Fri Sep 7 18:01:21 2001 +++ linux-2.5/net/ipv6/addrconf.c Thu Dec 13 16:32:37 2001 @@ -6,7 +6,7 @@ * Pedro Roque <roque@di.fc.ul.pt> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * - * $Id: addrconf.c,v 1.68 2001/09/01 00:31:50 davem Exp $ + * $Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1644,8 +1644,6 @@ mod_timer(&addr_chk_timer, jiffies + ADDR_CHECK_FREQUENCY); } -#ifdef CONFIG_RTNETLINK - static int inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { @@ -1806,13 +1804,11 @@ { inet6_rtm_getroute, inet6_dump_fib, }, { NULL, NULL, }, }; -#endif static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) { -#ifdef CONFIG_RTNETLINK inet6_ifa_notify(event ? : RTM_NEWADDR, ifp); -#endif + switch (event) { case RTM_NEWADDR: ip6_rt_addr_add(&ifp->addr, ifp->idev->dev); @@ -2021,9 +2017,7 @@ addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY; add_timer(&addr_chk_timer); -#ifdef CONFIG_RTNETLINK rtnetlink_links[PF_INET6] = inet6_rtnetlink_table; -#endif #ifdef CONFIG_SYSCTL addrconf_sysctl.sysctl_header = register_sysctl_table(addrconf_sysctl.addrconf_root_dir, 0); @@ -2039,9 +2033,7 @@ struct inet6_ifaddr *ifa; int i; -#ifdef CONFIG_RTNETLINK rtnetlink_links[PF_INET6] = NULL; -#endif #ifdef CONFIG_SYSCTL addrconf_sysctl_unregister(&ipv6_devconf_dflt); addrconf_sysctl_unregister(&ipv6_devconf); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv6/ip6_fib.c linux-2.5/net/ipv6/ip6_fib.c --- linux-2.5.1/net/ipv6/ip6_fib.c Thu Jun 14 21:16:58 2001 +++ linux-2.5/net/ipv6/ip6_fib.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_fib.c,v 1.24 2001/06/05 11:36:55 davem Exp $ + * $Id: ip6_fib.c,v 1.25 2001/10/31 21:55:55 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -466,9 +466,7 @@ *ins = rt; rt->rt6i_node = fn; atomic_inc(&rt->rt6i_ref); -#ifdef CONFIG_RTNETLINK inet6_rt_notify(RTM_NEWROUTE, rt); -#endif rt6_stats.fib_rt_entries++; if ((fn->fn_flags & RTN_RTINFO) == 0) { @@ -925,9 +923,7 @@ if (atomic_read(&rt->rt6i_ref) != 1) BUG(); } -#ifdef CONFIG_RTNETLINK inet6_rt_notify(RTM_DELROUTE, rt); -#endif rt6_release(rt); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv6/ip6_fw.c linux-2.5/net/ipv6/ip6_fw.c --- linux-2.5.1/net/ipv6/ip6_fw.c Tue Aug 31 18:23:03 1999 +++ linux-2.5/net/ipv6/ip6_fw.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_fw.c,v 1.15 1999/08/31 07:04:03 davem Exp $ + * $Id: ip6_fw.c,v 1.16 2001/10/31 08:17:58 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -379,16 +379,12 @@ void __init ip6_fw_init(void) { -#ifdef CONFIG_NETLINK netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv); -#endif } #ifdef MODULE void cleanup_module(void) { -#ifdef CONFIG_NETLINK netlink_detach(NETLINK_IP6_FW); -#endif } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv6/ndisc.c linux-2.5/net/ipv6/ndisc.c --- linux-2.5.1/net/ipv6/ndisc.c Mon Sep 10 14:57:00 2001 +++ linux-2.5/net/ipv6/ndisc.c Thu Dec 13 16:32:37 2001 @@ -1207,81 +1207,6 @@ return 0; } -#ifdef CONFIG_PROC_FS -#ifndef CONFIG_RTNETLINK -static int ndisc_get_info(char *buffer, char **start, off_t offset, int length) -{ - int len=0; - off_t pos=0; - int size; - unsigned long now = jiffies; - int i; - - for (i = 0; i <= NEIGH_HASHMASK; i++) { - struct neighbour *neigh; - - read_lock_bh(&nd_tbl.lock); - for (neigh = nd_tbl.hash_buckets[i]; neigh; neigh = neigh->next) { - int j; - - size = 0; - for (j=0; j<16; j++) { - sprintf(buffer+len+size, "%02x", neigh->primary_key[j]); - size += 2; - } - - read_lock(&neigh->lock); - size += sprintf(buffer+len+size, - " %02x %02x %02x %02x %08lx %08lx %08x %04x %04x %04x %8s ", i, - 128, - neigh->type, - neigh->nud_state, - now - neigh->used, - now - neigh->confirmed, - neigh->parms->reachable_time, - neigh->parms->gc_staletime, - atomic_read(&neigh->refcnt) - 1, - neigh->flags | (!neigh->hh ? 0 : (neigh->hh->hh_output==dev_queue_xmit ? 4 : 2)), - neigh->dev->name); - - if ((neigh->nud_state&NUD_VALID) && neigh->dev->addr_len) { - for (j=0; j < neigh->dev->addr_len; j++) { - sprintf(buffer+len+size, "%02x", neigh->ha[j]); - size += 2; - } - } else { - size += sprintf(buffer+len+size, "000000000000"); - } - read_unlock(&neigh->lock); - size += sprintf(buffer+len+size, "\n"); - len += size; - pos += size; - - if (pos <= offset) - len=0; - if (pos >= offset+length) { - read_unlock_bh(&nd_tbl.lock); - goto done; - } - } - read_unlock_bh(&nd_tbl.lock); - } - -done: - - *start = buffer+len-(pos-offset); /* Start of wanted data */ - len = pos-offset; /* Start slop */ - if (len>length) - len = length; /* Ending slop */ - if (len<0) - len = 0; - return len; -} - -#endif -#endif /* CONFIG_PROC_FS */ - - int __init ndisc_init(struct net_proto_family *ops) { struct sock *sk; @@ -1319,11 +1244,6 @@ neigh_table_init(&nd_tbl); -#ifdef CONFIG_PROC_FS -#ifndef CONFIG_RTNETLINK - proc_net_create("ndisc", 0, ndisc_get_info); -#endif -#endif #ifdef CONFIG_SYSCTL neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6"); #endif @@ -1333,11 +1253,6 @@ void ndisc_cleanup(void) { -#ifdef CONFIG_PROC_FS -#ifndef CONFIG_RTNETLINK - proc_net_remove("ndisc"); -#endif -#endif neigh_table_clear(&nd_tbl); sock_release(ndisc_socket); ndisc_socket = NULL; /* For safety. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv6/netfilter/Config.in linux-2.5/net/ipv6/netfilter/Config.in --- linux-2.5.1/net/ipv6/netfilter/Config.in Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/ipv6/netfilter/Config.in Thu Dec 13 16:32:37 2001 @@ -9,7 +9,7 @@ # dep_tristate ' FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK #fi -#if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NETLINK" = "y" ]; then +#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then # tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE #fi tristate 'IP6 tables support (required for filtering/masq/NAT)' CONFIG_IP6_NF_IPTABLES diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv6/netfilter/ip6t_MARK.c linux-2.5/net/ipv6/netfilter/ip6t_MARK.c --- linux-2.5.1/net/ipv6/netfilter/ip6t_MARK.c Sun Sep 30 19:26:08 2001 +++ linux-2.5/net/ipv6/netfilter/ip6t_MARK.c Fri Dec 28 20:41:36 2001 @@ -51,7 +51,7 @@ static int __init init(void) { - printk(KERN_DEBUG "registreing ipv6 mark target\n"); + printk(KERN_DEBUG "registering ipv6 mark target\n"); if (ip6t_register_target(&ip6t_mark_reg)) return -EINVAL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv6/route.c linux-2.5/net/ipv6/route.c --- linux-2.5.1/net/ipv6/route.c Thu Sep 20 21:12:56 2001 +++ linux-2.5/net/ipv6/route.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: route.c,v 1.55 2001/09/18 22:29:10 davem Exp $ + * $Id: route.c,v 1.56 2001/10/31 21:55:55 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1407,8 +1407,6 @@ read_unlock_bh(&rt6_lock); } -#ifdef CONFIG_RTNETLINK - static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta, struct in6_rtmsg *rtmsg) { @@ -1740,8 +1738,6 @@ NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_ROUTE; netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_ROUTE, gfp_any()); } - -#endif /* * /proc diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/ipv6/tcp_ipv6.c linux-2.5/net/ipv6/tcp_ipv6.c --- linux-2.5.1/net/ipv6/tcp_ipv6.c Mon Nov 5 17:46:12 2001 +++ linux-2.5/net/ipv6/tcp_ipv6.c Thu Dec 27 15:15:00 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: tcp_ipv6.c,v 1.140 2001/10/15 12:34:50 davem Exp $ + * $Id: tcp_ipv6.c,v 1.142 2001/11/06 22:21:08 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -1172,6 +1172,7 @@ tcp_parse_options(skb, &tp, 0); + tp.tstamp_ok = tp.saw_tstamp; tcp_openreq_init(req, &tp, skb); req->class = &or_ipv6; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/ircomm/ircomm_core.c linux-2.5/net/irda/ircomm/ircomm_core.c --- linux-2.5.1/net/irda/ircomm/ircomm_core.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/irda/ircomm/ircomm_core.c Thu Jan 10 13:32:21 2002 @@ -490,18 +490,34 @@ { struct ircomm_cb *self; unsigned long flags; - int i=0; save_flags(flags); cli(); len = 0; - len += sprintf(buf+len, "Instance %d:\n", i++); - self = (struct ircomm_cb *) hashbin_get_first(ircomm); while (self != NULL) { ASSERT(self->magic == IRCOMM_MAGIC, return len;); + + if(self->line < 0x10) + len += sprintf(buf+len, "ircomm%d", self->line); + else + len += sprintf(buf+len, "irlpt%d", self->line - 0x10); + len += sprintf(buf+len, " state: %s, ", + ircomm_state[ self->state]); + len += sprintf(buf+len, + "slsap_sel: %#02x, dlsap_sel: %#02x, mode:", + self->slsap_sel, self->dlsap_sel); + if(self->service_type & IRCOMM_3_WIRE_RAW) + len += sprintf(buf+len, " 3-wire-raw"); + if(self->service_type & IRCOMM_3_WIRE) + len += sprintf(buf+len, " 3-wire"); + if(self->service_type & IRCOMM_9_WIRE) + len += sprintf(buf+len, " 9-wire"); + if(self->service_type & IRCOMM_CENTRONICS) + len += sprintf(buf+len, " Centronics"); + len += sprintf(buf+len, "\n"); self = (struct ircomm_cb *) hashbin_get_next(ircomm); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/ircomm/ircomm_lmp.c linux-2.5/net/irda/ircomm/ircomm_lmp.c --- linux-2.5.1/net/irda/ircomm/ircomm_lmp.c Fri Mar 2 19:12:12 2001 +++ linux-2.5/net/irda/ircomm/ircomm_lmp.c Thu Jan 10 13:32:21 2002 @@ -103,12 +103,30 @@ * * */ -int ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *skb) +int ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *userdata) { + struct sk_buff *skb; int ret; IRDA_DEBUG(0, __FUNCTION__"()\n"); + /* Any userdata supplied? */ + if (userdata == NULL) { + skb = dev_alloc_skb(64); + if (!skb) + return -ENOMEM; + + /* Reserve space for MUX and LAP header */ + skb_reserve(skb, LMP_MAX_HEADER); + } else { + skb = userdata; + /* + * Check that the client has reserved enough space for + * headers + */ + ASSERT(skb_headroom(skb) >= LMP_MAX_HEADER, return -1;); + } + ret = irlmp_connect_response(self->lsap, skb); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/ircomm/ircomm_tty.c linux-2.5/net/irda/ircomm/ircomm_tty.c --- linux-2.5.1/net/irda/ircomm/ircomm_tty.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/irda/ircomm/ircomm_tty.c Wed Jan 2 17:23:52 2002 @@ -38,7 +38,6 @@ #include <linux/tty.h> #include <linux/interrupt.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <net/irda/irda.h> @@ -387,13 +386,13 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) { struct ircomm_tty_cb *self; - int line; + unsigned int line; int ret; IRDA_DEBUG(2, __FUNCTION__ "()\n"); MOD_INC_USE_COUNT; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) { MOD_DEC_USE_COUNT; return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/ircomm/ircomm_tty_ioctl.c linux-2.5/net/irda/ircomm/ircomm_tty_ioctl.c --- linux-2.5.1/net/irda/ircomm/ircomm_tty_ioctl.c Wed Jul 4 18:50:38 2001 +++ linux-2.5/net/irda/ircomm/ircomm_tty_ioctl.c Sun Dec 30 21:17:30 2001 @@ -35,7 +35,6 @@ #include <linux/tty.h> #include <linux/serial.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <net/irda/irda.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/irda_device.c linux-2.5/net/irda/irda_device.c --- linux-2.5.1/net/irda/irda_device.c Mon Nov 12 19:29:57 2001 +++ linux-2.5/net/irda/irda_device.c Thu Jan 10 13:32:21 2002 @@ -44,7 +44,6 @@ #include <linux/spinlock.h> #include <asm/ioctls.h> -#include <asm/segment.h> #include <asm/uaccess.h> #include <asm/dma.h> #include <asm/io.h> @@ -81,6 +80,7 @@ "TV_REMOTE", }; +#ifdef CONFIG_IRDA_DEBUG static const char *task_state[] = { "IRDA_TASK_INIT", "IRDA_TASK_DONE", @@ -92,6 +92,7 @@ "IRDA_TASK_CHILD_WAIT", "IRDA_TASK_CHILD_DONE", }; +#endif /* CONFIG_IRDA_DEBUG */ static void irda_task_timer_expired(void *data); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/iriap.c linux-2.5/net/irda/iriap.c --- linux-2.5.1/net/irda/iriap.c Fri Nov 30 21:25:10 2001 +++ linux-2.5/net/irda/iriap.c Thu Jan 10 13:32:21 2002 @@ -41,6 +41,7 @@ #include <net/irda/iriap_event.h> #include <net/irda/iriap.h> +#ifdef CONFIG_IRDA_DEBUG /* FIXME: This one should go in irlmp.c */ static const char *ias_charset_types[] = { "CS_ASCII", @@ -55,6 +56,7 @@ "CS_ISO_8859_9", "CS_UNICODE" }; +#endif /* CONFIG_IRDA_DEBUG */ static hashbin_t *iriap = NULL; static __u32 service_handle; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/irlan/irlan_common.c linux-2.5/net/irda/irlan/irlan_common.c --- linux-2.5.1/net/irda/irlan/irlan_common.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/irda/irlan/irlan_common.c Thu Jan 10 13:32:21 2002 @@ -317,8 +317,15 @@ del_timer(&self->watchdog_timer); - irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, skb); - irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, skb); + /* If you want to pass the skb to *both* state machines, you will + * need to skb_clone() it, so that you don't free it twice. + * As the state machines don't need it, git rid of it here... + * Jean II */ + if (skb) + dev_kfree_skb(skb); + + irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL); + irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL); if (self->provider.access_type == ACCESS_PEER) { /* @@ -421,6 +428,13 @@ break; } + /* If you want to pass the skb to *both* state machines, you will + * need to skb_clone() it, so that you don't free it twice. + * As the state machines don't need it, git rid of it here... + * Jean II */ + if (userdata) + dev_kfree_skb(userdata); + irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/irlan/irlan_eth.c linux-2.5/net/irda/irlan/irlan_eth.c --- linux-2.5.1/net/irda/irlan/irlan_eth.c Thu Feb 8 21:08:38 2001 +++ linux-2.5/net/irda/irlan/irlan_eth.c Thu Jan 10 13:32:21 2002 @@ -61,7 +61,16 @@ dev->hard_start_xmit = irlan_eth_xmit; dev->get_stats = irlan_eth_get_stats; dev->set_multicast_list = irlan_eth_set_multicast_list; - dev->features |= NETIF_F_DYNALLOC; + + /* NETIF_F_DYNALLOC feature was set by irlan_eth_init() and would + * cause the unregister_netdev() to do asynch completion _and_ + * kfree self->dev afterwards. Which is really bad because the + * netdevice was not allocated separately but is embedded in + * our control block and therefore gets freed with *self. + * The only reason why this would have been enabled is to hide + * some netdev refcount issues. If unregister_netdev() blocks + * forever, tell us about it... */ + //dev->features |= NETIF_F_DYNALLOC; ether_setup(dev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/irlap.c linux-2.5/net/irda/irlap.c --- linux-2.5.1/net/irda/irlap.c Fri Nov 30 21:25:10 2001 +++ linux-2.5/net/irda/irlap.c Thu Jan 10 13:32:21 2002 @@ -59,6 +59,7 @@ extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb); static void __irlap_close(struct irlap_cb *self); +#ifdef CONFIG_IRDA_DEBUG static char *lap_reasons[] = { "ERROR, NOT USED", "LAP_DISC_INDICATION", @@ -69,6 +70,7 @@ "LAP_PRIMARY_CONFLICT", "ERROR, NOT USED", }; +#endif /* CONFIG_IRDA_DEBUG */ #ifdef CONFIG_PROC_FS int irlap_proc_read(char *, char **, off_t, int); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/irlap_event.c linux-2.5/net/irda/irlap_event.c --- linux-2.5.1/net/irda/irlap_event.c Fri Nov 30 21:25:10 2001 +++ linux-2.5/net/irda/irlap_event.c Thu Jan 10 13:32:21 2002 @@ -77,6 +77,7 @@ static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event, struct sk_buff *, struct irlap_info *); +#ifdef CONFIG_IRDA_DEBUG static const char *irlap_event[] = { "DISCOVERY_REQUEST", "CONNECT_REQUEST", @@ -117,6 +118,7 @@ "BACKOFF_TIMER_EXPIRED", "MEDIA_BUSY_TIMER_EXPIRED", }; +#endif /* CONFIG_IRDA_DEBUG */ const char *irlap_state[] = { "LAP_NDM", @@ -312,7 +314,6 @@ { discovery_t *discovery_rsp; int ret = 0; - int i; ASSERT(self != NULL, return -1;); ASSERT(self->magic == LAP_MAGIC, return -1;); @@ -478,6 +479,8 @@ break; #ifdef CONFIG_IRDA_ULTRA case SEND_UI_FRAME: + { + int i; /* Only allowed to repeat an operation twice */ for (i=0; ((i<2) && (self->media_busy == FALSE)); i++) { skb = skb_dequeue(&self->txq_ultra); @@ -492,6 +495,7 @@ irda_device_set_media_busy(self->netdev, TRUE); } break; + } case RECV_UI_FRAME: /* Only accept broadcast frames in NDM mode */ if (info->caddr != CBROADCAST) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/irlmp_event.c linux-2.5/net/irda/irlmp_event.c --- linux-2.5.1/net/irda/irlmp_event.c Fri Nov 30 21:25:10 2001 +++ linux-2.5/net/irda/irlmp_event.c Thu Jan 10 13:32:21 2002 @@ -49,6 +49,7 @@ "LSAP_SETUP_PEND", }; +#ifdef CONFIG_IRDA_DEBUG static const char *irlmp_event[] = { "LM_CONNECT_REQUEST", "LM_CONNECT_CONFIRM", @@ -75,6 +76,7 @@ "LM_LAP_DISCOVERY_CONFIRM", "LM_LAP_IDLE_TIMEOUT", }; +#endif /* CONFIG_IRDA_DEBUG */ /* LAP Connection control proto declarations */ static void irlmp_state_standby (struct lap_cb *, IRLMP_EVENT, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/irsyms.c linux-2.5/net/irda/irsyms.c --- linux-2.5.1/net/irda/irsyms.c Fri Nov 9 22:22:17 2001 +++ linux-2.5/net/irda/irsyms.c Thu Jan 10 13:32:21 2002 @@ -31,7 +31,6 @@ #include <linux/proc_fs.h> #include <linux/smp_lock.h> -#include <asm/segment.h> #include <net/irda/irda.h> #include <net/irda/irmod.h> @@ -198,7 +197,7 @@ return 0; } -static void __exit irda_cleanup(void) +void __exit irda_cleanup(void) { #ifdef CONFIG_SYSCTL irda_sysctl_unregister(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/irda/irsysctl.c linux-2.5/net/irda/irsysctl.c --- linux-2.5.1/net/irda/irsysctl.c Fri Nov 30 21:25:10 2001 +++ linux-2.5/net/irda/irsysctl.c Sun Dec 30 21:17:30 2001 @@ -27,7 +27,6 @@ #include <linux/mm.h> #include <linux/ctype.h> #include <linux/sysctl.h> -#include <asm/segment.h> #include <net/irda/irda.h> #include <net/irda/irias_object.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/khttpd/main.c linux-2.5/net/khttpd/main.c --- linux-2.5.1/net/khttpd/main.c Mon Mar 26 02:14:25 2001 +++ linux-2.5/net/khttpd/main.c Tue Jan 1 13:27:22 2002 @@ -390,3 +390,5 @@ module_init(khttpd_init) module_exit(khttpd_cleanup) + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/netlink/af_netlink.c linux-2.5/net/netlink/af_netlink.c --- linux-2.5.1/net/netlink/af_netlink.c Sat Jun 30 02:38:26 2001 +++ linux-2.5/net/netlink/af_netlink.c Tue Jan 1 13:28:20 2002 @@ -996,3 +996,5 @@ module_init(netlink_proto_init); module_exit(netlink_proto_exit); + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/netlink/netlink_dev.c linux-2.5/net/netlink/netlink_dev.c --- linux-2.5.1/net/netlink/netlink_dev.c Fri Nov 9 22:12:55 2001 +++ linux-2.5/net/netlink/netlink_dev.c Tue Jan 1 23:49:28 2002 @@ -41,7 +41,7 @@ static unsigned int netlink_poll(struct file *file, poll_table * wait) { - struct socket *sock = netlink_user[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct socket *sock = netlink_user[minor(file->f_dentry->d_inode->i_rdev)]; if (sock->ops->poll==NULL) return 0; @@ -56,7 +56,7 @@ size_t count, loff_t *pos) { struct inode *inode = file->f_dentry->d_inode; - struct socket *sock = netlink_user[MINOR(inode->i_rdev)]; + struct socket *sock = netlink_user[minor(inode->i_rdev)]; struct msghdr msg; struct iovec iov; @@ -80,7 +80,7 @@ size_t count, loff_t *pos) { struct inode *inode = file->f_dentry->d_inode; - struct socket *sock = netlink_user[MINOR(inode->i_rdev)]; + struct socket *sock = netlink_user[minor(inode->i_rdev)]; struct msghdr msg; struct iovec iov; @@ -105,7 +105,7 @@ static int netlink_open(struct inode * inode, struct file * file) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct socket *sock; struct sockaddr_nl nladdr; int err; @@ -137,7 +137,7 @@ static int netlink_release(struct inode * inode, struct file * file) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); struct socket *sock; sock = netlink_user[minor]; @@ -151,7 +151,7 @@ static int netlink_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); int retval = 0; if (minor >= MAX_LINKS) @@ -195,11 +195,13 @@ /* Someone tell me the official names for the uppercase ones */ make_devfs_entries ("route", 0); make_devfs_entries ("skip", 1); - make_devfs_entries ("USERSOCK", 2); + make_devfs_entries ("usersock", 2); make_devfs_entries ("fwmonitor", 3); - make_devfs_entries ("ARPD", 8); - make_devfs_entries ("ROUTE6", 11); - make_devfs_entries ("IP6_FW", 13); + make_devfs_entries ("tcpdiag", 4); + make_devfs_entries ("arpd", 8); + make_devfs_entries ("route6", 11); + make_devfs_entries ("ip6_fw", 13); + make_devfs_entries ("dnrtmsg", 13); devfs_register_series (devfs_handle, "tap%u", 16, DEVFS_FL_DEFAULT, NETLINK_MAJOR, 16, S_IFCHR | S_IRUSR | S_IWUSR, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/netsyms.c linux-2.5/net/netsyms.c --- linux-2.5.1/net/netsyms.c Mon Nov 5 17:46:12 2001 +++ linux-2.5/net/netsyms.c Thu Dec 13 16:32:37 2001 @@ -116,6 +116,7 @@ EXPORT_SYMBOL(sk_free); EXPORT_SYMBOL(sock_wake_async); EXPORT_SYMBOL(sock_alloc_send_skb); +EXPORT_SYMBOL(sock_alloc_send_pskb); EXPORT_SYMBOL(sock_init_data); EXPORT_SYMBOL(sock_no_release); EXPORT_SYMBOL(sock_no_bind); @@ -406,7 +407,6 @@ #endif -#ifdef CONFIG_NETLINK EXPORT_SYMBOL(netlink_set_err); EXPORT_SYMBOL(netlink_broadcast); EXPORT_SYMBOL(netlink_unicast); @@ -418,9 +418,7 @@ EXPORT_SYMBOL(netlink_detach); EXPORT_SYMBOL(netlink_post); #endif -#endif -#ifdef CONFIG_RTNETLINK EXPORT_SYMBOL(rtattr_parse); EXPORT_SYMBOL(rtnetlink_links); EXPORT_SYMBOL(__rta_fill); @@ -430,7 +428,6 @@ EXPORT_SYMBOL(neigh_delete); EXPORT_SYMBOL(neigh_add); EXPORT_SYMBOL(neigh_dump_info); -#endif EXPORT_SYMBOL(dev_set_allmulti); EXPORT_SYMBOL(dev_set_promiscuity); @@ -553,9 +550,7 @@ EXPORT_SYMBOL(tcf_police); EXPORT_SYMBOL(tcf_police_locate); EXPORT_SYMBOL(tcf_police_destroy); -#ifdef CONFIG_RTNETLINK EXPORT_SYMBOL(tcf_police_dump); -#endif #endif #endif #ifdef CONFIG_NET_CLS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/packet/af_packet.c linux-2.5/net/packet/af_packet.c --- linux-2.5.1/net/packet/af_packet.c Tue Oct 30 23:08:12 2001 +++ linux-2.5/net/packet/af_packet.c Thu Dec 13 16:32:37 2001 @@ -5,7 +5,7 @@ * * PACKET - implements raw packet sockets. * - * Version: $Id: af_packet.c,v 1.57 2001/10/30 03:38:37 davem Exp $ + * Version: $Id: af_packet.c,v 1.58 2001/11/28 21:02:10 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -1902,3 +1902,4 @@ module_init(packet_init); module_exit(packet_exit); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/rose/af_rose.c linux-2.5/net/rose/af_rose.c --- linux-2.5.1/net/rose/af_rose.c Mon Sep 10 14:58:35 2001 +++ linux-2.5/net/rose/af_rose.c Sun Dec 30 21:17:30 2001 @@ -44,7 +44,6 @@ #include <linux/if_arp.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/fcntl.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/rose/rose_dev.c linux-2.5/net/rose/rose_dev.c --- linux-2.5.1/net/rose/rose_dev.c Thu Jun 28 00:10:55 2001 +++ linux-2.5/net/rose/rose_dev.c Sun Dec 30 21:17:30 2001 @@ -32,7 +32,6 @@ #include <linux/if_ether.h> /* For the statistics structure. */ #include <asm/system.h> -#include <asm/segment.h> #include <asm/io.h> #include <linux/inet.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/rose/rose_in.c linux-2.5/net/rose/rose_in.c --- linux-2.5.1/net/rose/rose_in.c Fri Dec 29 22:44:46 2000 +++ linux-2.5/net/rose/rose_in.c Sun Dec 30 21:17:30 2001 @@ -38,7 +38,6 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <net/ip.h> /* For ip_rcv */ -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/rose/rose_link.c linux-2.5/net/rose/rose_link.c --- linux-2.5.1/net/rose/rose_link.c Fri Dec 29 22:44:46 2000 +++ linux-2.5/net/rose/rose_link.c Sun Dec 30 21:17:30 2001 @@ -29,7 +29,6 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/rose/rose_out.c linux-2.5/net/rose/rose_out.c --- linux-2.5.1/net/rose/rose_out.c Fri Dec 29 22:44:46 2000 +++ linux-2.5/net/rose/rose_out.c Sun Dec 30 21:17:30 2001 @@ -30,7 +30,6 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/rose/rose_route.c linux-2.5/net/rose/rose_route.c --- linux-2.5.1/net/rose/rose_route.c Sat Jun 30 02:38:26 2001 +++ linux-2.5/net/rose/rose_route.c Sun Dec 30 21:17:30 2001 @@ -36,7 +36,6 @@ #include <linux/if_arp.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/fcntl.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/rose/rose_subr.c linux-2.5/net/rose/rose_subr.c --- linux-2.5.1/net/rose/rose_subr.c Sat Jun 30 02:38:26 2001 +++ linux-2.5/net/rose/rose_subr.c Sun Dec 30 21:17:30 2001 @@ -30,7 +30,6 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/rose/rose_timer.c linux-2.5/net/rose/rose_timer.c --- linux-2.5.1/net/rose/rose_timer.c Fri Dec 29 22:44:46 2000 +++ linux-2.5/net/rose/rose_timer.c Sun Dec 30 21:17:30 2001 @@ -30,7 +30,6 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/Config.in linux-2.5/net/sched/Config.in --- linux-2.5.1/net/sched/Config.in Sat Jan 15 03:18:53 2000 +++ linux-2.5/net/sched/Config.in Thu Dec 13 16:32:37 2001 @@ -1,8 +1,6 @@ # # Traffic control configuration. # -define_bool CONFIG_NETLINK y -define_bool CONFIG_RTNETLINK y tristate ' CBQ packet scheduler' CONFIG_NET_SCH_CBQ tristate ' CSZ packet scheduler' CONFIG_NET_SCH_CSZ #tristate ' H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/cls_api.c linux-2.5/net/sched/cls_api.c --- linux-2.5.1/net/sched/cls_api.c Sat Jan 8 00:57:13 2000 +++ linux-2.5/net/sched/cls_api.c Thu Dec 13 16:32:37 2001 @@ -97,8 +97,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK - static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n, struct tcf_proto *tp, unsigned long fh, int event); @@ -430,12 +428,9 @@ return skb->len; } -#endif - int __init tc_filter_init(void) { -#ifdef CONFIG_RTNETLINK struct rtnetlink_link *link_p = rtnetlink_links[PF_UNSPEC]; /* Setup rtnetlink links. It is made here to avoid @@ -448,7 +443,6 @@ link_p[RTM_GETTFILTER-RTM_BASE].doit = tc_ctl_tfilter; link_p[RTM_GETTFILTER-RTM_BASE].dumpit = tc_dump_tfilter; } -#endif #define INIT_TC_FILTER(name) { \ extern struct tcf_proto_ops cls_##name##_ops; \ register_tcf_proto_ops(&cls_##name##_ops); \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/cls_fw.c linux-2.5/net/sched/cls_fw.c --- linux-2.5.1/net/sched/cls_fw.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/cls_fw.c Thu Dec 13 16:32:37 2001 @@ -299,7 +299,6 @@ } } -#ifdef CONFIG_RTNETLINK static int fw_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { @@ -350,8 +349,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif - struct tcf_proto_ops cls_fw_ops = { NULL, @@ -365,11 +362,7 @@ fw_change, fw_delete, fw_walk, -#ifdef CONFIG_RTNETLINK fw_dump -#else - NULL -#endif }; #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/cls_route.c linux-2.5/net/sched/cls_route.c --- linux-2.5.1/net/sched/cls_route.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/cls_route.c Thu Dec 13 16:32:37 2001 @@ -550,7 +550,6 @@ } } -#ifdef CONFIG_RTNETLINK static int route4_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { @@ -606,7 +605,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct tcf_proto_ops cls_route4_ops = { NULL, @@ -620,11 +618,7 @@ route4_change, route4_delete, route4_walk, -#ifdef CONFIG_RTNETLINK route4_dump -#else - NULL -#endif }; #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/cls_rsvp.h linux-2.5/net/sched/cls_rsvp.h --- linux-2.5.1/net/sched/cls_rsvp.h Mon Dec 11 21:30:43 2000 +++ linux-2.5/net/sched/cls_rsvp.h Thu Dec 13 16:32:37 2001 @@ -615,7 +615,6 @@ } } -#ifdef CONFIG_RTNETLINK static int rsvp_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { @@ -672,7 +671,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct tcf_proto_ops RSVP_OPS = { NULL, @@ -686,11 +684,7 @@ rsvp_change, rsvp_delete, rsvp_walk, -#ifdef CONFIG_RTNETLINK rsvp_dump -#else - NULL -#endif }; #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/cls_tcindex.c linux-2.5/net/sched/cls_tcindex.c --- linux-2.5.1/net/sched/cls_tcindex.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/cls_tcindex.c Thu Dec 13 16:32:37 2001 @@ -421,8 +421,6 @@ } -#ifdef CONFIG_RTNETLINK - static int tcindex_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { @@ -481,9 +479,6 @@ return -1; } -#endif - - struct tcf_proto_ops cls_tcindex_ops = { NULL, "tcindex", @@ -496,11 +491,7 @@ tcindex_change, tcindex_delete, tcindex_walk, -#ifdef CONFIG_RTNETLINK tcindex_dump -#else - NULL -#endif }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/cls_u32.c linux-2.5/net/sched/cls_u32.c --- linux-2.5.1/net/sched/cls_u32.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/cls_u32.c Thu Dec 13 16:32:37 2001 @@ -635,7 +635,6 @@ } } -#ifdef CONFIG_RTNETLINK static int u32_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { @@ -694,7 +693,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct tcf_proto_ops cls_u32_ops = { NULL, @@ -708,11 +706,7 @@ u32_change, u32_delete, u32_walk, -#ifdef CONFIG_RTNETLINK u32_dump -#else - NULL -#endif }; #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/police.c linux-2.5/net/sched/police.c --- linux-2.5.1/net/sched/police.c Mon Aug 23 17:01:02 1999 +++ linux-2.5/net/sched/police.c Thu Dec 13 16:32:37 2001 @@ -219,7 +219,6 @@ return p->action; } -#ifdef CONFIG_RTNETLINK int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p) { unsigned char *b = skb->tail; @@ -250,5 +249,3 @@ skb_trim(skb, b - skb->data); return -1; } -#endif - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_api.c linux-2.5/net/sched/sch_api.c --- linux-2.5.1/net/sched/sch_api.c Fri Nov 9 22:12:54 2001 +++ linux-2.5/net/sched/sch_api.c Thu Dec 13 16:32:37 2001 @@ -41,12 +41,10 @@ #include <asm/system.h> #include <asm/bitops.h> -#ifdef CONFIG_RTNETLINK static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, struct Qdisc *old, struct Qdisc *new); static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, struct Qdisc *q, unsigned long cl, int event); -#endif /* @@ -379,8 +377,6 @@ return err; } -#ifdef CONFIG_RTNETLINK - /* Allocate and initialize new qdisc. @@ -1055,7 +1051,6 @@ dev_put(dev); return skb->len; } -#endif int psched_us_per_tick = 1; int psched_tick_per_us = 1; @@ -1169,9 +1164,7 @@ int __init pktsched_init(void) { -#ifdef CONFIG_RTNETLINK struct rtnetlink_link *link_p; -#endif #if PSCHED_CLOCK_SOURCE == PSCHED_CPU if (psched_calibrate_clock() < 0) @@ -1184,7 +1177,6 @@ #endif #endif -#ifdef CONFIG_RTNETLINK link_p = rtnetlink_links[PF_UNSPEC]; /* Setup rtnetlink links. It is made here to avoid @@ -1201,7 +1193,6 @@ link_p[RTM_GETTCLASS-RTM_BASE].doit = tc_ctl_tclass; link_p[RTM_GETTCLASS-RTM_BASE].dumpit = tc_dump_tclass; } -#endif #define INIT_QDISC(name) { \ extern struct Qdisc_ops name##_qdisc_ops; \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_atm.c linux-2.5/net/sched/sch_atm.c --- linux-2.5.1/net/sched/sch_atm.c Fri Feb 9 19:34:13 2001 +++ linux-2.5/net/sched/sch_atm.c Thu Dec 13 16:32:37 2001 @@ -619,8 +619,6 @@ } -#ifdef CONFIG_RTNETLINK - static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { @@ -668,9 +666,6 @@ return 0; } -#endif - - static struct Qdisc_class_ops atm_class_ops = { atm_tc_graft, /* graft */ @@ -685,9 +680,7 @@ atm_tc_bind_filter, /* bind_tcf */ atm_tc_put, /* unbind_tcf */ -#ifdef CONFIG_RTNETLINK atm_tc_dump_class, /* dump */ -#endif }; struct Qdisc_ops atm_qdisc_ops = @@ -707,9 +700,7 @@ atm_tc_destroy, /* destroy */ NULL, /* change */ -#ifdef CONFIG_RTNETLINK atm_tc_dump /* dump */ -#endif }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_cbq.c linux-2.5/net/sched/sch_cbq.c --- linux-2.5.1/net/sched/sch_cbq.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/sch_cbq.c Thu Dec 13 16:32:37 2001 @@ -1457,8 +1457,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK - static __inline__ int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl) { unsigned char *b = skb->tail; @@ -1658,8 +1656,6 @@ return -1; } -#endif - static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct Qdisc **old) { @@ -2082,9 +2078,7 @@ cbq_bind_filter, cbq_unbind_filter, -#ifdef CONFIG_RTNETLINK cbq_dump_class, -#endif }; struct Qdisc_ops cbq_qdisc_ops = @@ -2104,9 +2098,7 @@ cbq_destroy, NULL /* cbq_change */, -#ifdef CONFIG_RTNETLINK cbq_dump, -#endif }; #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_csz.c linux-2.5/net/sched/sch_csz.c --- linux-2.5.1/net/sched/sch_csz.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/sch_csz.c Thu Dec 13 16:32:37 2001 @@ -795,7 +795,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK static int csz_dump(struct Qdisc *sch, struct sk_buff *skb) { struct csz_sched_data *q = (struct csz_sched_data *)sch->data; @@ -817,8 +816,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif - static int csz_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, struct Qdisc **old) @@ -932,7 +929,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK static int csz_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { struct csz_sched_data *q = (struct csz_sched_data *)sch->data; @@ -978,7 +974,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif static void csz_walk(struct Qdisc *sch, struct qdisc_walker *arg) { @@ -1030,9 +1025,7 @@ csz_bind, csz_put, -#ifdef CONFIG_RTNETLINK csz_dump_class, -#endif }; struct Qdisc_ops csz_qdisc_ops = @@ -1052,9 +1045,7 @@ csz_destroy, NULL /* csz_change */, -#ifdef CONFIG_RTNETLINK csz_dump, -#endif }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_dsmark.c linux-2.5/net/sched/sch_dsmark.c --- linux-2.5.1/net/sched/sch_dsmark.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/sch_dsmark.c Thu Dec 13 16:32:37 2001 @@ -385,8 +385,6 @@ } -#ifdef CONFIG_RTNETLINK - static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { @@ -434,9 +432,6 @@ return -1; } -#endif - - static struct Qdisc_class_ops dsmark_class_ops = { dsmark_graft, /* graft */ @@ -451,9 +446,7 @@ dsmark_bind_filter, /* bind_tcf */ dsmark_put, /* unbind_tcf */ -#ifdef CONFIG_RTNETLINK dsmark_dump_class, /* dump */ -#endif }; struct Qdisc_ops dsmark_qdisc_ops = @@ -473,9 +466,7 @@ dsmark_destroy, /* destroy */ NULL, /* change */ -#ifdef CONFIG_RTNETLINK dsmark_dump /* dump */ -#endif }; #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_fifo.c linux-2.5/net/sched/sch_fifo.c --- linux-2.5.1/net/sched/sch_fifo.c Mon Aug 23 17:01:02 1999 +++ linux-2.5/net/sched/sch_fifo.c Thu Dec 13 16:32:37 2001 @@ -152,7 +152,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb) { struct fifo_sched_data *q = (void*)sch->data; @@ -168,7 +167,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct Qdisc_ops pfifo_qdisc_ops = { @@ -187,9 +185,7 @@ NULL, fifo_init, -#ifdef CONFIG_RTNETLINK fifo_dump, -#endif }; struct Qdisc_ops bfifo_qdisc_ops = @@ -208,7 +204,5 @@ fifo_reset, NULL, fifo_init, -#ifdef CONFIG_RTNETLINK fifo_dump, -#endif }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_generic.c linux-2.5/net/sched/sch_generic.c --- linux-2.5.1/net/sched/sch_generic.c Fri Aug 18 17:26:25 2000 +++ linux-2.5/net/sched/sch_generic.c Tue Jan 8 00:44:25 2002 @@ -475,10 +475,8 @@ dev_watchdog_down(dev); - while (test_bit(__LINK_STATE_SCHED, &dev->state)) { - current->policy |= SCHED_YIELD; - schedule(); - } + while (test_bit(__LINK_STATE_SCHED, &dev->state)) + yield(); spin_unlock_wait(&dev->xmit_lock); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_gred.c linux-2.5/net/sched/sch_gred.c --- linux-2.5.1/net/sched/sch_gred.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/sch_gred.c Thu Dec 13 16:32:37 2001 @@ -494,7 +494,6 @@ return -EINVAL; } -#ifdef CONFIG_RTNETLINK static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) { unsigned long qave; @@ -587,7 +586,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif static void gred_destroy(struct Qdisc *sch) { @@ -615,9 +613,7 @@ gred_reset, gred_destroy, gred_change, /* change */ -#ifdef CONFIG_RTNETLINK gred_dump, -#endif }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_ingress.c linux-2.5/net/sched/sch_ingress.c --- linux-2.5.1/net/sched/sch_ingress.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/sch_ingress.c Thu Dec 13 16:32:37 2001 @@ -304,9 +304,6 @@ } -#ifdef CONFIG_RTNETLINK - - static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb) { unsigned char *b = skb->tail; @@ -322,9 +319,6 @@ return -1; } -#endif - - static struct Qdisc_class_ops ingress_class_ops = { ingress_graft, /* graft */ @@ -339,9 +333,7 @@ ingress_bind_filter, /* bind_tcf */ ingress_put, /* unbind_tcf */ -#ifdef CONFIG_RTNETLINK NULL, /* dump */ -#endif }; struct Qdisc_ops ingress_qdisc_ops = @@ -361,9 +353,7 @@ ingress_destroy, /* destroy */ NULL, /* change */ -#ifdef CONFIG_RTNETLINK ingress_dump, /* dump */ -#endif }; #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_prio.c linux-2.5/net/sched/sch_prio.c --- linux-2.5.1/net/sched/sch_prio.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/sch_prio.c Thu Dec 13 16:32:37 2001 @@ -231,7 +231,6 @@ return 0; } -#ifdef CONFIG_RTNETLINK static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) { struct prio_sched_data *q = (struct prio_sched_data *)sch->data; @@ -247,7 +246,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct Qdisc **old) @@ -322,7 +320,6 @@ } -#ifdef CONFIG_RTNETLINK static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) { @@ -334,7 +331,6 @@ tcm->tcm_info = q->queues[cl-1]->handle; return 0; } -#endif static void prio_walk(struct Qdisc *sch, struct qdisc_walker *arg) { @@ -381,9 +377,7 @@ prio_bind, prio_put, -#ifdef CONFIG_RTNETLINK prio_dump_class, -#endif }; struct Qdisc_ops prio_qdisc_ops = @@ -403,9 +397,7 @@ prio_destroy, prio_tune, -#ifdef CONFIG_RTNETLINK prio_dump, -#endif }; #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_red.c linux-2.5/net/sched/sch_red.c --- linux-2.5.1/net/sched/sch_red.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/sch_red.c Thu Dec 13 16:32:37 2001 @@ -418,7 +418,6 @@ } -#ifdef CONFIG_RTNETLINK int red_copy_xstats(struct sk_buff *skb, struct tc_red_xstats *st) { RTA_PUT(skb, TCA_XSTATS, sizeof(*st), st); @@ -456,7 +455,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif static void red_destroy(struct Qdisc *sch) { @@ -480,9 +478,7 @@ red_destroy, red_change, -#ifdef CONFIG_RTNETLINK red_dump, -#endif }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_sfq.c linux-2.5/net/sched/sch_sfq.c --- linux-2.5.1/net/sched/sch_sfq.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/sch_sfq.c Thu Dec 13 16:32:37 2001 @@ -439,7 +439,6 @@ MOD_DEC_USE_COUNT; } -#ifdef CONFIG_RTNETLINK static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb) { struct sfq_sched_data *q = (struct sfq_sched_data *)sch->data; @@ -461,7 +460,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct Qdisc_ops sfq_qdisc_ops = { @@ -480,9 +478,7 @@ sfq_destroy, NULL, /* sfq_change */ -#ifdef CONFIG_RTNETLINK sfq_dump, -#endif }; #ifdef MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sched/sch_tbf.c linux-2.5/net/sched/sch_tbf.c --- linux-2.5.1/net/sched/sch_tbf.c Sun Sep 30 19:26:09 2001 +++ linux-2.5/net/sched/sch_tbf.c Thu Dec 13 16:32:37 2001 @@ -363,7 +363,6 @@ MOD_DEC_USE_COUNT; } -#ifdef CONFIG_RTNETLINK static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb) { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; @@ -391,7 +390,6 @@ skb_trim(skb, b - skb->data); return -1; } -#endif struct Qdisc_ops tbf_qdisc_ops = { @@ -410,9 +408,7 @@ tbf_destroy, tbf_change, -#ifdef CONFIG_RTNETLINK tbf_dump, -#endif }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/socket.c linux-2.5/net/socket.c --- linux-2.5.1/net/socket.c Wed Oct 17 21:38:28 2001 +++ linux-2.5/net/socket.c Tue Jan 8 00:44:25 2002 @@ -67,6 +67,8 @@ #include <linux/netdevice.h> #include <linux/proc_fs.h> #include <linux/wanrouter.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> #include <linux/init.h> #include <linux/poll.h> #include <linux/cache.h> @@ -79,11 +81,7 @@ #include <asm/uaccess.h> -#include <linux/inet.h> -#include <net/ip.h> #include <net/sock.h> -#include <net/tcp.h> -#include <net/udp.h> #include <net/scm.h> #include <linux/netfilter.h> @@ -150,8 +148,7 @@ while (atomic_read(&net_family_lockct) != 0) { spin_unlock(&net_family_lock); - current->policy |= SCHED_YIELD; - schedule(); + yield(); spin_lock(&net_family_lock); } @@ -1724,7 +1721,7 @@ * The netlink device handler may be needed early. */ -#ifdef CONFIG_RTNETLINK +#ifdef CONFIG_NET rtnetlink_init(); #endif #ifdef CONFIG_NETLINK_DEV diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sunrpc/auth_null.c linux-2.5/net/sunrpc/auth_null.c --- linux-2.5.1/net/sunrpc/auth_null.c Thu Aug 16 16:39:37 2001 +++ linux-2.5/net/sunrpc/auth_null.c Sun Dec 30 20:01:41 2001 @@ -7,11 +7,11 @@ */ #include <linux/types.h> -#include <linux/slab.h> #include <linux/socket.h> #include <linux/in.h> #include <linux/utsname.h> #include <linux/sunrpc/clnt.h> +#include <linux/sched.h> #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sunrpc/auth_unix.c linux-2.5/net/sunrpc/auth_unix.c --- linux-2.5.1/net/sunrpc/auth_unix.c Thu Aug 16 16:39:37 2001 +++ linux-2.5/net/sunrpc/auth_unix.c Sun Dec 30 20:01:41 2001 @@ -7,7 +7,7 @@ */ #include <linux/types.h> -#include <linux/slab.h> +#include <linux/sched.h> #include <linux/socket.h> #include <linux/in.h> #include <linux/sunrpc/clnt.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sunrpc/sched.c linux-2.5/net/sunrpc/sched.c --- linux-2.5.1/net/sunrpc/sched.c Thu Oct 11 15:12:52 2001 +++ linux-2.5/net/sunrpc/sched.c Tue Jan 8 00:44:25 2002 @@ -772,8 +772,7 @@ } if (flags & RPC_TASK_ASYNC) return NULL; - current->policy |= SCHED_YIELD; - schedule(); + yield(); } while (!signalled()); return NULL; @@ -1114,8 +1113,7 @@ __rpc_schedule(); if (all_tasks) { dprintk("rpciod_killall: waiting for tasks to exit\n"); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } @@ -1185,8 +1183,7 @@ * wait briefly before checking the process id. */ current->sigpending = 0; - current->policy |= SCHED_YIELD; - schedule(); + yield(); /* * Display a message if we're going to wait longer. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/sunrpc/xprt.c linux-2.5/net/sunrpc/xprt.c --- linux-2.5.1/net/sunrpc/xprt.c Mon Oct 8 19:36:07 2001 +++ linux-2.5/net/sunrpc/xprt.c Thu Dec 13 16:32:37 2001 @@ -630,10 +630,14 @@ int to_move = cur_len; if (to_move > copied) to_move = copied; - if (need_csum) - csum = skb_copy_and_csum_bits(skb, offset, cur_ptr, - to_move, csum); - else + if (need_csum) { + unsigned int csum2; + + csum2 = skb_copy_and_csum_bits(skb, offset, + cur_ptr, + to_move, 0); + csum = csum_block_add(csum, csum2, offset); + } else skb_copy_bits(skb, offset, cur_ptr, to_move); offset += to_move; copied -= to_move; @@ -647,8 +651,12 @@ } } if (need_csum) { - if (slack > 0) - csum = skb_checksum(skb, offset, slack, csum); + if (slack > 0) { + unsigned int csum2; + + csum2 = skb_checksum(skb, offset, slack, 0); + csum = csum_block_add(csum, csum2, offset); + } if ((unsigned short)csum_fold(csum)) return -1; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/unix/af_unix.c linux-2.5/net/unix/af_unix.c --- linux-2.5.1/net/unix/af_unix.c Mon Nov 5 16:32:32 2001 +++ linux-2.5/net/unix/af_unix.c Mon Jan 14 22:39:50 2002 @@ -564,10 +564,8 @@ addr->hash)) { write_unlock(&unix_table_lock); /* Sanity yield. It is unusual case, but yet... */ - if (!(ordernum&0xFF)) { - current->policy |= SCHED_YIELD; - schedule(); - } + if (!(ordernum&0xFF)) + yield(); goto retry; } addr->hash ^= sk->type; @@ -1053,8 +1051,12 @@ */ skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err); - if (!skb) + if (!skb) { + /* This means receive shutdown. */ + if (err == 0) + err = -EINVAL; goto out; + } tsk = skb->sk; skb_free_datagram(sk, skb); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/x25/af_x25.c linux-2.5/net/x25/af_x25.c --- linux-2.5.1/net/x25/af_x25.c Mon Sep 10 14:58:35 2001 +++ linux-2.5/net/x25/af_x25.c Sun Dec 30 21:17:30 2001 @@ -46,7 +46,6 @@ #include <linux/if_arp.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/fcntl.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/x25/x25_dev.c linux-2.5/net/x25/x25_dev.c --- linux-2.5.1/net/x25/x25_dev.c Mon Jan 22 21:32:10 2001 +++ linux-2.5/net/x25/x25_dev.c Sun Dec 30 21:17:30 2001 @@ -33,7 +33,6 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/fcntl.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/x25/x25_facilities.c linux-2.5/net/x25/x25_facilities.c --- linux-2.5.1/net/x25/x25_facilities.c Wed Jan 24 23:28:36 2001 +++ linux-2.5/net/x25/x25_facilities.c Sun Dec 30 21:17:30 2001 @@ -32,7 +32,6 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/x25/x25_in.c linux-2.5/net/x25/x25_in.c --- linux-2.5.1/net/x25/x25_in.c Wed Jan 24 23:28:36 2001 +++ linux-2.5/net/x25/x25_in.c Sun Dec 30 21:17:30 2001 @@ -37,7 +37,6 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <net/ip.h> /* For ip_rcv */ -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/x25/x25_link.c linux-2.5/net/x25/x25_link.c --- linux-2.5.1/net/x25/x25_link.c Sat Jun 30 02:38:26 2001 +++ linux-2.5/net/x25/x25_link.c Sun Dec 30 21:17:30 2001 @@ -34,7 +34,6 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/fcntl.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/x25/x25_out.c linux-2.5/net/x25/x25_out.c --- linux-2.5.1/net/x25/x25_out.c Thu Apr 12 19:11:39 2001 +++ linux-2.5/net/x25/x25_out.c Sun Dec 30 21:17:30 2001 @@ -35,7 +35,6 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/x25/x25_route.c linux-2.5/net/x25/x25_route.c --- linux-2.5.1/net/x25/x25_route.c Mon Jan 22 21:32:10 2001 +++ linux-2.5/net/x25/x25_route.c Sun Dec 30 21:17:30 2001 @@ -33,7 +33,6 @@ #include <linux/if_arp.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/fcntl.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/x25/x25_subr.c linux-2.5/net/x25/x25_subr.c --- linux-2.5.1/net/x25/x25_subr.c Sat Jun 30 02:38:26 2001 +++ linux-2.5/net/x25/x25_subr.c Sun Dec 30 21:17:30 2001 @@ -34,7 +34,6 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> diff -urN --exclude-from=/home/davej/.exclude linux-2.5.1/net/x25/x25_timer.c linux-2.5/net/x25/x25_timer.c --- linux-2.5.1/net/x25/x25_timer.c Wed Jan 24 23:28:36 2001 +++ linux-2.5/net/x25/x25_timer.c Sun Dec 30 21:17:30 2001 @@ -32,7 +32,6 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> -#include <asm/segment.h> #include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h>