S: USA
N: Johan Myreen
-E: jem@vipunen.hut.fi
+E: jem@iki.fi
D: PS/2 mouse driver writer etc.
S: Dragonvagen 1 A 13
S: FIN-00330 Helsingfors
S: 90491 Nuernberg
S: Germany
+N: Geert Uytterhoeven
+E: geert@linux-m68k.org
+W: http://www.cs.kuleuven.ac.be/~geert/
+P: 1024/EC4A1EE1 8B 88 38 35 88 1E 95 A1 CD 9E AE DC 4B 4A 2F 41
+D: m68k/Amiga and PPC/CHRP Longtrail coordinator
+D: Frame buffer device and XF68_FBDev maintainer
+D: m68k IDE maintainer
+D: Amiga Zorro maintainer
+S: C. Huysmansstraat 12
+S: B-3128 Baal
+S: Belgium
+
N: Petr Vandrovec
E: vandrove@vc.cvut.cz
D: Small contributions to ncpfs
S: The Netherlands
N: David Woodhouse
+E: Dave@mvhi.com
E: Dave@imladris.demon.co.uk
D: Extensive ARCnet rewrite
D: ARCnet COM20020, COM90xx IO-MAP drivers
D: SO_BINDTODEVICE in 2.1.x (from Elliot Poger's code in 2.0.31)
D: Contributed to NCPFS rewrite for 2.1.x dcache
D: Alpha platforms: SX164, LX164 and Ruffian ported to 2.1.x
-S: Robinson College, Grange Road
-S: Cambridge. CB3 9AN
+S: 29, David Bull Way
+S: Milton, Cambridge. CB4 6DP
S: England
N: Frank Xia
Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
needs.
-Last updated: September 3, 1998
+Last updated: October 9, 1998
Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu).
Current Minimal Requirements
encountered a bug! If you're unsure what version you're currently
running, the suggested command should tell you.
-- Kernel modules 2.1.85 ; insmod -V
+- Kernel modules 2.1.121 ; insmod -V
- Gnu C 2.7.2.3 ; gcc --version
- Binutils 2.8.1.0.23 ; ld -v
-- Linux C Library 5.4.46 ; ls -l /lib/libc.so.*
+- Linux libc5 C Library 5.4.46 ; ls -l /lib/libc.so.*
+- Linux libc6 C Library 2.0.7pre6 ; ls -l /lib/libc.so.*
- Dynamic Linker (ld.so) 1.9.9 ; ldd --version or ldd -v
- Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.*
-- Procps 1.2.8 ; ps --version
+- Procps 1.2.9 ; ps --version
- Procinfo 14 ; procinfo -v
- Psmisc 17 ; pstree -V
- Mount 2.7l ; mount --version
- Loadlin 1.6a
- Sh-utils 1.16 ; basename --v
- Autofs 0.3.11 ; automount --version
-- NFS 0.4.21 ; showmount --version
+- NFS 2.2beta37 ; showmount --version
- Bash 1.14.7 ; bash -version
- Ncpfs 2.2.0 ; ncpmount -v
- Pcmcia-cs 3.0.5 ; cardmgr -V
more information, see the files in Documentation/fb/ ; you may also
need to download the fbset utilities.
-Libc
-====
+Libc (libc5)
+============
Linux-2.1.x is ELF-only. You can still compile a.out apps if you
really want, but your kernel must be compiled ELF. If you can't
accompanying release notes. The section about it breaking make is not
a joke.
+GNU libc (libc6)
+================
+
+ Older versions of GNU libc (libc6) have a bug in the dynamic linker.
+/etc/ld.so.cache gets mapped into memory and is never unmapped. If one
+of your boot scripts calls ldconfig, /etc/ld.so.cache is deleted. Init,
+however, still references that file; as of 2.1.122, the kernel will
+consequently not be able to remount the root file system r/o at system
+shutdown. To fix this, upgrade to at least the pre6 release of GNU
+libc 2.0.7. As a temporary workaround, modify your boot scripts to do
+the following before calling ldconfig:
+
+ ln -f /etc/ld.so.cache /etc/ld.so.cache.old
+
Modules
=======
- You need to upgrade to modutils-2.1.85 for kernels 2.1.85 and later.
-This version will also work with 2.0.x kernels.
+ You need to upgrade to the latest version of modutils-2.1.x for
+development kernels. This version will also work with 2.0.x kernels.
As of 2.1.90-pre1, kerneld has been replaced by a kernel thread,
kmod. See Documentation/kmod.txt for more information. The main
features like IPv6.
As of 2.1.102, the IP firewalling code has been replaced; ipfwadm
-will no longer work. You need to optain "ipchains," available from
+will no longer work. You need to obtain "ipchains," available from
http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html, and use
that instead of ipfwadm.
- To use port forwarding and auto forwarding you will need 'ipmasqadm'
-tool, available from http://juanjox.home.ml.org.
+ To use port forwarding and auto forwarding you will need to obtain
+"ipmasqadm," available from http://juanjox.home.ml.org/.
Memory
======
/dev/lp0 with the new Plug-and-Play driver. If printing breaks with
the new driver, try checking your lpd configuration.
+Setserial
+=========
+
+ If you experience random problems (stuck lines, lost characters,
+etc.) with serial lines under recent kernels, upgrading setserial
+should help.
+
Syncookies
==========
ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.23
ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.23
-The 2.9.1.0.7 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.7-glibc.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.7-libc5.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.7.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.7-glibc.x86.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.7-libc5.x86.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.7.tar.gz
+The 2.9.1.0.12 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.12-glibc.x86.tar.gz
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.12-libc5.x86.tar.gz
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.12.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.12-glibc.x86.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.12-libc5.x86.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.12.tar.gz
Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.7
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.7
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.12
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.12
Gnu C
=====
-The 2.7.2.3 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/gcc-2.7.2.3.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/gcc-2.7.2.3.bin.tar.gz
-Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.gcc-2.7.2.3
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2.3
-
-The egcs-1.0.2 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.2-glibc.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.2-libc5.x86.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.2-glibc.x86.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.2-libc5.x86.tar.gz
+The egcs-1.0.3 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-glibc.x86.tar.bz2
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-libc5.x86.tar.bz2
+ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.3-glibc.x86.tar.bz2
+ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.3-libc5.x86.tar.bz2
Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.2
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.egcs-1.0.2
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.3
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.egcs-1.0.3
Gnu C 2.7.2.3 source:
ftp://prep.ai.mit.edu/pub/gnu/gcc-2.7.2.3.tar.gz
Linux C Library
===============
-The 5.4.46 release:
+The (libc5) 5.4.46 release:
ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.46.bin.tar.gz
ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.46.bin.tar.gz
Installation notes for 5.4.46:
ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.46
ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.46
+The (libc6) GNU libc 2.0.7pre6 release:
+ftp://ftp.kernel.org/pub/software/libs/glibc/glibc-2.0.7pre6.tar.gz
+ftp://ftp.kernel.org/pub/software/libs/glibc/glibc-2.0.7pre6.tar.bz2
+
Linux C++ Library
=================
Modules utilities
=================
-The 2.1.85 release:
-ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.85.tar.gz
+The 2.1.121 release:
+ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.121.tar.gz
Procps utilities
================
The 1.2 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.8.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.8.tgz
+ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.9.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.9.tgz
Procinfo utilities
==================
DOSEMU
======
-The 0.66.7 release:
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.66.7.tgz
+The 0.98.1 release:
+ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.98.1.tgz
+ftp://ftp.dosemu.org/dosemu/dosemu-0.98.1.tgz
Loadlin
=======
NFS
===
-The user-land 0.4.21 release:
-ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz
-ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz
+The user-land 2.2beta37 release:
+ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/nfs-server-2.2beta37.tar.gz
+ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/nfs-server-2.2beta37.tar.gz
-The kernel-level 8/30/98 release:
-ftp://ftp.yggdrasil.com/private/hjl/knfsd-980830.tar.gz
+The kernel-level 9/30/98 release:
+ftp://ftp.yggdrasil.com/private/hjl/knfsd-980930.tar.gz
+ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-980930.tar.gz
Net-tools
=========
The 3.0.5 release:
ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.5.tar.gz
+Setserial
+=========
+
+The 2.14 release:
+ftp://tsx-11.mit.edu/pub/linux/sources/sbin/setserial-2.14.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/serial/setserial-2.14.tar.gz
+
PPP
===
IP Masq Adm
===========
+
The 0.4.1 release:
http://juanjox.home.ml.org/ipmasqadm-0.4.1.tar.gz
your favorite Red Hat mirror site before installing the non-RPM
version. Remember, you might need to use the -force option to get the
upgrade to install. ftp://ftp.redhat.com/pub/contrib/ will have almost
-everything you need, as does Red Hat 5.0.
+everything you need, and Red Hat 5.1 ships with most necessary software.
Those of you running Debian (or a different distribution that
supports .deb packages) can look in the "unstable" and
"project/experimental" directories of your favorite Debian mirror. The
-Debian 2.0 release should have most packages you need as well.
+Debian 2.0 release ships with most packages you need as well.
For others, David Bourgin has put together a package of everything
necessary to quickly and easily upgrade to 2.1.x. See
Say Y here to enable support in the dumb serial driver to support
the HUB6 card.
-TGA Console Support
-CONFIG_TGA_CONSOLE
- Many Alpha systems (e.g the Multia) are shipped with a graphics card
- that implements the TGA interface (much like the VGA standard, but
- older TGA adapters are *not* VGA compatible). On such systems, you
- should say Y here so that the TGA driver rather than the standard
- VGA driver is used. Note that, at this time, there is no X server
- for these systems. If unsure, try N.
-
PCI support
CONFIG_PCI
Find out whether you have a PCI motherboard. PCI is the name of a
This is a backward compatibility option, choose Y for now.
This option will be removed soon.
+HIgh Performance Parallel Interface support (EXPERIMENTAL)
+CONFIG_HIPPI
+ HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
+ 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI
+ can run over copper (25m) or fiber (300m on multi-mode or 10km on
+ single-mode). If you are connected to a HIPPI network, and want
+ to enable HIPPI support in the kernel, say Y here (you must also
+ remember to enable the driver for your HIPPI card below). Most
+ people will say N here.
+
SCSI support?
CONFIG_SCSI
If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or
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@cam.ac.uk, especially if it works!
+ please mail David.Woodhouse@mvhi.com, 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
say more than an occasional beep, by programming the PC speaker.
Kernel patches and programs to do that are in the pcsndrv package on
ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console/ and in the
- pcsp patch at ftp://dwmw2.robinson.cam.ac.uk/pub/kernel/ .
+ pcsp patch at http://www.imladris.demon.co.uk/pcsp/
OSS sound modules
CONFIG_SOUND_OSS
Ariadne support
CONFIG_ARIADNE
- If you have a VillageTronics Ariadne Ethernet adapter, say Y.
+ If you have a Village Tronic Ariadne Ethernet adapter, say Y.
Otherwise, say N.
This driver is also available as a module ( = code which can be
Ariadne II support
CONFIG_ARIADNE2
- If you have a VillageTronics Ariadne II Ethernet adapter, say Y.
+ If you have a Village Tronic Ariadne II Ethernet adapter, say Y.
Otherwise, say N.
This driver is also available as a module ( = code which can be
Say 'Y' here for ARM systems with the VIDC video controller and 16-bit
Linear sound DACs. If unsure, say N.
+Backward compatibility mode for Xpmac
+CONFIG_FB_COMPAT_XPMAC
+ If you use the Xpmac X server (common with mklinux), you'll need
+ to enable this to use X. You should consider changing to XFree86
+ which includes a server that supports the frame buffer device
+ directly (XF68_FBDev).
+
+Support for PowerMac keyboard
+CONFIG_MAC_KEYBOARD
+ This option allows you to use an ADB keyboard attached to your
+ machine. Note that this disables any other (ie. PS/2) keyboard
+ support, even if your machine is physically capable of using both
+ at the same time.
+
+ 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.
+
+Support for PowerMac floppy
+CONFIG_MAC_FLOPPY
+ If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple)
+ floppy controller, say Y here. Most commonly found in PowerMacs.
+
+Support for PowerMac serial ports
+CONFIG_MAC_SERIAL
+ If you have Macintosh style serial ports (8 pin mini-DIN), this
+ is the driver for them. If you also have regular serial ports
+ and enable the driver for them, you can't currently use the
+ serial console feature.
+
+Support for PowerMac ADB mouse
+CONFIG_ADBMOUSE
+ If you have an ADB mouse (4 pin connector) as is common on
+ Macintoshes, say Y here.
+
+Winbond SL82c105 support
+CONFIG_BLK_DEV_SL82C105
+ If you have a Winbond SL82c105 IDE controller, say Y here to
+ enable special configuration for this chip. This is common
+ on various CHRP motherboards, but could be used elsewhere.
+ If in doubt, say Y.
#
# A couple of things I keep forgetting:
# capitalize: AppleTalk, Ethernet, DMA, FTP, Internet, Intel, IRQ,
# LocalWords: INSNS Ataris AutoConfig ZORRO OCS AMIFB Agnus Denise ECS CDTV GB
# LocalWords: AGA Cybervision CYBER GSP TMS DMI Zorro ACSI ROMs SLM BioNet GVP
# LocalWords: PAMsNet TekMagic Cyberstorm MkI CYBERSTORMII MkII BLZ onboard cx
-# LocalWords: VillageTronics ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB
+# LocalWords: Village Tronic ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB
# LocalWords: Rhotron BioData's Multiface AMIGAMOUSE COPCON Amiga's bitplanes
# LocalWords: ATARIMOUSE MFPSER SCC's MegaSTE ESCC Atari's GVPIOEXT DMASOUND
# LocalWords: fdutils cisco univercd rpcg htm iface lapb LAPBETHER tpqic qic
- use and state info about Linux/PPC on MP machines
sound.txt
- info on sound support under Linux/PPC
-
+zImage_layout.txt
+ - info on the kernel images for Linux/PPC
(Cort Dougan, cort@cs.nmt.edu) please email me if you have questions,
comments or corrections.
-Last Change: 4.1.98
+Last Change: 10.8.98
SMP support for Linux/PPC is still in its early stages and likely to
be buggy for a while. If you want to help by writing code or testing
1. State of Supported Hardware
- PowerSurge Architecture - UMAX s900, Apple 9500/9600/8500/8600/7500/7600
+ PowerSurge Architecture - tested on UMAX s900, Apple 9600
The second processor on this machine boots up just fine and
enters its idle loop. Hopefully a completely working SMP kernel
on this machine will be done shortly.
necessary to work with any number would not be overly difficult but
I don't have any machines with >2 processors so it's not high on my
list of priorities. If anyone else would like do to the work email
- me and I can point out the places that need changed.
+ me and I can point out the places that need changed. If you have >2
+ processors and don't want to add support yourself let me know and I
+ can take a look into it.
BeBox
BeBox support hasn't been added to the 2.1.X kernels from 2.0.X
Information about PowerPC Sound support
=====================================================================
-Please mail me me (Cort Dougan, cort@cs.nmt.edu) if you have questions,
+Please mail me (Cort Dougan, cort@cs.nmt.edu) if you have questions,
comments or corrections.
Last Change: 3.24.98
--- /dev/null
+ Information about the Linux/PPC kernel images
+=====================================================================
+
+Please mail me me (Cort Dougan, cort@cs.nmt.edu) if you have questions,
+comments or corrections.
+
+This document is meant to answer several questions I've had about how
+the PReP system boots and how Linux/PPC interacts with that mechanism.
+It would be nice if we could have information on how other architectures
+boot here as well. If you have anything to contribute, please
+let me know.
+
+
+1. PReP boot file
+
+ This is the file necessary to boot PReP systems from floppy or
+ hard drive. The firmware reads the PReP partition table entry
+ and will load the image accordingly.
+
+ To boot the zImage, copy it onto a floppy with dd if=zImage of=/dev/fd0h1440
+ or onto a PReP hard drive partition with dd if=zImage of=/dev/sda4
+ assuming you've created a PReP partition (type 0x41) with fdisk on
+ /dev/sda4.
+
+ The layout of the image format is:
+
+ 0x0 +------------+
+ | | PReP partition table entry
+ | |
+ 0x400 +------------+
+ | | Bootstrap program code + data
+ | |
+ | |
+ +------------+
+ | | compressed kernel, elf header removed
+ +------------+
+ | | initrd (if loaded)
+ +------------+
+ | | Elf section table for bootstrap program
+ +------------+
+
+
+2. MBX boot file
+
+ The MBX boards can load an elf image, and relocate it to the
+ proper location in memory - it copies the image to the location it was
+ linked at.
-Getting Firmware
-~~~~~~~~~~~~~~~~
-
-See the end of this document on how to obtain and create the necessary
-firmware files.
-
-
-Supported Features
-~~~~~~~~~~~~~~~~~~
-
-Currently digital audio and mixer functionality is supported. (memory
-mapped digital audio is not yet supported). Modular MultiSound
-support is composed of the following modules:
-
-msnd - MultiSound base (requires soundcore)
-msnd_classic - Base audio/mixer support for Classic, Monetery and
- Tahiti cards
-msnd_pinnacle - Base audio/mixer support for Pinnacle and Fiji cards
-
-
-Important Notes - Read Before Using
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* The firmware files are not included (may change in future). You
-must obtain these images from Turtle Beach (they are included in the
-MultiSound Development Kits), and place them in /etc/sound for
-example, and give the full paths in the Linux configuration. Please
-note these files must be binary files, not assembler.
-
-* You need the following information to use this driver: the card's
-I/O base (i.e. 0x250), the IRQ (i.e. 5), and the shared memory area
-(i.e. 0xd8000).
-
-* Probing is not currently implemented, and only the msnd_classic
-driver will actually program the card's IRQ and SMA locations; the
-msnd_pinnacle is primarily for use with the card in PnP mode, however
-it should work if you know what the card's resource values are (this
-will change in the future).
-
-* Note the Turtle Beach Pinnacle card contains a Kurzweil MA-1
-synthesizer with an MPU compatible interface, which should work with
-the mpu401 module. You must know the resource values of the MA-1.
-
-
-Examples
-~~~~~~~~
-
-* If you have a MultiSound Classic/Monterey/Tahiti:
-
-insmod soundcore
-insmod msnd
-insmod msnd_classic io=0x290 irq=7 mem=0xd0000
-
-* If you have a MultiSound Pinnacle:
-
-insmod soundcore
-insmod msnd
-insmod msnd_pinnacle io=0x210 irq=5 mem=0xd8000
-
-* To use the MPU-compatible Kurzweil synth on the Pinnacle, add the
-following:
-
-insmod sound
-insmod mpu401 io=0x330 irq=9
-
-
-msnd_classic, msnd_pinnacle Required Options
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If the following options are not given, the module will not load.
-Examine the kernel message log for informative error messages.
-WARNING--probing isn't supported so try to make sure you have the
-correct shared memory area, otherwise you may experience problems.
-
-io I/O base of DSP, e.g. io=0x210
-irq IRQ number, e.g. irq=5
-mem Shared memory area, e.g. mem=0xd8000
-
-
-msnd_classic, msnd_pinnacle Additional Options
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-fifosize The digital audio FIFOs, in kilobytes. The
- default is 64kB (two FIFOs are allocated, so
- this uses up 128kB).
-
-calibrate_signal Setting this to one calibrates the ADCs to the
- signal, zero calibrates to the card (defaults
- to zero).
-
-
-msnd_pinnacle Additional Options
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-digital Specify digital=1 to enable the S/PDIF input
- if you have the digital daughterboard
- adapter. This will enable access to the
- DIGITAL1 input for the soundcard in the mixer.
- Some mixer programs might have trouble setting
- the DIGITAL1 source as an input. If you have
- trouble, you can try the setdigital.c program
- at the bottom of this document.
-
-
-Obtaining and Creating Firmware Files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- For the Classic/Tahiti/Monterey
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Download to /tmp and unzip the following file from Turtle Beach:
-
- ftp://ftp.tbeach.com/pub/tbs/pinn/msndvkit.zip
-
-When unzipped, unzip the file named MsndFiles.zip. Then copy the
-following firmware files to /etc/sound (note the file renaming):
-
- cp DSPCODE/MSNDINIT.BIN /etc/sound/msndinit.bin
- cp DSPCODE/MSNDPERM.REB /etc/sound/msndperm.bin
-
-When configuring the Linux kernel, specify /etc/sound/msndinit.bin and
-/etc/sound/msndperm.bin for the two firmware files (Linux kernel
-versions older than 2.2 do not ask for firmware paths, and are
-hardcoded to /etc/sound).
-
-
- For the Pinnacle/Fiji
- ~~~~~~~~~~~~~~~~~~~~~
-
-Download to /tmp and unzip the following file from Turtle Beach (be
-sure to use the entire URL; some have had trouble navigating to the
-URL):
-
- ftp://ftp.tbeach.com/oldpub/tbs/pinn/pnddk100.zip
-
-Put the following lines into a file named conv.l (between the start
-and end lines):
-
--- conv.l start --
-%%
-[ \n\t,\r]
-\;.*
-DB
-[0-9A-Fa-f]+H { int n; sscanf(yytext, "%xH", &n); printf("%c", n); }
--- conv.l end --
-
-Then, compile the conv program with GNU make with the following
-command:
-
- make LEX=flex LOADLIBES=-lfl conv
-
-This should give you an executable named conv. Now, we create the
-binary firmware files by doing the following conversion (assuming the
-archive unpacked into a directory named PINNDDK):
-
- ./conv < PINNDDK/dspcode/pndspini.asm > /etc/sound/pndspini.bin
- ./conv < PINNDDK/dspcode/pndsperm.asm > /etc/sound/pndsperm.bin
-
-The conv (and conv.l) program is not needed after conversion and can
-be safely deleted. Then, when configuring the Linux kernel, specify
-/etc/sound/pndspini.bin and /etc/sound/pndsperm.bin for the two
-firmware files (Linux kernel versions older than 2.2 do not ask for
-firmware paths, and are hardcoded to /etc/sound).
-
-
-Recording from the S/PDIF Input
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you have a Pinnacle or Fiji with S/PDIF input and want to set it as
-the input source, you can use this program if you have trouble trying
-to do it with a mixer program (be sure to insert the module with the
-digital=1 option).
-
-Compile with:
-cc -O setdigital.c -o setdigital
-
--- start setdigital.c --
+#! /bin/sh
+#
+# Turtle Beach MultiSound Driver Notes
+# -- Andrew Veliath <andrewtv@usa.net>
+#
+# Last update: September 10, 1998
+# Corresponding msnd driver: 0.8.2
+#
+# ** This file is a README (top part) and shell archive (bottom part).
+# The corresponding archived utility sources can be unpacked by
+# running `sh MultiSound' (the utilities are only needed for the
+# Pinnacle and Fiji cards). **
+#
+#
+# -=-=- Getting Firmware -=-=-
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# See the section `Obtaining and Creating Firmware Files' in this
+# document for instructions on obtaining the necessary firmware
+# files.
+#
+#
+# Supported Features
+# ~~~~~~~~~~~~~~~~~~
+#
+# Currently, full-duplex digital audio (/dev/dsp only, /dev/audio is
+# not currently available) and mixer functionality (/dev/mixer) are
+# supported (memory mapped digital audio is not yet supported).
+# Digital transfers and monitoring can be done as well if you have
+# the digital daughterboard (see the section on using the S/PDIF port
+# for more information).
+#
+# Support for the Turtle Beach MultiSound Hurricane architecture is
+# composed of the following modules (these can also operate compiled
+# into the kernel):
+#
+# msnd - MultiSound base (requires soundcore)
+#
+# msnd_classic - Base audio/mixer support for Classic, Monetery and
+# Tahiti cards
+#
+# msnd_pinnacle - Base audio/mixer support for Pinnacle and Fiji cards
+#
+#
+# Important Notes - Read Before Using
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# The firmware files are not included (may change in future). You
+# must obtain these images from Turtle Beach (they are included in
+# the MultiSound Development Kits), and place them in /etc/sound for
+# example, and give the full paths in the Linux configuration. If
+# you are compiling in support for the MultiSound driver rather than
+# using it as a module, these firmware files must be accessible
+# during kernel compilation.
+#
+# Please note these files must be binary files, not assembler. See
+# the section later in this document for instructions to obtain these
+# files.
+#
+#
+# Configuring Card Resources
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# ** This section is very important, as your card may not work at all
+# or your machine may crash if you do not do this correctly. **
+#
+# * Classic/Monterey/Tahiti
+#
+# These cards are configured through the driver msnd_classic. You must
+# know the io port, then the driver will select the irq and memory resources
+# on the card. It is up to you to know if these are free locations or now,
+# a conflict can lock the machine up.
+#
+# * Pinnacle/Fiji
+#
+# The Pinnacle and Fiji cards have an extra config port, either
+# 0x250, 0x260 or 0x270. This port can be disabled to have the card
+# configured strictly through PnP, however you lose the ability to
+# access the IDE controller and joystick devices on this card when
+# using PnP. The included pinnaclecfg program in this shell archive
+# can be used to configure the card in non-PnP mode, and in PnP mode
+# you can use isapnptools. These are described briefly here.
+#
+# pinnaclecfg is not required; you can use the msnd_pinnacle module
+# to fully configure the card as well. However, pinnaclecfg can be
+# used to change the resource values of a particular device after the
+# msnd_pinnacle module has been loaded. If you are compiling the
+# driver into the kernel, you must set these values during compile
+# time, however other peripheral resource values can be changed with
+# the pinnaclecfg program after the kernel is loaded.
+#
+#
+# *** PnP mode
+#
+# Use pnpdump to obtain a sample configuration if you can; I was able
+# to obtain one with the command `pnpdump 1 0x203' -- this may vary
+# for you (running pnpdump by itself did not work for me). Then,
+# edit this file and use isapnp to uncomment and set the card values.
+# Use these values when inserting the msnd_pinnacle module. Using
+# this method, you can set the resources for the DSP and the Kurzweil
+# synth (Pinnacle). Since Linux does not directly support PnP
+# devices, you may have difficulty when using the card in PnP mode
+# when it the driver is compiled into the kernel. Using non-PnP mode
+# is preferable in this case.
+#
+# Here is an example mypinnacle.conf for isapnp that sets the card to
+# io base 0x210, irq 5 and mem 0xd8000, and also sets the Kurzweil
+# synth to 0x330 and irq 9 (may need editing for your system):
+#
+# (READPORT 0x0203)
+# (CSN 2)
+# (IDENTIFY *)
+#
+# # DSP
+# (CONFIGURE BVJ0440/-1 (LD 0
+# (INT 0 (IRQ 5 (MODE +E))) (IO 0 (BASE 0x0210)) (MEM 0 (BASE 0x0d8000))
+# (ACT Y)))
+#
+# # Kurzweil Synth (Pinnacle Only)
+# (CONFIGURE BVJ0440/-1 (LD 1
+# (IO 0 (BASE 0x0330)) (INT 0 (IRQ 9 (MODE +E)))
+# (ACT Y)))
+#
+# (WAITFORKEY)
+#
+#
+# *** Non-PnP mode
+#
+# The second way is by running the card in non-PnP mode. This
+# actually has some advantages in that you can access some other
+# devices on the card, such as the joystick and IDE controller. To
+# configure the card, unpack this shell archive and build the
+# pinnaclecfg program. Using this program, you can assign the
+# resource values to the card's devices, or disable the devices. As
+# an alternative to using pinnaclecfg, you can specify many of the
+# configuration values when loading the msnd_pinnacle module (or
+# during kernel configuration when compiling the driver into the
+# kernel).
+#
+# If you specify cfg=0x250 for the msnd_pinnacle module, it
+# automatically configure the card to the given io, irq and memory
+# values using that config port (the config port is jumper selectable
+# on the card to 0x250, 0x260 or 0x270).
+#
+# See the `msnd_pinnacle Additional Options' section below for more
+# information on these parameters (also, if you compile the driver
+# directly into the kernel, these extra parameters can be useful
+# here).
+#
+#
+# ** It is very easy to cause problems in your machine if you choose a
+# resource value which is incorrect. **
+#
+#
+# Examples
+# ~~~~~~~~
+#
+# * MultiSound Classic/Monterey/Tahiti:
+#
+# insmod soundcore
+# insmod msnd
+# insmod msnd_classic io=0x290 irq=7 mem=0xd0000
+#
+# * MultiSound Pinnacle in PnP mode:
+#
+# insmod soundcore
+# insmod msnd
+# isapnp mypinnacle.conf
+# insmod msnd_pinnacle io=0x210 irq=5 mem=0xd8000 <-- match mypinnacle.conf values
+#
+# * MultiSound Pinnacle in non-PnP mode (replace 0x250 with your configuration port,
+# one of 0x250, 0x260 or 0x270):
+#
+# insmod soundcore
+# insmod msnd
+# insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000
+#
+# * To use the MPU-compatible Kurzweil synth on the Pinnacle in PnP
+# mode, add the following (assumes you did `isapnp mypinnacle.conf'):
+#
+# insmod sound
+# insmod mpu401 io=0x330 irq=9 <-- match mypinnacle.conf values
+#
+# * To use the MPU-compatible Kurzweil synth on the Pinnacle in non-PnP
+# mode, add the following. Note how we first configure the peripheral's
+# resources, _then_ install a Linux driver for it:
+#
+# insmod sound
+# pinnaclecfg 0x250 mpu 0x330 9
+# insmod mpu401 io=0x330 irq=9
+#
+# -- OR you can use the following sequence without pinnaclecfg in non-PnP mode:
+#
+# insmod soundcore
+# insmod msnd
+# insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 mpu_io=0x330 mpu_irq=9
+# insmod sound
+# insmod mpu401 io=0x330 irq=9
+#
+# * To setup the joystick port on the Pinnacle in non-PnP mode (though
+# you have to find the actual Linux joystick driver elsewhere), you
+# can use pinnaclecfg:
+#
+# pinnaclecfg 0x250 joystick 0x200
+#
+# -- OR you can configure this using msnd_pinnacle with the following:
+#
+# insmod soundcore
+# insmod msnd
+# insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 joystick_io=0x200
+#
+#
+# msnd_classic, msnd_pinnacle Required Options
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# If the following options are not given, the module will not load.
+# Examine the kernel message log for informative error messages.
+# WARNING--probing isn't supported so try to make sure you have the
+# correct shared memory area, otherwise you may experience problems.
+#
+# io I/O base of DSP, e.g. io=0x210
+# irq IRQ number, e.g. irq=5
+# mem Shared memory area, e.g. mem=0xd8000
+#
+#
+# msnd_classic, msnd_pinnacle Additional Options
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# fifosize The digital audio FIFOs, in kilobytes. If not
+# specified, the default will be used. Increasing
+# this value will reduce the chance of a FIFO
+# underflow at the expense of increasing overall
+# latency. For example, fifosize=512 will
+# allocate 512kB read and write FIFOs (1MB total).
+# While this may reduce dropouts, a heavy machine
+# load will undoubtedly starve the FIFO of data
+# and you will eventually get dropouts. One
+# option is to alter the scheduling priority of
+# the playback process, using `nice' or some form
+# of POSIX soft real-time scheduling.
+#
+# calibrate_signal Setting this to one calibrates the ADCs to the
+# signal, zero calibrates to the card (defaults
+# to zero).
+#
+#
+# msnd_pinnacle Additional Options
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# digital Specify digital=1 to enable the S/PDIF input
+# if you have the digital daughterboard
+# adapter. This will enable access to the
+# DIGITAL1 input for the soundcard in the mixer.
+# Some mixer programs might have trouble setting
+# the DIGITAL1 source as an input. If you have
+# trouble, you can try the setdigital.c program
+# at the bottom of this document.
+#
+# cfg Non-PnP configuration port for the Pinnacle
+# and Fiji (typically 0x250, 0x260 or 0x270,
+# depending on the jumper configuration). If
+# this option is omitted, then it is assumed
+# that the card is in PnP mode, and that the
+# specified DSP resource values are already
+# configured with PnP (i.e. it won't attempt to
+# do any sort of configuration).
+#
+# When the Pinnacle is in non-PnP mode, you can use the following
+# options to configure particular devices. If a full specification
+# for a device is not given, then the device is not configured. Note
+# that you still must use a Linux driver for any of these devices
+# once their resources are setup (such as the Linux joystick driver,
+# or the MPU401 driver from OSS for the Kurzweil synth).
+#
+# mpu_io I/O port of MPU (on-board Kurzweil synth)
+# mpu_irq IRQ of MPU (on-board Kurzweil synth)
+# ide_io0 First I/O port of IDE controller
+# ide_io1 Second I/O port of IDE controller
+# ide_irq IRQ IDE controller
+# joystick_io I/O port of joystick
+#
+#
+# Obtaining and Creating Firmware Files
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# For the Classic/Tahiti/Monterey
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# Download to /tmp and unzip the following file from Turtle Beach:
+#
+# ftp://ftp.voyetra.com/pub/tbs/msndcl/msndvkit.zip
+#
+# When unzipped, unzip the file named MsndFiles.zip. Then copy the
+# following firmware files to /etc/sound (note the file renaming):
+#
+# cp DSPCODE/MSNDINIT.BIN /etc/sound/msndinit.bin
+# cp DSPCODE/MSNDPERM.REB /etc/sound/msndperm.bin
+#
+# When configuring the Linux kernel, specify /etc/sound/msndinit.bin and
+# /etc/sound/msndperm.bin for the two firmware files (Linux kernel
+# versions older than 2.2 do not ask for firmware paths, and are
+# hardcoded to /etc/sound).
+#
+# If you are compiling the driver into the kernel, these files must
+# be accessible during compilation, but will not be needed later.
+# The files must remain, however, if the driver is used as a module.
+#
+#
+# For the Pinnacle/Fiji
+# ~~~~~~~~~~~~~~~~~~~~~
+#
+# Download to /tmp and unzip the following file from Turtle Beach (be
+# sure to use the entire URL; some have had trouble navigating to the
+# URL):
+#
+# ftp://ftp.voyetra.com/pub/tbs/pinn/pnddk100.zip
+#
+# Unpack this shell archive, and run make in the created directory
+# (you need a C compiler and flex to build the utilities). This
+# should give you the executables conv, pinnaclecfg and setdigital.
+# conv is only used temporarily here to create the firmware files,
+# while pinnaclecfg is used to configure the Pinnacle or Fiji card in
+# non-PnP mode, and setdigital can be used to set the S/PDIF input on
+# the mixer (pinnaclecfg and setdigital should be copied to a
+# convenient place, possibly run during system initialization).
+#
+# To generating the firmware files with the `conv' program, we create
+# the binary firmware files by doing the following conversion
+# (assuming the archive unpacked into a directory named PINNDDK):
+#
+# ./conv < PINNDDK/dspcode/pndspini.asm > /etc/sound/pndspini.bin
+# ./conv < PINNDDK/dspcode/pndsperm.asm > /etc/sound/pndsperm.bin
+#
+# The conv (and conv.l) program is not needed after conversion and can
+# be safely deleted. Then, when configuring the Linux kernel, specify
+# /etc/sound/pndspini.bin and /etc/sound/pndsperm.bin for the two
+# firmware files (Linux kernel versions older than 2.2 do not ask for
+# firmware paths, and are hardcoded to /etc/sound).
+#
+# If you are compiling the driver into the kernel, these files must
+# be accessible during compilation, but will not be needed later.
+# The files must remain, however, if the driver is used as a module.
+#
+#
+# Using Digital I/O with the S/PDIF Port
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# If you have a Pinnacle or Fiji with the digital daughterboard and
+# want to set it as the input source, you can use this program if you
+# have trouble trying to do it with a mixer program (be sure to
+# insert the module with the digital=1 option, or say Y to the option
+# during compiled-in kernel operation). Upon selection of the S/PDIF
+# port, you should be able monitor and record from it.
+#
+# There is something to note about using the S/PDIF port. Digital
+# timing is taken from the digital signal, so if a signal is not
+# connected to the port and it is selected as recording input, you
+# will find PCM playback to be distorted in playback rate. Also,
+# attempting to record at a sampling rate other than the DAT rate may
+# be problematic (i.e. trying to record at 8000Hz when the DAT signal
+# is 44100Hz). If you have a problem with this, set the recording
+# input to the line in if you need to record at a rate other than
+# that of the DAT rate.
+#
+#
+# -- Shell archive attached below, just run `sh MultiSound' to extract.
+# Contains Pinnacle/Fiji utilities to convert firmware, configure
+# in non-PnP mode, and select the DIGITAL1 input for the mixer.
+#
+#
+#!/bin/sh
+# This is a shell archive (produced by GNU sharutils 4.2).
+# To extract the files from this archive, save it to some FILE, remove
+# everything before the `!/bin/sh' line above, then type `sh FILE'.
+#
+# Made on 1998-09-05 08:26 EDT by <andrewtv@ztransform.velsoft.com>.
+# Source directory was `/home/andrewtv/programming/pinnacle/pinnacle'.
+#
+# Existing files will *not* be overwritten unless `-c' is specified.
+#
+# This shar contains:
+# length mode name
+# ------ ---------- ------------------------------------------
+# 2111 -rw-rw-r-- MultiSound.d/setdigital.c
+# 10301 -rw-rw-r-- MultiSound.d/pinnaclecfg.c
+# 96 -rw-rw-r-- MultiSound.d/Makefile
+# 141 -rw-rw-r-- MultiSound.d/conv.l
+#
+save_IFS="${IFS}"
+IFS="${IFS}:"
+gettext_dir=FAILED
+locale_dir=FAILED
+first_param="$1"
+for dir in $PATH
+do
+ if test "$gettext_dir" = FAILED && test -f $dir/gettext \
+ && ($dir/gettext --version >/dev/null 2>&1)
+ then
+ set `$dir/gettext --version 2>&1`
+ if test "$3" = GNU
+ then
+ gettext_dir=$dir
+ fi
+ fi
+ if test "$locale_dir" = FAILED && test -f $dir/shar \
+ && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
+ then
+ locale_dir=`$dir/shar --print-text-domain-dir`
+ fi
+done
+IFS="$save_IFS"
+if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
+then
+ echo=echo
+else
+ TEXTDOMAINDIR=$locale_dir
+ export TEXTDOMAINDIR
+ TEXTDOMAIN=sharutils
+ export TEXTDOMAIN
+ echo="$gettext_dir/gettext -s"
+fi
+touch -am 1231235999 $$.touch >/dev/null 2>&1
+if test ! -f 1231235999 && test -f $$.touch; then
+ shar_touch=touch
+else
+ shar_touch=:
+ echo
+ $echo 'WARNING: not restoring timestamps. Consider getting and'
+ $echo "installing GNU \`touch', distributed in GNU File Utilities..."
+ echo
+fi
+rm -f 1231235999 $$.touch
+#
+if mkdir _sh21233; then
+ $echo 'x -' 'creating lock directory'
+else
+ $echo 'failed to create lock directory'
+ exit 1
+fi
+# ============= MultiSound.d/setdigital.c ==============
+if test ! -d 'MultiSound.d'; then
+ $echo 'x -' 'creating directory' 'MultiSound.d'
+ mkdir 'MultiSound.d'
+fi
+if test -f 'MultiSound.d/setdigital.c' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'MultiSound.d/setdigital.c' '(file already exists)'
+else
+ $echo 'x -' extracting 'MultiSound.d/setdigital.c' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/setdigital.c' &&
+/*********************************************************************
+X *
+X * setdigital.c - sets the DIGITAL1 input for a mixer
+X *
+X * Copyright (C) 1998 Andrew Veliath
+X *
+X * This program is free software; you can redistribute it and/or modify
+X * it under the terms of the GNU General Public License as published by
+X * the Free Software Foundation; either version 2 of the License, or
+X * (at your option) any later version.
+X *
+X * This program is distributed in the hope that it will be useful,
+X * but WITHOUT ANY WARRANTY; without even the implied warranty of
+X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+X * GNU General Public License for more details.
+X *
+X * You should have received a copy of the GNU General Public License
+X * along with this program; if not, write to the Free Software
+X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+X *
+X * $Id: setdigital.c,v 1.1 1998/08/29 03:32:33 andrewtv Exp $
+X *
+X ********************************************************************/
+X
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
-
+X
int main(int argc, char *argv[])
{
- int fd;
- unsigned long recmask, recsrc;
-
- if (argc != 2) {
- fprintf(stderr, "usage: setdigital <mixer device>\n");
- exit(1);
- } else
-
- if ((fd = open(argv[1], O_RDWR)) < 0) {
- perror(argv[1]);
- exit(1);
- }
-
- if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) < 0) {
- fprintf(stderr, "error: ioctl read recmask failed\n");
- perror("ioctl");
- close(fd);
- exit(1);
- }
-
- if (!(recmask & SOUND_MASK_DIGITAL1)) {
- fprintf(stderr, "error: cannot find DIGITAL1 device in mixer\n");
- close(fd);
- exit(1);
- }
-
- if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) < 0) {
- fprintf(stderr, "error: ioctl read recsrc failed\n");
- perror("ioctl");
- close(fd);
- exit(1);
- }
-
- recsrc |= SOUND_MASK_DIGITAL1;
-
- if (ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) < 0) {
- fprintf(stderr, "error: ioctl write recsrc failed\n");
- perror("ioctl");
- close(fd);
- exit(1);
- }
-
- close(fd);
-
- return 0;
-}
--- end setdigital.c --
+X int fd;
+X unsigned long recmask, recsrc;
+X
+X if (argc != 2) {
+X fprintf(stderr, "usage: setdigital <mixer device>\n");
+X exit(1);
+X }
+X
+X if ((fd = open(argv[1], O_RDWR)) < 0) {
+X perror(argv[1]);
+X exit(1);
+X }
+X
+X if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) < 0) {
+X fprintf(stderr, "error: ioctl read recording mask failed\n");
+X perror("ioctl");
+X close(fd);
+X exit(1);
+X }
+X
+X if (!(recmask & SOUND_MASK_DIGITAL1)) {
+X fprintf(stderr, "error: cannot find DIGITAL1 device in mixer\n");
+X close(fd);
+X exit(1);
+X }
+X
+X if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) < 0) {
+X fprintf(stderr, "error: ioctl read recording source failed\n");
+X perror("ioctl");
+X close(fd);
+X exit(1);
+X }
+X
+X recsrc |= SOUND_MASK_DIGITAL1;
+X
+X if (ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) < 0) {
+X fprintf(stderr, "error: ioctl write recording source failed\n");
+X perror("ioctl");
+X close(fd);
+X exit(1);
+X }
+X
+X close(fd);
+X
+X return 0;
+}
+SHAR_EOF
+ $shar_touch -am 0828233298 'MultiSound.d/setdigital.c' &&
+ chmod 0664 'MultiSound.d/setdigital.c' ||
+ $echo 'restore of' 'MultiSound.d/setdigital.c' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'MultiSound.d/setdigital.c:' 'MD5 check failed'
+47720746d4367bae9954787c311c56fd MultiSound.d/setdigital.c
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/setdigital.c'`"
+ test 2111 -eq "$shar_count" ||
+ $echo 'MultiSound.d/setdigital.c:' 'original size' '2111,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= MultiSound.d/pinnaclecfg.c ==============
+if test -f 'MultiSound.d/pinnaclecfg.c' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'MultiSound.d/pinnaclecfg.c' '(file already exists)'
+else
+ $echo 'x -' extracting 'MultiSound.d/pinnaclecfg.c' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/pinnaclecfg.c' &&
+/*********************************************************************
+X *
+X * pinnaclecfg.c - Pinnacle/Fiji Device Configuration Program
+X *
+X * This is for NON-PnP mode only. For PnP mode, use isapnptools.
+X *
+X * This is Linux-specific, and must be run with root permissions.
+X *
+X * Part of the Turtle Beach MultiSound Sound Card Driver for Linux
+X *
+X * Copyright (C) 1998 Andrew Veliath
+X *
+X * This program is free software; you can redistribute it and/or modify
+X * it under the terms of the GNU General Public License as published by
+X * the Free Software Foundation; either version 2 of the License, or
+X * (at your option) any later version.
+X *
+X * This program is distributed in the hope that it will be useful,
+X * but WITHOUT ANY WARRANTY; without even the implied warranty of
+X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+X * GNU General Public License for more details.
+X *
+X * You should have received a copy of the GNU General Public License
+X * along with this program; if not, write to the Free Software
+X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+X *
+X * $Id: pinnaclecfg.c,v 1.3 1998/08/29 03:32:32 andrewtv Exp $
+X *
+X ********************************************************************/
+X
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <asm/io.h>
+#include <asm/types.h>
+X
+#define IREG_LOGDEVICE 0x07
+#define IREG_ACTIVATE 0x30
+#define LD_ACTIVATE 0x01
+#define LD_DISACTIVATE 0x00
+#define IREG_EECONTROL 0x3F
+#define IREG_MEMBASEHI 0x40
+#define IREG_MEMBASELO 0x41
+#define IREG_MEMCONTROL 0x42
+#define IREG_MEMRANGEHI 0x43
+#define IREG_MEMRANGELO 0x44
+#define MEMTYPE_8BIT 0x00
+#define MEMTYPE_16BIT 0x02
+#define MEMTYPE_RANGE 0x00
+#define MEMTYPE_HIADDR 0x01
+#define IREG_IO0_BASEHI 0x60
+#define IREG_IO0_BASELO 0x61
+#define IREG_IO1_BASEHI 0x62
+#define IREG_IO1_BASELO 0x63
+#define IREG_IRQ_NUMBER 0x70
+#define IREG_IRQ_TYPE 0x71
+#define IRQTYPE_HIGH 0x02
+#define IRQTYPE_LOW 0x00
+#define IRQTYPE_LEVEL 0x01
+#define IRQTYPE_EDGE 0x00
+X
+#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
+#define LOBYTE(w) ((BYTE)(w))
+#define MAKEWORD(low,hi) ((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8)))
+X
+typedef __u8 BYTE;
+typedef __u16 USHORT;
+typedef __u16 WORD;
+X
+static int config_port = -1;
+X
+static int msnd_write_cfg(int cfg, int reg, int value)
+{
+X outb(reg, cfg);
+X outb(value, cfg + 1);
+X if (value != inb(cfg + 1)) {
+X fprintf(stderr, "error: msnd_write_cfg: I/O error\n");
+X return -EIO;
+X }
+X return 0;
+}
+X
+static int msnd_read_cfg(int cfg, int reg)
+{
+X outb(reg, cfg);
+X return inb(cfg + 1);
+}
+X
+static int msnd_write_cfg_io0(int cfg, int num, WORD io)
+{
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X if (msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
+X return -EIO;
+X if (msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
+X return -EIO;
+X return 0;
+}
+X
+static int msnd_read_cfg_io0(int cfg, int num, WORD *io)
+{
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X
+X *io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO0_BASELO),
+X msnd_read_cfg(cfg, IREG_IO0_BASEHI));
+X
+X return 0;
+}
+X
+static int msnd_write_cfg_io1(int cfg, int num, WORD io)
+{
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X if (msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
+X return -EIO;
+X if (msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
+X return -EIO;
+X return 0;
+}
+X
+static int msnd_read_cfg_io1(int cfg, int num, WORD *io)
+{
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X
+X *io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO1_BASELO),
+X msnd_read_cfg(cfg, IREG_IO1_BASEHI));
+X
+X return 0;
+}
+X
+static int msnd_write_cfg_irq(int cfg, int num, WORD irq)
+{
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X if (msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
+X return -EIO;
+X if (msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
+X return -EIO;
+X return 0;
+}
+X
+static int msnd_read_cfg_irq(int cfg, int num, WORD *irq)
+{
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X
+X *irq = msnd_read_cfg(cfg, IREG_IRQ_NUMBER);
+X
+X return 0;
+}
+X
+static int msnd_write_cfg_mem(int cfg, int num, int mem)
+{
+X WORD wmem;
+X
+X mem >>= 8;
+X mem &= 0xfff;
+X wmem = (WORD)mem;
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X if (msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
+X return -EIO;
+X if (msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
+X return -EIO;
+X if (wmem && msnd_write_cfg(cfg, IREG_MEMCONTROL, (MEMTYPE_HIADDR | MEMTYPE_16BIT)))
+X return -EIO;
+X return 0;
+}
+X
+static int msnd_read_cfg_mem(int cfg, int num, int *mem)
+{
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X
+X *mem = MAKEWORD(msnd_read_cfg(cfg, IREG_MEMBASELO),
+X msnd_read_cfg(cfg, IREG_MEMBASEHI));
+X *mem <<= 8;
+X
+X return 0;
+}
+X
+static int msnd_activate_logical(int cfg, int num)
+{
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X if (msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
+X return -EIO;
+X return 0;
+}
+X
+static int msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem)
+{
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X if (msnd_write_cfg_io0(cfg, num, io0))
+X return -EIO;
+X if (msnd_write_cfg_io1(cfg, num, io1))
+X return -EIO;
+X if (msnd_write_cfg_irq(cfg, num, irq))
+X return -EIO;
+X if (msnd_write_cfg_mem(cfg, num, mem))
+X return -EIO;
+X if (msnd_activate_logical(cfg, num))
+X return -EIO;
+X return 0;
+}
+X
+static int msnd_read_cfg_logical(int cfg, int num, WORD *io0, WORD *io1, WORD *irq, int *mem)
+{
+X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X return -EIO;
+X if (msnd_read_cfg_io0(cfg, num, io0))
+X return -EIO;
+X if (msnd_read_cfg_io1(cfg, num, io1))
+X return -EIO;
+X if (msnd_read_cfg_irq(cfg, num, irq))
+X return -EIO;
+X if (msnd_read_cfg_mem(cfg, num, mem))
+X return -EIO;
+X return 0;
+}
+X
+static void usage(void)
+{
+X fprintf(stderr,
+X "\n"
+X "pinnaclecfg 1.0\n"
+X "\n"
+X "usage: pinnaclecfg <config port> [device config]\n"
+X "\n"
+X "This is for use with the card in NON-PnP mode only.\n"
+X "\n"
+X "Available devices (not all available for Fiji):\n"
+X "\n"
+X " Device Description\n"
+X " -------------------------------------------------------------------\n"
+X " reset Reset all devices (i.e. disable)\n"
+X " show Display current device configurations\n"
+X "\n"
+X " dsp <io> <irq> <mem> Audio device\n"
+X " mpu <io> <irq> Internal Kurzweil synth\n"
+X " ide <io0> <io1> <irq> On-board IDE controller\n"
+X " joystick <io> Joystick port\n"
+X "\n");
+X exit(1);
+}
+X
+static int cfg_reset(void)
+{
+X int i;
+X
+X for (i = 0; i < 4; ++i)
+X msnd_write_cfg_logical(config_port, i, 0, 0, 0, 0);
+X
+X return 0;
+}
+X
+static int cfg_show(void)
+{
+X int i;
+X int count = 0;
+X
+X for (i = 0; i < 4; ++i) {
+X WORD io0, io1, irq;
+X int mem;
+X msnd_read_cfg_logical(config_port, i, &io0, &io1, &irq, &mem);
+X switch (i) {
+X case 0:
+X if (io0 || irq || mem) {
+X printf("dsp 0x%x %d 0x%x\n", io0, irq, mem);
+X ++count;
+X }
+X break;
+X case 1:
+X if (io0 || irq) {
+X printf("mpu 0x%x %d\n", io0, irq);
+X ++count;
+X }
+X break;
+X case 2:
+X if (io0 || io1 || irq) {
+X printf("ide 0x%x 0x%x %d\n", io0, io1, irq);
+X ++count;
+X }
+X break;
+X case 3:
+X if (io0) {
+X printf("joystick 0x%x\n", io0);
+X ++count;
+X }
+X break;
+X }
+X }
+X
+X if (count == 0)
+X fprintf(stderr, "no devices configured\n");
+X
+X return 0;
+}
+X
+static int cfg_dsp(int argc, char *argv[])
+{
+X int io, irq, mem;
+X
+X if (argc < 3 ||
+X sscanf(argv[0], "0x%x", &io) != 1 ||
+X sscanf(argv[1], "%d", &irq) != 1 ||
+X sscanf(argv[2], "0x%x", &mem) != 1)
+X usage();
+X
+X if (!(io == 0x290 ||
+X io == 0x260 ||
+X io == 0x250 ||
+X io == 0x240 ||
+X io == 0x230 ||
+X io == 0x220 ||
+X io == 0x210 ||
+X io == 0x3e0)) {
+X fprintf(stderr, "error: io must be one of "
+X "210, 220, 230, 240, 250, 260, 290, or 3E0\n");
+X usage();
+X }
+X
+X if (!(irq == 5 ||
+X irq == 7 ||
+X irq == 9 ||
+X irq == 10 ||
+X irq == 11 ||
+X irq == 12)) {
+X fprintf(stderr, "error: irq must be one of "
+X "5, 7, 9, 10, 11 or 12\n");
+X usage();
+X }
+X
+X if (!(mem == 0xb0000 ||
+X mem == 0xc8000 ||
+X mem == 0xd0000 ||
+X mem == 0xd8000 ||
+X mem == 0xe0000 ||
+X mem == 0xe8000)) {
+X fprintf(stderr, "error: mem must be one of "
+X "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
+X usage();
+X }
+X
+X return msnd_write_cfg_logical(config_port, 0, io, 0, irq, mem);
+}
+X
+static int cfg_mpu(int argc, char *argv[])
+{
+X int io, irq;
+X
+X if (argc < 2 ||
+X sscanf(argv[0], "0x%x", &io) != 1 ||
+X sscanf(argv[1], "%d", &irq) != 1)
+X usage();
+X
+X return msnd_write_cfg_logical(config_port, 1, io, 0, irq, 0);
+}
+X
+static int cfg_ide(int argc, char *argv[])
+{
+X int io0, io1, irq;
+X
+X if (argc < 3 ||
+X sscanf(argv[0], "0x%x", &io0) != 1 ||
+X sscanf(argv[0], "0x%x", &io1) != 1 ||
+X sscanf(argv[1], "%d", &irq) != 1)
+X usage();
+X
+X return msnd_write_cfg_logical(config_port, 2, io0, io1, irq, 0);
+}
+X
+static int cfg_joystick(int argc, char *argv[])
+{
+X int io;
+X
+X if (argc < 1 ||
+X sscanf(argv[0], "0x%x", &io) != 1)
+X usage();
+X
+X return msnd_write_cfg_logical(config_port, 3, io, 0, 0, 0);
+}
+X
+int main(int argc, char *argv[])
+{
+X char *device;
+X int rv = 0;
+X
+X --argc; ++argv;
+X
+X if (argc < 2)
+X usage();
+X
+X sscanf(argv[0], "0x%x", &config_port);
+X if (config_port != 0x250 && config_port != 0x260 && config_port != 0x270) {
+X fprintf(stderr, "error: <config port> must be 0x250, 0x260 or 0x270\n");
+X exit(1);
+X }
+X if (ioperm(config_port, 2, 1)) {
+X perror("ioperm");
+X fprintf(stderr, "note: pinnaclecfg must be run as root\n");
+X exit(1);
+X }
+X device = argv[1];
+X
+X argc -= 2; argv += 2;
+X
+X if (strcmp(device, "reset") == 0)
+X rv = cfg_reset();
+X else if (strcmp(device, "show") == 0)
+X rv = cfg_show();
+X else if (strcmp(device, "dsp") == 0)
+X rv = cfg_dsp(argc, argv);
+X else if (strcmp(device, "mpu") == 0)
+X rv = cfg_mpu(argc, argv);
+X else if (strcmp(device, "ide") == 0)
+X rv = cfg_ide(argc, argv);
+X else if (strcmp(device, "joystick") == 0)
+X rv = cfg_joystick(argc, argv);
+X else {
+X fprintf(stderr, "error: unknown device %s\n", device);
+X usage();
+X }
+X
+X if (rv)
+X fprintf(stderr, "error: device configuration failed\n");
+X
+X return 0;
+}
+SHAR_EOF
+ $shar_touch -am 0905082598 'MultiSound.d/pinnaclecfg.c' &&
+ chmod 0664 'MultiSound.d/pinnaclecfg.c' ||
+ $echo 'restore of' 'MultiSound.d/pinnaclecfg.c' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'MultiSound.d/pinnaclecfg.c:' 'MD5 check failed'
+71f99b834a2845daae8ae034623e313e MultiSound.d/pinnaclecfg.c
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/pinnaclecfg.c'`"
+ test 10301 -eq "$shar_count" ||
+ $echo 'MultiSound.d/pinnaclecfg.c:' 'original size' '10301,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= MultiSound.d/Makefile ==============
+if test -f 'MultiSound.d/Makefile' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'MultiSound.d/Makefile' '(file already exists)'
+else
+ $echo 'x -' extracting 'MultiSound.d/Makefile' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/Makefile' &&
+CC = gcc
+CFLAGS = -O
+PROGS = setdigital pinnaclecfg conv
+X
+all: $(PROGS)
+X
+clean:
+X rm -f $(PROGS)
+SHAR_EOF
+ $shar_touch -am 0828231798 'MultiSound.d/Makefile' &&
+ chmod 0664 'MultiSound.d/Makefile' ||
+ $echo 'restore of' 'MultiSound.d/Makefile' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'MultiSound.d/Makefile:' 'MD5 check failed'
+ab95a049d10611a5e5d559a56965b33f MultiSound.d/Makefile
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/Makefile'`"
+ test 96 -eq "$shar_count" ||
+ $echo 'MultiSound.d/Makefile:' 'original size' '96,' 'current size' "$shar_count!"
+ fi
+fi
+# ============= MultiSound.d/conv.l ==============
+if test -f 'MultiSound.d/conv.l' && test "$first_param" != -c; then
+ $echo 'x -' SKIPPING 'MultiSound.d/conv.l' '(file already exists)'
+else
+ $echo 'x -' extracting 'MultiSound.d/conv.l' '(text)'
+ sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/conv.l' &&
+%%
+[ \n\t,\r]
+\;.*
+DB
+[0-9A-Fa-f]+H { int n; sscanf(yytext, "%xH", &n); printf("%c", n); }
+%%
+int yywrap() { return 1; }
+main() { yylex(); }
+SHAR_EOF
+ $shar_touch -am 0828231798 'MultiSound.d/conv.l' &&
+ chmod 0664 'MultiSound.d/conv.l' ||
+ $echo 'restore of' 'MultiSound.d/conv.l' 'failed'
+ if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+ md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+ || $echo 'MultiSound.d/conv.l:' 'MD5 check failed'
+d2411fc32cd71a00dcdc1f009e858dd2 MultiSound.d/conv.l
+SHAR_EOF
+ else
+ shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/conv.l'`"
+ test 141 -eq "$shar_count" ||
+ $echo 'MultiSound.d/conv.l:' 'original size' '141,' 'current size' "$shar_count!"
+ fi
+fi
+rm -fr _sh21233
+exit 0
SMC etherpower for that.)
3. Make sure your changes compile correctly in multiple
- configurations.
+ configurations. In paticular check changes work both as a module
+ and built into the kernel.
4. When you are happy with a change make it generally available for
testing and await feedback.
job the maintainers (and especially Linus) do is to keep things
looking the same. Sometimes this means that the clever hack in
your driver to get around a problem actual needs to become a
- generalized kernel feature ready for next time.
+ generalized kernel feature ready for next time. See
+ Documentation/CodingStyle for guidance here.
PLEASE try to include any credit lines you want added with the
patch. It avoids people being missed off by mistake and makes
L: linux-net@vger.rutgers.edu
S: Maintained
+ETHERTEAM 16I DRIVER
+P: Mika Kuoppala
+M: miku@iki.fi
+S: Maintained
+
EXT2 FILE SYSTEM
P: Remy Card
M: Remy.Card@linux.org
L: linux-hams@vger.rutgers.edu
S: Maintained
+HIPPI
+P: Jes Sorensen
+M: Jes.Sorensen@cern.ch
+L: linux-hippi@sunsite.auc.dk
+S: Maintained
+
HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
P: Jaroslav Kysela
M: perex@jcu.cz
L: linux-x25@vger.rutgers.edu
S: Maintained
+Z85230 SYNCHRONOUS DRIVER
+P: Alan Cox
+M: alan@redhat.com
+W: http://roadrunner.swansea.linux.org.uk/synchronous.shtml
+S: Maintained
+
Z8530 DRIVER FOR AX.25
P: Joerg Reuter
M: jreuter@poboxes.com
L: linux-hams@vger.rutgers.edu
S: Maintained
-
REST:
P: Linus Torvalds
S: Buried alive in diapers
the current directory, but an alternative directory can be specified
as the second argument.
- - Make sure your /usr/include/asm, /usr/include/linux, and /usr/include/scsi
- directories are just symlinks to the kernel sources:
-
- cd /usr/include
- rm -rf asm linux scsi
- ln -s /usr/src/linux/include/asm-i386 asm
- ln -s /usr/src/linux/include/linux linux
- ln -s /usr/src/linux/include/scsi scsi
-
- Make sure you have no stale .o files and dependencies lying around:
cd /usr/src/linux
# Determine if GCC understands the -mcpu= option.
have_mcpu := $(shell if $(CC) -mcpu=ev5 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi)
-# If GENERIC, make sure to turn off any instruction set extensions that
-# the host compiler might have on by default. Given that EV4 and EV5
-# have the same instruction set, prefer EV5 because an EV5 schedule is
-# more likely to keep an EV4 processor busy than vice-versa.
-ifeq ($(CONFIG_ALPHA_GENERIC)$(have_mcpu),yy)
- CFLAGS := $(CFLAGS) -mcpu=ev5
-endif
-
-# If EV6, turn on the proper optimizations.
-ifeq ($(CONFIG_ALPHA_EV6)$(have_mcpu),yy)
- CFLAGS := $(CFLAGS) -mcpu=ev6
+# Turn on the proper cpu optimizations.
+ifeq ($(have_mcpu),y)
+ # If GENERIC, make sure to turn off any instruction set extensions that
+ # the host compiler might have on by default. Given that EV4 and EV5
+ # have the same instruction set, prefer EV5 because an EV5 schedule is
+ # more likely to keep an EV4 processor busy than vice-versa.
+ ifeq ($(CONFIG_ALPHA_GENERIC),y)
+ CFLAGS := $(CFLAGS) -mcpu=ev5
+ endif
+ ifeq ($(CONFIG_ALPHA_EV4),y)
+ CFLAGS := $(CFLAGS) -mcpu=ev4
+ endif
+ # Leave out EV5, since it is too hard to figure out whether we
+ # should use EV56 insns or not.
+ ifeq ($(CONFIG_ALPHA_EV6),y)
+ CFLAGS := $(CFLAGS) -mcpu=ev6
+ endif
endif
# For TSUNAMI, we must have the assembler not emulate our instructions.
tools/mkbb bootimage tools/lxboot
bootpfile: tools/bootph vmlinux.nh
- ( cat tools/bootph vmlinux.nh ) > bootpfile
+ cat tools/bootph vmlinux.nh > bootpfile
+ifdef INITRD
+ cat $(INITRD) >> bootpfile
+endif
srmboot: bootdevice bootimage
dd if=bootimage of=$(BOOTDEV) bs=512 seek=1 skip=1
vmlinux.gz: vmlinux
gzip -fv9 vmlinux
-#
-# A raw binary without header. Used by raw boot.
-#
main.o: ksize.h
bootp.o: ksize.h
-ksize.h: $(OBJSTRIP) vmlinux.nh
- echo "#define KERNEL_SIZE `$(OBJSTRIP) -p vmlinux.nh /dev/null`" > $@
+ksize.h: vmlinux.nh dummy
+ echo "#define KERNEL_SIZE `ls -l vmlinux.nh | awk '{print $$5}'`" > $@T
+ifdef INITRD
+ [ -f $(INITRD) ] || exit 1
+ echo "#define INITRD_SIZE `ls -l $(INITRD) | awk '{print $$5}'`" >> $@T
+endif
+ cmp -s $@T $@ || mv -f $@T $@
+ rm -f $@T
vmlinux.nh: $(VMLINUX) $(OBJSTRIP)
$(OBJSTRIP) -v $(VMLINUX) vmlinux.nh
rm -f vmlinux.nh ksize.h
dep:
+
+dummy:
#include "ksize.h"
-extern int vsprintf(char *, const char *, va_list);
extern unsigned long switch_to_osf_pal(unsigned long nr,
struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
- unsigned long vptb, unsigned long *kstk);
+ unsigned long *vptb);
-extern long dispatch(long code, ...);
-
-static void
-puts(const char *str, int len)
-{
- long written;
-
- while (len > 0) {
- written = dispatch(CCB_PUTS, 0, str, len);
- if (written < 0)
- break;
- len -= (unsigned int) written;
- str += (unsigned int) written;
- }
-}
-
-int printk(const char * fmt, ...)
-{
- va_list args;
- int i, j, remaining, num_nl;
- static char buf[1024];
-
- va_start(args, fmt);
- i = vsprintf(buf, fmt, args);
- va_end(args);
-
- /* expand \n into \r\n: */
-
- num_nl = 0;
- for (j = 0; j < i; ++j) {
- if (buf[j] == '\n')
- ++num_nl;
- }
- remaining = i + num_nl;
- for (j = i - 1; j >= 0; --j) {
- buf[j + num_nl] = buf[j];
- if (buf[j] == '\n') {
- --num_nl;
- buf[j + num_nl] = '\r';
- }
- }
-
- puts(buf, remaining);
- return i;
-}
-
-#define hwrpb (*INIT_HWRPB)
+struct hwrpb_struct *hwrpb = INIT_HWRPB;
+static struct pcb_struct pcb_va[1];
/*
* Find a physical address of a virtual object..
*
* This is easy using the virtual page table address.
*/
-struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb)
+
+static inline void *
+find_pa(unsigned long *vptb, void *ptr)
{
- unsigned long address = (unsigned long) pcb;
+ unsigned long address = (unsigned long) ptr;
unsigned long result;
result = vptb[address >> 13];
result >>= 32;
result <<= 13;
result |= address & 0x1fff;
- return (struct pcb_struct *) result;
+ return (void *) result;
}
/*
* code has the L1 page table identity-map itself in the second PTE
* in the L1 page table. Thus the L1-page is virtually addressable
* itself (through three levels) at virtual address 0x200802000.
- *
- * As we don't want it there anyway, we also move the L1 self-map
- * up as high as we can, so that the last entry in the L1 page table
- * maps the page tables.
- *
- * As a result, the OSF/1 pal-code will instead use a virtual page table
- * map located at 0xffffffe00000000.
*/
-#define pcb_va ((struct pcb_struct *) 0x20000000)
-#define old_vptb (0x0000000200000000UL)
-#define new_vptb (0xfffffffe00000000UL)
-void pal_init(void)
+
+#define VPTB ((unsigned long *) 0x200000000)
+#define L1 ((unsigned long *) 0x200802000)
+
+void
+pal_init(void)
{
- unsigned long i, rev, sum;
- unsigned long *L1, *l;
+ unsigned long i, rev;
struct percpu_struct * percpu;
struct pcb_struct * pcb_pa;
- /* Find the level 1 page table and duplicate it in high memory */
- L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */
- L1[1023] = L1[1];
-
- percpu = (struct percpu_struct *)
- (hwrpb.processor_offset + (unsigned long) &hwrpb),
-
+ /* Create the dummy PCB. */
pcb_va->ksp = 0;
pcb_va->usp = 0;
pcb_va->ptbr = L1[1] >> 32;
pcb_va->pcc = 0;
pcb_va->unique = 0;
pcb_va->flags = 1;
- pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va);
- printk("Switching to OSF PAL-code .. ");
+ pcb_va->res1 = 0;
+ pcb_va->res2 = 0;
+ pcb_pa = find_pa(VPTB, pcb_va);
+
/*
* a0 = 2 (OSF)
* a1 = return address, but we give the asm the vaddr of the PCB
* a2 = physical addr of PCB
* a3 = new virtual page table pointer
- * a4 = KSP (but we give it 0, asm sets it)
+ * a4 = KSP (but the asm sets it)
*/
- i = switch_to_osf_pal(
- 2,
- pcb_va,
- pcb_pa,
- new_vptb,
- 0);
+ srm_printk("Switching to OSF PAL-code .. ");
+
+ i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
if (i) {
- printk("failed, code %ld\n", i);
+ srm_printk("failed, code %ld\n", i);
halt();
}
- rev = percpu->pal_revision = percpu->palcode_avail[2];
- hwrpb.vptb = new_vptb;
-
- /* update checksum: */
- sum = 0;
- for (l = (unsigned long *) &hwrpb;
- l < (unsigned long *) &hwrpb.chksum;
- ++l)
- sum += *l;
- hwrpb.chksum = sum;
+ percpu = (struct percpu_struct *)
+ (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
+ rev = percpu->pal_revision = percpu->palcode_avail[2];
- printk("Ok (rev %lx)\n", rev);
- /* remove the old virtual page-table mapping */
- L1[1] = 0;
+ srm_printk("Ok (rev %lx)\n", rev);
tbia(); /* do it directly in case we are SMP */
}
-static inline long load(unsigned long dst,
- unsigned long src,
- unsigned long count)
+static inline void
+load(unsigned long dst, unsigned long src, unsigned long count)
{
- extern void * memcpy(void *, const void *, size_t);
-
memcpy((void *)dst, (void *)src, count);
- return count;
}
/*
* Start the kernel.
*/
-static void runkernel(void)
+static inline void
+runkernel(void)
{
__asm__ __volatile__(
"bis %1,%1,$30\n\t"
#define KERNEL_ORIGIN \
((((unsigned long)&_end) + 511) & ~511)
-void start_kernel(void)
+void
+start_kernel(void)
{
- static long i;
- static int nbytes;
/*
- * note that this crufty stuff with static and envval and envbuf
- * is because:
+ * Note that this crufty stuff with static and envval
+ * and envbuf is because:
*
- * 1. frequently, the stack is is short, and we don't want to overrun;
- * 2. frequently the stack is where we are going to copy the kernel to;
- * 3. a certain SRM console required the GET_ENV output to stack.
+ * 1. Frequently, the stack is short, and we don't want to overrun;
+ * 2. Frequently the stack is where we are going to copy the kernel to;
+ * 3. A certain SRM console required the GET_ENV output to stack.
+ * ??? A comment in the aboot sources indicates that the GET_ENV
+ * destination must be quadword aligned. Might this explain the
+ * behaviour, rather than requiring output to the stack, which
+ * seems rather far-fetched.
*/
- static char envval[256];
- char envbuf[256];
+ static long nbytes;
+ static char envval[256] __attribute__((aligned(8)));
+#ifdef INITRD_SIZE
+ static unsigned long initrd_start;
+#endif
- printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n");
- if (hwrpb.pagesize != 8192) {
- printk("Expected 8kB pages, got %ldkB\n",
- hwrpb.pagesize >> 10);
+ srm_printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n");
+ if (INIT_HWRPB->pagesize != 8192) {
+ srm_printk("Expected 8kB pages, got %ldkB\n",
+ INIT_HWRPB->pagesize >> 10);
+ return;
+ }
+ if (INIT_HWRPB->vptb != (unsigned long) VPTB) {
+ srm_printk("Expected vptb at %p, got %p\n",
+ VPTB, (void *)INIT_HWRPB->vptb);
return;
}
pal_init();
- nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS,
- envbuf, sizeof(envbuf));
- if (nbytes < 0 || nbytes >= sizeof(envbuf)) {
+#ifdef INITRD_SIZE
+ /* The initrd must be page-aligned. See below for the
+ cause of the magic number 5. */
+ initrd_start = ((START_ADDR + 5*KERNEL_SIZE) | (PAGE_SIZE-1)) + 1;
+ srm_printk("Initrd positioned at %#lx\n", initrd_start);
+#endif
+
+ nbytes = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS,
+ envval, sizeof(envval));
+ if (nbytes < 0 || nbytes >= sizeof(envval)) {
nbytes = 0;
}
- envbuf[nbytes] = '\0';
- memcpy(envval, envbuf, nbytes+1);
- printk("Loading the kernel...'%s'\n", envval);
+ envval[nbytes] = '\0';
+ srm_printk("Loading the kernel...'%s'\n", envval);
/* NOTE: *no* callbacks or printouts from here on out!!! */
-#if 1
/*
- * this is a hack, as some consoles seem to get virtual 20000000
+ * This is a hack, as some consoles seem to get virtual 20000000
* (ie where the SRM console puts the kernel bootp image) memory
* overlapping physical 310000 memory, which causes real problems
* when attempting to copy the former to the latter... :-(
*
- * so, we first move the kernel virtual-to-physical way above where
+ * So, we first move the kernel virtual-to-physical way above where
* we physically want the kernel to end up, then copy it from there
* to its final resting place... ;-}
*
- * sigh...
+ * Sigh...
*/
- i = load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE);
- i = load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE);
-#else
- i = load(START_ADDR, KERNEL_ORIGIN, KERNEL_SIZE);
+#ifdef INITRD_SIZE
+ load(initrd_start, KERNEL_ORIGIN+KERNEL_SIZE, INITRD_SIZE);
#endif
+ load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE);
+ load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE);
+ memset((char*)ZERO_PAGE, 0, PAGE_SIZE);
strcpy((char*)ZERO_PAGE, envval);
+#ifdef INITRD_SIZE
+ ((long *)(ZERO_PAGE+256))[0] = initrd_start;
+ ((long *)(ZERO_PAGE+256))[1] = INITRD_SIZE;
+#endif
runkernel();
-
- for (i = 0 ; i < 0x100000000 ; i++)
- /* nothing */;
- halt();
}
#include <asm/system.h>
-#define halt .long PAL_halt
-
.set noreorder
.globl __start
.ent __start
__start:
- bis $31,$31,$31
- br 1f
- /* room for the initial PCB, which comes here */
- .quad 0,0,0,0,0,0,0,0
-1: br $27,2f
-2: ldgp $29,0($27)
- lda $27,start_kernel
- jsr $26,($27),start_kernel
- halt
+ br $29,2f
+2: ldgp $29,0($29)
+ jsr $26,start_kernel
+ call_pal PAL_halt
.end __start
.align 5
.globl wrent
.ent wrent
wrent:
- .long PAL_wrent
+ .prologue 0
+ call_pal PAL_wrent
ret ($26)
.end wrent
.globl wrkgp
.ent wrkgp
wrkgp:
- .long PAL_wrkgp
+ .prologue 0
+ call_pal PAL_wrkgp
ret ($26)
.end wrkgp
.ent switch_to_osf_pal
switch_to_osf_pal:
subq $30,128,$30
+ .frame $30,128,$26
stq $26,0($30)
stq $1,8($30)
stq $2,16($30)
stq $13,104($30)
stq $14,112($30)
stq $15,120($30)
+ .prologue 0
stq $30,0($17) /* save KSP in PCB */
bis $30,$30,$20 /* a4 = KSP */
- br $17,__do_swppal
+ br $17,1f
ldq $26,0($30)
ldq $1,8($30)
ldq $15,120($30)
addq $30,128,$30
ret ($26)
-
-__do_swppal:
- .long PAL_swppal
+1: call_pal PAL_swppal
.end switch_to_osf_pal
-.globl dispatch
-.ent dispatch
-dispatch:
- subq $30,80,$30
- stq $26,0($30)
- stq $29,8($30)
-
- stq $8,16($30)
- stq $9,24($30)
- stq $10,32($30)
- stq $11,40($30)
- stq $12,48($30)
- stq $13,56($30)
- stq $14,64($30)
- stq $15,72($30)
-
- lda $1,0x10000000 /* hwrpb */
- ldq $2,0xc0($1) /* crb offset */
- addq $2,$1,$2 /* crb */
- ldq $27,0($2) /* dispatch procedure value */
-
- ldq $2,8($27) /* dispatch call address */
- jsr $26,($2) /* call it (weird VMS call seq) */
-
- ldq $26,0($30)
- ldq $29,8($30)
-
- ldq $8,16($30)
- ldq $9,24($30)
- ldq $10,32($30)
- ldq $11,40($30)
- ldq $12,48($30)
- ldq $13,56($30)
- ldq $14,64($30)
- ldq $15,72($30)
-
- addq $30,80,$30
- ret $31,($26)
-.end dispatch
-
.align 3
.globl tbi
.ent tbi
tbi:
- .long PAL_tbi
+ .prologue 0
+ call_pal PAL_tbi
ret ($26)
.end tbi
+ .align 3
+ .globl halt
+ .ent halt
+halt:
+ .prologue 0
+ call_pal PAL_halt
+ .end halt
define_bool CONFIG_ALPHA_AVANTI y
fi
-#bool 'Echo console messages on /dev/ttyS0 (COM1)' CONFIG_SERIAL_ECHO
-
if [ "$CONFIG_PCI" = "y" ]; then
bool 'PCI quirks' CONFIG_PCI_QUIRKS
if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__strlen_user);
+/*
+ * SMP-specific symbols.
+ */
+
+#ifdef __SMP__
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(flush_tlb_all);
+EXPORT_SYMBOL(flush_tlb_mm);
+EXPORT_SYMBOL(flush_tlb_page);
+EXPORT_SYMBOL(flush_tlb_range);
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL(cpu_number_map);
+EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(global_bh_count);
+EXPORT_SYMBOL(synchronize_bh);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+#if DEBUG_SPINLOCK
+EXPORT_SYMBOL(spin_unlock);
+EXPORT_SYMBOL(spin_lock);
+EXPORT_SYMBOL(spin_trylock);
+#endif
+#if DEBUG_RWLOCK
+EXPORT_SYMBOL(write_lock);
+EXPORT_SYMBOL(read_lock);
+#endif
+#endif /* __SMP__ */
+
/*
* The following are special because they're not called
* explicitly (the C compiler or assembler generates them in
size = (mask & base) & 0xffffffff;
switch (type) {
case PCI_BASE_ADDRESS_MEM_TYPE_32:
- break;
-
case PCI_BASE_ADDRESS_MEM_TYPE_64:
- printk("bios32 WARNING: "
- "ignoring 64-bit device in "
- "slot %d, function %d: \n",
- PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn));
- idx++; /* skip extra 4 bytes */
- continue;
+ break;
case PCI_BASE_ADDRESS_MEM_TYPE_1M:
/*
off, base);
handle = PCI_HANDLE(bus->number) | base;
dev->base_address[idx] = handle;
+
+ /*
+ * Currently for 64-bit cards, we simply do the usual
+ * for setup of the first register (low) of the pair,
+ * and then clear out the second (high) register, as
+ * we are not yet able to do 64-bit addresses, and
+ * setting the high register to 0 allows 32-bit SAC
+ * addresses to be used.
+ */
+ if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ pcibios_write_config_dword(bus->number,
+ dev->devfn,
+ off+4, 0);
+ /* Bypass hi reg in the loop. */
+ dev->base_address[++idx] = 0;
+
+ printk("bios32 WARNING: "
+ "handling 64-bit device in "
+ "slot %d, function %d: \n",
+ PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
+ }
+
DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%lx (0x%x)\n",
dev->device, handle, size));
}
struct pci_dev *bridge = bus->self;
DBG_DEVS(("layout_bus: config bus %d bridge\n", bus->number));
+
/*
* Set up the top and bottom of the PCI I/O segment
* for this bus.
*/
pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
- 0x1c, &l);
+ PCI_IO_BASE, &l);
l &= 0xffff0000;
l |= ((bio >> 8) & 0x00f0) | ((tio - 1) & 0xf000);
pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- 0x1c, l);
+ PCI_IO_BASE, l);
+
+ /* Also clear out the upper 16 bits. */
+ pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
+ PCI_IO_BASE_UPPER16, 0);
+
/*
* Set up the top and bottom of the PCI Memory segment
* for this bus.
*/
l = ((bmem & 0xfff00000) >> 16) | ((tmem - 1) & 0xfff00000);
pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- 0x20, l);
+ PCI_MEMORY_BASE, l);
/*
* Turn off downstream PF memory address range:
*/
pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- 0x24, 0x0000ffff);
+ PCI_PREF_MEMORY_BASE, 0x0000ffff);
+
/*
* Tell bridge that there is an ISA bus in the system,
* and (possibly) a VGA as well.
*/
+ /* ??? This appears to be a single-byte write into MIN_GNT.
+ What is up with this? */
l = 0x00040000; /* ISA present */
if (found_vga) l |= 0x00080000; /* VGA present */
pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
0x3c, l);
+
/*
* Clear status bits, enable I/O (for downstream I/O),
* turn on master enable (for upstream I/O), turn on
* master enable (for upstream memory and I/O).
*/
pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
- 0x4, 0xffff0007);
+ PCI_COMMAND, 0xffff0007);
}
DBG_DEVS(("layout_bus: bus %d finished\n", bus->number));
return found_vga;
mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr,
unsigned char *type1)
{
- unsigned long addr;
+ *type1 = (bus == 0) ? 0 : 1;
+ *pci_addr = (bus << 16) | (device_fn << 8) | (where);
DBG_CNF(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
- " pci_addr=0x%p, type1=0x%p)\n",
- bus, device_fn, where, pci_addr, type1));
-
- if (bus == 0) {
- int device;
-
- device = device_fn >> 3;
- /* Type 0 configuration cycle. */
-#if NOT_NOW
- if (device > 20) {
- DBG_CNF(("mk_conf_addr: device (%d) > 20, return -1\n",
- device));
- return -1;
- }
-#endif
- *type1 = 0;
- addr = (device_fn << 8) | (where);
- } else {
- /* Type 1 configuration cycle. */
- *type1 = 1;
- addr = (bus << 16) | (device_fn << 8) | (where);
- }
- *pci_addr = addr;
- DBG_CNF(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+ " returning address 0x%p\n"
+ bus, device_fn, where, *pci_addr));
+
return 0;
}
stat0 = *(vuip)PYXIS_ERR;
*(vuip)PYXIS_ERR = stat0; mb();
temp = *(vuip)PYXIS_ERR; /* re-read to force write */
- DBG_CNF(("conf_read: PYXIS ERR was 0x%x\n", stat0));
/* If Type1 access, must set PYXIS CFG. */
if (type1) {
pyxis_cfg = *(vuip)PYXIS_CFG;
- *(vuip)PYXIS_CFG = pyxis_cfg | 1; mb();
+ *(vuip)PYXIS_CFG = (pyxis_cfg & ~3L) | 1; mb();
temp = *(vuip)PYXIS_CFG; /* re-read to force write */
}
/* If Type1 access, must reset IOC CFG so normal IO space ops work. */
if (type1) {
- *(vuip)PYXIS_CFG = pyxis_cfg & ~1; mb();
+ *(vuip)PYXIS_CFG = pyxis_cfg & ~3L; mb();
temp = *(vuip)PYXIS_CFG; /* re-read to force write */
}
+ __restore_flags(flags);
+
DBG_CNF(("conf_read(addr=0x%lx, type1=%d) = %#x\n",
addr, type1, value));
- __restore_flags(flags);
return value;
}
unsigned int stat0, temp;
unsigned int pyxis_cfg = 0;
- DBG_CNF(("conf_write(addr=%#lx, value=%#x, type1=%d)\n",
- addr, value, type1));
-
__save_and_cli(flags); /* avoid getting hit by machine check */
/* Reset status register to avoid losing errors. */
/* If Type1 access, must set PYXIS CFG. */
if (type1) {
pyxis_cfg = *(vuip)PYXIS_CFG;
- *(vuip)PYXIS_CFG = pyxis_cfg | 1; mb();
+ *(vuip)PYXIS_CFG = (pyxis_cfg & ~3L) | 1; mb();
temp = *(vuip)PYXIS_CFG; /* re-read to force write */
}
/* Access configuration space. */
*(vuip)addr = value;
mb();
- mb(); /* magic */
- temp = *(vuip)PYXIS_ERR; /* do a PYXIS read to force the write */
+ temp = *(vuip)addr; /* read back to force the write */
PYXIS_mcheck_expected = 0;
mb();
/* If Type1 access, must reset IOC CFG so normal IO space ops work. */
if (type1) {
- *(vuip)PYXIS_CFG = pyxis_cfg & ~1; mb();
+ *(vuip)PYXIS_CFG = pyxis_cfg & ~3L; mb();
temp = *(vuip)PYXIS_CFG; /* re-read to force write */
}
__restore_flags(flags);
+
+ DBG_CNF(("conf_write(addr=%#lx, value=%#x, type1=%d)\n",
+ addr, value, type1));
}
int
ret_from_sys_call:
cmovne $26,0,$19 /* $19 = 0 => non-restartable */
/* check bottom half interrupts */
- bne $1,ret_from_handle_bh
ldq $3,bh_active
ldq $4,bh_mask
and $3,$4,$2
bis $30,$30,$18
bis $31,$31,$16
jsr $26,do_signal
- lda $30,SWITCH_STACK_SIZE($30)
+ bsr $1,undo_switch_stack
br $31,restore_all
.end entSys
#include <asm/system.h>
-#define halt call_pal PAL_halt
-
.globl swapper_pg_dir
.globl _stext
swapper_pg_dir=SWAPPER_PGD
lda $30,0x4000($8)
/* ... and then we can start the kernel. */
jsr $26,start_kernel
- halt
+ call_pal PAL_halt
.end __start
#ifdef __SMP__
.align 3
.globl __start_cpu
.ent __start_cpu
- /* on entry here from SRM console, the HWPCB of this processor */
- /* has been loaded, and $27 contains the task pointer */
+ /* On entry here from SRM console, the HWPCB of this processor
+ has been loaded, and $27 contains the task pointer */
__start_cpu:
.prologue 0
- /* first order of business, load the GP */
+ /* First order of business, load the GP */
br $26,1f
1: ldgp $29,0($26)
/* We need to get current loaded up with our first task... */
- lda $8,0($27)
- /* set FEN */
+ mov $27,$8
+ /* Set FEN */
lda $16,1($31)
call_pal PAL_wrfen
/* ... and then we can start the processor. */
jsr $26,start_secondary
- halt
+ call_pal PAL_halt
.end __start_cpu
#endif /* __SMP__ */
.globl wripir
.ent wripir
wripir:
+ .prologue 0
call_pal PAL_wripir
ret ($26)
.end wripir
+ .align 3
+ .globl wrvptptr
+ .ent wrvptptr
+wrvptptr:
+ .prologue 0
+ call_pal PAL_wrvptptr
+ ret ($26)
+ .end wrvptptr
+
#
# The following two functions are needed for supporting SRM PALcode
# on the PC164 (at least), since that PALcode manages the interrupt
call_pal PAL_cserve
ret ($26)
.end cserve_dis
+
+ #
+ # It is handy, on occasion, to make halt actually just loop.
+ # Putting it here means we dont have to recompile the whole
+ # kernel.
+ #
+
+ .align 3
+ .globl halt
+ .ent halt
+halt:
+ .prologue 0
+ call_pal PAL_halt
+ .end halt
int get_irq_list(char *buf)
{
- int i, len = 0;
+ int i, j;
struct irqaction * action;
- int cpu = smp_processor_id();
+ char *p = buf;
+
+#ifdef __SMP__
+ p += sprintf(p, " ");
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "CPU%d ", j);
+ *p++ = '\n';
+#endif
for (i = 0; i < NR_IRQS; i++) {
action = irq_action[i];
if (!action)
continue;
- len += sprintf(buf+len, "%2d: %10u %c %s",
- i, kstat.irqs[cpu][i],
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
+ p += sprintf(p, "%3d: ",i);
+#ifndef __SMP__
+ p += sprintf(p, "%10u ", kstat_irqs(i));
+#else
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10u ",
+ kstat.irqs[cpu_logical_map(j)][i]);
+#endif
+ p += sprintf(p, " %c%s",
+ (action->flags & SA_INTERRUPT)?'+':' ',
+ action->name);
+
for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ", %s%s",
- (action->flags & SA_INTERRUPT) ? "+":"",
- action->name);
+ p += sprintf(p, ", %c%s",
+ (action->flags & SA_INTERRUPT)?'+':' ',
+ action->name);
}
- len += sprintf(buf+len, "\n");
+ *p++ = '\n';
}
- return len;
+ return p - buf;
}
#ifdef __SMP__
/*
* Finally.
*/
+#if DEBUG_SPINLOCK
global_irq_lock.task = current;
global_irq_lock.previous = where;
+#endif
global_irq_holder = cpu;
previous_irqholder = where;
}
#define STANDARD_INIT_IRQ_PROLOG \
outb(0, DMA1_RESET_REG); \
outb(0, DMA2_RESET_REG); \
- outb(0, DMA1_MASK_REG); \
- outb(0, DMA2_MASK_REG); \
outb(0, DMA1_CLR_MASK_REG); \
- outb(0, DMA2_CLR_MASK_REG); \
- outb(DMA_MODE_CASCADE, DMA2_MODE_REG)
-
+ outb(0, DMA2_CLR_MASK_REG)
extern unsigned long alpha_irq_mask;
#define CAT1(x,y) x##y
#define CAT(x,y) CAT1(x,y)
-#define DO_DEFAULT_RTC \
- rtc_port: 0x70, rtc_addr: 0x80, rtc_bcd: 0
+#define DO_DEFAULT_RTC rtc_port: 0x70
#define DO_EV4_MMU \
max_asn: EV4_MAX_ASN, \
return;
}
+ if (alpha_using_srm)
+ srm_paging_stop();
+
halt();
}
/* time.c */
extern void timer_interrupt(int irq, void *dev, struct pt_regs * regs);
+extern unsigned long est_cycle_freq;
/* smc37c93x.c */
extern void SMC93x_Init(void);
extern void entUna(void);
/* process.c */
-void generic_kill_arch (int mode, char *reboot_cmd);
-void cpu_idle(void *) __attribute__((noreturn));
+extern void generic_kill_arch (int mode, char *reboot_cmd);
+extern void cpu_idle(void *) __attribute__((noreturn));
+
+/* ptrace.c */
+extern int ptrace_set_bpt (struct task_struct *child);
+extern int ptrace_cancel_bpt (struct task_struct *child);
+
+/* ../mm/init.c */
+void srm_paging_stop(void);
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
+#include <linux/malloc.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
+#include "proto.h"
+
+#define DEBUG DBG_MEM
#undef DEBUG
#ifdef DEBUG
-
enum {
DBG_MEM = (1<<0),
DBG_BPT = (1<<1),
DBG_MEM_ALL = (1<<2)
};
-
-int debug_mask = DBG_BPT;
-
-# define DBG(fac,args) {if ((fac) & debug_mask) printk args;}
-
+#define DBG(fac,args) {if ((fac) & DEBUG) printk args;}
#else
-# define DBG(fac,args)
+#define DBG(fac,args)
#endif
#define BREAKINST 0x00000080 /* call_pal bpt */
/*
* Processes always block with the following stack-layout:
*
- * +================================+ --------------------------
- * | PALcode saved frame (ps, pc, | ^ ^
- * | gp, a0, a1, a2) | | |
- * +================================+ | struct pt_regs |
- * | | | |
- * | frame generated by SAVE_ALL | | |
- * | | v | P
- * +================================+ | A
- * | | ^ | G
- * | frame saved by do_switch_stack | | struct switch_stack | E
- * | | v | _
- * +================================+ | S
- * | | | I
- * | | | Z
- * / / | E
- * / / |
- * | | |
- * | | |
- * | | v
- * +================================+ <-------------------------
- * task + PAGE_SIZE
+ * +================================+ <---- task + 2*PAGE_SIZE
+ * | PALcode saved frame (ps, pc, | ^
+ * | gp, a0, a1, a2) | |
+ * +================================+ | struct pt_regs
+ * | | |
+ * | frame generated by SAVE_ALL | |
+ * | | v
+ * +================================+
+ * | | ^
+ * | frame saved by do_switch_stack | | struct switch_stack
+ * | | v
+ * +================================+
*/
-#define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
+#define PT_REG(reg) (PAGE_SIZE*2 - sizeof(struct pt_regs) \
+ (long)&((struct pt_regs *)0)->reg)
-#define SW_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
- - sizeof(struct switch_stack) \
+
+#define SW_REG(reg) (PAGE_SIZE*2 - sizeof(struct pt_regs) \
+ - sizeof(struct switch_stack) \
+ (long)&((struct switch_stack *)0)->reg)
+
/*
* The following table maps a register index into the stack offset at
* which the register is saved. Register indices are 0-31 for integer
* get_reg/put_reg below).
*/
enum {
- REG_R0 = 0, REG_F0 = 32, REG_PC = 64
+ REG_R0 = 0, REG_F0 = 32, REG_FPCR = 63, REG_PC = 64
};
-static unsigned short regoff[] = {
+static int regoff[] = {
PT_REG( r0), PT_REG( r1), PT_REG( r2), PT_REG( r3),
PT_REG( r4), PT_REG( r5), PT_REG( r6), PT_REG( r7),
PT_REG( r8), SW_REG( r9), SW_REG( r10), SW_REG( r11),
static long zero;
/*
- * Get contents of register REGNO in task TASK.
+ * Get address of register REGNO in task TASK.
*/
-static inline long get_reg(struct task_struct * task, long regno)
+static long *
+get_reg_addr(struct task_struct * task, unsigned long regno)
{
long *addr;
if (regno == 30) {
addr = &task->tss.usp;
- } else if (regno == 31) {
+ } else if (regno == 31 || regno > 64) {
zero = 0;
addr = &zero;
} else {
- addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task);
+ addr = (long *)((long)task + regoff[regno]);
}
- return *addr;
+ return addr;
}
/*
- * Write contents of register REGNO in task TASK.
+ * Get contents of register REGNO in task TASK.
*/
-static inline int put_reg(struct task_struct *task, long regno, long data)
+static inline long
+get_reg(struct task_struct * task, unsigned long regno)
{
- long *addr, zero;
+ return *get_reg_addr(task, regno);
+}
- if (regno == 30) {
- addr = &task->tss.usp;
- } else if (regno == 31) {
- addr = &zero;
- } else {
- addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task);
- }
- *addr = data;
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int
+put_reg(struct task_struct *task, unsigned long regno, long data)
+{
+ *get_reg_addr(task, regno) = data;
return 0;
}
* and that it is in the task area before calling this: this routine does
* no checking.
*/
-static unsigned long get_long(struct task_struct * tsk,
- struct vm_area_struct * vma, unsigned long addr)
+static unsigned long
+get_long(struct task_struct * tsk, struct vm_area_struct * vma,
+ unsigned long addr)
{
pgd_t * pgdir;
pmd_t * pgmiddle;
* Now keeps R/W state of page so that a text page stays readonly
* even if a debugger scribbles breakpoints into it. -M.U-
*/
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
- unsigned long addr, unsigned long data)
+static void
+put_long(struct task_struct * tsk, struct vm_area_struct * vma,
+ unsigned long addr, unsigned long data)
{
pgd_t *pgdir;
pmd_t *pgmiddle;
flush_tlb();
}
-static struct vm_area_struct * find_extend_vma(struct task_struct * tsk,
- unsigned long addr)
+static struct vm_area_struct *
+find_extend_vma(struct task_struct * tsk, unsigned long addr)
{
struct vm_area_struct * vma;
* This routine checks the page boundaries, and that the offset is
* within the task area. It then calls get_long() to read a long.
*/
-static int read_long(struct task_struct * tsk, unsigned long addr,
- unsigned long * result)
+static int
+read_long(struct task_struct * tsk, unsigned long addr, unsigned long * result)
{
struct vm_area_struct * vma = find_extend_vma(tsk, addr);
* This routine checks the page boundaries, and that the offset is
* within the task area. It then calls put_long() to write a long.
*/
-static int write_long(struct task_struct * tsk, unsigned long addr,
- unsigned long data)
+static int
+write_long(struct task_struct * tsk, unsigned long addr, unsigned long data)
{
struct vm_area_struct * vma = find_extend_vma(tsk, addr);
/*
* Read a 32bit int from address space TSK.
*/
-static int read_int(struct task_struct * tsk, unsigned long addr,
- unsigned int *data)
+static int
+read_int(struct task_struct * tsk, unsigned long addr, unsigned int *data)
{
unsigned long l, align;
int res;
* For simplicity, do a read-modify-write of the 64bit word that
* contains the 32bit word that we are about to write.
*/
-static int write_int(struct task_struct * tsk, unsigned long addr,
- unsigned int data)
+static int
+write_int(struct task_struct * tsk, unsigned long addr, unsigned int data)
{
unsigned long l, align;
int res;
/*
* Set breakpoint.
*/
-int ptrace_set_bpt(struct task_struct * child)
+int
+ptrace_set_bpt(struct task_struct * child)
{
int displ, i, res, reg_b, nsaved = 0;
u32 insn, op_code;
* branch (emulation can be tricky for fp branches).
*/
displ = ((s32)(insn << 11)) >> 9;
- child->tss.debugreg[nsaved++] = pc + 4;
+ child->tss.bpt_addr[nsaved++] = pc + 4;
if (displ) /* guard against unoptimized code */
- child->tss.debugreg[nsaved++] = pc + 4 + displ;
+ child->tss.bpt_addr[nsaved++] = pc + 4 + displ;
DBG(DBG_BPT, ("execing branch\n"));
} else if (op_code == 0x1a) {
reg_b = (insn >> 16) & 0x1f;
- child->tss.debugreg[nsaved++] = get_reg(child, reg_b);
+ child->tss.bpt_addr[nsaved++] = get_reg(child, reg_b);
DBG(DBG_BPT, ("execing jump\n"));
} else {
- child->tss.debugreg[nsaved++] = pc + 4;
+ child->tss.bpt_addr[nsaved++] = pc + 4;
DBG(DBG_BPT, ("execing normal insn\n"));
}
/* install breakpoints: */
for (i = 0; i < nsaved; ++i) {
- res = read_int(child, child->tss.debugreg[i], &insn);
+ res = read_int(child, child->tss.bpt_addr[i], &insn);
if (res < 0)
return res;
- child->tss.debugreg[i + 2] = insn;
- DBG(DBG_BPT, (" -> next_pc=%lx\n", child->tss.debugreg[i]));
- res = write_int(child, child->tss.debugreg[i], BREAKINST);
+ child->tss.bpt_insn[i] = insn;
+ DBG(DBG_BPT, (" -> next_pc=%lx\n", child->tss.bpt_addr[i]));
+ res = write_int(child, child->tss.bpt_addr[i], BREAKINST);
if (res < 0)
return res;
}
- child->tss.debugreg[4] = nsaved;
+ child->tss.bpt_nsaved = nsaved;
return 0;
}
* Ensure no single-step breakpoint is pending. Returns non-zero
* value if child was being single-stepped.
*/
-int ptrace_cancel_bpt(struct task_struct * child)
+int
+ptrace_cancel_bpt(struct task_struct * child)
{
- int i, nsaved = child->tss.debugreg[4];
+ int i, nsaved = child->tss.bpt_nsaved;
- child->tss.debugreg[4] = 0;
+ child->tss.bpt_nsaved = 0;
if (nsaved > 2) {
printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
}
for (i = 0; i < nsaved; ++i) {
- write_int(child, child->tss.debugreg[i],
- child->tss.debugreg[i + 2]);
+ write_int(child, child->tss.bpt_addr[i],
+ child->tss.bpt_insn[i]);
}
return (nsaved != 0);
}
-asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
- int a4, int a5, struct pt_regs regs)
+asmlinkage long
+sys_ptrace(long request, long pid, long addr, long data,
+ int a4, int a5, struct pt_regs regs)
{
struct task_struct *child;
+ unsigned long tmp;
long ret;
lock_kernel();
switch (request) {
/* When I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
-
+ case PTRACE_PEEKDATA:
ret = read_long(child, addr, &tmp);
DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp));
if (ret < 0)
regs.r0 = 0; /* special return: no errors */
ret = tmp;
goto out;
- }
- /* read register number ADDR. */
+ /* Read register number ADDR. */
case PTRACE_PEEKUSR:
regs.r0 = 0; /* special return: no errors */
- DBG(DBG_MEM, ("peek $%ld=%#lx\n", addr, regs.r0));
ret = get_reg(child, addr);
+ DBG(DBG_MEM, ("peek $%ld->%#lx\n", addr, ret));
goto out;
/* When I and D space are separate, this will have to be fixed. */
case PTRACE_SYSCALL: /* continue and stop at next
(return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
+ case PTRACE_CONT: /* restart after signal. */
ret = -EIO;
if ((unsigned long) data > _NSIG)
goto out;
ptrace_cancel_bpt(child);
ret = data;
goto out;
- }
/*
* 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: {
+ case PTRACE_KILL:
if (child->state != TASK_ZOMBIE) {
wake_up_process(child);
child->exit_code = SIGKILL;
ptrace_cancel_bpt(child);
ret = 0;
goto out;
- }
- case PTRACE_SINGLESTEP: { /* execute single instruction. */
+ case PTRACE_SINGLESTEP: /* execute single instruction. */
ret = -EIO;
if ((unsigned long) data > _NSIG)
goto out;
- child->tss.debugreg[4] = -1; /* mark single-stepping */
+ child->tss.bpt_nsaved = -1; /* mark single-stepping */
child->flags &= ~PF_TRACESYS;
wake_up_process(child);
child->exit_code = data;
/* give it a chance to run. */
ret = 0;
goto out;
- }
- case PTRACE_DETACH: { /* detach a process that was attached. */
+ case PTRACE_DETACH: /* detach a process that was attached. */
ret = -EIO;
if ((unsigned long) data > _NSIG)
goto out;
ptrace_cancel_bpt(child);
ret = 0;
goto out;
- }
default:
ret = -EIO;
return ret;
}
-asmlinkage void syscall_trace(void)
+asmlinkage void
+syscall_trace(void)
{
if ((current->flags & (PF_PTRACED|PF_TRACESYS))
!= (PF_PTRACED|PF_TRACESYS))
vec = eb66_vecs[eb66_indices[member]];
break;
case ST_DEC_1000:
- if (cpu == EV5_CPU)
+ cpu &= 0xffffffff;
+ if (cpu == EV5_CPU || cpu == EV56_CPU)
vec = &mikasa_primo_mv;
else
vec = &mikasa_mv;
break;
case ST_DEC_NORITAKE:
- if (cpu == EV5_CPU)
+ cpu &= 0xffffffff;
+ if (cpu == EV5_CPU || cpu == EV56_CPU)
vec = &noritake_primo_mv;
else
vec = &noritake_mv;
break;
case ST_DEC_2100_A500:
- if (cpu == EV5_CPU)
+ cpu &= 0xffffffff;
+ if (cpu == EV5_CPU || cpu == EV56_CPU)
vec = &sable_gamma_mv;
else
vec = &sable_mv;
"system variation\t: %s\n"
"system revision\t\t: %ld\n"
"system serial number\t: %s\n"
- "cycle frequency [Hz]\t: %lu\n"
+ "cycle frequency [Hz]\t: %lu %s\n"
"timer frequency [Hz]\t: %lu.%02lu\n"
"page size [bytes]\t: %ld\n"
"phys. address bits\t: %ld\n"
(char*)cpu->serial_no,
systype_name, sysvariation_name, hwrpb->sys_revision,
(char*)hwrpb->ssn,
- hwrpb->cycle_freq,
+ hwrpb->cycle_freq ? : est_cycle_freq,
+ hwrpb->cycle_freq ? "" : "est.",
hwrpb->intr_freq / 4096,
(100 * hwrpb->intr_freq / 4096) % 100,
hwrpb->pagesize,
platform_string());
#ifdef __SMP__
- return len + smp_info(buffer+len);
-#else
- return len;
+ len += smp_info(buffer+len);
#endif
+
+ return len;
}
asmlinkage int do_signal(sigset_t *, struct pt_regs *,
struct switch_stack *, unsigned long, unsigned long);
-extern int ptrace_set_bpt (struct task_struct *child);
-extern int ptrace_cancel_bpt (struct task_struct *child);
-
/*
* The OSF/1 sigprocmask calling sequence is different from the
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/hwrpb.h>
#include <asm/io.h>
unsigned long indexPort;
unsigned long dataPort;
+ int i;
+
configPort = indexPort = baseAddr;
dataPort = configPort + 1;
- outb(CONFIG_ON_KEY, configPort);
- outb(CONFIG_ON_KEY, configPort);
- outb(DEVICE_ID, indexPort);
- devId = inb(dataPort);
- if ( devId == VALID_DEVICE_ID ) {
- outb(DEVICE_REV, indexPort);
- devRev = inb(dataPort);
- }
- else {
- baseAddr = 0;
+#define NUM_RETRIES 5
+
+ for (i = 0; i < NUM_RETRIES; i++)
+ {
+ outb(CONFIG_ON_KEY, configPort);
+ outb(CONFIG_ON_KEY, configPort);
+ outb(DEVICE_ID, indexPort);
+ devId = inb(dataPort);
+ if (devId == VALID_DEVICE_ID) {
+ outb(DEVICE_REV, indexPort);
+ devRev = inb(dataPort);
+ break;
+ }
+ else
+ udelay(100);
}
- return baseAddr;
+ return (i != NUM_RETRIES) ? baseAddr : 0L;
}
static void __init SMCRunState(unsigned long baseAddr)
unsigned int boot_cpu_id = 0;
static int smp_activated = 0;
+static unsigned long ipicnt[NR_CPUS] = {0,}; /* IPI counts */
int smp_found_config = 0; /* Have we found an SMP box */
static int max_cpus = -1;
{
tbia();
clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
- mb();
return 0;
}
local_flush_tlb_mm(unsigned int this_cpu)
{
struct mm_struct * mm = ipi_msg_flush_tb.p.flush_mm;
- if (mm != current->mm)
- flush_tlb_other(mm);
- else
+ if (mm == current->mm)
flush_tlb_current(mm);
clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
- mb();
return 0;
}
struct vm_area_struct * vma = ipi_msg_flush_tb.p.flush_vma;
struct mm_struct * mm = vma->vm_mm;
- if (mm != current->mm)
- flush_tlb_other(mm);
- else
+ if (mm == current->mm)
flush_tlb_current_page(mm, vma, ipi_msg_flush_tb.flush_addr);
clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
- mb();
return 0;
}
volatile int * pending_ipis = &ipi_bits[this_cpu];
int ops;
- mb();
+ mb(); /* Order bit setting and interrupt. */
#if 0
printk("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n",
this_cpu, *pending_ipis, regs->pc);
for (first = 0; (ops & 1) == 0; ++first, ops >>= 1)
; /* look for the first thing to do */
clear_bit(first, pending_ipis);
- mb();
+ mb(); /* Order bit clearing and data access. */
if ((*ipi_func[first])(this_cpu))
- printk("%d\n", first);
- mb();
+ printk("%d\n", first);
+ mb(); /* Order data access and bit clearing. */
}
if (hwrpb->txrdy)
secondary_console_message();
int i;
unsigned int j;
+ mb(); /* Order out-of-band data and bit setting. */
for (i = 0, j = 1; i < NR_CPUS; ++i, j += j) {
if ((to_whom & j) == 0)
continue;
set_bit(operation, &ipi_bits[i]);
- mb();
+ mb(); /* Order bit setting and interrupt. */
wripir(i);
}
}
-int smp_info(char *buffer)
+int
+smp_info(char *buffer)
{
- return sprintf(buffer, "CPUs probed %d active %d map 0x%x\n",
- smp_num_probed, smp_num_cpus, cpu_present_map);
+ int i;
+ unsigned long sum = 0;
+ for (i = 0; i < NR_CPUS; i++)
+ sum += ipicnt[i];
+
+ return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n",
+ smp_num_probed, smp_num_cpus, cpu_present_map, sum);
}
/* wrapper for call from panic() */
unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id());
int timeout = 10000;
+ spin_lock_own(&kernel_flag, "flush_tlb_all");
+
ipi_msg_flush_tb.flush_tb_mask = to_whom;
send_ipi_message(to_whom, TLB_ALL);
tbia();
while (ipi_msg_flush_tb.flush_tb_mask) {
- if (--timeout < 0) {
- printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n",
- smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask);
- ipi_msg_flush_tb.flush_tb_mask = 0;
- break;
- }
- udelay(100);
- ; /* Wait for all clear from other CPUs. */
+ if (--timeout < 0) {
+ printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n",
+ smp_processor_id(),
+ ipi_msg_flush_tb.flush_tb_mask);
+ ipi_msg_flush_tb.flush_tb_mask = 0;
+ break;
+ }
+ /* Wait for all clear from other CPUs. */
+ udelay(100);
}
}
unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id());
int timeout = 10000;
+ spin_lock_own(&kernel_flag, "flush_tlb_mm");
+
ipi_msg_flush_tb.p.flush_mm = mm;
ipi_msg_flush_tb.flush_tb_mask = to_whom;
send_ipi_message(to_whom, TLB_MM);
struct mm_struct * mm = vma->vm_mm;
int timeout = 10000;
+ spin_lock_own(&kernel_flag, "flush_tlb_page");
+
ipi_msg_flush_tb.p.flush_vma = vma;
ipi_msg_flush_tb.flush_addr = addr;
ipi_msg_flush_tb.flush_tb_mask = to_whom;
timeout = 10000;
to_whom = cpu_present_map ^ (1 << smp_processor_id());
+ spin_lock_own(&kernel_flag, "flush_tlb_range");
+
ipi_msg_flush_tb.p.flush_mm = mm;
ipi_msg_flush_tb.flush_tb_mask = to_whom;
send_ipi_message(to_whom, TLB_MM);
}
#if DEBUG_SPINLOCK
-void spin_lock(spinlock_t * lock)
+
+#ifdef MANAGE_SPINLOCK_IPL
+
+static inline long
+spinlock_raise_ipl(spinlock_t * lock)
+{
+ long min_ipl = lock->target_ipl;
+ long last_ipl = swpipl(7);
+ if (last_ipl < 7 && min_ipl < 7)
+ setipl(min_ipl < last_ipl ? last_ipl : min_ipl);
+ return last_ipl;
+}
+
+static inline void
+spinlock_restore_ipl(long prev)
+{
+ setipl(prev);
+}
+
+#else
+
+#define spinlock_raise_ipl(LOCK) 0
+#define spinlock_restore_ipl(PREV) ((void)0)
+
+#endif /* MANAGE_SPINLOCK_IPL */
+
+void
+spin_unlock(spinlock_t * lock)
+{
+ long old_ipl = lock->saved_ipl;
+ mb();
+ lock->lock = 0;
+ spinlock_restore_ipl(old_ipl);
+}
+
+void
+spin_lock(spinlock_t * lock)
{
long tmp;
- long stuck;
+ long stuck = 1<<27;
void *inline_pc = __builtin_return_address(0);
+ unsigned long started = jiffies;
+ int printed = 0;
+ int cpu = smp_processor_id();
+ long old_ipl = spinlock_raise_ipl(lock);
try_again:
of this object file's text section so as to perfect
branch prediction. */
__asm__ __volatile__(
- "1: ldq_l %0,%1\n"
+ "1: ldl_l %0,%1\n"
" subq %2,1,%2\n"
" blbs %0,2f\n"
" or %0,1,%0\n"
- " stq_c %0,%1\n"
+ " stl_c %0,%1\n"
" beq %0,3f\n"
"4: mb\n"
".section .text2,\"ax\"\n"
- "2: ldq %0,%1\n"
+ "2: ldl %0,%1\n"
" subq %2,1,%2\n"
"3: blt %2,4b\n"
" blbs %0,2b\n"
: "2" (stuck));
if (stuck < 0) {
- printk("spinlock stuck at %p (cur=%p, own=%p, prev=%p)\n",
- inline_pc, current, lock->task, lock->previous);
+ if (!printed) {
+ printk("spinlock stuck at %p(%d) owner %s at %p\n",
+ inline_pc, cpu, lock->task->comm,
+ lock->previous);
+ printed = 1;
+ }
+ stuck = 1<<30;
goto try_again;
- } else {
- lock->previous = inline_pc;
+ }
+
+ /* Exiting. Got the lock. */
+ lock->saved_ipl = old_ipl;
+ lock->on_cpu = cpu;
+ lock->previous = inline_pc;
+ lock->task = current;
+
+ if (printed) {
+ printk("spinlock grabbed at %p(%d) %ld ticks\n",
+ inline_pc, cpu, jiffies - started);
+ }
+}
+
+int
+spin_trylock(spinlock_t * lock)
+{
+ long old_ipl = spinlock_raise_ipl(lock);
+ int ret;
+ if ((ret = !test_and_set_bit(0, lock))) {
+ mb();
+ lock->saved_ipl = old_ipl;
+ lock->on_cpu = smp_processor_id();
+ lock->previous = __builtin_return_address(0);
lock->task = current;
+ } else {
+ spinlock_restore_ipl(old_ipl);
}
+ return ret;
}
#endif /* DEBUG_SPINLOCK */
__asm__ __volatile__(
"1: ldl_l %1,%0\n"
" blbs %1,6f\n"
- " or %1,1,%2\n"
- " stl_c %2,%0\n"
- " beq %2,6f\n"
" blt %1,8f\n"
+ " mov 1,%1\n"
+ " stl_c %1,%0\n"
+ " beq %1,6f\n"
"4: mb\n"
".section .text2,\"ax\"\n"
- "6: ldl %1,%0\n"
- " blt %3,4b # debug\n"
+ "6: blt %3,4b # debug\n"
" subl %3,1,%3 # debug\n"
+ " ldl %1,%0\n"
" blbs %1,6b\n"
- " br 1b\n"
- "8: ldl %1,%0\n"
- " blt %4,4b # debug\n"
+ "8: blt %4,4b # debug\n"
" subl %4,1,%4 # debug\n"
+ " ldl %1,%0\n"
" blt %1,8b\n"
- " br 4b\n"
+ " br 1b\n"
".previous"
: "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy)
, "=&r" (stuck_lock), "=&r" (stuck_reader)
BUS(jensen),
machine_check: jensen_machine_check,
max_dma_address: ALPHA_MAX_DMA_ADDRESS,
- rtc_port: 0x170, rtc_addr: 0, rtc_bcd: 1,
+ rtc_port: 0x170,
nr_irqs: 16,
irq_probe_mask: _PROBE_MASK(16),
struct alpha_machine_vector ruffian_mv __initmv = {
vector_name: "Ruffian",
DO_EV5_MMU,
- /* RUFFIAN always uses BCD, like a PeeCee. */
- rtc_port: 0x70, rtc_addr: 0x80, rtc_bcd: 1,
+ DO_DEFAULT_RTC,
/* For the moment, do not use BWIO on RUFFIAN. */
IO(PYXIS,pyxis,pyxis),
DO_PYXIS_BUS,
static void
sx164_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
+ outb(0, DMA1_RESET_REG);
+ outb(0, DMA2_RESET_REG);
+ outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
+ outb(0, DMA2_MASK_REG);
if (alpha_using_srm) {
alpha_mv.update_irq_hw = sx164_srm_update_irq_hw;
time_t last_rtc_update;
} state;
+unsigned long est_cycle_freq;
+
static inline __u32 rpcc(void)
{
* drivers depend on them being initialized (e.g., joystick driver).
*/
-/* It is (normally) only counter 1 that presents config problems, so
+/* It is (normally) only counter 0 that presents config problems, so
provide this support function to do the rest of the job. */
void inline
static inline void
rtc_init_pit (void)
{
+ unsigned char control;
+
/* Setup interval timer if /dev/rtc is being used */
outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */
outb(LATCH & 0xff, 0x40); /* LSB */
outb(LATCH >> 8, 0x40); /* MSB */
request_region(0x40, 0x20, "timer"); /* reserve pit */
+ /* Turn off RTC interrupts before /dev/rtc is initialized */
+ control = CMOS_READ(RTC_CONTROL);
+ control &= ~(RTC_PIE | RTC_AIE | RTC_UIE);
+ CMOS_WRITE(control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+
init_pit_rest();
}
#endif
void
generic_init_pit (void)
{
- int x;
- if ((x = (CMOS_READ(RTC_FREQ_SELECT) & 0x3f)) != 0x26) {
+ unsigned char x;
+
+ /* Reset periodic interrupt frequency. */
+ x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f;
+ if (x != 0x26 && x != 0x19 && x != 0x06) {
printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x);
CMOS_WRITE(0x26, RTC_FREQ_SELECT);
}
+
+ /* Turn on periodic interrupts. */
+ x = CMOS_READ(RTC_CONTROL);
+ if (!(x & RTC_PIE)) {
+ printk("Turning on RTC interrupts.\n");
+ x |= RTC_PIE;
+ x &= ~(RTC_AIE | RTC_UIE);
+ CMOS_WRITE(x, RTC_CONTROL);
+ }
+ CMOS_READ(RTC_INTR_FLAGS);
+
request_region(RTC_PORT(0), 0x10, "timer"); /* reserve rtc */
/* Turn off the PIT. */
void
time_init(void)
{
-#ifdef CONFIG_RTC
- unsigned char save_control;
-#endif
void (*irq_handler)(int, void *, struct pt_regs *);
unsigned int year, mon, day, hour, min, sec, cc1, cc2;
+ unsigned long cycle_freq;
/* Initialize the timers. */
init_pit();
/* If our cycle frequency isn't valid, go another round and give
a guess at what it should be. */
- if (hwrpb->cycle_freq == 0) {
+ cycle_freq = hwrpb->cycle_freq;
+ if (cycle_freq == 0) {
printk("HWRPB cycle frequency bogus. Estimating... ");
do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
cc2 = rpcc();
- hwrpb->cycle_freq = cc2 - cc1;
+ est_cycle_freq = cycle_freq = cc2 - cc1;
cc1 = cc2;
- printk("%lu Hz\n", hwrpb->cycle_freq);
+ printk("%lu Hz\n", cycle_freq);
}
/* From John Bowman <bowman@math.ualberta.ca>: allow the values
state.last_time = cc1;
state.scaled_ticks_per_cycle
- = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq;
+ = ((unsigned long) HZ << FIX_SHIFT) / cycle_freq;
state.last_rtc_update = 0;
-#ifdef CONFIG_RTC
- /* turn off RTC interrupts before /dev/rtc is initialized */
- save_control = CMOS_READ(RTC_CONTROL);
- save_control &= ~RTC_PIE;
- save_control &= ~RTC_AIE;
- save_control &= ~RTC_UIE;
- CMOS_WRITE(save_control, RTC_CONTROL);
- CMOS_READ(RTC_INTR_FLAGS);
-#endif
-
/* setup timer */
irq_handler = timer_interrupt;
if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL))
unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs)
{
- extern int ptrace_cancel_bpt (struct task_struct *who);
-
lock_kernel();
die_if_kernel("Instruction fault", ®s, type, 0);
switch (type) {
#define OP_INT_MASK ( 1L << 0x28 | 1L << 0x2c /* ldl stl */ \
| 1L << 0x29 | 1L << 0x2d /* ldq stq */ \
- | 1L << 0x0c | 1L << 0x0d ) /* ldwu stw */
+ | 1L << 0x0c | 1L << 0x0d /* ldwu stw */ \
+ | 1L << 0x0a | 1L << 0x0e ) /* ldbu stb */
#define OP_WRITE_MASK ( 1L << 0x26 | 1L << 0x27 /* sts stt */ \
| 1L << 0x2c | 1L << 0x2d /* stl stq */ \
- | 1L << 0xd ) /* stw */
+ | 1L << 0x0d | 1L << 0x0e ) /* stw stb */
#define R(x) ((size_t) &((struct pt_regs *)0)->x)
strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \
strchr.o strrchr.o \
copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \
- csum_ipv6_magic.o strcasecmp.o
+ csum_ipv6_magic.o strcasecmp.o \
+ srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
--- /dev/null
+/*
+ * arch/alpha/lib/srm_dispatch.S
+ */
+
+.globl srm_dispatch
+.ent srm_dispatch
+srm_dispatch:
+ .frame $30,30,$26
+ subq $30,80,$30
+ stq $26,0($30)
+ stq $8,8($30)
+ stq $9,16($30)
+ stq $10,24($30)
+ stq $11,32($30)
+ stq $12,40($30)
+ stq $13,48($30)
+ stq $14,56($30)
+ stq $15,64($30)
+ stq $29,72($30)
+ .mask 0x2400FF00, -80
+ .prologue 0
+
+ ldq $1,hwrpb
+ ldq $2,0xc0($1) /* crb offset */
+ addq $2,$1,$2 /* crb */
+ ldq $27,0($2) /* dispatch procedure value */
+
+ ldq $2,8($27) /* dispatch call address */
+ jsr $26,($2) /* call it (weird VMS call seq) */
+
+ ldq $26,0($30)
+ ldq $8,8($30)
+ ldq $9,16($30)
+ ldq $10,24($30)
+ ldq $11,32($30)
+ ldq $12,40($30)
+ ldq $13,48($30)
+ ldq $14,56($30)
+ ldq $15,64($30)
+ ldq $29,72($30)
+ addq $30,80,$30
+ ret $31,($26),1
+.end srm_dispatch
--- /dev/null
+/*
+ * arch/alpha/lib/srm_fixup.S
+ */
+
+.globl srm_fixup
+.ent srm_fixup
+srm_fixup:
+ .frame $30,30,$26
+ subq $30,80,$30
+ stq $26,0($30)
+ stq $8,8($30)
+ stq $9,16($30)
+ stq $10,24($30)
+ stq $11,32($30)
+ stq $12,40($30)
+ stq $13,48($30)
+ stq $14,56($30)
+ stq $15,64($30)
+ stq $29,72($30)
+ .mask 0x2400FF00, -80
+ .prologue 0
+
+ ldq $2,0xc0($17) /* crb offset */
+ addq $2,$1,$2 /* crb */
+ ldq $27,16($2) /* fixup procedure value */
+
+ ldq $2,8($27) /* dispatch call address */
+ jsr $26,($2) /* call it (weird VMS call seq) */
+
+ ldq $26,0($30)
+ ldq $8,8($30)
+ ldq $9,16($30)
+ ldq $10,24($30)
+ ldq $11,32($30)
+ ldq $12,40($30)
+ ldq $13,48($30)
+ ldq $14,56($30)
+ ldq $15,64($30)
+ ldq $29,72($30)
+ addq $30,80,$30
+ ret $31,($26),1
+.end srm_fixup
--- /dev/null
+/*
+ * arch/alpha/lib/srm_printk.c
+ */
+
+#include <linux/kernel.h>
+#include <asm/console.h>
+
+long
+srm_printk(const char *fmt, ...)
+{
+ static char buf[1024];
+ va_list args;
+ long i;
+
+ va_start(args, fmt);
+ i = vsprintf(buf,fmt,args);
+ va_end(args);
+
+ srm_puts(buf);
+ return i;
+}
--- /dev/null
+/*
+ * arch/alpha/lib/srm_puts.c
+ */
+
+#include <linux/string.h>
+#include <asm/console.h>
+
+void
+srm_puts(const char *str)
+{
+ /* Expand \n to \r\n as we go. */
+
+ while (*str) {
+ long len;
+ const char *e = str;
+
+ if (*str == '\n') {
+ if (srm_dispatch(CCB_PUTS, 0, "\r", 1) < 0)
+ return;
+ ++e;
+ }
+
+ e = strchr(e, '\n') ? : strchr(e, '\0');
+ len = e - str;
+
+ while (len > 0) {
+ long written = srm_dispatch(CCB_PUTS, 0, str, len);
+ if (written < 0)
+ return;
+ len -= written & 0xffffffff;
+ str += written & 0xffffffff;
+ }
+ }
+}
extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);
-struct thread_struct * original_pcb_ptr;
+struct thread_struct original_pcb;
#ifndef __SMP__
struct pgtable_cache_struct quicklists;
unsigned long newptbr;
struct memclust_struct * cluster;
struct memdesc_struct * memdesc;
+ struct thread_struct *original_pcb_ptr;
/* initialize mem_map[] */
start_mem = free_area_init(start_mem, end_mem);
/* find free clusters, update mem_map[] accordingly */
memdesc = (struct memdesc_struct *)
- (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
+ (hwrpb->mddt_offset + (unsigned long) hwrpb);
cluster = memdesc->cluster;
for (i = memdesc->numclusters ; i > 0; i--, cluster++) {
unsigned long pfn, nr;
- if (cluster->usage & 1)
+
+ /* Bit 0 is console/PALcode reserved. Bit 1 is
+ non-volatile memory -- we might want to mark
+ this for later */
+ if (cluster->usage & 3)
continue;
pfn = cluster->start_pfn;
nr = cluster->numpages;
- /* non-volatile memory. We might want to mark this for later */
- if (cluster->usage & 2)
- continue;
-
while (nr--)
clear_bit(PG_reserved, &mem_map[pfn++].flags);
}
- /* unmap the console stuff: we don't need it, and we don't want it */
- /* Also set up the real kernel PCB while we're at it.. */
+ /* Initialize the kernel's page tables. Linux puts the vptb in
+ the last slot of the L1 page table. */
memset((void *) ZERO_PAGE, 0, PAGE_SIZE);
memset(swapper_pg_dir, 0, PAGE_SIZE);
newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
pgd_val(swapper_pg_dir[1023]) =
(newptbr << 32) | pgprot_val(PAGE_KERNEL);
+
+ /* Set the vptb. This is often done by the bootloader, but
+ shouldn't be required. */
+ if (hwrpb->vptb != 0xfffffffe00000000) {
+ wrvptptr(0xfffffffe00000000);
+ hwrpb->vptb = 0xfffffffe00000000;
+ hwrpb_update_checksum(hwrpb);
+ }
+
+ /* Also set up the real kernel PCB while we're at it. */
init_task.tss.ptbr = newptbr;
init_task.tss.pal_flags = 1; /* set FEN, clear everything else */
init_task.tss.flags = 0;
- original_pcb_ptr =
- phys_to_virt((unsigned long)load_PCB(&init_task.tss));
-#if 0
-printk("OKSP 0x%lx OPTBR 0x%lx\n",
- original_pcb_ptr->ksp, original_pcb_ptr->ptbr);
-#endif
-
+ original_pcb_ptr = load_PCB(&init_task.tss);
tbia();
+
+ /* Save off the contents of the original PCB so that we can
+ restore the original console's page tables for a clean reboot.
+
+ Note that the PCB is supposed to be a physical address, but
+ since KSEG values also happen to work, folks get confused.
+ Check this here. */
+
+ if ((unsigned long)original_pcb_ptr < PAGE_OFFSET) {
+ original_pcb_ptr = (struct thread_struct *)
+ phys_to_virt((unsigned long) original_pcb_ptr);
+ }
+ original_pcb = *original_pcb_ptr;
+
return start_mem;
}
current->tss.ptbr = init_task.tss.ptbr;
current->tss.pal_flags = 1;
current->tss.flags = 0;
-
-#if 0
-printk("paging_init_secondary: KSP 0x%lx PTBR 0x%lx\n",
- current->tss.ksp, current->tss.ptbr);
-#endif
-
load_PCB(¤t->tss);
tbia();
}
#endif /* __SMP__ */
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
+void
+srm_paging_stop (void)
+{
+ /* Move the vptb back to where the SRM console expects it. */
+ swapper_pg_dir[1] = swapper_pg_dir[1023];
+ tbia();
+ wrvptptr(0x200000000);
+ hwrpb->vptb = 0x200000000;
+ hwrpb_update_checksum(hwrpb);
+
+ /* Reload the page tables that the console had in use. */
+ load_PCB(&original_pcb);
+ tbia();
+}
+#endif
+
#if DEBUG_POISON
static void
kill_page(unsigned long pg)
* attempt to make use of direct access hints provided by the PCI BIOS).
*
* This should be close to trivial, but it isn't, because there are buggy
- * chipsets (yes, you guessed it, by Intel) that have no class ID.
+ * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
*/
__initfunc(int pci_sanity_check(struct pci_access *a))
{
return 1;
for(dfn=0; dfn < 0x100; dfn++)
if ((!a->read_config_word(0, dfn, PCI_CLASS_DEVICE, &x) &&
- x == PCI_CLASS_BRIDGE_HOST) ||
+ (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
(!a->read_config_word(0, dfn, PCI_VENDOR_ID, &x) &&
- x == PCI_VENDOR_ID_INTEL))
+ (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
return 1;
DBG("PCI: Sanity check failed\n");
return 0;
"486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL,
NULL, NULL, NULL, NULL, NULL }},
{ X86_VENDOR_INTEL, 5,
- { "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75+",
+ { "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75 - 200",
"OverDrive PODP5V83", "Pentium MMX", NULL, NULL,
- "Mobile Pentium 75+", "Mobile Pentium MMX", NULL, NULL, NULL,
+ "Mobile Pentium 75 - 200", "Mobile Pentium MMX", NULL, NULL, NULL,
NULL, NULL, NULL, NULL }},
{ X86_VENDOR_INTEL, 6,
{ "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)",
* precision CMOS clock update
* 1996-05-03 Ingo Molnar
* fixed time warps in do_[slow|fast]_gettimeoffset()
+ * 1998-09-05 (Various)
+ * More robust do_fast_gettimeoffset() algorithm implemented
+ * (works with APM, Cyrix 6x86MX and Centaur C6),
+ * monotonic gettimeofday() with fast_get_timeoffset(),
+ * drift-proof precision TSC calibration on boot
+ * (C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D.
+ * Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>;
+ * ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>).
*/
+
+/* What about the "updated NTP code" stuff in 2.0 time.c? It's not in
+ * 2.1, perhaps it should be ported, too.
+ *
+ * What about the BUGGY_NEPTUN_TIMER stuff in do_slow_gettimeoffset()?
+ * Whatever it fixes, is it also fixed in the new code from the Jumbo
+ * patch, so that that code can be used instead?
+ *
+ * The CPU Hz should probably be displayed in check_bugs() together
+ * with the CPU vendor and type. Perhaps even only in MHz, though that
+ * takes away some of the fun of the new code :)
+ *
+ * - Michael Krause */
+
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include "irq.h"
extern int setup_x86_irq(int, struct irqaction *);
-extern volatile unsigned long lost_ticks;
-/* change this if you have some constant time drift */
-#define USECS_PER_JIFFY (1000020/HZ)
+unsigned long cpu_hz; /* Detected as we calibrate the TSC */
+
+/* Number of usecs that the last interrupt was delayed */
+static int delay_at_last_interrupt;
+
+static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
-#ifndef CONFIG_APM /* cycle counter may be unreliable */
-/* Cycle counter value at the previous timer interrupt.. */
-static struct {
- unsigned long low;
- unsigned long high;
-} init_timer_cc, last_timer_cc;
+/* Cached *multiplier* to convert TSC counts to microseconds.
+ * (see the equation below).
+ * Equal to 2^32 * (1 / (clocks per usec) ).
+ * Initialized in time_init.
+ */
+static unsigned long fast_gettimeoffset_quotient=0;
static unsigned long do_fast_gettimeoffset(void)
{
register unsigned long eax asm("ax");
register unsigned long edx asm("dx");
- unsigned long tmp, quotient, low_timer;
-
- /* Last jiffy when do_fast_gettimeoffset() was called. */
- static unsigned long last_jiffies=0;
-
- /*
- * Cached "1/(clocks per usec)*2^32" value.
- * It has to be recalculated once each jiffy.
- */
- static unsigned long cached_quotient=0;
-
- tmp = jiffies;
-
- quotient = cached_quotient;
- low_timer = last_timer_cc.low;
-
- if (last_jiffies != tmp) {
- last_jiffies = tmp;
-
- /* Get last timer tick in absolute kernel time */
- eax = low_timer;
- edx = last_timer_cc.high;
- __asm__("subl "SYMBOL_NAME_STR(init_timer_cc)",%0\n\t"
- "sbbl "SYMBOL_NAME_STR(init_timer_cc)"+4,%1"
- :"=a" (eax), "=d" (edx)
- :"0" (eax), "1" (edx));
-
- /*
- * Divide the 64-bit time with the 32-bit jiffy counter,
- * getting the quotient in clocks.
- *
- * Giving quotient = "1/(average internal clocks per usec)*2^32"
- * we do this '1/...' trick to get the 'mull' into the critical
- * path. 'mull' is much faster than divl (10 vs. 41 clocks)
- */
- __asm__("divl %2"
- :"=a" (eax), "=d" (edx)
- :"r" (tmp),
- "0" (eax), "1" (edx));
-
- edx = USECS_PER_JIFFY;
- tmp = eax;
- eax = 0;
-
- __asm__("divl %2"
- :"=a" (eax), "=d" (edx)
- :"r" (tmp),
- "0" (eax), "1" (edx));
- cached_quotient = eax;
- quotient = eax;
- }
- /* Read the time counter */
- __asm__("rdtsc" : "=a" (eax), "=d" (edx));
+ /* Read the Time Stamp Counter */
+ __asm__("rdtsc"
+ :"=a" (eax), "=d" (edx));
/* .. relative to previous jiffy (32 bits is enough) */
edx = 0;
- eax -= low_timer;
+ eax -= last_tsc_low; /* tsc_low delta */
/*
- * Time offset = (USECS_PER_JIFFY * time_low) * quotient.
- */
+ * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient.
+ * = (tsc_low delta) / (clocks_per_usec)
+ * = (tsc_low delta) / (clocks_per_jiffy / usecs_per_jiffy)
+ *
+ * Using a mull instead of a divl saves up to 31 clock cycles
+ * in the critical path.
+ */
__asm__("mull %2"
:"=a" (eax), "=d" (edx)
- :"r" (quotient),
+ :"r" (fast_gettimeoffset_quotient),
"0" (eax), "1" (edx));
- /*
- * Due to possible jiffies inconsistencies, we need to check
- * the result so that we'll get a timer that is monotonic.
- */
- if (edx >= USECS_PER_JIFFY)
- edx = USECS_PER_JIFFY-1;
-
- return edx;
+ /* our adjusted time offset in microseconds */
+ return edx + delay_at_last_interrupt;
}
-#endif
/* This function must be called with interrupts disabled
* It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
return count;
}
-#ifndef CONFIG_APM
-/*
- * this is only used if we have fast gettimeoffset:
- */
-static void do_x86_get_fast_time(struct timeval * tv)
-{
- do_gettimeofday(tv);
-}
-#endif
-
static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
/*
- * This version of gettimeofday has near microsecond resolution.
+ * This version of gettimeofday has microsecond resolution
+ * and better than microsecond precision on fast x86 machines with TSC.
*/
void do_gettimeofday(struct timeval *tv)
{
cli();
*tv = xtime;
tv->tv_usec += do_gettimeoffset();
-
- /*
- * xtime is atomically updated in timer_bh. lost_ticks is
- * nonzero if the timer bottom half hasnt executed yet.
- */
- if (lost_ticks)
- tv->tv_usec += USECS_PER_JIFFY;
-
- restore_flags(flags);
-
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
}
+ restore_flags(flags);
}
void do_settimeofday(struct timeval *tv)
sti();
}
-
/*
* In order to set the CMOS clock precisely, set_rtc_mmss has to be
* called 500 ms after the second nowtime has started, because when
* nowtime is written into the registers of the CMOS clock, it will
* jump to the next second precisely 500 ms later. Check the Motorola
* MC146818A or Dallas DS12887 data sheet for details.
+ *
+ * BUG: This routine does not handle hour overflow properly; it just
+ * sets the minutes. Usually you'll only notice that after reboot!
*/
static int set_rtc_mmss(unsigned long nowtime)
{
}
CMOS_WRITE(real_seconds,RTC_SECONDS);
CMOS_WRITE(real_minutes,RTC_MINUTES);
- } else
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
retval = -1;
+ }
/* The following flags have to be released exactly in this order,
* otherwise the DS12887 (popular MC146818A clone with integrated
#endif
}
-#ifndef CONFIG_APM /* cycle counter may be unreliable */
/*
* This is the same as the above, except we _also_ save the current
- * cycle counter value at the time of the timer interrupt, so that
+ * Time Stamp Counter value at the time of the timer interrupt, so that
* we later on can estimate the time of day more exactly.
*/
static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
+ int count, flags;
+
+ /* It is important that these two operations happen almost at the
+ * same time. We do the RDTSC stuff first, since it's faster. To
+ * avoid any inconsistencies, we disable interrupts locally.
+ */
+
+ __save_flags(flags);
+ __cli();
/* read Pentium cycle counter */
__asm__("rdtsc"
- :"=a" (last_timer_cc.low),
- "=d" (last_timer_cc.high));
+ :"=a" (last_tsc_low):: "eax", "edx");
+
+ outb_p(0x00, 0x43); /* latch the count ASAP */
+
+ count = inb_p(0x40); /* read the latched count */
+ count |= inb(0x40) << 8;
+
+ count = ((LATCH-1) - count) * TICK_SIZE;
+ delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+ __restore_flags(flags);
+
timer_interrupt(irq, NULL, regs);
}
-#endif
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
+/* ------ Calibrate the TSC -------
+ * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
+ * Too much 64-bit arithmetic here to do this cleanly in C, and for
+ * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
+ * output busy loop as low as possible. We avoid reading the CTC registers
+ * directly because of the awkward 8-bit access mechanism of the 82C54
+ * device.
+ */
+
+__initfunc(static unsigned long calibrate_tsc(void))
+{
+ unsigned long retval;
+
+ __asm__( /* set the Gate high, program CTC channel 2 for mode 0
+ * (interrupt on terminal count mode), binary count,
+ * load 5 * LATCH count, (LSB and MSB)
+ * to begin countdown, read the TSC and busy wait.
+ * BTW LATCH is calculated in timex.h from the HZ value
+ */
+
+ /* Set the Gate high, disable speaker */
+ "inb $0x61, %%al\n\t" /* Read port */
+ "andb $0xfd, %%al\n\t" /* Turn off speaker Data */
+ "orb $0x01, %%al\n\t" /* Set Gate high */
+ "outb %%al, $0x61\n\t" /* Write port */
+
+ /* Now let's take care of CTC channel 2 */
+ "movb $0xb0, %%al\n\t" /* binary, mode 0, LSB/MSB, ch 2*/
+ "outb %%al, $0x43\n\t" /* Write to CTC command port */
+ "movb $0x0c, %%al\n\t"
+ "outb %%al, $0x42\n\t" /* LSB of count */
+ "movb $0xe9, %%al\n\t"
+ "outb %%al, $0x42\n\t" /* MSB of count */
+
+ /* Read the TSC; counting has just started */
+ "rdtsc\n\t"
+ /* Move the value for safe-keeping. */
+ "movl %%eax, %%ebx\n\t"
+ "movl %%edx, %%ecx\n\t"
+
+ /* Busy wait. Only 50 ms wasted at boot time. */
+ "0: inb $0x61, %%al\n\t" /* Read Speaker Output Port */
+ "testb $0x20, %%al\n\t" /* Check CTC channel 2 output (bit 5) */
+ "jz 0b\n\t"
+
+ /* And read the TSC. 5 jiffies (50.00077ms) have elapsed. */
+ "rdtsc\n\t"
+
+ /* Great. So far so good. Store last TSC reading in
+ * last_tsc_low (only 32 lsb bits needed) */
+ "movl %%eax, last_tsc_low\n\t"
+ /* And now calculate the difference between the readings. */
+ "subl %%ebx, %%eax\n\t"
+ "sbbl %%ecx, %%edx\n\t" /* 64-bit subtract */
+ /* but probably edx = 0 at this point (see below). */
+ /* Now we have 5 * (TSC counts per jiffy) in eax. We want
+ * to calculate TSC->microsecond conversion factor. */
+
+ /* Note that edx (high 32-bits of difference) will now be
+ * zero iff CPU clock speed is less than 85 GHz. Moore's
+ * law says that this is likely to be true for the next
+ * 12 years or so. You will have to change this code to
+ * do a real 64-by-64 divide before that time's up. */
+ "movl %%eax, %%ecx\n\t"
+ "xorl %%eax, %%eax\n\t"
+ "movl %1, %%edx\n\t"
+ "divl %%ecx\n\t" /* eax= 2^32 / (1 * TSC counts per microsecond) */
+ /* Return eax for the use of fast_gettimeoffset */
+ "movl %%eax, %0\n\t"
+ : "=r" (retval)
+ : "r" (5 * 1000020/HZ)
+ : /* we clobber: */ "ax", "bx", "cx", "dx", "cc", "memory");
+ return retval;
+}
__initfunc(void time_init(void))
{
xtime.tv_usec = 0;
/*
- * If we have APM enabled we can't currently depend
- * on the cycle counter, because a suspend to disk
- * will reset it. Somebody should come up with a
- * better solution than to just disable the fast time
- * code..
+ * If we have APM enabled or the CPU clock speed is variable
+ * (CPU stops clock on HLT or slows clock to save power)
+ * then the TSC timestamps may diverge by up to 1 jiffy from
+ * 'real time' but nothing will break.
+ * The most frequent case is that the CPU is "woken" from a halt
+ * state by the timer interrupt itself, so we get 0 error. In the
+ * rare cases where a driver would "wake" the CPU and request a
+ * timestamp, the maximum error is < 1 jiffy. But timestamps are
+ * still perfectly ordered.
+ * Note that the TSC counter will be reset if APM suspends
+ * to disk; this won't break the kernel, though, 'cuz we're
+ * smart. See devices/char/apm_bios.c.
*/
-#ifndef CONFIG_APM
- /* If we have the CPU hardware time counters, use them */
- if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
+ if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
do_gettimeoffset = do_fast_gettimeoffset;
- do_get_fast_time = do_x86_get_fast_time;
-
- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
- boot_cpu_data.x86 == 5 &&
- boot_cpu_data.x86_model == 0) {
- /* turn on cycle counters during power down */
- __asm__ __volatile__ (" movl $0x83, %%ecx \n \
- rdmsr \n \
- orl $1,%%eax \n \
- wrmsr \n "
- : : : "ax", "cx", "dx" );
- udelay(500);
- }
-
- /* read Pentium cycle counter */
- __asm__("rdtsc"
- :"=a" (init_timer_cc.low),
- "=d" (init_timer_cc.high));
+ do_get_fast_time = do_gettimeofday;
irq0.handler = pentium_timer_interrupt;
+ fast_gettimeoffset_quotient = calibrate_tsc();
+
+ /* report CPU clock rate in Hz.
+ * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
+ * clock/second. Our precision is about 100 ppm.
+ */
+ { unsigned long eax=0, edx=1000000;
+ __asm__("divl %2"
+ :"=a" (cpu_hz), "=d" (edx)
+ :"r" (fast_gettimeoffset_quotient),
+ "0" (eax), "1" (edx));
+ printk("Detected %ld Hz processor.\n", cpu_hz);
+ }
}
-#endif
setup_x86_irq(0, &irq0);
}
#include "../../../drivers/scsi/sd.h"
#include "../../../drivers/scsi/hosts.h"
+#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))
+#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8)
+#define SD_MINOR_NUMBER(i) ((i) & 255)
+#define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), SD_MINOR_NUMBER(i))
+#define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4)
+
kdev_t sd_find_target(void *host, int tgt)
{
Scsi_Disk *dp;
for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp)
if (dp->device != NULL && dp->device->host == host
&& dp->device->id == tgt)
- return MKDEV(SCSI_DISK_MAJOR, i << 4);
+ return MKDEV_SD(i);
return 0;
}
#endif
--- /dev/null
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Adapted for Power Macintosh by Paul Mackerras
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * Derived from "arch/alpha/kernel/setup.c"
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/adb.h>
+#include <asm/cuda.h>
+#include <asm/pmu.h>
+#include <asm/mediabay.h>
+#include <asm/ohare.h>
+#include <asm/mediabay.h>
+#include "time.h"
+
+unsigned char drive_info;
+
+extern char saved_command_line[];
+
+#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */
+
+extern void zs_kgdb_hook(int tty_num);
+static void ohare_init(void);
+
+__pmac
+
+int
+pmac_get_cpuinfo(char *buffer)
+{
+ int len;
+ struct device_node *np;
+ char *pp;
+ int plen;
+
+ /* find motherboard type */
+ len = sprintf(buffer, "machine\t\t: ");
+ np = find_devices("device-tree");
+ if (np != NULL) {
+ pp = (char *) get_property(np, "model", NULL);
+ if (pp != NULL)
+ len += sprintf(buffer+len, "%s\n", pp);
+ else
+ len += sprintf(buffer+len, "PowerMac\n");
+ pp = (char *) get_property(np, "compatible", &plen);
+ if (pp != NULL) {
+ len += sprintf(buffer+len, "motherboard\t:");
+ while (plen > 0) {
+ int l = strlen(pp) + 1;
+ len += sprintf(buffer+len, " %s", pp);
+ plen -= l;
+ pp += l;
+ }
+ buffer[len++] = '\n';
+ }
+ } else
+ len += sprintf(buffer+len, "PowerMac\n");
+
+ /* find l2 cache info */
+ np = find_devices("l2-cache");
+ if (np == 0)
+ np = find_type_devices("cache");
+ if (np != 0) {
+ unsigned int *ic = (unsigned int *)
+ get_property(np, "i-cache-size", NULL);
+ unsigned int *dc = (unsigned int *)
+ get_property(np, "d-cache-size", NULL);
+ len += sprintf(buffer+len, "L2 cache\t:");
+ if (get_property(np, "cache-unified", NULL) != 0 && dc) {
+ len += sprintf(buffer+len, " %dK unified", *dc / 1024);
+ } else {
+ if (ic)
+ len += sprintf(buffer+len, " %dK instruction",
+ *ic / 1024);
+ if (dc)
+ len += sprintf(buffer+len, "%s %dK data",
+ (ic? " +": ""), *dc / 1024);
+ }
+ pp = get_property(np, "ram-type", NULL);
+ if (pp)
+ len += sprintf(buffer+len, " %s", pp);
+ buffer[len++] = '\n';
+ }
+
+ /* find ram info */
+ np = find_devices("memory");
+ if (np != 0) {
+ struct reg_property *reg = (struct reg_property *)
+ get_property(np, "reg", NULL);
+ if (reg != 0) {
+ len += sprintf(buffer+len, "memory\t\t: %dMB\n",
+ reg->size >> 20);
+ }
+ }
+
+ return len;
+}
+
+#ifdef CONFIG_SCSI
+/* Find the device number for the disk (if any) at target tgt
+ on host adaptor host.
+ XXX this really really should be in drivers/scsi/sd.c. */
+#include <linux/blkdev.h>
+#include "../../../drivers/scsi/scsi.h"
+#include "../../../drivers/scsi/sd.h"
+#include "../../../drivers/scsi/hosts.h"
+
+kdev_t sd_find_target(void *host, int tgt)
+{
+ Scsi_Disk *dp;
+ int i;
+
+ for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp)
+ if (dp->device != NULL && dp->device->host == host
+ && dp->device->id == tgt)
+ return MKDEV(SCSI_DISK_MAJOR, i << 4);
+ return 0;
+}
+#endif
+
+/*
+ * Dummy mksound function that does nothing.
+ * The real one is in the dmasound driver.
+ */
+static void
+pmac_mksound(unsigned int hz, unsigned int ticks)
+{
+}
+
+static volatile u32 *sysctrl_regs;
+static volatile u32 *feature_addr;
+
+__initfunc(void
+pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
+{
+ struct device_node *cpu;
+ int *fp;
+
+ /* Set loops_per_sec to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ cpu = find_type_devices("cpu");
+ if (cpu != 0) {
+ fp = (int *) get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0) {
+ switch (_get_PVR() >> 16) {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 10: /* mach V (604ev5) */
+ case 20: /* 620 */
+ loops_per_sec = *fp;
+ break;
+ default: /* 601, 603, etc. */
+ loops_per_sec = *fp / 2;
+ }
+ } else
+ loops_per_sec = 50000000;
+ }
+
+ /* this area has the CPU identification register
+ and some registers used by smp boards */
+ sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
+ __ioremap(0xffc00000, 0x400000, pgprot_val(PAGE_READONLY));
+
+ *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+
+ ohare_init();
+
+#ifdef CONFIG_KGDB
+ zs_kgdb_hook(0);
+#endif
+
+ find_via_cuda();
+ find_via_pmu();
+
+#ifdef CONFIG_DUMMY_CONSOLE
+ conswitchp = &dummy_con;
+#endif
+
+ kd_mksound = pmac_mksound;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ else
+#endif
+ ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
+}
+
+__initfunc(static void ohare_init(void))
+{
+ struct device_node *np;
+
+ np = find_devices("ohare");
+ if (np == 0)
+ return;
+ if (np->next != 0)
+ printk(KERN_WARNING "only using the first ohare\n");
+ if (np->n_addrs == 0) {
+ printk(KERN_ERR "No addresses for %s\n", np->full_name);
+ return;
+ }
+ feature_addr = (volatile u32 *)
+ ioremap(np->addrs[0].address + OHARE_FEATURE_REG, 4);
+
+ if (find_devices("via-pmu") == 0) {
+ printk(KERN_INFO "Twiddling the magic ohare bits\n");
+ out_le32(feature_addr, STARMAX_FEATURES);
+ } else {
+ out_le32(feature_addr, in_le32(feature_addr) | PBOOK_FEATURES);
+ printk(KERN_DEBUG "feature reg = %x\n", in_le32(feature_addr));
+ }
+
+ /*
+ * Turn on the L2 cache.
+ * We assume that we have a PSX memory controller iff
+ * we have an ohare I/O controller.
+ */
+ if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
+ if (sysctrl_regs[4] & 0x10)
+ sysctrl_regs[4] |= 0x04000020;
+ else
+ sysctrl_regs[4] |= 0x04000000;
+ printk(KERN_INFO "Level 2 cache enabled\n");
+ }
+}
+
+extern char *bootpath;
+extern char *bootdevice;
+void *boot_host;
+int boot_target;
+int boot_part;
+kdev_t boot_dev;
+
+__initfunc(void powermac_init(void))
+{
+ adb_init();
+ pmac_nvram_init();
+ if (_machine == _MACH_Pmac) {
+ media_bay_init();
+ }
+}
+
+#ifdef CONFIG_SCSI
+__initfunc(void
+note_scsi_host(struct device_node *node, void *host))
+{
+ int l;
+ char *p;
+
+ l = strlen(node->full_name);
+ if (bootpath != NULL && bootdevice != NULL
+ && strncmp(node->full_name, bootdevice, l) == 0
+ && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
+ boot_host = host;
+ /*
+ * There's a bug in OF 1.0.5. (Why am I not surprised.)
+ * If you pass a path like scsi/sd@1:0 to canon, it returns
+ * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+ * That is, the scsi target number doesn't get preserved.
+ * So we pick the target number out of bootpath and use that.
+ */
+ p = strstr(bootpath, "/sd@");
+ if (p != NULL) {
+ p += 4;
+ boot_target = simple_strtoul(p, NULL, 10);
+ p = strchr(p, ':');
+ if (p != NULL)
+ boot_part = simple_strtoul(p + 1, NULL, 10);
+ }
+ }
+}
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+extern int pmac_ide_count;
+extern struct device_node *pmac_ide_node[];
+static int ide_majors[] = { 3, 22, 33, 34, 56, 57 };
+
+__initfunc(kdev_t find_ide_boot(void))
+{
+ char *p;
+ int i, n;
+
+ if (bootdevice == NULL)
+ return 0;
+ p = strrchr(bootdevice, '/');
+ if (p == NULL)
+ return 0;
+ n = p - bootdevice;
+
+ /*
+ * Look through the list of IDE interfaces for this one.
+ */
+ for (i = 0; i < pmac_ide_count; ++i) {
+ char *name = pmac_ide_node[i]->full_name;
+ if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
+ /* XXX should cope with the 2nd drive as well... */
+ return MKDEV(ide_majors[i], 0);
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+
+__initfunc(void find_boot_device(void))
+{
+#ifdef CONFIG_SCSI
+ if (boot_host != NULL) {
+ boot_dev = sd_find_target(boot_host, boot_target);
+ if (boot_dev != 0)
+ return;
+ }
+#endif
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+ boot_dev = find_ide_boot();
+#endif
+}
+
+__initfunc(void note_bootable_part(kdev_t dev, int part))
+{
+ static int found_boot = 0;
+ char *p;
+
+ /* Do nothing if the root has been set already. */
+ if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))
+ return;
+ p = strstr(saved_command_line, "root=");
+ if (p != NULL && (p == saved_command_line || p[-1] == ' '))
+ return;
+
+ if (!found_boot) {
+ find_boot_device();
+ found_boot = 1;
+ }
+ if (dev == boot_dev) {
+ ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
+ boot_dev = NODEV;
+ printk(" (root)");
+ }
+}
+
bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
+ bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
fi
fi
fi
Tells the floppy driver that a workable DMA channel is available
(the default).
-floppy=nofifo
+ floppy=nofifo
Disables the FIFO entirely. This is needed if you get "Bus
master arbitration error" messages from your Ethernet card (or
from other devices) while accessing the floppy.
-floppy=fifo
+ floppy=fifo
Enables the FIFO (default)
floppy=<threshold>,fifo_depth
floppy=<nr>,dma
Sets the floppy DMA channel to <nr> instead of 2
+ floppy=slow
+ Use PS/2 stepping rate:
+ " PS/2 floppies have much slower step rates than regular floppies.
+ It's been recommended that take about 1/4 of the default speed
+ in some more extreme cases."
+
+
Supporting utilities and additional documentation:
==================================================
*
* Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
*
- * Some parts are based on hd.c by Linus Thorvalds
+ * Some parts are based on hd.c by Linus Torvalds
*
* 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
#include <linux/interrupt.h>
#include <linux/init.h>
+/*
+ * PS/2 floppies have much slower step rates than regular floppies.
+ * It's been recommended that take about 1/4 of the default speed
+ * in some more extreme cases.
+ */
static int slow_floppy = 0;
#include <asm/dma.h>
0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
- 0, { 2, 5, 6,23,10,20,11, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
+ 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
static void setup_DMA(void)
{
unsigned long flags;
+ unsigned long f;
#ifdef FLOPPY_SANITY_CHECK
if (raw_cmd->length == 0){
}
#endif
INT_OFF;
+ f=claim_dma_lock();
fd_disable_dma();
#ifdef fd_dma_setup
if(fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
(raw_cmd->flags & FD_RAW_READ)?
DMA_MODE_READ : DMA_MODE_WRITE,
FDCS->address) < 0) {
+ release_dma_lock(f);
INT_ON;
cont->done(0);
FDCS->reset=1;
return;
}
+ release_dma_lock(f);
#else
fd_clear_dma_ff();
fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
fd_set_dma_count(raw_cmd->length);
virtual_dma_port = FDCS->address;
fd_enable_dma();
+ release_dma_lock(f);
#endif
INT_ON;
floppy_disable_hlt();
{
void (*handler)(void) = DEVICE_INTR;
int do_print;
+ unsigned long f;
lasthandler = handler;
interruptjiffies = jiffies;
+ f=claim_dma_lock();
fd_disable_dma();
+ release_dma_lock(f);
+
floppy_enable_hlt();
CLEAR_INTR;
if (fdc >= N_FDC || FDCS->address == -1){
*/
static void reset_fdc(void)
{
+ unsigned long flags;
+
SET_INTR(reset_interrupt);
FDCS->reset = 0;
reset_fdc_info(0);
/* Pseudo-DMA may intercept 'reset finished' interrupt. */
/* Irrelevant for systems with true DMA (i386). */
+
+ flags=claim_dma_lock();
fd_disable_dma();
+ release_dma_lock(flags);
if (FDCS->version >= FDC_82072A)
fd_outb(0x80 | (FDCS->dtr &3), FD_STATUS);
static void floppy_shutdown(void)
{
+ unsigned long flags;
+
if (!initialising)
show_floppy();
cancel_activity();
floppy_enable_hlt();
+
+ flags=claim_dma_lock();
fd_disable_dma();
+ release_dma_lock(flags);
+
/* avoid dma going to a random drive after shutdown */
if (!initialising)
static void floppy_ready(void)
{
+ unsigned long flags;
+
CHECK_RESET;
if (start_motor(floppy_ready)) return;
if (fdc_dtr()) return;
#ifdef fd_chose_dma_mode
if ((raw_cmd->flags & FD_RAW_READ) ||
(raw_cmd->flags & FD_RAW_WRITE))
+ {
+ flags=claim_dma_lock();
fd_chose_dma_mode(raw_cmd->kernel_data,
raw_cmd->length);
+ release_dma_lock(flags);
+ }
#endif
if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){
raw_cmd->reply[i] = reply_buffer[i];
if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE))
+ {
+ unsigned long flags;
+ flags=claim_dma_lock();
raw_cmd->length = fd_get_dma_residue();
+ release_dma_lock(flags);
+ }
if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
(!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
{ "usefifo", 0, &no_fifo, 0, 0 },
{ "cmos", set_cmos, 0, 0, 0 },
+ { "slow", 0, &slow_floppy, 1, 0 },
{ "unexpected_interrupts", 0, &print_unex, 1, 0 },
{ "no_unexpected_interrupts", 0, &print_unex, 0, 0 },
int i;
int param;
if (str) {
- /*
- * PS/2 floppies have much slower step rates than regular floppies.
- * It's been recommended that take about 1/4 of the default speed
- * in some more extreme cases.
- */
- if( strcmp(str,"slow") == 0) {
- slow_floppy = 1;
- return;
- }
for (i=0; i< ARRAY_SIZE(config_params); i++){
if (strcmp(str,config_params[i].name) == 0){
if (ints[0])
#endif
if (floppy_grab_irq_and_dma()){
+ del_timer(&fd_timeout);
+ blk_dev[MAJOR_NR].request_fn = NULL;
unregister_blkdev(MAJOR_NR,"fd");
del_timer(&fd_timeout);
return -EBUSY;
current_drive = 0;
floppy_release_irq_and_dma();
initialising=0;
- if (have_no_fdc) {
+ if (have_no_fdc)
+ {
DPRINT("no floppy controllers found\n");
unregister_blkdev(MAJOR_NR,"fd");
}
{
unsigned int part;
const char *maj = hd->major_name;
- char unit = (minor >> hd->minor_shift) + 'a';
+ int unit = (minor >> hd->minor_shift) + 'a';
/*
* IDE devices use multiple major numbers, but the drives
unit += 2;
case IDE0_MAJOR:
maj = "hd";
+ break;
}
part = minor & ((1 << hd->minor_shift) - 1);
+ if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) {
+ unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16;
+ if (unit > 'z') {
+ unit -= 'z' + 1;
+ sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26);
+ if (part)
+ sprintf(buf + 4, "%d", part);
+ return buf;
+ }
+ }
if (part)
sprintf(buf, "%s%c%d", maj, unit, part);
else
}
}
+/*
+ * Needed for allowing full modular support of ide-driver
+ */
+int ide_release_dma (ide_hwif_t *hwif)
+{
+ if (hwif->dmatable) {
+ clear_page((unsigned long)hwif->dmatable); /* clear PRD 1st */
+ free_page((unsigned long)hwif->dmatable); /* free PRD 2nd */
+ }
+ if ((hwif->dma_extra) && (hwif->channel == 0))
+ release_region((hwif->dma_base + 16), hwif->dma_extra);
+ release_region(hwif->dma_base, 8);
+ return 1;
+}
+
__initfunc(void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports))
{
static unsigned long dmatable = 0;
if (extra) /* PDC20246 & HPT343 */
request_region(dma_base+16, extra, name);
dma_base += hwif->channel ? 8 : 0;
+ hwif->dma_extra = extra;
if (inb(dma_base+2) & 0x80) {
printk("%s: simplex device: DMA disabled\n", name);
dma_base = 0;
if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */
#if IDEFLOPPY_DEBUG_LOG
- printk (KERN_INFO "ide-floppy: %s: I/O error, ",drive->name);
+ printk (KERN_INFO "ide-floppy: %s: I/O error\n",drive->name);
#endif /* IDEFLOPPY_DEBUG_LOG */
rq->errors++;
if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD;
pc->c[7] = 255;
pc->c[8] = 255;
+ pc->request_transfer = 255;
}
/*
unsigned int extra;
} ide_pci_device_t;
-#ifdef CONFIG_BLK_DEV_OFFBOARD
-# define ON_BOARD 0
-# define OFF_BOARD 1
-# define NEVER_BOARD 0
-#else /* CONFIG_BLK_DEV_OFFBOARD */
-# define ON_BOARD 1
-# define OFF_BOARD 0
-# define NEVER_BOARD 0
-#endif /* CONFIG_BLK_DEV_OFFBOARD */
-
static ide_pci_device_t ide_pci_chipsets[] __initdata = {
{DEVID_PIIXa, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
{DEVID_PIIXb, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
else
hwgroup->hwif = HWIF(hwgroup->drive);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (hwif->dma_base)
+ (void) ide_release_dma(hwif);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
/*
* Remove us from the kernel's knowledge
*/
{
int index;
- for (index = 0; index < MAX_HWIFS; ++index)
+ for (index = 0; index < MAX_HWIFS; ++index) {
ide_unregister(index);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (ide_hwifs[index].dma_base)
+ (void) ide_release_dma(&ide_hwifs[index]);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+ }
#ifdef CONFIG_PROC_FS
proc_ide_destroy();
#endif
unsigned long *dmatable; /* dma physical region descriptor table */
struct hwif_s *mate; /* other hwif from same PCI chip */
unsigned long dma_base; /* base addr for dma ports */
+ unsigned dma_extra; /* extra addr for dma ports */
unsigned long config_data; /* for use by chipset-specific code */
unsigned long select_data; /* for use by chipset-specific code */
struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
#ifdef CONFIG_BLK_DEV_IDEPCI
+#define ON_BOARD 1
+#define NEVER_BOARD 0
+#ifdef CONFIG_BLK_DEV_OFFBOARD
+# define OFF_BOARD ON_BOARD
+#else /* CONFIG_BLK_DEV_OFFBOARD */
+# define OFF_BOARD NEVER_BOARD
+#endif /* CONFIG_BLK_DEV_OFFBOARD */
+
unsigned long ide_find_free_region (unsigned short size) __init;
void ide_scan_pcibus (void) __init;
#endif
void ide_dma_intr (ide_drive_t *drive);
int check_drive_lists (ide_drive_t *drive, int good_bad);
int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
+int ide_release_dma (ide_hwif_t *hwif);
void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
#endif
* then 512 bytes is assumed.
* else
* sector_size is hardsect_size[MAJOR][MINOR]
- * This is currently set by some scsi device and read by the msdos fs driver
- * This might be a some uses later.
+ * This is currently set by some scsi devices and read by the msdos fs driver.
+ * Other uses may appear later.
*/
int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
int queue_new_request = 0;
switch (MAJOR(req->rq_dev)) {
- case SCSI_DISK_MAJOR:
- disk_index = (MINOR(req->rq_dev) & 0x0070) >> 4;
+ case SCSI_DISK0_MAJOR:
+ disk_index = (MINOR(req->rq_dev) & 0x00f0) >> 4;
if (disk_index < 4)
drive_stat_acct(req->cmd, req->nr_sectors, disk_index);
break;
break;
/* fall through */
- case SCSI_DISK_MAJOR:
+ case SCSI_DISK0_MAJOR:
+ case SCSI_DISK1_MAJOR:
+ case SCSI_DISK2_MAJOR:
+ case SCSI_DISK3_MAJOR:
+ case SCSI_DISK4_MAJOR:
+ case SCSI_DISK5_MAJOR:
+ case SCSI_DISK6_MAJOR:
+ case SCSI_DISK7_MAJOR:
case SCSI_CDROM_MAJOR:
do {
/* xd_setup_dma: set up the DMA controller for a data transfer */
static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
{
+ unsigned long f;
+
if (nodma)
return (PIO_MODE);
if (((u_int) buffer & 0xFFFF0000) != (((u_int) buffer + count) & 0xFFFF0000)) {
#endif /* DEBUG_OTHER */
return (PIO_MODE);
}
+
+ f=claim_dma_lock();
disable_dma(xd_dma);
clear_dma_ff(xd_dma);
set_dma_mode(xd_dma,mode);
set_dma_addr(xd_dma,(u_int) buffer);
set_dma_count(xd_dma,count);
+
+ release_dma_lock(f);
return (DMA_MODE); /* use DMA and INT */
}
static inline u_int xd_wait_for_IRQ (void)
{
+ unsigned long flags;
xd_watchdog_int.expires = jiffies + 8 * HZ;
add_timer(&xd_watchdog_int);
+
+ flags=claim_dma_lock();
enable_dma(xd_dma);
+ release_dma_lock(flags);
+
sleep_on(&xd_wait_int);
del_timer(&xd_watchdog_int);
xdc_busy = 0;
+
+ flags=claim_dma_lock();
disable_dma(xd_dma);
+ release_dma_lock(flags);
+
if (xd_error) {
printk("xd: missed IRQ - command aborted\n");
xd_error = 0;
{
return -EIO;
}
-
+
+ copy_from_user(&ra, (char *) arg, sizeof(ra));
+
if (ra.nframes == 0)
{
return 0;
i=verify_area(VERIFY_WRITE, ra.buf, CD_FRAMESIZE_RAW * ra.nframes);
if(i<0)
return i;
- copy_from_user(&ra, (char *) arg, sizeof(ra));
if (ra.addr_format == CDROM_LBA)
{
tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE
tristate 'Logitech busmouse support' CONFIG_BUSMOUSE
tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE
- tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
+ bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
tristate 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
tristate 'PC110 digitizer pad support' CONFIG_PC110_PAD
fi
endif
endif
-ifeq ($(CONFIG_PSMOUSE),y)
-L_OBJS += psaux.o
-else
- ifeq ($(CONFIG_PSMOUSE),m)
- M_OBJS += psaux.o
- endif
-endif
-
ifeq ($(CONFIG_SOFT_WATCHDOG),y)
L_OBJS += softdog.o
else
static unsigned int radio[BTTV_MAX];
static unsigned int card[BTTV_MAX] = { 0, 0,
0, 0 };
-static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0 };
+static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0 };
static int bttv_num; /* number of Bt848s in use */
static struct bttv bttvs[BTTV_MAX];
{ btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); }
#define I2C_GET() (btread(BT848_I2C)&1)
-#define AUDIO_MUTE_DELAY 10000
-#define FREQ_CHANGE_DELAY 20000
#define EEPROM_WRITE_DELAY 20000
/*******************************/
{0, 0xc00, 0x800, 0x400, 0xc00, 0}},
/* TurboTV */
{ 3, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0}},
- /* Newer Hauppauge */
+ /* Newer Hauppauge */
{ 2, 0, 2, 1, { 2, 0, 0, 0}, {0, 1, 2, 3, 4}},
-
+
};
#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
else
{
btwrite(0x08,BT848_TGCTRL);
- btv->pll.pll_crystal|=2;
+ btv->pll.pll_crystal|=2;
return 1;
}
udelay(10000);
#define VBIBUF_SIZE 65536
-/* Maximum sample number per VBI line is 2044, can NTSC deliver this?
+/* Maximum sample number per VBI line is 2044, NTSC delivers 1600
Note that we write 2048-aligned to keep alignment to memory pages
+ VBI_RISC is written so that it applies to either 2044 or 1600
*/
#define VBI_SPL 2044
return 0;
}
-/* does this really make a difference ???? */
-#define BURST_MAX 4096
-
-static inline void write_risc_segment(unsigned int **rp, unsigned long line_adr, unsigned int command,
- int *x, uint dx, uint bpp, uint width)
+static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int h)
{
- unsigned int flags, len;
-
- if (!dx)
- return;
- len=dx*bpp;
-
-#ifdef LIMIT_DMA
- if (command==BT848_RISC_WRITEC)
- {
- unsigned int dx2=BURST_MAX/bpp;
- while (len>BURST_MAX)
- {
- write_risc_segment(rp, line_adr, command,
- &x,dx2, bpp, width);
- dx-=dx2;
- len=dx*bpp;
- }
- }
-#endif
-
- /* mask upper 8 bits for 24+8 bit overlay modes */
- flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0);
-
- if (*x==0)
- {
- if (command==BT848_RISC_SKIP)
- {
- if (dx<width)
- {
- flags|=BT848_RISC_BYTE_ALL;
- command=BT848_RISC_WRITE;
- }
- }
- else
- if (command==BT848_RISC_WRITEC)
- command=BT848_RISC_WRITE;
- flags|=BT848_RISC_SOL;
- }
- if (*x+dx==width)
- flags|=BT848_RISC_EOL;
- *((*rp)++)=command|flags|len;
- if (command==BT848_RISC_WRITE)
- *((*rp)++)=line_adr+*x*bpp;
- *x+=dx;
+ int i, j;
+ /* bitmap is fixed width, 128 bytes (1024 pixels represented) */
+ if (x < 0 || y < 0 || w < 0 || h < 0) /* catch bad clips */
+ return;
+ /* out of range data should just fall through */
+ for (i = y; i < y + h && i < 625; i++)
+ for (j = x; j < x + w && j < 1024; j++)
+ clipmap[(i<<7)+(j>>3)] |= (1<<(j&7));
}
static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
{
- int i,t;
- int yy, y, x, dx;
- struct video_clip first, *cur, *cur2, *nx, first2, *prev, *nx2;
- int bpp, bpl, width, height, inter;
- unsigned int **rp,*ro,*re;
+ int i, line, x, y, bpl, width, height, inter;
+ unsigned int bpp, dx, sx, **rp, *ro, *re, flags, len;
unsigned long adr;
- int cx,cx2,cy,cy2;
+ unsigned char *clipmap, cbit, lastbit, outofmem;
inter=(btv->win.interlace&1)^1;
bpp=btv->win.bpp;
+ if (bpp==15) /* handle 15bpp as 16bpp in calculations */
+ bpp++;
bpl=btv->win.bpl;
ro=btv->risc_odd;
re=btv->risc_even;
- width=btv->win.width;
- height=btv->win.height;
+ if((width=btv->win.width)>1023)
+ width = 1023; /* sanity check */
+ if((height=btv->win.height)>625)
+ height = 625; /* sanity check */
adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl;
-
- /* clip clipping rects against viewing window AND screen
+ if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {
+ /* can't clip, don't generate any risc code */
+ *(ro++)=BT848_RISC_JUMP;
+ *(ro++)=btv->bus_vbi_even;
+ *(re++)=BT848_RISC_JUMP;
+ *(re++)=btv->bus_vbi_odd;
+ }
+ if (ncr < 0) { /* bitmap was pased */
+ memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE);
+ } else { /* convert rectangular clips to a bitmap */
+ memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */
+ for (i=0; i<ncr; i++)
+ clip_draw_rectangle(clipmap, cr[i].x, cr[i].y,
+ cr[i].width, cr[i].height);
+ }
+ /* clip against viewing window AND screen
so we do not have to rely on the user program
*/
- cx=(btv->win.x<0) ? (-btv->win.x) : 0;
- cy=(btv->win.y<0) ? (-btv->win.y) : 0;
- cx2=(btv->win.x+width>btv->win.swidth) ?
- (btv->win.swidth-btv->win.x) : width;
- cy2=(btv->win.y+height>btv->win.sheight) ?
- (btv->win.sheight-btv->win.y) : height;
- first.next=NULL;
- for (i=0; i<ncr; i++)
- {
- if ((t=cy-cr[i].y)>0)
- {
- if (cr[i].height<=t)
- continue;
- cr[i].height-=t;
- cr[i].y=cy;
- }
- if ((t=cy2-cr[i].y)<cr[i].height)
- {
- if (t<=0)
- continue;
- cr[i].height=t;
- }
- if ((t=cx-cr[i].x)>0)
- {
- if (cr[i].width<=t)
- continue;
- cr[i].width-=t;
- cr[i].x=cx;
- }
- if ((t=cx2-cr[i].x)<cr[i].width)
- {
- if (t<=0)
- continue;
- cr[i].width=t;
- }
- cur=&first;
- while ((nx=cur->next) && (cr[i].y > cur->next->y))
- cur=nx;
- cur->next=&(cr[i]);
- cr[i].next=nx;
- }
- first2.next=NULL;
+ clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ?
+ (btv->win.swidth-btv->win.x) : width, 0, 1024, 768);
+ clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ?
+ (btv->win.sheight-btv->win.y) : height,1024,768);
+ if (btv->win.x<0)
+ clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768);
+ if (btv->win.y<0)
+ clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y));
*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
- /* loop through all lines */
- for (yy=0; yy<(height<<inter); yy++)
+ /* translate bitmap to risc code */
+ for (line=outofmem=0; line < (height<<inter) && !outofmem; line++)
{
- y=yy>>inter;
- rp= (yy&1) ? &re : &ro;
-
- /* remove rects with y2 > y */
- if ((cur=first2.next))
- {
- prev=&first2;
- do
- {
- if (cur->y+cur->height <= y)
- prev->next=cur->next;
- else
- prev=cur;
- }
- while ((cur=cur->next));
- }
-
- /* add rect to second (x-sorted) list if rect.y == y */
- if ((cur=first.next))
- {
- while ((cur) && (cur->y == y))
- {
- first.next=cur->next;
- cur2=&first2;
- while ((nx2=cur2->next) && (cur->x > cur2->next->x))
- cur2=nx2;
- cur2->next=cur;
- cur->next=nx2;
- cur=first.next;
- }
- }
- x=0;
- if ((btv->win.y+y<=0)||(btv->win.y+y>=btv->win.sheight))
- write_risc_segment(rp, adr, BT848_RISC_SKIP, &x,
- width, bpp, width);
- else
- {
- dx=cx;
- for (cur2=first2.next; cur2; cur2=cur2->next)
- {
- if (x+dx < cur2->x)
- {
- write_risc_segment(rp, adr, BT848_RISC_SKIP,
- &x, dx, bpp, width);
- dx=cur2->x-x;
- write_risc_segment(rp, adr, BT848_RISC_WRITEC,
- &x, dx, bpp, width);
- dx=cur2->width;
- }
- else if (x+dx < cur2->x+cur2->width)
- dx=cur2->x+cur2->width-x;
- }
- if (cx2<width)
- {
- write_risc_segment(rp, adr, BT848_RISC_SKIP,
- &x, dx, bpp, width);
- write_risc_segment(rp, adr, BT848_RISC_WRITEC,
- &x, cx2-x, bpp, width);
- dx=width-x;
- }
- write_risc_segment(rp, adr, BT848_RISC_SKIP,
- &x, dx, bpp, width);
- write_risc_segment(rp, adr, BT848_RISC_WRITEC,
- &x, width-x, bpp, width);
- }
- if ((!inter)||(yy&1))
+ y = line>>inter;
+ rp= (line&1) ? &re : &ro;
+ lastbit=(clipmap[y<<7]&1);
+ for(x=dx=1,sx=0; x<=width && !outofmem; x++) {
+ cbit = (clipmap[(y<<7)+(x>>3)] & (1<<(x&7)));
+ if (x < width && !lastbit == !cbit)
+ dx++;
+ else { /* generate the dma controller code */
+ len = dx * bpp;
+ flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0);
+ flags |= ((!sx) ? BT848_RISC_SOL : 0);
+ flags |= ((sx + dx == width) ? BT848_RISC_EOL : 0);
+ if (!lastbit) {
+ *((*rp)++)=BT848_RISC_WRITE|flags|len;
+ *((*rp)++)=adr + bpp * sx;
+ } else
+ *((*rp)++)=BT848_RISC_SKIP|flags|len;
+ lastbit=cbit;
+ sx += dx;
+ dx = 1;
+ if (ro - btv->risc_odd > RISCMEM_LEN/2 - 16)
+ outofmem++;
+ if (re - btv->risc_even > RISCMEM_LEN/2 - 16)
+ outofmem++;
+ }
+ }
+ if ((!inter)||(line&1))
adr+=bpl;
}
-
- *(ro++)=BT848_RISC_JUMP;
+ vfree(clipmap);
+ /* outofmem flag relies on the following code to discard extra data */
+ *(ro++)=BT848_RISC_JUMP;
*(ro++)=btv->bus_vbi_even;
*(re++)=BT848_RISC_JUMP;
*(re++)=btv->bus_vbi_odd;
static struct tvnorm tvnorms[] = {
/* PAL-BDGHI */
/* max. active video is actually 922, but 924 is divisible by 4 and 3! */
+ /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
{ 35468950,
924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
- 1135, 186, 924, 0x20},
+ 1135, 178, 924, 0x20},
/*
{ 35468950,
768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
- 944, 186, 922, 0x20},
+ 944, 178, 922, 0x20},
*/
/* NTSC */
{ 28636363,
640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
- 780, 135, 754, 0x1a},
- /* SECAM */
- { 28636363,
- 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
- 780, 135, 754, 0x16},
+ 780, 122, 754, 0x1a},
+ /* SECAM - phase means nothing in SECAM, bdelay is useless */
+ { 35468950,
+ 924, 576,1135, 0x7f, 0x72, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
+ 1135, 178, 924, 0x20},
/* PAL-M */
{ 28636363,
640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
- 780, 135, 754, 0x16},
+ 780, 122, 754, 0x1a},
/* PAL-N */
{ 35468950,
768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
- 944, 186, 922, 0x20},
+ 944, 178, 922, 0x20},
/* PAL-NC */
{ 35468950,
768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
- 944, 186, 922, 0x20},
+ 944, 178, 922, 0x20},
/* NTSC-Japan */
{ 28636363,
640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
- 780, 135, 754, 0x16},
+ 780, 122, 754, 0x1a},
};
#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
{
unsigned short format;
+ /* setup proper VBI capture length for given video mode */
+ if (btv->win.norm == VIDEO_MODE_NTSC)
+ btwrite(144, BT848_VBI_PACK_SIZE); /* 1600 samples */
+ else
+ btwrite(255, BT848_VBI_PACK_SIZE); /* 2044 samples */
+ btwrite(1, BT848_VBI_PACK_DEL); /* bit 9 for above */
btv->win.color_fmt = format =
(btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
bpp2fmt[(btv->win.bpp-1)&3];
static void set_freq(struct bttv *btv, unsigned short freq)
{
int fixme = freq; /* XXX */
- int oldAudio = btv->audio;
- audio(btv, AUDIO_MUTE);
- udelay(AUDIO_MUTE_DELAY);
-
if (btv->radio)
{
if (btv->have_tuner)
}
}
- if (!(oldAudio & AUDIO_MUTE)) {
- udelay(FREQ_CHANGE_DELAY);
- audio(btv, AUDIO_UNMUTE);
- }
}
case VIDIOCSWIN:
{
struct video_window vw;
- struct video_clip *vcp;
+ struct video_clip *vcp = NULL;
int on;
if(copy_from_user(&vw,arg,sizeof(vw)))
return -EFAULT;
- if(vw.flags)
+ if(vw.flags || vw.width < 16 || vw.height < 16) {
+ bt848_cap(btv,0);
return -EINVAL;
-
+ }
+ if (btv->win.bpp < 4) { /* adjust and align writes */
+ vw.x = (vw.x + 3) & ~3;
+ vw.width = (vw.width - 3) & ~3;
+ }
btv->win.x=vw.x;
btv->win.y=vw.y;
btv->win.width=vw.width;
else
btv->win.interlace=0;
- on=(btv->cap&3)?1:0;
+ on=(btv->cap&3);
bt848_cap(btv,0);
bt848_set_winsize(btv);
- if(vw.clipcount>256)
- return -EDOM; /* Too many! */
-
/*
* Do any clips.
*/
-
- vcp=vmalloc(sizeof(struct video_clip)*(vw.clipcount+4));
- if(vcp==NULL)
- return -ENOMEM;
- if(vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount))
- return -EFAULT;
- make_clip_tab(btv,vcp, vw.clipcount);
- vfree(vcp);
- if(on && btv->win.vidadr!=0)
+ if(vw.clipcount<0) {
+ if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL)
+ return -ENOMEM;
+ if(copy_from_user(vcp, vw.clips,
+ VIDEO_CLIPMAP_SIZE)) {
+ vfree(vcp);
+ return -EFAULT;
+ }
+ } else if (vw.clipcount) {
+ if((vcp=vmalloc(sizeof(struct video_clip)*
+ (vw.clipcount))) == NULL)
+ return -ENOMEM;
+ if(copy_from_user(vcp,vw.clips,
+ sizeof(struct video_clip)*
+ vw.clipcount)) {
+ vfree(vcp);
+ return -EFAULT;
+ }
+ }
+ make_clip_tab(btv, vcp, vw.clipcount);
+ if (vw.clipcount != 0)
+ vfree(vcp);
+ if(on && btv->win.vidadr != 0)
bt848_cap(btv,1);
return 0;
}
return -EPERM;
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
- if(v.depth!=8 && v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32)
+ if(v.depth!=8 && v.depth!=15 && v.depth!=16 &&
+ v.depth!=24 && v.depth!=32 && v.width > 16 &&
+ v.height > 16 && v.bytesperline > 16)
return -EINVAL;
btv->win.vidadr=(unsigned long)v.base;
btv->win.sheight=v.height;
case VIDIOCSYNC:
if(copy_from_user((void *)&i,arg,sizeof(int)))
return -EFAULT;
- if(i>1 || i<0)
- return -EINVAL;
-
switch (btv->frame_stat[i]) {
case GBUFFER_UNUSED:
return -EINVAL;
return -EFAULT;
break;
- case BTTV_FIELDNR:
+ case BTTV_FIELDNR:
if(copy_to_user((void *) arg, (void *) &btv->last_field,
sizeof(btv->last_field)))
return -EFAULT;
break;
-
- case BTTV_PLLSET: {
- struct bttv_pll_info p;
- if(!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if(copy_from_user(&p , (void *) arg, sizeof(btv->pll)))
- return -EFAULT;
- btv->pll.pll_ifreq = p.pll_ifreq;
- btv->pll.pll_ofreq = p.pll_ofreq;
- btv->pll.pll_crystal = p.pll_crystal;
+ case BTTV_PLLSET:
+ {
+ struct bttv_pll_info p;
+ if(!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if(copy_from_user(&p , (void *) arg, sizeof(btv->pll)))
+ return -EFAULT;
+ btv->pll.pll_ifreq = p.pll_ifreq;
+ btv->pll.pll_ofreq = p.pll_ofreq;
+ btv->pll.pll_crystal = p.pll_crystal;
break;
- }
+ }
+
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
{
btv->type=BTTV_MIRO;
- if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0)
- {
+ if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0) {
if(btv->id>849)
btv->type=BTTV_HAUPPAUGE878;
else
- btv->type=BTTV_HAUPPAUGE;
+ btv->type=BTTV_HAUPPAUGE;
}
else
if (I2CRead(&(btv->i2c), I2C_STBEE)>=0)
/* How do I detect the tuner type for other cards but Miro ??? */
printk(KERN_INFO "bttv%d: model: ", btv->nr);
-
sprintf(btv->video_dev.name,"BT%d",btv->id);
switch (btv->type)
{
I2C_DRIVERID_TUNER,
TUNER_SET_TYPE,&tunertype);
}
- strcat(btv->video_dev.name, "(Miro)");
+ strcat(btv->video_dev.name,"(Miro)");
break;
case BTTV_HAUPPAUGE:
- case BTTV_HAUPPAUGE878:
printk("HAUPPAUGE\n");
strcat(btv->video_dev.name,"(Hauppauge)");
break;
/* select direct input */
btwrite(0x00, BT848_GPIO_REG_INP);
-
- btwrite(0xff, BT848_VBI_PACK_SIZE);
- btwrite(1, BT848_VBI_PACK_DEL);
-
-
btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI,
BT848_IFORM);
if (stat&(1<<28))
{
btv->vbip=0;
+ /* inc vbi frame count for detecting drops */
+ (*(u32 *)&(btv->vbibuf[VBIBUF_SIZE - 4]))++;
wake_up_interruptible(&btv->vbiq);
}
}
if (astat&BT848_INT_HLOCK)
{
+#if 0
if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio))
audio(btv, AUDIO_ON);
else
audio(btv, AUDIO_OFF);
+#endif
}
if (astat&BT848_INT_I2CDONE)
printk("irq: %d, ",btv->irq);
printk("memory: 0x%08x.\n", btv->bt848_adr);
- btv->pll.pll_ifreq=0;
- btv->pll.pll_ofreq=0;
- btv->pll.pll_crystal=0;
+ btv->pll.pll_ifreq=0;
+ btv->pll.pll_ofreq=0;
+ btv->pll.pll_crystal=0;
if(pll[btv->nr])
if (!(btv->id==848 && btv->revision==0x11))
{
printk(KERN_INFO "bttv%d: internal PLL, single crystal operation enabled\n",bttv_num);
- btv->pll.pll_ofreq=28636363;
- btv->pll.pll_ifreq=35468950;
- btv->pll.pll_crystal=BT848_IFORM_XT1;
+ btv->pll.pll_ofreq=28636363;
+ btv->pll.pll_ifreq=35468950;
+ btv->pll.pll_crystal=BT848_IFORM_XT1;
}
btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
dev = dev->next;
}
if(bttv_num)
- printk(KERN_INFO "bttv: %d BT8xx card(s) found.\n", bttv_num);
+ printk(KERN_INFO "bttv: %d Bt8xx card(s) found.\n", bttv_num);
return bttv_num;
}
* tab-width: 8
* End:
*/
-
#include "bt848.h"
#include <linux/videodev.h>
-#define MAX_CLIPRECS 100
#define MAX_GBUFFERS 2
#define RISCMEM_LEN (32744*2)
ushort depth;
};
-
struct bttv_pll_info {
- unsigned int pll_ifreq; /* PLL input frequency */
- unsigned int pll_ofreq; /* PLL output frequency */
+ unsigned int pll_ifreq; /* PLL input frequency */
+ unsigned int pll_ofreq; /* PLL output frequency */
unsigned int pll_crystal; /* Crystal used for input */
};
int i2c_command;
int triton1;
};
+
#endif
/*The following should be done in more portable way. It depends on define
if (reg != lastreg)
count++;
lastreg = reg;
- mdelay(1);
+ mdelay(2);
}
/* Be liberal in what you accept... */
static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes)
{
+ unsigned long flags;
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
dma_bytes = num_bytes;
info->stat_flags |= ESP_STAT_DMA_RX;
+
+ flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma, DMA_MODE_READ);
set_dma_addr(dma, virt_to_bus(dma_buffer));
set_dma_count(dma, dma_bytes);
enable_dma(dma);
+ release_dma_lock(flags);
+
serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
}
{
struct tty_struct *tty = info->tty;
int num_bytes;
-
+ unsigned long flags;
+
+
+ flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
info->stat_flags &= ~ESP_STAT_DMA_RX;
num_bytes = dma_bytes - get_dma_residue(dma);
+ release_dma_lock(flags);
+
info->icount.rx += num_bytes;
memcpy(tty->flip.char_buf_ptr, dma_buffer, num_bytes);
static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes)
{
+ unsigned long flags;
+
dma_bytes = num_bytes;
if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) {
}
info->stat_flags |= ESP_STAT_DMA_TX;
+
+ flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma, DMA_MODE_WRITE);
set_dma_addr(dma, virt_to_bus(dma_buffer));
set_dma_count(dma, dma_bytes);
enable_dma(dma);
+ release_dma_lock(flags);
+
serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
}
static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info)
{
int num_bytes;
+ unsigned long flags;
+
+ flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
num_bytes = dma_bytes - get_dma_residue(dma);
info->icount.tx += dma_bytes;
+ release_dma_lock(flags);
if (dma_bytes != num_bytes) {
dma_bytes -= num_bytes;
memmove(dma_buffer, dma_buffer + num_bytes, dma_bytes);
+
+ flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma, DMA_MODE_WRITE);
set_dma_addr(dma, virt_to_bus(dma_buffer));
set_dma_count(dma, dma_bytes);
enable_dma(dma);
+ release_dma_lock(flags);
+
serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
} else {
dma_bytes = 0;
*/
static void shutdown(struct esp_struct * info)
{
- unsigned long flags;
+ unsigned long flags, f;
if (!(info->flags & ASYNC_INITIALIZED))
return;
/* stop a DMA transfer on the port being closed */
if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) {
+ f=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
+ release_dma_lock(f);
+
dma_bytes = 0;
}
#define SP_PAR 2
#define SP_MIDI 4
-/* ---------------------------------------------------------------------- */
-
-static int parptt_preempt(void *handle)
-{
- /* we cannot relinquish the port in the middle of an operation */
- return 1;
-}
-
/* --------------------------------------------------------------------- */
static void parptt_wakeup(void *handle)
pp = pp->next;
if (!pp)
return 0;
- if (!(dev->ptt_out.pardev = parport_register_device(pp, hfmodem_drvname, parptt_preempt, parptt_wakeup,
- NULL, PARPORT_DEV_LURK, dev)))
+ if (!(dev->ptt_out.pardev = parport_register_device(pp, hfmodem_drvname, NULL, parptt_wakeup,
+ NULL, PARPORT_DEV_EXCL, dev)))
return 0;
return 1;
}
return port;
}
- info.port = parport_register_device(pp, "joystick (console)", NULL, js_console_wakeup, NULL, 0, NULL);
+ info.port = parport_register_device(pp, "joystick (console)", NULL, js_console_wakeup, NULL, PARPORT_DEV_EXCL, NULL);
+ if (!info.port)
+ return port;
info.wanted = 0;
info.use = 0;
}
return port;
}
- info.port = parport_register_device(pp, "joystick (db9)", NULL, js_db9_wakeup, NULL, 0, NULL);
+ info.port = parport_register_device(pp, "joystick (db9)", NULL, js_db9_wakeup, NULL, PARPORT_DEV_EXCL, NULL);
+ if (!info.port)
+ return port;
info.wanted = 0;
}
#else
#ifdef MODULE
int init_module(void)
#else
-int __init js_l4_an_init(void)
+int __init js_l4_init(void)
#endif
{
int i, cards;
return port;
}
- info.port = parport_register_device(pp, "joystick (turbografx)", NULL, js_tg_wakeup, NULL, 0, NULL);
+ info.port = parport_register_device(pp, "joystick (turbografx)", NULL, js_tg_wakeup, NULL, PARPORT_DEV_EXCL, NULL);
+ if (!info.port)
+ return port;
info.wanted = 0;
info.use = 0;
}
lp_table[nr].dev = parport_register_device(port, "lp",
lp_preempt, NULL,
lp_interrupt,
- PARPORT_DEV_TRAN,
+ 0,
(void *) &lp_table[nr]);
if (lp_table[nr].dev == NULL)
return 1;
extern int adbdev_init(void);
extern int bus_mouse_init(void);
-extern int psaux_init(void);
extern int qpmouse_init(void);
extern int ms_bus_mouse_init(void);
extern int atixl_busmouse_init(void);
}
if (misc->minor < DYNAMIC_MINORS)
misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
- misc->next = &misc_list;
- misc->prev = misc_list.prev;
+
+ /*
+ * Add it to the front, so that later devices can "override"
+ * earlier defaults
+ */
+ misc->prev = &misc_list;
+ misc->next = misc_list.next;
misc->prev->next = misc;
misc->next->prev = misc;
return 0;
bus_mouse_init();
#endif
#if defined CONFIG_82C710_MOUSE
- qpmouse_init(); /* This must be before psaux_init */
-#endif
-#if defined CONFIG_PSMOUSE
- psaux_init();
+ qpmouse_init();
#endif
#ifdef CONFIG_MS_BUSMOUSE
ms_bus_mouse_init();
* See keyboard.c for the whole history.
*
* Major cleanup by Martin Mares, May 1997
+ *
+ * Combined the keyboard and PS/2 mouse handling into one file,
+ * because they share the same hardware.
+ * Johan Myreen <jem@iki.fi> 1998-10-08.
+ *
*/
#include <linux/config.h>
+#include <asm/spinlock.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/kbd_ll.h>
#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
#include <asm/keyboard.h>
#include <asm/bitops.h>
#include <asm/io.h>
+#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/irq.h>
"\r\000/"; /* 0x60 - 0x6f */
#endif
-unsigned char pckbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */
+static void kbd_write(int address, int data);
+
+static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
/* used only by send_data - set by keyboard_interrupt */
static volatile unsigned char reply_expected = 0;
static volatile unsigned char acknowledge = 0;
static volatile unsigned char resend = 0;
+
+#if defined CONFIG_PSMOUSE
/*
- * Wait for keyboard controller input buffer is empty.
+ * PS/2 Auxiliary Device
+ */
+
+static int __init psaux_init(void);
+
+static struct aux_queue *queue; /* Mouse data buffer. */
+static int aux_count = 0;
+
+#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
+#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
+
+#define MAX_RETRIES 60 /* some aux operations take long time*/
+#if defined(__alpha__) && !defined(CONFIG_PCI)
+# define AUX_IRQ 9 /* Jensen is odd indeed */
+#else
+# define AUX_IRQ 12
+#endif
+#endif /* CONFIG_PSMOUSE */
+
+/*
+ * Wait for keyboard controller input buffer is empty.
+ *
+ * Don't use 'jiffies' so that we don't depend on
+ * interrupts..
+ *
+ * Quote from PS/2 System Reference Manual:
*
- * Don't use 'jiffies' so that we don't depend on
- * interrupts..
+ * "Address hex 0060 and address hex 0064 should be written only when
+ * the input-buffer-full bit and output-buffer-full bit in the
+ * Controller Status register are set 0."
*/
static inline void kb_wait(void)
{
unsigned long timeout = KBC_TIMEOUT;
+ unsigned char status;
do {
+ status = inb_p(KBD_STATUS_REG);
+ if (status & KBD_STAT_OBF) {
+ if (status & KBD_STAT_MOUSE_OBF)
+ inb_p(KBD_DATA_REG); /* Flush. */
+ }
+
if (! (inb_p(KBD_STATUS_REG) & KBD_STAT_IBF))
return;
mdelay(1);
timeout--;
} while (timeout);
#ifdef KBD_REPORT_TIMEOUTS
- printk(KERN_WARNING "Keyboard timed out\n");
+ printk(KERN_WARNING "Keyboard timed out[1]\n");
#endif
}
#if DISABLE_KBD_DURING_INTERRUPTS
static inline void send_cmd(unsigned char c)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
kb_wait();
outb(c, KBD_CNTL_REG);
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
}
-#define disable_keyboard() do { send_cmd(KBD_CCMD_KBD_DISABLE); kb_wait(); } while (0)
+/* #define disable_keyboard() do { send_cmd(KBD_CCMD_KBD_DISABLE); kb_wait(); } while (0) */
+#define disable_keyboard() send_cmd(KBD_CCMD_KBD_DISABLE)
#define enable_keyboard() send_cmd(KBD_CCMD_KBD_ENABLE)
#else
#define disable_keyboard() /* nothing */
static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
+ unsigned long flags;
unsigned char status;
- kbd_pt_regs = regs;
disable_keyboard();
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kbd_pt_regs = regs;
- status = inb_p(KBD_STATUS_REG);
- do {
+ status = inb(KBD_STATUS_REG);
+ while (status & KBD_STAT_OBF) {
unsigned char scancode;
- /* mouse data? */
- if (status & pckbd_read_mask & KBD_STAT_MOUSE_OBF)
- break;
-
scancode = inb(KBD_DATA_REG);
- if ((status & KBD_STAT_OBF) && do_acknowledge(scancode))
- handle_scancode(scancode);
+
+ if (status & KBD_STAT_MOUSE_OBF) {
+#ifdef CONFIG_PSMOUSE
+ /* Mouse data. */
+ if (aux_count) {
+ int head = queue->head;
+ queue->buf[head] = scancode;
+ add_mouse_randomness(scancode);
+ head = (head + 1) & (AUX_BUF_SIZE-1);
+ if (head != queue->tail) {
+ queue->head = head;
+ if (queue->fasync)
+ kill_fasync(queue->fasync, SIGIO);
+ wake_up_interruptible(&queue->proc_list);
+ }
+ }
+#endif
+ } else {
+ if (do_acknowledge(scancode))
+ handle_scancode(scancode);
+ mark_bh(KEYBOARD_BH);
+ }
status = inb(KBD_STATUS_REG);
- } while (status & KBD_STAT_OBF);
+ }
- mark_bh(KEYBOARD_BH);
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
enable_keyboard();
}
do {
unsigned long timeout = KBD_TIMEOUT;
- kb_wait();
- acknowledge = 0;
+ acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */
resend = 0;
reply_expected = 1;
- outb_p(data, KBD_DATA_REG);
+ kbd_write(KBD_DATA_REG, data);
for (;;) {
if (acknowledge)
return 1;
mdelay(1);
if (!--timeout) {
#ifdef KBD_REPORT_TIMEOUTS
- printk(KERN_WARNING "Keyboard timeout\n");
+ printk(KERN_WARNING "Keyboard timeout[2]\n");
#endif
return 0;
}
return -1;
}
-static void __init kbd_write(int address, int data)
+static void kbd_write(int address, int data)
{
- int status;
+ unsigned long flags;
- do {
- status = inb(KBD_STATUS_REG);
- } while (status & KBD_STAT_IBF);
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kb_wait();
outb(data, address);
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
}
+#if defined CONFIG_PSMOUSE
+static void kbd_write_cmd(int cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kb_wait();
+ outb(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);
+ kb_wait();
+ outb(cmd, KBD_DATA_REG);
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+}
+#endif /* CONFIG_PSMOUSE */
+
static char * __init initialize_kbd(void)
{
int status;
printk(KERN_WARNING "initialize_kbd: %s\n", msg);
}
+#if defined CONFIG_PSMOUSE
+ psaux_init();
+#endif
+
/* Ok, finally allocate the IRQ, and off we go.. */
request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
}
+
+#if defined CONFIG_PSMOUSE
+/*
+ * Send a byte to the mouse.
+ */
+static void aux_write_dev(int val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kb_wait();
+ outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
+ kb_wait();
+ outb(val, KBD_DATA_REG);
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+}
+
+static unsigned int get_from_queue(void)
+{
+ unsigned int result;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ result = queue->buf[queue->tail];
+ queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
+ restore_flags(flags);
+ return result;
+}
+
+
+static inline int queue_empty(void)
+{
+ return queue->head == queue->tail;
+}
+
+static int fasync_aux(int fd, struct file *filp, int on)
+{
+ int retval;
+
+ retval = fasync_helper(fd, filp, on, &queue->fasync);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+
+static int release_aux(struct inode * inode, struct file * file)
+{
+ fasync_aux(-1, file, 0);
+ if (--aux_count)
+ return 0;
+ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
+ kbd_write(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG);
+#ifdef CONFIG_MCA
+ free_irq(AUX_IRQ, inode);
+#else
+ free_irq(AUX_IRQ, NULL);
+#endif
+ return 0;
+}
+
+/*
+ * Install interrupt handler.
+ * Enable auxiliary device.
+ */
+
+static int open_aux(struct inode * inode, struct file * file)
+{
+ if (aux_count++) {
+ return 0;
+ }
+ queue->head = queue->tail = 0; /* Flush input queue */
+#ifdef CONFIG_MCA
+ if (request_irq(AUX_IRQ, keyboard_interrupt, MCA_bus ? SA_SHIRQ : 0, "PS/2 Mouse", inode)) {
+#else
+ if (request_irq(AUX_IRQ, keyboard_interrupt, 0, "PS/2 Mouse", NULL)) {
+#endif
+ aux_count--;
+ return -EBUSY;
+ }
+ kbd_write(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable the
+ auxiliary port on
+ controller. */
+ aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */
+ kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
+
+ return 0;
+}
+
+/*
+ * Put bytes from input queue to buffer.
+ */
+
+static ssize_t read_aux(struct file * file, char * buffer,
+ size_t count, loff_t *ppos)
+{
+ struct wait_queue wait = { current, NULL };
+ ssize_t i = count;
+ unsigned char c;
+
+ if (queue_empty()) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ add_wait_queue(&queue->proc_list, &wait);
+repeat:
+ current->state = TASK_INTERRUPTIBLE;
+ if (queue_empty() && !signal_pending(current)) {
+ schedule();
+ goto repeat;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&queue->proc_list, &wait);
+ }
+ while (i > 0 && !queue_empty()) {
+ c = get_from_queue();
+ put_user(c, buffer++);
+ i--;
+ }
+ if (count-i) {
+ file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+ return count-i;
+ }
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
+/*
+ * Write to the aux device.
+ */
+
+static ssize_t write_aux(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
+{
+ ssize_t retval = 0;
+
+ if (count) {
+ ssize_t written = 0;
+
+ if (count > 32)
+ count = 32; /* Limit to 32 bytes. */
+ do {
+ char c;
+ get_user(c, buffer++);
+ aux_write_dev(c);
+ written++;
+ } while (--count);
+ retval = -EIO;
+ if (written) {
+ retval = written;
+ file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+ }
+ }
+
+ return retval;
+}
+
+static unsigned int aux_poll(struct file *file, poll_table * wait)
+{
+ poll_wait(file, &queue->proc_list, wait);
+ if (!queue_empty())
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+struct file_operations psaux_fops = {
+ NULL, /* seek */
+ read_aux,
+ write_aux,
+ NULL, /* readdir */
+ aux_poll,
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ open_aux,
+ NULL, /* flush */
+ release_aux,
+ NULL,
+ fasync_aux,
+};
+
+/*
+ * Initialize driver.
+ */
+static struct miscdevice psaux_mouse = {
+ PSMOUSE_MINOR, "psaux", &psaux_fops
+};
+
+static int __init psaux_init(void)
+{
+ if (aux_device_present != 0xaa)
+ return -EIO;
+
+ printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
+ misc_register(&psaux_mouse);
+ queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+ memset(queue, 0, sizeof(*queue));
+ queue->head = queue->tail = 0;
+ queue->proc_list = NULL;
+
+#ifdef INITIALIZE_MOUSE
+ kbd_write(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux. */
+ aux_write_dev(AUX_SET_SAMPLE);
+ aux_write_dev(100); /* 100 samples/sec */
+ aux_write_dev(AUX_SET_RES);
+ aux_write_dev(3); /* 8 counts per mm */
+ aux_write_dev(AUX_SET_SCALE21); /* 2:1 scaling */
+#endif /* INITIALIZE_MOUSE */
+ kbd_write(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable aux device. */
+ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
+
+ return 0;
+}
+
+#endif /* CONFIG_PSMOUSE */
#define KBD_REPORT_UNKN /* Report unknown scan codes */
#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */
#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */
+#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */
+
+
#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */
#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */
#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
#define AUX_RESET 0xFF /* Reset aux device */
+
+#define AUX_BUF_SIZE 2048
+
+struct aux_queue {
+ unsigned long head;
+ unsigned long tail;
+ struct wait_queue *proc_list;
+ struct fasync_struct *fasync;
+ unsigned char buf[AUX_BUF_SIZE];
+};
+++ /dev/null
-/*
- * linux/drivers/char/psaux.c
- *
- * Driver for PS/2 type mouse by Johan Myreen.
- *
- * Supports pointing devices attached to a PS/2 type
- * Keyboard and Auxiliary Device Controller.
- *
- * Corrections in device setup for some laptop mice & trackballs.
- * 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca)
- *
- * Changed to prevent keyboard lockups on AST Power Exec.
- * 28Jul93 Brad Bosch - brad@lachman.com
- *
- * Added support for SIGIO. 28Jul95 jem@pandora.pp.fi
- *
- * Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com
- *
- * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
- *
- * Fixed keyboard lockups at open time
- * 3-Jul-96, 22-Aug-96 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
- *
- * Cleanup by Martin Mares, 01-Jun-97 (now uses the new PC kbd include)
- *
- * Renamed misc. name to "psaux",more in keeping with Documentation/devices.txt
- * 13-Jan-1998, Richard Gooch <rgooch@atnf.csiro.au>
- */
-
-/*
- * This really should be part of the pc_kbd driver - they share the same
- * controller, and right now we have ridiculous synchronization problems.
- * Some of the SMP bootup problems may be due to not getting synchronization
- * right.
- *
- * I moved the C&T mouse driver to a file of its own, hopefully that will
- * make it easier to eventually fix this all.
- *
- * Linus
- */
-
-/* Uncomment the following line if your mouse needs initialization. */
-
-/* #define INITIALIZE_DEVICE */
-
-#include <linux/module.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/malloc.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/semaphore.h>
-
-#include <linux/config.h>
-
-#include "pc_keyb.h"
-
-/*
- * Generic declarations for both PS2 and 82C710
- */
-
-#define PSMOUSE_MINOR 1 /* Minor device # for this mouse */
-#define AUX_BUF_SIZE 2048
-
-struct aux_queue {
- unsigned long head;
- unsigned long tail;
- struct wait_queue *proc_list;
- struct fasync_struct *fasync;
- unsigned char buf[AUX_BUF_SIZE];
-};
-
-static struct aux_queue *queue;
-static int aux_count = 0;
-
-static unsigned int get_from_queue(void)
-{
- unsigned int result;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- result = queue->buf[queue->tail];
- queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
- restore_flags(flags);
- return result;
-}
-
-
-static inline int queue_empty(void)
-{
- return queue->head == queue->tail;
-}
-
-static int fasync_aux(int fd, struct file *filp, int on)
-{
- int retval;
-
- retval = fasync_helper(fd, filp, on, &queue->fasync);
- if (retval < 0)
- return retval;
- return 0;
-}
-
-/*
- * PS/2 Aux Device
- */
-
-#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
-#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
-
-#define MAX_RETRIES 60 /* some aux operations take long time*/
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-# define AUX_IRQ 9 /* Jensen is odd indeed */
-#else
-# define AUX_IRQ 12
-#endif
-
-/*
- * Status polling
- */
-
-static int poll_aux_status(void)
-{
- int retries=0;
-
- while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) {
- if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
- inb_p(KBD_DATA_REG);
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + (5*HZ + 99) / 100;
- schedule();
- retries++;
- }
- return (retries < MAX_RETRIES);
-}
-
-/*
- * Write to aux device
- */
-
-static void aux_write_dev(int val)
-{
- poll_aux_status();
- outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); /* Write magic cookie */
- poll_aux_status();
- outb_p(val, KBD_DATA_REG); /* Write data */
-}
-
-/*
- * Write to device & handle returned ack
- */
-
-#ifdef INITIALIZE_DEVICE
-__initfunc(static int aux_write_ack(int val))
-{
- aux_write_dev(val);
- poll_aux_status();
-
- if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
- {
- return (inb(KBD_DATA_REG));
- }
- return 0;
-}
-#endif /* INITIALIZE_DEVICE */
-
-/*
- * Write aux device command
- */
-
-static void aux_write_cmd(int val)
-{
- poll_aux_status();
- outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);
- poll_aux_status();
- outb_p(val, KBD_DATA_REG);
-}
-
-/*
- * AUX handler critical section start and end.
- *
- * Only one process can be in the critical section and all keyboard sends are
- * deferred as long as we're inside. This is necessary as we may sleep when
- * waiting for the keyboard controller and other processes / BH's can
- * preempt us. Please note that the input buffer must be flushed when
- * aux_end_atomic() is called and the interrupt is no longer enabled as not
- * doing so might cause the keyboard driver to ignore all incoming keystrokes.
- */
-
-static struct semaphore aux_sema4 = MUTEX;
-
-static inline void aux_start_atomic(void)
-{
- down(&aux_sema4);
- disable_bh(KEYBOARD_BH);
-}
-
-static inline void aux_end_atomic(void)
-{
- enable_bh(KEYBOARD_BH);
- up(&aux_sema4);
-}
-
-/*
- * Interrupt from the auxiliary device: a character
- * is waiting in the keyboard/aux controller.
- */
-
-static void aux_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
-{
- int head = queue->head;
- int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
-
- if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF)
- return;
-
- add_mouse_randomness(queue->buf[head] = inb(KBD_DATA_REG));
- if (head != maxhead) {
- head++;
- head &= AUX_BUF_SIZE-1;
- }
- queue->head = head;
- if (queue->fasync)
- kill_fasync(queue->fasync, SIGIO);
- wake_up_interruptible(&queue->proc_list);
-}
-
-static int release_aux(struct inode * inode, struct file * file)
-{
- fasync_aux(-1, file, 0);
- if (--aux_count)
- return 0;
-#ifdef CONFIG_VT
- pckbd_read_mask = KBD_STAT_OBF;
-#endif
- aux_start_atomic();
- aux_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
- poll_aux_status();
- outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
- poll_aux_status();
- aux_end_atomic();
-#ifdef CONFIG_MCA
- free_irq(AUX_IRQ, inode);
-#else
- free_irq(AUX_IRQ, NULL);
-#endif
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
- * Install interrupt handler.
- * Enable auxiliary device.
- */
-
-static int open_aux(struct inode * inode, struct file * file)
-{
- aux_start_atomic();
- if (aux_count++) {
- aux_end_atomic();
- return 0;
- }
- if (!poll_aux_status()) { /* FIXME: Race condition */
- aux_count--;
- aux_end_atomic();
- return -EBUSY;
- }
- queue->head = queue->tail = 0; /* Flush input queue */
-#ifdef CONFIG_MCA
- if (request_irq(AUX_IRQ, aux_interrupt, MCA_bus ? SA_SHIRQ : 0, "PS/2 Mouse", inode)) {
-#else
- if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)) {
-#endif
- aux_count--;
- aux_end_atomic();
- return -EBUSY;
- }
- MOD_INC_USE_COUNT;
- poll_aux_status();
- outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
- aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */
- aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */
- poll_aux_status();
- aux_end_atomic();
-
-#ifdef CONFIG_VT
- pckbd_read_mask = AUX_STAT_OBF;
-#endif
-
- return 0;
-}
-
-/*
- * Write to the aux device.
- */
-
-static ssize_t write_aux(struct file * file, const char * buffer,
- size_t count, loff_t *ppos)
-{
- ssize_t retval = 0;
-
- if (count) {
- ssize_t written = 0;
-
- aux_start_atomic();
- do {
- char c;
- if (!poll_aux_status())
- break;
- outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
- if (!poll_aux_status())
- break;
- get_user(c, buffer++);
- outb_p(c, KBD_DATA_REG);
- written++;
- } while (--count);
- aux_end_atomic();
- retval = -EIO;
- if (written) {
- retval = written;
- file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
- }
- }
-
- return retval;
-}
-
-/*
- * Put bytes from input queue to buffer.
- */
-
-static ssize_t read_aux(struct file * file, char * buffer,
- size_t count, loff_t *ppos)
-{
- struct wait_queue wait = { current, NULL };
- ssize_t i = count;
- unsigned char c;
-
- if (queue_empty()) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
- add_wait_queue(&queue->proc_list, &wait);
-repeat:
- current->state = TASK_INTERRUPTIBLE;
- if (queue_empty() && !signal_pending(current)) {
- schedule();
- goto repeat;
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&queue->proc_list, &wait);
- }
- while (i > 0 && !queue_empty()) {
- c = get_from_queue();
- put_user(c, buffer++);
- i--;
- }
- if (count-i) {
- file->f_dentry->d_inode->i_atime = CURRENT_TIME;
- return count-i;
- }
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-static unsigned int aux_poll(struct file *file, poll_table * wait)
-{
- poll_wait(file, &queue->proc_list, wait);
- if (!queue_empty())
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-struct file_operations psaux_fops = {
- NULL, /* seek */
- read_aux,
- write_aux,
- NULL, /* readdir */
- aux_poll,
- NULL, /* ioctl */
- NULL, /* mmap */
- open_aux,
- NULL, /* flush */
- release_aux,
- NULL,
- fasync_aux,
-};
-
-/*
- * Initialize driver.
- */
-static struct miscdevice psaux_mouse = {
- PSMOUSE_MINOR, "psaux", &psaux_fops
-};
-
-__initfunc(int psaux_init(void))
-{
- if (aux_device_present != 0xaa)
- return -EIO;
-
- printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
- misc_register(&psaux_mouse);
- queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
- memset(queue, 0, sizeof(*queue));
- queue->head = queue->tail = 0;
- queue->proc_list = NULL;
-
- aux_start_atomic();
-#ifdef INITIALIZE_DEVICE
- outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
- aux_write_ack(AUX_SET_SAMPLE);
- aux_write_ack(100); /* 100 samples/sec */
- aux_write_ack(AUX_SET_RES);
- aux_write_ack(3); /* 8 counts per mm */
- aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
- poll_aux_status();
-#endif /* INITIALIZE_DEVICE */
- outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
- poll_aux_status();
- outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); /* Disable controller interrupts */
- poll_aux_status();
- outb_p(AUX_INTS_OFF, KBD_DATA_REG);
- poll_aux_status();
- aux_end_atomic();
-
- return 0;
-}
-
-#ifdef MODULE
-int init_module(void)
-{
- return psaux_init();
-}
-
-void cleanup_module(void)
-{
- misc_deregister(&psaux_mouse);
- kfree(queue);
-}
-#endif
* Corrections in device setup for some laptop mice & trackballs.
* 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca)
*
- * Modified by Johan Myreen (jem@pandora.pp.fi) 04Aug93
+ * Modified by Johan Myreen (jem@iki.fi) 04Aug93
* to include support for QuickPort mouse.
*
* Changed references to "QuickPort" with "82C710" since "QuickPort"
* is not what this driver is all about -- QuickPort is just a
* connector type, and this driver is for the mouse port on the Chips
- * & Technologies 82C710 interface chip. 15Nov93 jem@pandora.pp.fi
+ * & Technologies 82C710 interface chip. 15Nov93 jem@iki.fi
*
- * Added support for SIGIO. 28Jul95 jem@pandora.pp.fi
+ * Added support for SIGIO. 28Jul95 jem@iki.fi
*
* Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com
*
case IDE1_MAJOR:
case IDE2_MAJOR:
case IDE3_MAJOR:
- case SCSI_DISK_MAJOR:
+ case SCSI_DISK0_MAJOR:
+ case SCSI_DISK1_MAJOR:
+ case SCSI_DISK2_MAJOR:
+ case SCSI_DISK3_MAJOR:
+ case SCSI_DISK4_MAJOR:
+ case SCSI_DISK5_MAJOR:
+ case SCSI_DISK6_MAJOR:
+ case SCSI_DISK7_MAJOR:
return 1;
default:
return 0;
*/
static inline void dma_transfer(void)
{
+ unsigned long flags;
if (QIC02_TAPE_IFC == WANGTEK) /* or EVEREX */
outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT); /* back to normal */
outb_p(ctlbits, QIC02_CTL_PORT);
+ flags=claim_dma_lock();
clear_dma_ff(QIC02_TAPE_DMA);
set_dma_mode(QIC02_TAPE_DMA, dma_mode);
set_dma_addr(QIC02_TAPE_DMA, buffaddr+dma_bytes_done); /* full address */
/* start computer DMA controller */
enable_dma(QIC02_TAPE_DMA);
+
+ release_dma_lock(flags);
+
/* block transfer should start now, jumping to the
* interrupt routine when done or an exception was detected.
*/
/* assume 'bytes_todo'>0 */
{
int stat;
+ unsigned long flags;
tpqputs(TPQD_DEBUG, "start_dma() enter");
TPQDEB({printk(TPQIC02_NAME ": doing_read==%d, doing_write==%d\n", doing_read, doing_write);})
/* initiate first data block read from/write to the tape controller */
+ save_flags(flags);
cli();
dma_transfer();
- sti();
+ restore_flags(flags);
TPQPUTS("start_dma() end");
return TE_OK;
static void end_dma(unsigned long * bytes_done)
{
int stat = TE_OK;
+ unsigned long flags;
TIMEROFF;
TPQPUTS("end_dma() enter");
+ flags=claim_dma_lock();
+
disable_dma(QIC02_TAPE_DMA);
clear_dma_ff(QIC02_TAPE_DMA);
+
+ release_dma_lock(flags);
if (QIC02_TAPE_IFC == WANGTEK) /* or EVEREX */
outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT); /* back to normal */
static void qic02_tape_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
int stat, r, i;
+ unsigned long flags;
TIMEROFF;
r = 1;
}
+ flags=claim_dma_lock();
+
if ( (i = get_dma_residue(QIC02_TAPE_DMA)) != 0 ) {
printk(TPQIC02_NAME ": dma_residue == %x !!!\n", i);
r = 1; /* big trouble, but can't do much about it... */
}
+
+ release_dma_lock(flags);
if (r)
return;
* both sides, and we've completed the last operation that could
* block, so it's safe to proceed with closing.
*/
-
if (pty_master) {
if (--o_tty->count < 0) {
printk("release_dev: bad pty slave count (%d) for %s\n",
tty->count = 0;
}
+ /*
+ * We've decremented tty->count, so we should zero out
+ * filp->private_data, to break the link between the tty and
+ * the file descriptor. Otherwise if close_fp() blocks before
+ * the the file descriptor is removed from the inuse_filp
+ * list, check_tty_count() could observe a discrepancy and
+ * printk a warning message to the user.
+ */
+ filp->private_data = 0;
+
/*
* Perform some housekeeping before deciding whether to return.
*
/* check whether both sides are closing ... */
if (!tty_closing || (o_tty && !o_tty_closing))
return;
- filp->private_data = 0;
#ifdef TTY_DEBUG_HANGUP
printk("freeing tty structure...");
return retval;
#ifdef CONFIG_UNIX98_PTYS
- /* N.B. this error exit may leave filp->f_flags with O_NONBLOCK set */
init_dev_done:
#endif
filp->private_data = tty;
if (tty_register_driver(&dev_syscons_driver))
panic("Couldn't register /dev/console driver\n");
+#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;
if (tty_register_driver(&dev_ptmx_driver))
panic("Couldn't register /dev/ptmx driver\n");
-
+#endif
+
#ifdef CONFIG_VT
dev_console_driver = dev_tty_driver;
dev_console_driver.driver_name = "/dev/tty0";
/* ARC can't read from the data latch, so we must use a soft copy. */
static unsigned char data_copy;
+static void arc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
static void arc_write_data(struct parport *p, unsigned char data)
{
data_copy = data;
arc_enable_irq,
arc_disable_irq,
- arc_examine_irq,
+ arc_interrupt,
arc_inc_use_count,
arc_dec_use_count,
#define CONFIGB 0x401
#define ECONTROL 0x402
-static void
-parport_ax_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
+static void parport_ax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- /* NULL function - Does nothing */
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
}
void
{
if (p->irq != PARPORT_IRQ_NONE) {
parport_ax_disable_irq(p);
- free_irq(p->irq, NULL);
+ free_irq(p->irq, p);
}
release_region(p->base, p->size);
if (p->modes & PARPORT_MODE_PCECR)
parport_ax_claim_resources(struct parport *p)
{
/* FIXME check that resources are free */
- if (p->irq != PARPORT_IRQ_NONE) {
- request_irq(p->irq, parport_ax_null_intr_func,
- 0, p->name, NULL);
- parport_ax_enable_irq(p);
- }
+ int err;
+
+ if (p->irq != PARPORT_IRQ_NONE)
+ if ((err = request_irq(p->irq, parport_ax_interrupt,
+ 0, p->name, p)) != 0)
+ return err;
+ else
+ parport_ax_enable_irq(p);
+
request_region(p->base, p->size, p->name);
if (p->modes & PARPORT_MODE_PCECR)
request_region(p->base+0x400, 3, p->name);
return 0; /* FIXME */
}
-int
-parport_ax_examine_irq(struct parport *p)
-{
- return 0; /* FIXME */
-}
-
void
parport_ax_inc_use_count(void)
{
parport_ax_enable_irq,
parport_ax_disable_irq,
- parport_ax_examine_irq,
+ parport_ax_interrupt,
parport_ax_inc_use_count,
parport_ax_dec_use_count,
-/* Low-level parallel-port routines for PC-style hardware.
+/* Low-level parallel-port routines for 8255-based PC-style hardware.
*
* Authors: Phil Blundell <Philip.Blundell@pobox.com>
* Tim Waugh <tim@cyberelk.demon.co.uk>
* accomodate this.
*/
-#include <linux/stddef.h>
-#include <linux/tasks.h>
-
-#include <asm/ptrace.h>
-#include <asm/io.h>
-
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
+#include <asm/io.h>
+
#include <linux/parport.h>
#include <linux/parport_pc.h>
than PARPORT_MAX (in <linux/parport.h>). */
#define PARPORT_PC_MAX_PORTS 8
-static void parport_pc_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
+static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- /* Null function - does nothing */
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
}
void parport_pc_write_epp(struct parport *p, unsigned char d)
void parport_pc_release_resources(struct parport *p)
{
if (p->irq != PARPORT_IRQ_NONE)
- free_irq(p->irq, NULL);
+ free_irq(p->irq, p);
release_region(p->base, p->size);
if (p->modes & PARPORT_MODE_PCECR)
release_region(p->base+0x400, 3);
{
int err;
if (p->irq != PARPORT_IRQ_NONE)
- if ((err = request_irq(p->irq, parport_pc_null_intr_func, 0, p->name, NULL)) != 0) return err;
+ if ((err = request_irq(p->irq, parport_pc_interrupt,
+ 0, p->name, p)) != 0)
+ return err;
request_region(p->base, p->size, p->name);
if (p->modes & PARPORT_MODE_PCECR)
request_region(p->base+0x400, 3, p->name);
return -ENOSYS; /* FIXME */
}
-int parport_pc_examine_irq(struct parport *p)
-{
- return 0; /* FIXME */
-}
-
void parport_pc_inc_use_count(void)
{
#ifdef MODULE
parport_pc_enable_irq,
parport_pc_disable_irq,
- parport_pc_examine_irq,
+ parport_pc_interrupt,
parport_pc_inc_use_count,
parport_pc_dec_use_count,
struct proc_dir_entry *base = NULL;
-extern void parport_null_intr_func(int irq, void *dev_id, struct pt_regs *regs);
-
static int irq_write_proc(struct file *file, const char *buffer,
- unsigned long count, void *data)
+ unsigned long count, void *data)
{
int retval = -EINVAL;
int newirq = PARPORT_IRQ_NONE;
struct parport *pp = (struct parport *)data;
int oldirq = pp->irq;
- unsigned long flags;
/*
* We can have these valid cases:
if (oldirq == newirq)
goto out;
- spin_lock_irqsave(&pp->lock, flags);
if (pp->flags & PARPORT_FLAG_COMA)
goto out_ok;
retval = -EBUSY;
+
+ /*
+ * Here we don' t need the irq version of spinlocks because
+ * the parport_lowlevel irq handler must not change the cad,
+ * and so has no one reason to write_lock() the cad_lock spinlock.
+ * -arca
+ */
+ read_lock(&pp->cad_lock);
+
if (pp->cad)
- goto out_unlock;
+ {
+ read_unlock(&pp->cad_lock);
+ return retval;
+ }
if (newirq != PARPORT_IRQ_NONE) {
- retval = request_irq(newirq, parport_null_intr_func,
- SA_INTERRUPT, pp->name, NULL);
+ retval = request_irq(newirq, pp->ops->interrupt,
+ 0, pp->name, pp);
if (retval)
- goto out_unlock;
- else retval = count;
+ {
+ read_unlock(&pp->cad_lock);
+ return retval;
+ }
}
if (oldirq != PARPORT_IRQ_NONE)
- free_irq(oldirq, NULL);
+ free_irq(oldirq, pp);
+
+ retval = count;
+
+ read_unlock(&pp->cad_lock);
out_ok:
pp->irq = newirq;
-out_unlock:
- spin_unlock_irqrestore (&pp->lock, flags);
-
out:
return retval;
}
#include <linux/sched.h>
#include <asm/spinlock.h>
+#include <asm/irq.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
return portlist;
}
-void parport_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
-{
- /* Null function - does nothing. IRQs are pointed here whenever
- there is no real handler for them. */
-}
-
struct parport *parport_register_port(unsigned long base, int irq, int dma,
struct parport_operations *ops)
{
struct parport *tmp;
int portnum;
char *name;
- unsigned long flags;
/* Check for a previously registered port.
NOTE: we will ignore irq and dma if we find a previously
tmp->ops = ops;
tmp->number = portnum;
memset (&tmp->probe_info, 0, sizeof (struct parport_device_info));
- spin_lock_init (&tmp->lock);
+ spin_lock_init(&tmp->cad_lock);
+ spin_lock_init(&tmp->waitlist_lock);
+ spin_lock_init(&tmp->pardevice_lock);
name = kmalloc(15, GFP_KERNEL);
if (!name) {
sprintf(name, "parport%d", portnum);
tmp->name = name;
- /* Chain the entry to our list. */
- spin_lock_irqsave (&parportlist_lock, flags);
+ /*
+ * Chain the entry to our list.
+ *
+ * This function must not run from an irq handler so we don' t need
+ * to clear irq on the local CPU. -arca
+ */
+ spin_lock(&parportlist_lock);
if (portlist_tail)
portlist_tail->next = tmp;
portlist_tail = tmp;
if (!portlist)
portlist = tmp;
- spin_unlock_irqrestore (&parportlist_lock, flags);
+ spin_unlock(&parportlist_lock);
tmp->probe_info.class = PARPORT_CLASS_LEGACY; /* assume the worst */
tmp->waithead = tmp->waittail = NULL;
void parport_unregister_port(struct parport *port)
{
struct parport *p;
- unsigned long flags;
- spin_lock_irqsave (&parportlist_lock, flags);
+
+ spin_lock(&parportlist_lock);
if (portlist == port) {
if ((portlist = port->next) == NULL)
portlist_tail = NULL;
else printk (KERN_WARNING
"%s not found in port list!\n", port->name);
}
- spin_unlock_irqrestore (&parportlist_lock, flags);
+ spin_unlock(&parportlist_lock);
if (port->probe_info.class_name)
kfree (port->probe_info.class_name);
if (port->probe_info.mfr)
int flags, void *handle)
{
struct pardevice *tmp;
- unsigned long flgs;
+
+ if (port->flags & PARPORT_FLAG_EXCL) {
+ /* An exclusive device is registered. */
+ printk (KERN_DEBUG "%s: no more devices allowed\n",
+ port->name);
+ return NULL;
+ }
if (flags & PARPORT_DEV_LURK) {
if (!pf || !kf) {
/* Chain this onto the list */
tmp->prev = NULL;
- spin_lock_irqsave (&port->lock, flgs);
+ /*
+ * This function must not run from an irq handler so we don' t need
+ * to clear irq on the local CPU. -arca
+ */
+ spin_lock(&port->pardevice_lock);
+
+ if (flags & PARPORT_DEV_EXCL) {
+ if (port->devices) {
+ spin_unlock (&port->pardevice_lock);
+ kfree (tmp->state);
+ kfree (tmp);
+ printk (KERN_DEBUG
+ "%s: cannot grant exclusive access for "
+ "device %s\n", port->name, name);
+ return NULL;
+ }
+ port->flags |= PARPORT_FLAG_EXCL;
+ }
+
tmp->next = port->devices;
if (port->devices)
port->devices->prev = tmp;
port->devices = tmp;
- spin_unlock_irqrestore (&port->lock, flgs);
+ spin_unlock(&port->pardevice_lock);
inc_parport_count();
port->ops->inc_use_count();
void parport_unregister_device(struct pardevice *dev)
{
struct parport *port;
- unsigned long flags;
#ifdef PARPORT_PARANOID
if (dev == NULL) {
return;
}
- spin_lock_irqsave (&port->lock, flags);
+ spin_lock(&port->pardevice_lock);
if (dev->next)
dev->next->prev = dev->prev;
if (dev->prev)
dev->prev->next = dev->next;
else
port->devices = dev->next;
- spin_unlock_irqrestore (&port->lock, flags);
+
+ if (dev->flags & PARPORT_DEV_EXCL)
+ port->flags &= ~PARPORT_FLAG_EXCL;
+
+ spin_unlock(&port->pardevice_lock);
kfree(dev->state);
kfree(dev);
dev->waiting = 0;
/* Take ourselves out of the wait list again. */
- spin_lock_irqsave (&port->lock, flags);
+ spin_lock_irqsave (&port->waitlist_lock, flags);
if (dev->waitprev)
dev->waitprev->waitnext = dev->waitnext;
else
dev->waitnext->waitprev = dev->waitprev;
else
port->waittail = dev->waitprev;
- spin_unlock_irqrestore (&port->lock, flags);
+ spin_unlock_irqrestore (&port->waitlist_lock, flags);
dev->waitprev = dev->waitnext = NULL;
}
+ if (oldcad && port->irq != PARPORT_IRQ_NONE && !oldcad->irq_func)
+ /*
+ * If there was an irq pending it should hopefully happen
+ * before return from enable_irq(). -arca
+ */
+ enable_irq(port->irq);
+
+ /*
+ * Avoid running irq handlers if the pardevice doesn' t use it. -arca
+ */
+ if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func)
+ disable_irq(port->irq);
+
/* Now we do the change of devices */
- spin_lock_irqsave(&port->lock, flags);
+ write_lock_irqsave(&port->cad_lock, flags);
port->cad = dev;
- spin_unlock_irqrestore(&port->lock, flags);
-
- /* Swap the IRQ handlers. */
- if (port->irq != PARPORT_IRQ_NONE) {
- if (oldcad && oldcad->irq_func) {
- free_irq(port->irq, oldcad->private);
- request_irq(port->irq, parport_null_intr_func,
- SA_INTERRUPT, port->name, NULL);
- }
- if (dev->irq_func) {
- free_irq(port->irq, NULL);
- request_irq(port->irq, dev->irq_func,
- SA_INTERRUPT, dev->name, dev->private);
- }
- }
+ write_unlock_irqrestore(&port->cad_lock, flags);
/* Restore control registers */
port->ops->restore_state(port, dev->state);
interest. This is only allowed for devices sleeping in
parport_claim_or_block(), or those with a wakeup function. */
if (dev->waiting & 2 || dev->wakeup) {
- spin_lock_irqsave (&port->lock, flags);
+ spin_lock_irqsave (&port->waitlist_lock, flags);
if (port->cad == NULL) {
/* The port got released in the meantime. */
- spin_unlock_irqrestore (&port->lock, flags);
+ spin_unlock_irqrestore (&port->waitlist_lock, flags);
goto try_again;
}
if (test_and_set_bit(0, &dev->waiting) == 0) {
} else
port->waithead = port->waittail = dev;
}
- spin_unlock_irqrestore (&port->lock, flags);
+ spin_unlock_irqrestore (&port->waitlist_lock, flags);
}
return -EAGAIN;
}
"when not owner\n", port->name, dev->name);
return;
}
- spin_lock_irqsave(&port->lock, flags);
+ write_lock_irqsave(&port->cad_lock, flags);
port->cad = NULL;
- spin_unlock_irqrestore(&port->lock, flags);
+ write_unlock_irqrestore(&port->cad_lock, flags);
+
+ /*
+ * Reenable irq and so discard the eventually pending irq while
+ * cad is NULL. -arca
+ */
+ if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func)
+ enable_irq(port->irq);
/* Save control registers */
port->ops->save_state(port, dev->state);
- /* Point IRQs somewhere harmless. */
- if (port->irq != PARPORT_IRQ_NONE && dev->irq_func) {
- free_irq(port->irq, dev->private);
- request_irq(port->irq, parport_null_intr_func,
- SA_INTERRUPT, port->name, NULL);
- }
-
/* If anybody is waiting, find out who's been there longest and
then wake them up. (Note: no locking required) */
for (pd = port->waithead; pd; pd = pd->waitnext) {
{
elp_device *adapter = dev->priv;
if (adapter->dmaing && (jiffies > (adapter->current_dma.start_time + 10))) {
- unsigned long flags;
+ unsigned long flags, f;
printk("%s: DMA %s timed out, %d bytes left\n", dev->name, adapter->current_dma.direction ? "download" : "upload", get_dma_residue(dev->dma));
save_flags(flags);
cli();
adapter->dmaing = 0;
adapter->busy = 0;
+
+ f=claim_dma_lock();
disable_dma(dev->dma);
+ release_dma_lock(f);
+
if (adapter->rx_active)
adapter->rx_active--;
outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
elp_device *adapter = dev->priv;
void *target;
struct sk_buff *skb;
+ unsigned long flags;
rlen = (len + 1) & ~1;
skb = dev_alloc_skb(rlen + 2);
outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev);
+ flags=claim_dma_lock();
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
set_dma_mode(dev->dma, 0x04); /* dma read */
set_dma_addr(dev->dma, virt_to_bus(target));
set_dma_count(dev->dma, rlen);
enable_dma(dev->dma);
+ release_dma_lock(flags);
if (elp_debug >= 3) {
printk("%s: rx DMA transfer started\n", dev->name);
{
elp_device *adapter = dev->priv;
unsigned long target;
+ unsigned long flags;
/*
* make sure the length is even and no shorter than 60 bytes
target = virt_to_bus(adapter->dma_buffer);
}
adapter->current_dma.skb = skb;
- cli();
+
+ flags=claim_dma_lock();
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
set_dma_mode(dev->dma, 0x48); /* dma memory -> io */
set_dma_count(dev->dma, nlen);
outb_control(adapter->hcr_val | DMAE | TCEN, dev);
enable_dma(dev->dma);
+ release_dma_lock(flags);
+
if (elp_debug >= 3)
printk("%s: DMA transfer started\n", dev->name);
/* drivers/net/eepro100.c: An Intel i82557 Ethernet driver for Linux. */
/*
NOTICE: this version tested with kernels 1.3.72 and later only!
- Written 1996-1997 by Donald Becker.
+ Written 1996-1998 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
This driver is for the Intel EtherExpress Pro 100B boards.
- It should work with other i82557 boards (if any others exist).
+ It should work with other i82557 and i82558 boards.
To use a built-in driver, install as drivers/net/eepro100.c.
To use as a module, use the compile-command at the end of the file.
Center of Excellence in Space Data and Information Sciences
Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
For updates see
- <base href="http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html">
+ http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html
+ There is also a mailing list based at
+ linux-eepro100@cesdis.gsfc.nasa.gov
*/
static const char *version =
-"eepro100.c:v0.36 10/20/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
+"eepro100.c:v1.04 10/8/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
/* A few user-configurable values that apply to all boards.
First set are undocumented and spelled per Intel recommendations. */
/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
Lower values use more memory, but are faster. */
-/*
- * NOTE! The value of 2000 means that this optimization never gets
- * used. Rationale: it seems to be broken when in low-memory situations,
- * apparently when alloc_skb() can return NULL the clever list of
- * copy-buffers can get buggered.
- *
- * My personal suspicion is that the allocation failure will cause
- * us to not remove the skb from the list of available buffers, but
- * we'd already have done a "skb_push()" with the data we got, so
- * the buffer stays on the list but the available memory in it
- * shrinks until we panic.
- *
- * Donald, when you fix this you can shrink this value again.
- *
- * Linus
- */
-static int rx_copybreak = 2000;
+static int rx_copybreak = 200;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 200;
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
+static int multicast_filter_limit = 64;
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
#include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
#include <linux/version.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
-#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <linux/delay.h>
-#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
-#include <asm/dma.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-
-/* A nominally proper method to handle version dependencies is to use
- LINUX_VERSION_CODE in version.h, but that triggers recompiles w/'make'. */
-#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s)
-#ifdef MODULE
-#if (LINUX_VERSION_CODE < VERSION(1,3,0))
-#define KERNEL_1_2
-#else /* 1.3.0 */
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
-#define NEW_MULTICAST
-#define LINUX_1_4
-#else
-#warning "This driver is tested for 1.3.44 and later development kernels only."
-#endif /* 1.3.44 */
-#endif
-#else
-
-#if (LINUX_VERSION_CODE >= 0x10344)
-#define NEW_MULTICAST
#include <linux/delay.h>
-#endif
-#ifdef HAVE_HEADER_CACHE
-#define LINUX_1_4
-#define NEW_MULTICAST
-#else
-#ifdef ETH_P_DDCMP /* Warning: Bogus! This means IS_LINUX_1_3. */
-#define KERNEL_1_3
-#else
-#define KERNEL_1_2
-#endif
-#endif
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(congenb, "i");
+MODULE_PARM(txfifo, "i");
+MODULE_PARM(rxfifo, "i");
+MODULE_PARM(txdmacount, "i");
+MODULE_PARM(rxdmacount, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(multicast_filter_limit, "i");
-#endif
-/* This should be in a header file. */
-#if (LINUX_VERSION_CODE < VERSION(1,3,44))
-struct device *init_etherdev(struct device *dev, int sizeof_priv,
- unsigned long *mem_startp);
-#endif
-#if LINUX_VERSION_CODE < 0x10300
-#define RUN_AT(x) (x) /* What to put in timer->expires. */
-#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
-#define virt_to_bus(addr) ((unsigned long)addr)
-#define bus_to_virt(addr) ((void*)addr)
-#else /* 1.3.0 and later */
#define RUN_AT(x) (jiffies + (x))
-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
-#endif
-#if (LINUX_VERSION_CODE < 0x20123)
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#include <linux/bios32.h>
-#endif
+#define dev_free_skb(skb) dev_kfree_skb(skb);
-/* The total I/O port extent of the board. Nominally 0x18, but rounded up
- for PCI allocation. */
+/* The total I/O port extent of the board.
+ The registers beyond 0x18 only exist on the i82558. */
#define SPEEDO3_TOTAL_SIZE 0x20
-#ifdef HAVE_DEVLIST
-struct netdev_entry eepro100_drv =
-{"EEPro-100", eepro100_init, SPEEDO3_TOTAL_SIZE, NULL};
-#endif
-
-#ifdef SPEEDO3_DEBUG
-int speedo_debug = SPEEDO3_DEBUG;
-#else
-int speedo_debug = 3;
-#endif
+int speedo_debug = 0;
/*
Theory of Operation
Despite the extra space overhead in each receive skbuff, the driver must use
the simplified Rx buffer mode to assure that only a single data buffer is
associated with each RxFD. The driver implements this by reserving space
-for the Rx descriptor at the head of each Rx skbuff
+for the Rx descriptor at the head of each Rx skbuff.
The Speedo-3 has receive and command unit base addresses that are added to
almost all descriptor pointers. The driver sets these to zero, so that all
The driver must use the complex Tx command+descriptor mode in order to
have a indirect pointer to the skbuff data section. Each Tx command block
-(TxCB) is associated with a single, immediately appended Tx buffer descriptor
+(TxCB) is associated with two immediately appended Tx Buffer Descriptor
(TxBD). A fixed ring of these TxCB+TxBD pairs are kept as part of the
speedo_private data structure for each adapter instance.
+The newer i82558 explicitly supports this structure, and can read the two
+TxBDs in the same PCI burst as the TxCB.
+
This ring structure is used for all normal transmit packets, but the
transmit packet descriptors aren't long enough for most non-Tx commands such
as CmdConfigure. This is complicated by the possibility that the chip has
#define PKT_BUF_SZ 1536
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT ((400*HZ)/1000)
+#define TX_TIMEOUT ((800*HZ)/1000)
/* How to wait for the command unit to accept a command.
Typically this takes 0 ticks. */
-static inline void wait_for_cmd_done(int cmd_ioaddr)
+static inline void wait_for_cmd_done(long cmd_ioaddr)
{
- short wait = 100;
- do ;
- while(inb(cmd_ioaddr) && --wait >= 0);
+ int wait = 100;
+ do ;
+ while(inb(cmd_ioaddr) && --wait >= 0);
}
/* Operational parameter that usually are not changed. */
-#ifndef PCI_VENDOR_ID_INTEL /* Now defined in linux/pci.h */
-#define PCI_VENDOR_ID_INTEL 0x8086 /* Hmmmm, how did they pick that? */
-#endif
-#ifndef PCI_DEVICE_ID_INTEL_82557
-#define PCI_DEVICE_ID_INTEL_82557 0x1229
-#endif
-
/* The rest of these values should never change. */
/* Offsets to the various registers.
u16 size;
};
-/* Elements of the RxFD.status word. */
-#define RX_COMPLETE 0x8000
+/* Selected elements of the Tx/RxFD.status word. */
+enum RxFD_bits {
+ RxComplete=0x8000, RxOK=0x2000,
+ RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
+ RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
+ StatusComplete=0x8000,
+};
struct TxFD { /* Transmit frame descriptor set. */
s32 status;
u32 link; /* void * */
u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
s32 count; /* # of TBD (=1), Tx start thresh., etc. */
- /* This constitutes a single "TBD" entry -- we only use one. */
- u32 tx_buf_addr; /* void *, frame to be transmitted. */
- s32 tx_buf_size; /* Length of Tx frame. */
+ /* This constitutes two "TBD" entries -- we only use one. */
+ u32 tx_buf_addr0; /* void *, frame to be transmitted. */
+ s32 tx_buf_size0; /* Length of Tx frame. */
+ u32 tx_buf_addr1; /* void *, frame to be transmitted. */
+ s32 tx_buf_size1; /* Length of Tx frame. */
};
/* Elements of the dump_statistics block. This block must be lword aligned. */
/* Rx descriptor ring & addresses of receive-in-place skbuffs. */
struct RxFD *rx_ringp[RX_RING_SIZE];
struct sk_buff* rx_skbuff[RX_RING_SIZE];
-#if (LINUX_VERSION_CODE < 0x10300) /* Kernel v1.2.*. */
- struct RxFD saved_skhead[RX_RING_SIZE]; /* Saved skbuff header chunk. */
-#endif
struct RxFD *last_rxf; /* Last command sent. */
struct enet_statistics stats;
struct speedo_stats lstats;
long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
- struct descriptor config_cmd; /* A configure command, with header... */
- u8 config_cmd_data[22]; /* .. and setup parameters. */
int mc_setup_frm_len; /* The length of an allocated.. */
struct descriptor *mc_setup_frm; /* ..multicast setup frame. */
+ int mc_setup_busy; /* Avoid double-use of setup frame. */
+ int in_interrupt; /* Word-aligned dev->interrupt */
char rx_mode; /* Current PROMISC/ALLMULTI setting. */
unsigned int tx_full:1; /* The Tx queue is full. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
/* The parameters for a CmdConfigure operation.
There are so many options that it would be difficult to document each bit.
We mostly use the default or recommended settings. */
-const char basic_config_cmd[22] = {
+const char i82557_config_cmd[22] = {
22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */
0, 0x2E, 0, 0x60, 0,
0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */
0x3f, 0x05, };
+const char i82558_config_cmd[22] = {
+ 22, 0x08, 0, 1, 0, 0x80, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */
+ 0, 0x2E, 0, 0x60, 0x08, 0x88,
+ 0x68, 0, 0x40, 0xf2, 0xBD, /* 0xBD->0xFD=Force full-duplex */
+ 0x31, 0x05, };
/* PHY media interface chips. */
static const char *phys[] = {
S80C24, I82555, DP83840A=10, };
static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
-static void speedo_found1(struct device *dev, int ioaddr, int irq,
- int options, int card_idx);
+static void speedo_found1(struct device *dev, long ioaddr, int irq,
+ int card_idx);
-static int read_eeprom(int ioaddr, int location);
-static int mdio_read(int ioaddr, int phy_id, int location);
-static int mdio_write(int ioaddr, int phy_id, int location, int value);
+static int read_eeprom(long ioaddr, int location, int addr_len);
+static int mdio_read(long ioaddr, int phy_id, int location);
+static int mdio_write(long ioaddr, int phy_id, int location, int value);
static int speedo_open(struct device *dev);
static void speedo_timer(unsigned long data);
static void speedo_init_rx_ring(struct device *dev);
static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static int speedo_close(struct device *dev);
static struct enet_statistics *speedo_get_stats(struct device *dev);
-#ifdef HAVE_PRIVATE_IOCTL
static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd);
-#endif
static void set_rx_mode(struct device *dev);
\f
/* 'options' is used to pass a transceiver override or full-duplex flag
e.g. "options=16" for FD, "options=32" for 100mbps-only. */
static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-#ifdef MODULE
static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#ifdef MODULE
static int debug = -1; /* The debug level */
#endif
+#ifdef honor_default_port
+/* Optional driver feature to allow forcing the transceiver setting.
+ Not recommended. */
+static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100,
+ 0x2000, 0x2100, 0x0400, 0x3100};
+#endif
+
/* A list of all installed Speedo devices, for removing the driver module. */
static struct device *root_speedo_dev = NULL;
int eepro100_init(struct device *dev)
{
int cards_found = 0;
+ static int pci_index = 0;
- if (pci_present()) {
- static int pci_index = 0;
+ if (! pcibios_present())
+ return cards_found;
- for (; pci_index < 8; pci_index++) {
- unsigned char pci_bus, pci_device_fn, pci_latency;
-#if (LINUX_VERSION_CODE >= VERSION(2,1,85))
- unsigned int pci_irq_line;
- struct pci_dev *pdev;
-#else
- unsigned char pci_irq_line;
-#endif
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
- int pci_ioaddr;
-#else
- long pci_ioaddr;
-#endif
- unsigned short pci_command;
-
- if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82557,
- pci_index, &pci_bus,
- &pci_device_fn))
- break;
-#if (LINUX_VERSION_CODE >= VERSION(2,1,85))
- pdev = pci_find_slot(pci_bus, pci_device_fn);
- pci_irq_line = pdev->irq;
- pci_ioaddr = pdev->base_address[1];
-#else
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- /* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_1, &pci_ioaddr);
-#endif
- /* Remove I/O space marker in bit 0. */
- pci_ioaddr &= ~3;
- if (speedo_debug > 2)
- printk("Found Intel i82557 PCI Speedo at I/O %#x, IRQ %d.\n",
- (int)pci_ioaddr, pci_irq_line);
-
- /* Get and check the bus-master and latency values. */
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- if ( ! (pci_command & PCI_COMMAND_MASTER)) {
- printk(" PCI Master Bit has not been set! Setting...\n");
- pci_command |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, pci_command);
- }
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < 10) {
- printk(" PCI latency timer (CFLT) is unreasonably low at %d."
- " Setting to 255 clocks.\n", pci_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 255);
- } else if (speedo_debug > 1)
- printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency);
+ for (; pci_index < 8; pci_index++) {
+ unsigned char pci_bus, pci_device_fn, pci_latency;
+ long ioaddr;
+ int irq;
-#ifdef MODULE
- speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found],
- cards_found);
-#else
- speedo_found1(dev, pci_ioaddr, pci_irq_line,
- dev ? dev->mem_start : 0, -1);
-#endif
- dev = NULL;
- cards_found++;
+ u16 pci_command, new_command;
+
+ if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82557,
+ pci_index, &pci_bus,
+ &pci_device_fn))
+ break;
+ {
+ struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+ ioaddr = pdev->base_address[1]; /* Use [0] to mem-map */
+ irq = pdev->irq;
+ }
+ /* Remove I/O space marker in bit 0. */
+ ioaddr &= ~3;
+ if (speedo_debug > 2)
+ printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
+ ioaddr, irq);
+
+ /* Get and check the bus-master and latency values. */
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);
+ new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+ if (pci_command != new_command) {
+ printk(KERN_INFO " The PCI BIOS has not enabled this"
+ " device! Updating PCI command %4.4x->%4.4x.\n",
+ pci_command, new_command);
+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, new_command);
}
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, &pci_latency);
+ if (pci_latency < 32) {
+ printk(" PCI latency timer (CFLT) is unreasonably low at %d."
+ " Setting to 32 clocks.\n", pci_latency);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, 32);
+ } else if (speedo_debug > 1)
+ printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency);
+
+ speedo_found1(dev, ioaddr, irq, cards_found);
+ dev = NULL;
+ cards_found++;
}
return cards_found;
}
-static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
+static void speedo_found1(struct device *dev, long ioaddr, int irq,
int card_idx)
{
static int did_version = 0; /* Already printed version info. */
struct speedo_private *sp;
char *product;
- int i;
+ int i, option;
u16 eeprom[0x40];
if (speedo_debug > 0 && did_version++ == 0)
printk(version);
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
dev = init_etherdev(dev, sizeof(struct speedo_private));
-#else
- dev = init_etherdev(dev, sizeof(struct speedo_private), 0);
-#endif
+
+ if (dev->mem_start > 0)
+ option = dev->mem_start;
+ else if (card_idx >= 0 && options[card_idx] >= 0)
+ option = options[card_idx];
+ else
+ option = 0;
/* Read the station address EEPROM before doing the reset.
Perhaps this should even be done before accepting the device,
{
u16 sum = 0;
int j;
+ int addr_len = read_eeprom(ioaddr, 0, 6) == 0xffff ? 8 : 6;
+
for (j = 0, i = 0; i < 0x40; i++) {
- u16 value = read_eeprom(ioaddr, i);
+ u16 value = read_eeprom(ioaddr, i, addr_len);
eeprom[i] = value;
sum += value;
if (i < 3) {
else
product = "Intel EtherExpress Pro 10/100";
- printk(KERN_INFO "%s: %s at %#3x, ", dev->name, product, ioaddr);
+ printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
for (i = 0; i < 5; i++)
printk("%2.2X:", dev->dev_addr[i]);
if (eeprom[7] & 0x0700)
printk(KERN_INFO " Secondary interface chip %s.\n",
phys[(eeprom[7]>>8)&7]);
-#if defined(notdef)
- /* ToDo: Read and set PHY registers through MDIO port. */
- for (i = 0; i < 2; i++)
- printk(KERN_INFO" MDIO register %d is %4.4x.\n",
- i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
- for (i = 5; i < 7; i++)
- printk(KERN_INFO" MDIO register %d is %4.4x.\n",
- i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
- printk(KERN_INFO" MDIO register %d is %4.4x.\n",
- 25, mdio_read(ioaddr, eeprom[6] & 0x1f, 25));
-#endif
if (((eeprom[6]>>8) & 0x3f) == DP83840
|| ((eeprom[6]>>8) & 0x3f) == DP83840A) {
int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
mdi_reg23);
mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
}
- if ((options >= 0) && (options & 0x60)) {
+ if ((option >= 0) && (option & 0x70)) {
printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n",
- (options & 0x20 ? 100 : 10),
- (options & 0x10 ? "full" : "half"));
+ (option & 0x20 ? 100 : 10),
+ (option & 0x10 ? "full" : "half"));
mdio_write(ioaddr, eeprom[6] & 0x1f, 0,
- ((options & 0x20) ? 0x2000 : 0) | /* 100mbps? */
- ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+ ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */
+ ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
}
/* Perform a system self-test. */
self_test_results[1] = -1;
outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort);
do {
-#ifdef _LINUX_DELAY_H
udelay(10);
-#else
- SLOW_DOWN_IO;
-#endif
} while (self_test_results[1] == -1 && --boguscnt >= 0);
if (boguscnt < 0) { /* Test optimized out. */
sp->next_module = root_speedo_dev;
root_speedo_dev = dev;
+ sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
if (card_idx >= 0) {
if (full_duplex[card_idx] >= 0)
sp->full_duplex = full_duplex[card_idx];
- } else
- sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0;
- sp->default_port = options >= 0 ? (options & 0x0f) : 0;
+ }
+ sp->default_port = option >= 0 ? (option & 0x0f) : 0;
sp->phy[0] = eeprom[6];
sp->phy[1] = eeprom[7];
dev->hard_start_xmit = &speedo_start_xmit;
dev->stop = &speedo_close;
dev->get_stats = &speedo_get_stats;
-#ifdef NEW_MULTICAST
dev->set_multicast_list = &set_rx_mode;
-#endif
-#ifdef HAVE_PRIVATE_IOCTL
dev->do_ioctl = &speedo_ioctl;
-#endif
return;
}
#define EE_ENB (0x4800 | EE_CS)
/* Delay between EEPROM clock transitions.
- This is a "nasty" timing loop, but PC compatible machines are defined
- to delay an ISA compatible period for the SLOW_DOWN_IO macro. */
-#ifdef _LINUX_DELAY_H
+ This will actually work with no delay on 33Mhz PCI. */
#define eeprom_delay(nanosec) udelay(1);
-#else
-#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
-#endif
/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD (5 << 6)
-#define EE_READ_CMD (6 << 6)
-#define EE_ERASE_CMD (7 << 6)
+#define EE_WRITE_CMD (5 << addr_len)
+#define EE_READ_CMD (6 << addr_len)
+#define EE_ERASE_CMD (7 << addr_len)
-static int read_eeprom(int ioaddr, int location)
+static int read_eeprom(long ioaddr, int location, int addr_len)
{
- int i;
unsigned short retval = 0;
int ee_addr = ioaddr + SCBeeprom;
int read_cmd = location | EE_READ_CMD;
+ int i;
outw(EE_ENB & ~EE_CS, ee_addr);
outw(EE_ENB, ee_addr);
/* Shift the read command bits out. */
- for (i = 10; i >= 0; i--) {
+ for (i = 12; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
outw(EE_ENB | dataval, ee_addr);
eeprom_delay(100);
outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
eeprom_delay(150);
- outw(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */
- eeprom_delay(250);
}
outw(EE_ENB, ee_addr);
return retval;
}
-static int mdio_read(int ioaddr, int phy_id, int location)
+static int mdio_read(long ioaddr, int phy_id, int location)
{
- int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */
+ int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */
outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
do {
-#ifdef _LINUX_DELAY_H
- udelay(16);
-#else
- SLOW_DOWN_IO;
-#endif
val = inl(ioaddr + SCBCtrlMDI);
if (--boguscnt < 0) {
printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val);
return val & 0xffff;
}
-static int mdio_write(int ioaddr, int phy_id, int location, int value)
+static int mdio_write(long ioaddr, int phy_id, int location, int value)
{
- int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */
+ int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */
outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
ioaddr + SCBCtrlMDI);
do {
-#ifdef _LINUX_DELAY_H
- udelay(16);
-#else
- SLOW_DOWN_IO;
-#endif
val = inl(ioaddr + SCBCtrlMDI);
if (--boguscnt < 0) {
printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val);
speedo_open(struct device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
#ifdef notdef
/* We could reset the chip, but should not need to. */
outl(0, ioaddr + SCBPort);
- for (i = 40; i >= 0; i--)
- SLOW_DOWN_IO; /* At least 250ns */
+ udelay(10);
#endif
if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ,
"Intel EtherExpress Pro 10/100 Ethernet", dev)) {
return -EAGAIN;
}
-
if (speedo_debug > 1)
printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
MOD_INC_USE_COUNT;
+ /* Retrigger negotiation to reset previous errors. */
+ if ((sp->phy[0] & 0x8000) == 0) {
+ int phy_addr = sp->phy[0] & 0x1f;
+ /* Use 0x3300 for restarting NWay, other values to force xcvr:
+ 0x0000 10-HD
+ 0x0100 10-FD
+ 0x2000 100-HD
+ 0x2100 100-FD
+ */
+#ifdef honor_default_port
+ mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+#else
+ mdio_write(ioaddr, phy_addr, 0, 0x3300);
+#endif
+ }
+
/* Load the statistics block address. */
wait_for_cmd_done(ioaddr + SCBCmd);
outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
dev->if_port = sp->default_port;
+ sp->in_interrupt = 0;
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
/* Setup the chip and configure the multicast list. */
sp->mc_setup_frm = NULL;
sp->mc_setup_frm_len = 0;
+ sp->mc_setup_busy = 0;
sp->rx_mode = -1; /* Invalid -> always reset the mode. */
set_rx_mode(dev);
{
struct device *dev = (struct device *)data;
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int tickssofar = jiffies - sp->last_rx_time;
if (speedo_debug > 3) {
- int ioaddr = dev->base_addr;
- printk(KERN_DEBUG "%s: Media selection tick, status %4.4x.\n",
+ long ioaddr = dev->base_addr;
+ printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",
dev->name, inw(ioaddr + SCBStatus));
}
- if (sp->rx_bug) {
- if (tickssofar > 2*HZ || sp->rx_mode < 0) {
- /* We haven't received a packet in a Long Time. We might have been
- bitten by the receiver hang bug. This can be cleared by sending
- a set multicast list command. */
- set_rx_mode(dev);
- }
- /* We must continue to monitor the media. */
- sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */
- add_timer(&sp->timer);
+ if (sp->rx_mode < 0 ||
+ (sp->rx_bug && jiffies - sp->last_rx_time > 2*HZ)) {
+ /* We haven't received a packet in a Long Time. We might have been
+ bitten by the receiver hang bug. This can be cleared by sending
+ a set multicast list command. */
+ set_rx_mode(dev);
}
+ /* We must continue to monitor the media. */
+ sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */
+ add_timer(&sp->timer);
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
int i;
sp->cur_rx = 0;
- sp->dirty_rx = RX_RING_SIZE - 1;
for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb;
-#ifndef KERNEL_1_2
skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-#else
- skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
-#endif
sp->rx_skbuff[i] = skb;
if (skb == NULL)
- break; /* Bad news! */
+ break; /* OK. Just initially short of Rx bufs. */
skb->dev = dev; /* Mark as being used by this device. */
-
-#if LINUX_VERSION_CODE >= 0x10300
rxf = (struct RxFD *)skb->tail;
- skb_reserve(skb, sizeof(struct RxFD));
-#else
- /* Save the data in the header region -- it's restored later. */
- rxf = (struct RxFD *)(skb->data - sizeof(struct RxFD));
- memcpy(&sp->saved_skhead[i], rxf, sizeof(struct RxFD));
-#endif
sp->rx_ringp[i] = rxf;
+ skb_reserve(skb, sizeof(struct RxFD));
if (last_rxf)
last_rxf->link = virt_to_bus(rxf);
last_rxf = rxf;
rxf->status = 0x00000001; /* '1' is flag value only. */
rxf->link = 0; /* None yet. */
-#if LINUX_VERSION_CODE < 0x10300
/* This field unused by i82557, we use it as a consistency check. */
- rxf->rx_buf_addr = virt_to_bus(skb->data);
+#ifdef final_version
+ rxf->rx_buf_addr = 0xffffffff;
#else
rxf->rx_buf_addr = virt_to_bus(skb->tail);
#endif
rxf->count = 0;
rxf->size = PKT_BUF_SZ;
}
+ sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
/* Mark the last entry as end-of-list. */
last_rxf->status = 0xC0000002; /* '2' is flag value only. */
sp->last_rxf = last_rxf;
static void speedo_tx_timeout(struct device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
- int i;
+ long ioaddr = dev->base_addr;
printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
- "command %4.4x.\n",
- dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd));
-#ifndef final_version
- printk(KERN_WARNING "%s: Tx timeout fill index %d scavenge index %d.\n",
- dev->name, sp->cur_tx, sp->dirty_tx);
- printk(KERN_WARNING " Tx queue ");
- for (i = 0; i < TX_RING_SIZE; i++)
- printk(" %8.8x", (int)sp->tx_ring[i].status);
- printk(".\n" KERN_WARNING " Rx ring ");
- for (i = 0; i < RX_RING_SIZE; i++)
- printk(" %8.8x", (int)sp->rx_ringp[i]->status);
- printk(".\n");
-
-#else
- dev->if_port ^= 1;
- printk(KERN_WARNING " (Media type switching not yet implemented.)\n");
- /* Do not do 'dev->tbusy = 0;' there -- it is incorrect. */
-#endif
+ " %4.4x at %d/%d command %8.8x.\n",
+ dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd),
+ sp->dirty_tx, sp->cur_tx,
+ sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {
- printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
- dev->name);
- outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
- ioaddr + SCBPointer);
- outw(CU_START, ioaddr + SCBCmd);
+ printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
+ dev->name);
+ outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
+ ioaddr + SCBPointer);
+ outw(CU_START, ioaddr + SCBCmd);
} else {
- outw(DRVR_INT, ioaddr + SCBCmd);
+ outw(DRVR_INT, ioaddr + SCBCmd);
+ }
+ /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
+ if ((sp->phy[0] & 0x8000) == 0) {
+ int phy_addr = sp->phy[0] & 0x1f;
+ mdio_write(ioaddr, phy_addr, 0, 0x0400);
+ mdio_write(ioaddr, phy_addr, 1, 0x0000);
+ mdio_write(ioaddr, phy_addr, 4, 0x0000);
+ mdio_write(ioaddr, phy_addr, 0, 0x8000);
+#ifdef honor_default_port
+ mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+#endif
}
- /* Reset the MII transceiver. */
- if ((sp->phy[0] & 0x8000) == 0)
- mdio_write(ioaddr, sp->phy[0] & 0x1f, 0, 0x8000);
sp->stats.tx_errors++;
dev->trans_start = jiffies;
return;
speedo_start_xmit(struct sk_buff *skb, struct device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int entry;
/* Block a timer-based transmit from overlapping. This could better be
return 1;
}
speedo_tx_timeout(dev);
- return 0;
+ return 1;
}
/* Caution: the write order is important here, set the base address
sp->tx_ring[entry].link =
virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
sp->tx_ring[entry].tx_desc_addr =
- virt_to_bus(&sp->tx_ring[entry].tx_buf_addr);
+ virt_to_bus(&sp->tx_ring[entry].tx_buf_addr0);
/* The data region is always in one buffer descriptor, Tx FIFO
threshold of 256. */
sp->tx_ring[entry].count = 0x01208000;
- sp->tx_ring[entry].tx_buf_addr = virt_to_bus(skb->data);
- sp->tx_ring[entry].tx_buf_size = skb->len;
+ sp->tx_ring[entry].tx_buf_addr0 = virt_to_bus(skb->data);
+ sp->tx_ring[entry].tx_buf_size0 = skb->len;
/* Todo: perhaps leave the interrupt bit set if the Tx queue is more
than half full. Argument against: we should be receiving packets
and scavenging the queue. Argument for: if so, it shouldn't
matter. */
sp->last_cmd->command &= ~(CmdSuspend | CmdIntr);
sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+ restore_flags(flags);
/* Trigger the command unit resume. */
wait_for_cmd_done(ioaddr + SCBCmd);
outw(CU_RESUME, ioaddr + SCBCmd);
- restore_flags(flags);
}
/* Leave room for set_rx_mode() to fill two entries. */
if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3)
sp->tx_full = 1;
else
- dev->tbusy = 0;
+ clear_bit(0, (void*)&dev->tbusy);
dev->trans_start = jiffies;
{
struct device *dev = (struct device *)dev_instance;
struct speedo_private *sp;
- int ioaddr, boguscnt = max_interrupt_work;
+ long ioaddr, boguscnt = max_interrupt_work;
unsigned short status;
#ifndef final_version
ioaddr = dev->base_addr;
sp = (struct speedo_private *)dev->priv;
#ifndef final_version
- if (dev->interrupt) {
- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+ /* A lock to prevent simultaneous entry on SMP machines. */
+ if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
+ printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+ dev->name);
+ sp->in_interrupt = 0; /* Avoid halting machine. */
return;
}
dev->interrupt = 1;
speedo_rx(dev);
if (status & 0x1000) {
-#ifdef notdef
- int i;
- printk(KERN_WARNING"%s: The EEPro100 receiver left the ready"
- " state -- %4.4x! Index %d (%d).\n", dev->name, status,
- sp->cur_rx, sp->cur_rx % RX_RING_SIZE);
- printk(KERN_WARNING " Rx ring:\n ");
- for (i = 0; i < RX_RING_SIZE; i++)
- printk(" %d %8.8x %8.8x %8.8x %d %d.\n",
- i, sp->rx_ringp[i]->status, sp->rx_ringp[i]->link,
- sp->rx_ringp[i]->rx_buf_addr, sp->rx_ringp[i]->count,
- sp->rx_ringp[i]->size);
-#endif
-
if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */
outw(RX_RESUMENR, ioaddr + SCBCmd);
else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */
if (speedo_debug > 5)
printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
entry, status);
- if ((status & 0x8000) == 0)
+ if ((status & StatusComplete) == 0)
break; /* It still hasn't been processed. */
/* Free the original skb. */
if (sp->tx_skbuff[entry]) {
sp->stats.tx_packets++; /* Count only user packets. */
- dev_kfree_skb(sp->tx_skbuff[entry]);
+ dev_free_skb(sp->tx_skbuff[entry]);
sp->tx_skbuff[entry] = 0;
- }
+ } else if ((sp->tx_ring[entry].status&0x70000) == CmdNOp << 16)
+ sp->mc_setup_busy = 0;
dirty_tx++;
}
&& dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) {
/* The ring is no longer full, clear tbusy. */
sp->tx_full = 0;
- dev->tbusy = 0;
+ clear_bit(0, (void*)&dev->tbusy);
mark_bh(NET_BH);
}
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
dev->name, inw(ioaddr + SCBStatus));
-#ifndef final_version
- /* Special code for testing *only*. */
- {
- static int stopit = 100;
- if (dev->start == 0 && --stopit < 0) {
- printk(KERN_ALERT "%s: Emergency stop, interrupt is stuck.\n",
- dev->name);
- free_irq(irq, dev);
- }
- }
-#endif
-
dev->interrupt = 0;
+ clear_bit(0, (void*)&sp->in_interrupt);
return;
}
struct speedo_private *sp = (struct speedo_private *)dev->priv;
int entry = sp->cur_rx % RX_RING_SIZE;
int status;
+ int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
if (speedo_debug > 4)
printk(KERN_DEBUG " In speedo_rx().\n");
/* If we own the next entry, it's a new packet. Send it up. */
- while ((status = sp->rx_ringp[entry]->status) & RX_COMPLETE) {
+ while (sp->rx_ringp[entry] != NULL &&
+ (status = sp->rx_ringp[entry]->status) & RxComplete) {
if (speedo_debug > 4)
printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status,
sp->rx_ringp[entry]->count & 0x3fff);
- if (status & 0x0200) {
- printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
- "status %8.8x!\n", dev->name, status);
- } else if ( ! (status & 0x2000)) {
- /* There was a fatal error. This *should* be impossible. */
- sp->stats.rx_errors++;
- printk(KERN_ERR "%s: Anomalous event in speedo_rx(), status %8.8x.\n",
- dev->name, status);
+ if ((status & (RxErrTooBig|RxOK)) != RxOK) {
+ if (status & RxErrTooBig)
+ printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
+ "status %8.8x!\n", dev->name, status);
+ else if ( ! (status & 0x2000)) {
+ /* There was a fatal error. This *should* be impossible. */
+ sp->stats.rx_errors++;
+ printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "
+ "status %8.8x.\n",
+ dev->name, status);
+ }
} else {
- /* Malloc up new buffer, compatible with net-2e. */
int pkt_len = sp->rx_ringp[entry]->count & 0x3fff;
struct sk_buff *skb;
- int rx_in_place = 0;
/* Check if the packet is long enough to just accept without
copying to a properly sized skbuff. */
- if (pkt_len > rx_copybreak) {
- struct sk_buff *newskb;
- char *temp;
-
- /* Pass up the skb already on the Rx ring. */
- skb = sp->rx_skbuff[entry];
-#ifdef KERNEL_1_2
- temp = skb->data;
- if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
- printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
- " in speedo_rx: %p vs. %p / %p.\n", dev->name,
- bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
- temp, skb->data);
- /* Get a fresh skbuff to replace the filled one. */
- newskb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
-#else
- temp = skb_put(skb, pkt_len);
- if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
- printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
- " in speedo_rx: %8.8x vs. %p / %p.\n", dev->name,
- sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp);
- /* Get a fresh skbuff to replace the filled one. */
- newskb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-#endif
- if (newskb) {
- struct RxFD *rxf;
- rx_in_place = 1;
- sp->rx_skbuff[entry] = newskb;
- newskb->dev = dev;
-#ifdef KERNEL_1_2
- /* Restore the data in the old header region. */
- memcpy(skb->data - sizeof(struct RxFD),
- &sp->saved_skhead[entry], sizeof(struct RxFD));
- /* Save the data in this header region. */
- rxf = (struct RxFD *)(newskb->data - sizeof(struct RxFD));
- sp->rx_ringp[entry] = rxf;
- memcpy(&sp->saved_skhead[entry], rxf, sizeof(struct RxFD));
- rxf->rx_buf_addr = virt_to_bus(newskb->data);
-#else
- rxf = sp->rx_ringp[entry] = (struct RxFD *)newskb->tail;
- skb_reserve(newskb, sizeof(struct RxFD));
- /* Unused by i82557, consistency check only. */
- rxf->rx_buf_addr = virt_to_bus(newskb->tail);
-#endif
- rxf->status = 0x00000001;
- } else /* No memory, drop the packet. */
- skb = 0;
- } else
-#ifdef KERNEL_1_2
- skb = alloc_skb(pkt_len, GFP_ATOMIC);
-#else
- skb = dev_alloc_skb(pkt_len + 2);
-#endif
- if (skb == NULL) {
- int i;
- printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
- /* Check that at least two ring entries are free.
- If not, free one and mark stats->rx_dropped++. */
- /* ToDo: This is not correct!!!! We should count the number
- of linked-in Rx buffer to very that we have at least two
- remaining. */
- for (i = 0; i < RX_RING_SIZE; i++)
- if (! ((sp->rx_ringp[(entry+i) % RX_RING_SIZE]->status)
- & RX_COMPLETE))
- break;
-
- if (i > RX_RING_SIZE -2) {
- sp->stats.rx_dropped++;
- sp->rx_ringp[entry]->status = 0;
- sp->cur_rx++;
- }
- break;
- }
- skb->dev = dev;
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
- if (! rx_in_place) {
- skb_reserve(skb, 2); /* 16 byte align the data fields */
-#if defined(__i386__) && notyet
+ if (pkt_len < rx_copybreak
+ && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
+ /* 'skb_put()' points to the start of sk_buff data area. */
+#if 1 || USE_IP_CSUM
/* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
- pkt_len, 0);
+ eth_copy_and_sum(skb,
+ bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+ pkt_len, 0);
+ skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len),
bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
#endif
+ } else {
+ void *temp;
+ /* Pass up the already-filled skbuff. */
+ skb = sp->rx_skbuff[entry];
+ if (skb == NULL) {
+ printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n",
+ dev->name);
+ break;
+ }
+ sp->rx_skbuff[entry] = NULL;
+ temp = skb_put(skb, pkt_len);
+ if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
+ printk(KERN_ERR "%s: Rx consistency error -- the skbuff "
+ "addresses do not match in speedo_rx: %p vs. %p "
+ "/ %p.\n", dev->name,
+ bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+ skb->head, temp);
+ sp->rx_ringp[entry] = NULL;
}
skb->protocol = eth_type_trans(skb, dev);
-#else
-#ifdef KERNEL_1_3
-#warning This code has only been tested with later 1.3.* kernels.
- skb->len = pkt_len;
- memcpy(skb->data, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
- pkt_len);
- /* Needed for 1.3.*. */
- skb->protocol = eth_type_trans(skb, dev);
-#else /* KERNEL_1_2 */
- skb->len = pkt_len;
- if (! rx_in_place) {
- memcpy(skb->data,
- bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
- }
-#endif
-#endif
netif_rx(skb);
sp->stats.rx_packets++;
}
+ entry = (++sp->cur_rx) % RX_RING_SIZE;
+ if (--rx_work_limit < 0)
+ break;
+ }
- /* ToDo: This is better than before, but should be checked. */
- {
- struct RxFD *rxf = sp->rx_ringp[entry];
- rxf->status = 0xC0000003; /* '3' for verification only */
- rxf->link = 0; /* None yet. */
- rxf->count = 0;
- rxf->size = PKT_BUF_SZ;
- sp->last_rxf->link = virt_to_bus(rxf);
- sp->last_rxf->status &= ~0xC0000000;
- sp->last_rxf = rxf;
- entry = (++sp->cur_rx) % RX_RING_SIZE;
+ /* Refill the Rx ring buffers. */
+ for (; sp->dirty_rx < sp->cur_rx; sp->dirty_rx++) {
+ struct RxFD *rxf;
+ entry = sp->dirty_rx % RX_RING_SIZE;
+ if (sp->rx_skbuff[entry] == NULL) {
+ struct sk_buff *skb;
+ /* Get a fresh skbuff to replace the consumed one. */
+ skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+ sp->rx_skbuff[entry] = skb;
+ if (skb == NULL) {
+ sp->rx_ringp[entry] = NULL;
+ break; /* Better luck next time! */
+ }
+ rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
+ skb->dev = dev;
+ skb_reserve(skb, sizeof(struct RxFD));
+ rxf->rx_buf_addr = virt_to_bus(skb->tail);
+ } else {
+ rxf = sp->rx_ringp[entry];
}
+ rxf->status = 0xC0000001; /* '1' for driver use only. */
+ rxf->link = 0; /* None yet. */
+ rxf->count = 0;
+ rxf->size = PKT_BUF_SZ;
+ sp->last_rxf->link = virt_to_bus(rxf);
+ sp->last_rxf->status &= ~0xC0000000;
+ sp->last_rxf = rxf;
}
sp->last_rx_time = jiffies;
static int
speedo_close(struct device *dev)
{
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
struct speedo_private *sp = (struct speedo_private *)dev->priv;
int i;
sp->rx_skbuff[i] = 0;
/* Clear the Rx descriptors. */
if (skb)
- dev_kfree_skb(skb);
+ dev_free_skb(skb);
}
for (i = 0; i < TX_RING_SIZE; i++) {
sp->tx_skbuff[i] = 0;
/* Clear the Tx descriptors. */
if (skb)
- dev_kfree_skb(skb);
+ dev_free_skb(skb);
}
if (sp->mc_setup_frm) {
kfree(sp->mc_setup_frm);
speedo_get_stats(struct device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
if (sp->lstats.done_marker == 0xA007) { /* Previous dump finished */
sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs;
return &sp->stats;
}
-#ifdef HAVE_PRIVATE_IOCTL
static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
u16 *data = (u16 *)&rq->ifr_data;
int phy = sp->phy[0] & 0x1f;
data[3] = mdio_read(ioaddr, data[0], data[1]);
return 0;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!capable(CAP_NET_ADMIN))
+ if (!suser())
return -EPERM;
mdio_write(ioaddr, data[0], data[1], data[2]);
return 0;
return -EOPNOTSUPP;
}
}
-#endif /* HAVE_PRIVATE_IOCTL */
/* Set or clear the multicast filter for this adaptor.
This is very ugly with Intel chips -- we usually have to execute an
set_rx_mode(struct device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
+ struct descriptor *last_cmd;
char new_rx_mode;
unsigned long flags;
int entry, i;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
new_rx_mode = 3;
- } else if (dev->flags & IFF_ALLMULTI) {
+ } else if ((dev->flags & IFF_ALLMULTI) ||
+ dev->mc_count > multicast_filter_limit) {
new_rx_mode = 1;
} else
new_rx_mode = 0;
}
if (new_rx_mode != sp->rx_mode) {
- /* We must change the configuration. Construct a CmdConfig frame. */
- memcpy(sp->config_cmd_data, basic_config_cmd,sizeof(basic_config_cmd));
- sp->config_cmd_data[1] = (txfifo << 4) | rxfifo;
- sp->config_cmd_data[4] = rxdmacount;
- sp->config_cmd_data[5] = txdmacount + 0x80;
- sp->config_cmd_data[15] = (new_rx_mode & 2) ? 0x49 : 0x48;
- sp->config_cmd_data[19] = sp->full_duplex ? 0xC0 : 0x80;
- sp->config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
- if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */
- sp->config_cmd_data[15] |= 0x80;
- sp->config_cmd_data[8] = 0;
- }
- save_flags(flags);
+ u8 *config_cmd_data;
+
+ save_flags(flags); /* Lock to protect sp->cur_tx. */
cli();
- /* Fill the "real" tx_ring frame with a no-op and point it to us. */
entry = sp->cur_tx++ % TX_RING_SIZE;
- sp->tx_skbuff[entry] = 0; /* Nothing to free. */
- sp->tx_ring[entry].status = CmdNOp << 16;
- sp->tx_ring[entry].link = virt_to_bus(&sp->config_cmd);
- sp->config_cmd.status = 0;
- sp->config_cmd.command = CmdSuspend | CmdConfigure;
- sp->config_cmd.link =
- virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE]));
- sp->last_cmd->command &= ~CmdSuspend;
- /* Immediately trigger the command unit resume. */
- wait_for_cmd_done(ioaddr + SCBCmd);
- outw(CU_RESUME, ioaddr + SCBCmd);
- sp->last_cmd = &sp->config_cmd;
+ last_cmd = sp->last_cmd;
+ sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
restore_flags(flags);
- if (speedo_debug > 5) {
- int i;
- printk(KERN_DEBUG " CmdConfig frame in entry %d.\n", entry);
- for(i = 0; i < 32; i++)
- printk(" %2.2x", ((unsigned char *)&sp->config_cmd)[i]);
- printk(".\n");
+
+ sp->tx_skbuff[entry] = 0; /* Redundant. */
+ sp->tx_ring[entry].status = (CmdSuspend | CmdConfigure) << 16;
+ sp->tx_ring[entry].link =
+ virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
+ config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr;
+ /* Construct a full CmdConfig frame. */
+ memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd));
+ config_cmd_data[1] = (txfifo << 4) | rxfifo;
+ config_cmd_data[4] = rxdmacount;
+ config_cmd_data[5] = txdmacount + 0x80;
+ config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
+ config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
+ config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
+ if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */
+ config_cmd_data[15] |= 0x80;
+ config_cmd_data[8] = 0;
}
+ /* Trigger the command unit resume. */
+ last_cmd->command &= ~CmdSuspend;
+ wait_for_cmd_done(ioaddr + SCBCmd);
+ outw(CU_RESUME, ioaddr + SCBCmd);
}
- if (new_rx_mode == 0 && dev->mc_count < 3) {
- /* The simple case of 0-2 multicast list entries occurs often, and
+ if (new_rx_mode == 0 && dev->mc_count < 4) {
+ /* The simple case of 0-3 multicast list entries occurs often, and
fits within one tx_ring[] entry. */
- u16 *setup_params, *eaddrs;
struct dev_mc_list *mclist;
+ u16 *setup_params, *eaddrs;
- save_flags(flags);
+ save_flags(flags); /* Lock to protect sp->cur_tx. */
cli();
entry = sp->cur_tx++ % TX_RING_SIZE;
+ last_cmd = sp->last_cmd;
+ sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+ restore_flags(flags);
+
sp->tx_skbuff[entry] = 0;
sp->tx_ring[entry].status = (CmdSuspend | CmdMulticastList) << 16;
sp->tx_ring[entry].link =
- virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
+ virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr;
*setup_params++ = dev->mc_count*6;
*setup_params++ = *eaddrs++;
}
- sp->last_cmd->command &= ~CmdSuspend;
+ last_cmd->command &= ~CmdSuspend;
/* Immediately trigger the command unit resume. */
wait_for_cmd_done(ioaddr + SCBCmd);
outw(CU_RESUME, ioaddr + SCBCmd);
- sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
- restore_flags(flags);
} else if (new_rx_mode == 0) {
- /* This does not work correctly, but why not? */
struct dev_mc_list *mclist;
- u16 *eaddrs;
+ u16 *setup_params, *eaddrs;
struct descriptor *mc_setup_frm = sp->mc_setup_frm;
- u16 *setup_params = (u16 *)mc_setup_frm->params;
int i;
if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
|| sp->mc_setup_frm == NULL) {
- /* Allocate a new frame, 10bytes + addrs, with a few
- extra entries for growth. */
+ /* Allocate a full setup frame, 10bytes + <max addrs>. */
if (sp->mc_setup_frm)
kfree(sp->mc_setup_frm);
- sp->mc_setup_frm_len = 10 + dev->mc_count*6 + 24;
+ sp->mc_setup_busy = 0;
+ sp->mc_setup_frm_len = 10 + multicast_filter_limit*6;
sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC);
if (sp->mc_setup_frm == NULL) {
- printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", dev->name);
+ printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
+ dev->name);
sp->rx_mode = -1; /* We failed, try again. */
return;
}
}
+ /* If we are busy, someone might be quickly adding to the MC list.
+ Try again later when the list changes stop. */
+ if (sp->mc_setup_busy) {
+ sp->rx_mode = -1;
+ return;
+ }
mc_setup_frm = sp->mc_setup_frm;
- /* Construct the new setup frame. */
+ /* Fill the setup frame. */
if (speedo_debug > 1)
printk(KERN_DEBUG "%s: Constructing a setup frame at %p, "
"%d bytes.\n",
mc_setup_frm->status = 0;
mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList;
/* Link set below. */
- setup_params = (u16 *)mc_setup_frm->params;
+ setup_params = (u16 *)&mc_setup_frm->params;
*setup_params++ = dev->mc_count*6;
/* Fill in the multicast addresses. */
for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
save_flags(flags);
cli();
entry = sp->cur_tx++ % TX_RING_SIZE;
-
- if (speedo_debug > 5)
- printk(" CmdMCSetup frame length %d in entry %d.\n",
- dev->mc_count, entry);
+ last_cmd = sp->last_cmd;
+ sp->last_cmd = mc_setup_frm;
+ sp->mc_setup_busy++;
+ restore_flags(flags);
/* Change the command to a NoOp, pointing to the CmdMulti command. */
sp->tx_skbuff[entry] = 0;
/* Set the link in the setup frame. */
mc_setup_frm->link =
- virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE]));
+ virt_to_bus(&(sp->tx_ring[(entry+1) % TX_RING_SIZE]));
- sp->last_cmd->command &= ~CmdSuspend;
+ last_cmd->command &= ~CmdSuspend;
/* Immediately trigger the command unit resume. */
wait_for_cmd_done(ioaddr + SCBCmd);
outw(CU_RESUME, ioaddr + SCBCmd);
- sp->last_cmd = mc_setup_frm;
- restore_flags(flags);
- if (speedo_debug > 1)
- printk(KERN_DEBUG "%s: Last command at %p is %4.4x.\n",
- dev->name, sp->last_cmd, sp->last_cmd->command);
+ if (speedo_debug > 5)
+ printk(" CmdMCSetup frame length %d in entry %d.\n",
+ dev->mc_count, entry);
}
sp->rx_mode = new_rx_mode;
}
\f
#ifdef MODULE
-#if (LINUX_VERSION_CODE < VERSION(1,3,38)) /* 1.3.38 and later */
-char kernel_version[] = UTS_RELEASE;
-#endif
-
-#if LINUX_VERSION_CODE > 0x20118
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(congenb, "i");
-MODULE_PARM(txfifo, "i");
-MODULE_PARM(rxfifo, "i");
-MODULE_PARM(txdmacount, "i");
-MODULE_PARM(rxdmacount, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-#endif
int
init_module(void)
\f
/*
* Local variables:
- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
/* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
-
- Written 1994-95 by Mika Kuoppala
-
- Copyright (C) 1994, 1995 by Mika Kuoppala
- Based on skeleton.c and at1700.c by Donald Becker
+
+ Written 1994-1998 by Mika Kuoppala
+
+ Copyright (C) 1994-1998 by Mika Kuoppala
+ Based on skeleton.c and heavily on at1700.c by Donald Becker
This software may be used and distributed according to the terms
of the GNU Public Licence, incorporated herein by reference.
- The author may be reached as miku@elt.icl.fi
+ The author may be reached as miku@iki.fi
This driver supports following cards :
- ICL EtherTeam 16i
- - ICL EtherTeam 32 EISA
+ - ICL EtherTeam 32 EISA
+ (Uses true 32 bit transfers rather than 16i compability mode)
+
+ Example Module usage:
+ insmod eth16i.o ioaddr=0x2a0 mediatype=bnc
+
+ mediatype can be one of the following: bnc,tp,dix,auto,eprom
+ 'auto' will try to autoprobe mediatype.
+ 'eprom' will use whatever type defined in eprom.
+
+ I have benchmarked driver with PII/300Mhz as a ftp client
+ and 486/33Mhz as a ftp server. Top speed was 1128.37 kilobytes/sec.
+
Sources:
- skeleton.c a sample network driver core for linux,
written by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
- - at1700.c a driver for Allied Telesis AT1700, written
+ - at1700.c a driver for Allied Telesis AT1700, written
by Donald Becker.
- e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i
written by Markku Viima
- The Fujitsu MB86965 databook.
-
- Valuable assistance from:
- Markku Viima (ICL)
- Ari Valve (ICL)
+
+ Author thanks following persons due to their valueble assistance:
+ Markku Viima (ICL)
+ Ari Valve (ICL)
+ Donald Becker
+ Kurt Huwig <kurt@huwig.de>
Revision history:
Version Date Description
-
- 0.01 15.12-94 Initial version (card detection)
+
+ 0.01 15.12-94 Initial version (card detection)
0.02 23.01-95 Interrupt is now hooked correctly
0.03 01.02-95 Rewrote initialization part
0.04 07.02-95 Base skeleton done...
- Made a few changes to signature checking
- to make it a bit reliable.
- - fixed bug in tx_buf mapping
- - fixed bug in initialization (DLC_EN
- wasn't enabled when initialization
- was done.)
- 0.05 08.02-95 If there were more than one packet to send,
- transmit was jammed due to invalid
- register write...now fixed
- 0.06 19.02-95 Rewrote interrupt handling
+ Made a few changes to signature checking
+ to make it a bit reliable.
+ - fixed bug in tx_buf mapping
+ - fixed bug in initialization (DLC_EN
+ wasn't enabled when initialization
+ was done.)
+ 0.05 08.02-95 If there were more than one packet to send,
+ transmit was jammed due to invalid
+ register write...now fixed
+ 0.06 19.02-95 Rewrote interrupt handling
0.07 13.04-95 Wrote EEPROM read routines
Card configuration now set according to
- data read from EEPROM
+ data read from EEPROM
0.08 23.06-95 Wrote part that tries to probe used interface
port if AUTO is selected
- 0.09 01.09-95 Added module support
-
- 0.10 04.09-95 Fixed receive packet allocation to work
- with kernels > 1.3.x
+ 0.09 01.09-95 Added module support
+
+ 0.10 04.09-95 Fixed receive packet allocation to work
+ with kernels > 1.3.x
+
+ 0.20 20.09-95 Added support for EtherTeam32 EISA
- 0.20 20.09-95 Added support for EtherTeam32 EISA
-
- 0.21 17.10-95 Removed the unnecessary extern
+ 0.21 17.10-95 Removed the unnecessary extern
init_etherdev() declaration. Some
other cleanups.
+
+ 0.22 22.02-96 Receive buffer was not flushed
+ correctly when faulty packet was
+ received. Now fixed.
+
+ 0.23 26.02-96 Made resetting the adapter
+ more reliable.
+
+ 0.24 27.02-96 Rewrote faulty packet handling in eth16i_rx
+
+ 0.25 22.05-96 kfree() was missing from cleanup_module.
+
+ 0.26 11.06-96 Sometimes card was not found by
+ check_signature(). Now made more reliable.
+
+ 0.27 23.06-96 Oops. 16 consecutive collisions halted
+ adapter. Now will try to retransmit
+ MAX_COL_16 times before finally giving up.
+
+ 0.28 28.10-97 Added dev_id parameter (NULL) for free_irq
+
+ 0.29 29.10-97 Multiple card support for module users
+
+ 0.30 30.10-97 Fixed irq allocation bug.
+ (request_irq moved from probe to open)
+
+ 0.30a 21.08-98 Card detection made more relaxed. Driver
+ had problems with some TCP/IP-PROM boots
+ to find the card. Suggested by
+ Kurt Huwig <kurt@huwig.de>
+
+ 0.31 28.08-98 Media interface port can now be selected
+ with module parameters or kernel
+ boot parameters.
+
+ 0.32 31.08-98 IRQ was never freed if open/close
+ pair wasn't called. Now fixed.
+
+ 0.33 10.09-98 When eth16i_open() was called after
+ eth16i_close() chip never recovered.
+ Now more shallow reset is made on
+ close.
+
Bugs:
- In some cases the interface autoprobing code doesn't find
- the correct interface type. In this case you can
- manually choose the interface type in DOS with E16IC.EXE which is
+ In some cases the media interface autoprobing code doesn't find
+ the correct interface type. In this case you can
+ manually choose the interface type in DOS with E16IC.EXE which is
configuration software for EtherTeam16i and EtherTeam32 cards.
+ This is also true for IRQ setting. You cannot use module
+ parameter to configure IRQ of the card (yet).
To do:
- Real multicast support
+ - Rewrite the media interface autoprobing code. Its _horrible_ !
+ - Possibly merge all the MB86965 specific code to external
+ module for use by eth16.c and Donald's at1700.c
+ - IRQ configuration with module parameter. I will do
+ this when i will get enough info about setting
+ irq without configuration utility.
*/
-static char *version =
- "eth16i.c: v0.21 17-10-95 Mika Kuoppala (miku@elt.icl.fi)\n";
+static char *version =
+ "eth16i.c: v0.33 10-09-98 Mika Kuoppala (miku@iki.fi)\n";
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/delay.h>
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
+#if LINUX_VERSION_CODE < 0x20138
+#define test_and_set_bit(val,addr) set_bit(val,addr)
+#endif
+
+#if LINUX_VERSION_CODE < 0x020100
+typedef struct enet_statistics eth16i_stats_type;
+#else
+typedef struct net_device_stats eth16i_stats_type;
+#endif
/* Few macros */
-#define BIT(a) ( (1 << (a)) )
-#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
+#define BIT(a) ( (1 << (a)) )
+#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
#define BITCLR(ioaddr, bnum) ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr)))
/* This is the I/O address space for Etherteam 16i adapter. */
-#define ETH16I_IO_EXTENT 32
+#define ETH16I_IO_EXTENT 32
/* Ticks before deciding that transmit has timed out */
-#define TIMEOUT_TICKS 30
+#define TX_TIMEOUT (400*HZ/1000)
/* Maximum loop count when receiving packets */
-#define MAX_RX_LOOP 40
+#define MAX_RX_LOOP 20
/* Some interrupt masks */
-#define ETH16I_INTR_ON 0x8f82
+#define ETH16I_INTR_ON 0xef8a /* Higher is receive mask */
#define ETH16I_INTR_OFF 0x0000
-
+
/* Buffers header status byte meanings */
#define PKT_GOOD BIT(5)
#define PKT_GOOD_RMT BIT(4)
#define NET_BUSY BIT(6)
#define TX_PKT_RCD BIT(5)
#define CR_LOST BIT(4)
+#define TX_JABBER_ERR BIT(3)
#define COLLISION BIT(2)
#define COLLISIONS_16 BIT(1)
#define ALIGN_ERR BIT(2)
#define CRC_ERR BIT(1)
#define RX_BUF_OVERFLOW BIT(0)
-
+
/* Transmit Interrupt Enable Register (DLCR2) */
#define TX_INTR_REG 2
#define TX_INTR_DONE BIT(7)
#define SRAM_CYCLE_TIME_100NS BIT(6)
#define SYSTEM_BUS_WIDTH_8 BIT(5) /* 1 = 8bit, 0 = 16bit */
#define BUFFER_WIDTH_8 BIT(4) /* 1 = 8bit, 0 = 16bit */
-#define TBS1 BIT(3)
+#define TBS1 BIT(3)
#define TBS0 BIT(2)
-#define MBS1 BIT(1) /* 00=8kb, 01=16kb */
-#define MBS0 BIT(0) /* 10=32kb, 11=64kb */
+#define SRAM_BS1 BIT(1) /* 00=8kb, 01=16kb */
+#define SRAM_BS0 BIT(0) /* 10=32kb, 11=64kb */
-#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */
-#define ETH16I_TX_BUF_SIZE 2 /* 2 = 8kb, 3 = 16kb */
-#endif
-#define TX_BUF_1x2048 0
-#define TX_BUF_2x2048 1
-#define TX_BUF_2x4098 2
-#define TX_BUF_2x8192 3
+#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */
+#define ETH16I_TX_BUF_SIZE 3 /* 2 = 8kb, 3 = 16kb */
+#endif
+#define TX_BUF_1x2048 0
+#define TX_BUF_2x2048 1
+#define TX_BUF_2x4098 2
+#define TX_BUF_2x8192 3
/* Configuration Register 1 (DLCR7) */
#define CONFIG_REG_1 7
#define HASH_TABLE_RB 1
/* Buffer memory ports */
-#define BUFFER_MEM_PORT_LB 8
-#define DATAPORT BUFFER_MEM_PORT_LB
-#define BUFFER_MEM_PORT_HB 9
+#define BUFFER_MEM_PORT_LB 8
+#define DATAPORT BUFFER_MEM_PORT_LB
+#define BUFFER_MEM_PORT_HB 9
/* 16 Collision control register (BMPR11) */
#define COL_16_REG 11
#define HALT_ON_16 0x00
#define RETRANS_AND_HALT_ON_16 0x02
+/* Maximum number of attempts to send after 16 concecutive collisions */
+#define MAX_COL_16 10
+
/* DMA Burst and Transceiver Mode Register (BMPR13) */
#define TRANSCEIVER_MODE_REG 13
-#define TRANSCEIVER_MODE_RB 2
+#define TRANSCEIVER_MODE_RB 2
#define IO_BASE_UNLOCK BIT(7)
#define LOWER_SQUELCH_TRESH BIT(6)
#define LINK_TEST_DISABLE BIT(5)
/* Filter Self Receive Register (BMPR14) */
#define FILTER_SELF_RX_REG 14
-#define SKIP_RECEIVE_PACKET BIT(2)
+#define SKIP_RX_PACKET BIT(2)
#define FILTER_SELF_RECEIVE BIT(0)
-#define RX_BUF_SKIP_PACKET SKIP_RECEIVE_PACKET | FILTER_SELF_RECEIVE
/* EEPROM Control Register (BMPR 16) */
#define EEPROM_CTRL_REG 16
#define EEPROM_READ 0x80
/* NMC93CSx6 EEPROM Addresses */
-#define E_NODEID_0 0x02
-#define E_NODEID_1 0x03
-#define E_NODEID_2 0x04
-#define E_PORT_SELECT 0x14
- #define E_PORT_BNC 0
- #define E_PORT_DIX 1
- #define E_PORT_TP 2
- #define E_PORT_AUTO 3
-#define E_PRODUCT_CFG 0x30
-
+#define E_NODEID_0 0x02
+#define E_NODEID_1 0x03
+#define E_NODEID_2 0x04
+#define E_PORT_SELECT 0x14
+ #define E_PORT_BNC 0x00
+ #define E_PORT_DIX 0x01
+ #define E_PORT_TP 0x02
+ #define E_PORT_AUTO 0x03
+ #define E_PORT_FROM_EPROM 0x04
+#define E_PRODUCT_CFG 0x30
+
/* Macro to slow down io between EEPROM clock transitions */
-#define eeprom_slow_io() udelay(100) /* FIXME: smaller but right value here */
+#define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0)
/* Jumperless Configuration Register (BMPR19) */
#define JUMPERLESS_CONFIG 19
#define RESET ID_ROM_0
/* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] __initdata = {
- 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
-};
+static unsigned int eth16i_portlist[] =
+ { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 };
-static unsigned int eth32i_portlist[] __initdata = {
- 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
- 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
-};
+static unsigned int eth32i_portlist[] =
+ { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
+ 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 };
/* This is the Interrupt lookup table for Eth16i card */
-static unsigned int eth16i_irqmap[] __initdata = {
- 9, 10, 5, 15
-};
+static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15, 0 };
+#define NUM_OF_ISA_IRQS 4
/* This is the Interrupt lookup table for Eth32i card */
-static unsigned int eth32i_irqmap[] __initdata = {
- 3, 5, 7, 9, 10, 11, 12, 15
-};
-
+static unsigned int eth32i_irqmap[] = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };
#define EISA_IRQ_REG 0xc89
+#define NUM_OF_EISA_IRQS 8
-static unsigned int eth16i_tx_buf_map[] = {
- 2048, 2048, 4096, 8192
-};
-unsigned int boot = 1;
+static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 };
+static unsigned int boot = 1;
/* Use 0 for production, 1 for verification, >2 for debug */
#ifndef ETH16I_DEBUG
static unsigned int eth16i_debug = ETH16I_DEBUG;
/* Information for each board */
-struct eth16i_local
-{
- struct net_device_stats stats;
- unsigned int tx_started:1;
- unsigned char tx_queue; /* Number of packets in transmit buffer */
- unsigned short tx_queue_len;
- unsigned int tx_buf_size;
- unsigned long open_time;
+
+struct eth16i_local {
+ eth16i_stats_type stats;
+ unsigned char tx_started;
+ unsigned char tx_buf_busy;
+ unsigned short tx_queue; /* Number of packets in transmit buffer */
+ unsigned short tx_queue_len;
+ unsigned int tx_buf_size;
+ unsigned long open_time;
+ unsigned long tx_buffered_packets;
+ unsigned long col_16;
};
/* Function prototypes */
-extern int eth16i_probe(struct device *dev);
-
-static int eth16i_probe1(struct device *dev, short ioaddr);
-static int eth16i_check_signature(short ioaddr);
-static int eth16i_probe_port(short ioaddr);
-static void eth16i_set_port(short ioaddr, int porttype);
-static int eth16i_send_probe_packet(short ioaddr, unsigned char *b, int l);
-static int eth16i_receive_probe_packet(short ioaddr);
-static int eth16i_get_irq(short ioaddr);
-static int eth16i_read_eeprom(int ioaddr, int offset);
-static int eth16i_read_eeprom_word(int ioaddr);
-static void eth16i_eeprom_cmd(int ioaddr, unsigned char command);
-static int eth16i_open(struct device *dev);
-static int eth16i_close(struct device *dev);
-static int eth16i_tx(struct sk_buff *skb, struct device *dev);
-static void eth16i_rx(struct device *dev);
-static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void eth16i_multicast(struct device *dev);
-static void eth16i_select_regbank(unsigned char regbank, short ioaddr);
-static void eth16i_initialize(struct device *dev);
-static struct net_device_stats *eth16i_get_stats(struct device *dev);
+extern int eth16i_probe(struct device *dev);
+
+static int eth16i_probe1(struct device *dev, int ioaddr);
+static int eth16i_check_signature(int ioaddr);
+static int eth16i_probe_port(int ioaddr);
+static void eth16i_set_port(int ioaddr, int porttype);
+static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l);
+static int eth16i_receive_probe_packet(int ioaddr);
+static int eth16i_get_irq(int ioaddr);
+static int eth16i_read_eeprom(int ioaddr, int offset);
+static int eth16i_read_eeprom_word(int ioaddr);
+static void eth16i_eeprom_cmd(int ioaddr, unsigned char command);
+static int eth16i_open(struct device *dev);
+static int eth16i_close(struct device *dev);
+static int eth16i_tx(struct sk_buff *skb, struct device *dev);
+static void eth16i_rx(struct device *dev);
+static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void eth16i_reset(struct device *dev);
+static void eth16i_skip_packet(struct device *dev);
+static void eth16i_multicast(struct device *dev);
+static void eth16i_select_regbank(unsigned char regbank, int ioaddr);
+static void eth16i_initialize(struct device *dev);
+
+#if 0
+static int eth16i_set_irq(struct device *dev);
+#endif
+
+#ifdef MODULE
+static ushort eth16i_parse_mediatype(const char* s);
+#endif
+
+static struct enet_statistics *eth16i_get_stats(struct device *dev);
static char *cardname = "ICL EtherTeam 16i/32";
-#ifdef HAVE_DEVLIST
+#ifdef HAVE_DEVLIST
+
/* Support for alternate probe manager */
-/struct netdev_entry eth16i_drv =
- {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list};
+/struct netdev_entry eth16i_drv =
+ {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list};
#else /* Not HAVE_DEVLIST */
+
__initfunc(int eth16i_probe(struct device *dev))
{
int i;
int ioaddr;
int base_addr = dev ? dev->base_addr : 0;
+
+ if(eth16i_debug > 4)
+ printk(KERN_DEBUG "Probing started for %s\n", cardname);
- if(eth16i_debug > 4)
- printk("Probing started for %s\n", cardname);
-
- if(base_addr > 0x1ff) /* Check only single location */
+ if(base_addr > 0x1ff) /* Check only single location */
return eth16i_probe1(dev, base_addr);
- else if(base_addr != 0) /* Don't probe at all */
+ else if(base_addr != 0) /* Don't probe at all */
return ENXIO;
/* Seek card from the ISA io address space */
/* Seek card from the EISA io address space */
for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++) {
if(check_region(ioaddr, ETH16I_IO_EXTENT))
- continue;
+ continue;
if(eth16i_probe1(dev, ioaddr) == 0)
- return 0;
- }
+ return 0;
+ }
return ENODEV;
}
-#endif /* Not HAVE_DEVLIST */
+#endif /* Not HAVE_DEVLIST */
-__initfunc(static int eth16i_probe1(struct device *dev, short ioaddr))
+__initfunc(static int eth16i_probe1(struct device *dev, int ioaddr))
{
static unsigned version_printed = 0;
- unsigned int irq = 0;
- boot = 1; /* To inform initialization that we are in boot probe */
+ boot = 1; /* To inform initilization that we are in boot probe */
/*
- The MB86985 chip has on register which holds information in which
- io address the chip lies. First read this register and compare
- it to our current io address and if match then this could
- be our chip.
- */
+ The MB86985 chip has on register which holds information in which
+ io address the chip lies. First read this register and compare
+ it to our current io address and if match then this could
+ be our chip.
+ */
if(ioaddr < 0x1000) {
- if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)] != ioaddr)
+
+ if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)]
+ != ioaddr)
return -ENODEV;
}
/* Now we will go a bit deeper and try to find the chip's signature */
- if(eth16i_check_signature(ioaddr) != 0) /* Can we find the signature here */
+ if(eth16i_check_signature(ioaddr) != 0)
return -ENODEV;
- /*
- Now it seems that we have found an ethernet chip in this particular
- ioaddr. The MB86985 chip has this feature, that when you read a
- certain register it will increase its io base address to next
- configurable slot. Now when we have found the chip, first thing is
- to make sure that the chip's ioaddr will hold still here.
- */
+ /*
+ Now it seems that we have found a ethernet chip in this particular
+ ioaddr. The MB86985 chip has this feature, that when you read a
+ certain register it will increase it's io base address to next
+ configurable slot. Now when we have found the chip, first thing is
+ to make sure that the chip's ioaddr will hold still here.
+ */
eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
outb(0x00, ioaddr + TRANSCEIVER_MODE_REG);
- outb(0x00, ioaddr + RESET); /* Will reset some parts of chip */
- BITSET(ioaddr + CONFIG_REG_0, BIT(7)); /* This will disable the data link */
+ outb(0x00, ioaddr + RESET); /* Reset some parts of chip */
+ BITSET(ioaddr + CONFIG_REG_0, BIT(7)); /* Disable the data link */
if(dev == NULL)
- dev = init_etherdev(0, sizeof(struct eth16i_local));
+ dev = init_etherdev(0, 0);
if( (eth16i_debug & version_printed++) == 0)
- printk(version);
+ printk(KERN_INFO "%s", version);
dev->base_addr = ioaddr;
+
+#if 0
+ if(dev->irq) {
+ if(eth16i_set_irq(dev)) {
+ dev->irq = eth16i_get_irq(ioaddr);
+ }
+
+ }
+ else {
+#endif
- irq = eth16i_get_irq(ioaddr);
- dev->irq = irq;
+ dev->irq = eth16i_get_irq(ioaddr);
/* Try to obtain interrupt vector */
- if(request_irq(dev->irq, ð16i_interrupt, 0, "eth16i", dev)) {
- printk("%s: %s at %#3x, but is unusable due
- conflict on IRQ %d.\n", dev->name, cardname, ioaddr, irq);
- return EAGAIN;
+
+ if (request_irq(dev->irq, (void *)ð16i_interrupt, 0, "eth16i", dev)) {
+ printk(KERN_WARNING "%s: %s at %#3x, but is unusable due conflicting IRQ %d.\n",
+ dev->name, cardname, ioaddr, dev->irq);
+ return -EAGAIN;
}
- printk("%s: %s at %#3x, IRQ %d, ",
- dev->name, cardname, ioaddr, dev->irq);
+#if 0
+ irq2dev_map[dev->irq] = dev;
+#endif
+
+ printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
+ dev->name, cardname, ioaddr, dev->irq);
/* Let's grab the region */
request_region(ioaddr, ETH16I_IO_EXTENT, "eth16i");
/* Now we will have to lock the chip's io address */
eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
- outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
+ outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
- eth16i_initialize(dev); /* Initialize rest of the chip's registers */
+ eth16i_initialize(dev); /* Initialize rest of the chip's registers */
/* Now let's same some energy by shutting down the chip ;) */
BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
/* Initialize the device structure */
- if(dev->priv == NULL)
+ if(dev->priv == NULL) {
dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL);
+ if(dev->priv == NULL)
+ return -ENOMEM;
+ }
+
memset(dev->priv, 0, sizeof(struct eth16i_local));
dev->open = eth16i_open;
static void eth16i_initialize(struct device *dev)
{
- short ioaddr = dev->base_addr;
+ int ioaddr = dev->base_addr;
int i, node_w = 0;
unsigned char node_byte = 0;
((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
}
- for(i = 0; i < 6; i++)
- {
+ for(i = 0; i < 6; i++) {
outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
- if(boot)
- {
+ if(boot) {
printk("%02x", inb(ioaddr + NODE_ID_0 + i));
if(i != 5)
printk(":");
/* Now we will set multicast addresses to accept none */
eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
- for(i = 0; i < 8; i++)
+ for(i = 0; i < 8; i++)
outb(0x00, ioaddr + HASH_TABLE_0 + i);
/*
- Now let's disable the transmitter and receiver, set the buffer ram
- cycle time, bus width and buffer data path width. Also we shall
- set transmit buffer size and total buffer size.
- */
+ Now let's disable the transmitter and receiver, set the buffer ram
+ cycle time, bus width and buffer data path width. Also we shall
+ set transmit buffer size and total buffer size.
+ */
eth16i_select_regbank(2, ioaddr);
if( (node_w & 0xFF00) == 0x0800)
node_byte |= BUFFER_WIDTH_8;
- node_byte |= MBS1;
+ node_byte |= SRAM_BS1;
if( (node_w & 0x00FF) == 64)
- node_byte |= MBS0;
+ node_byte |= SRAM_BS0;
node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2);
outb(node_byte, ioaddr + CONFIG_REG_0);
/* We shall halt the transmitting, if 16 collisions are detected */
- outb(RETRANS_AND_HALT_ON_16, ioaddr + COL_16_REG);
+ outb(HALT_ON_16, ioaddr + COL_16_REG);
- if(boot) /* Now set port type */
- {
- char *porttype[] = {"BNC", "DIX", "TP", "AUTO"};
+#ifdef MODULE
+ /* if_port already set by init_module() */
+#else
+ dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ?
+ dev->mem_start : E_PORT_FROM_EPROM;
+#endif
- ushort ptype = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
- dev->if_port = (ptype & 0x00FF);
+ /* Set interface port type */
+ if(boot) {
+ char *porttype[] = {"BNC", "DIX", "TP", "AUTO", "FROM_EPROM" };
- printk(" %s interface.\n", porttype[dev->if_port]);
+ switch(dev->if_port)
+ {
+
+ case E_PORT_FROM_EPROM:
+ dev->if_port = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
+ break;
+
+ case E_PORT_AUTO:
+ dev->if_port = eth16i_probe_port(ioaddr);
+ break;
+
+ case E_PORT_BNC:
+ case E_PORT_TP:
+ case E_PORT_DIX:
+ break;
+ }
- if(ptype == E_PORT_AUTO)
- ptype = eth16i_probe_port(ioaddr);
+ printk(" %s interface.\n", porttype[dev->if_port]);
- eth16i_set_port(ioaddr, ptype);
+ eth16i_set_port(ioaddr, dev->if_port);
}
/* Set Receive Mode to normal operation */
outb(MODE_2, ioaddr + RECEIVE_MODE_REG);
}
-static int eth16i_probe_port(short ioaddr)
+static int eth16i_probe_port(int ioaddr)
{
int i;
int retcode;
eth16i_set_port(ioaddr, i);
if(eth16i_debug > 1)
- printk("Set port number %d\n", i);
+ printk(KERN_DEBUG "Set port number %d\n", i);
retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64);
- if(retcode == 0)
- {
+ if(retcode == 0) {
retcode = eth16i_receive_probe_packet(ioaddr);
- if(retcode != -1)
- {
+ if(retcode != -1) {
if(eth16i_debug > 1)
- printk("Eth16i interface port found at %d\n", i);
+ printk(KERN_DEBUG "Eth16i interface port found at %d\n", i);
return i;
}
}
else {
if(eth16i_debug > 1)
- printk("TRANSMIT_DONE timeout\n");
+ printk(KERN_DEBUG "TRANSMIT_DONE timeout when probing interface port\n");
}
}
if( eth16i_debug > 1)
- printk("Using default port\n");
+ printk(KERN_DEBUG "Using default port\n");
return E_PORT_BNC;
}
-static void eth16i_set_port(short ioaddr, int porttype)
-{
+static void eth16i_set_port(int ioaddr, int porttype)
+{
unsigned short temp = 0;
eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG);
temp |= DIS_AUTO_PORT_SEL;
- switch(porttype)
- {
- case E_PORT_BNC :
- temp |= AUI_SELECT;
- break;
+ switch(porttype) {
- case E_PORT_TP :
- break;
+ case E_PORT_BNC :
+ temp |= AUI_SELECT;
+ break;
+
+ case E_PORT_TP :
+ break;
+
+ case E_PORT_DIX :
+ temp |= AUI_SELECT;
+ BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
+ break;
+ }
- case E_PORT_DIX :
- temp |= AUI_SELECT;
- BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
- break;
- }
outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
if(eth16i_debug > 1) {
- printk("TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
- printk("TRANSCEIVER_MODE_REG = %x\n", inb(ioaddr+TRANSCEIVER_MODE_REG));
+ printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
+ printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n",
+ inb(ioaddr+TRANSCEIVER_MODE_REG));
}
}
-static int eth16i_send_probe_packet(short ioaddr, unsigned char *b, int l)
+static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l)
{
int starttime;
outb(0xff, ioaddr + TX_STATUS_REG);
outw(l, ioaddr + DATAPORT);
- outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
+ outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
starttime = jiffies;
- outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
+ outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
- while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0)
- if( (jiffies - starttime) > TIMEOUT_TICKS)
- break;
- return(0);
+ while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
+ if( (jiffies - starttime) > TX_TIMEOUT) {
+ return -1;
+ }
+ }
+
+ return 0;
}
-static int eth16i_receive_probe_packet(short ioaddr)
+static int eth16i_receive_probe_packet(int ioaddr)
{
int starttime;
starttime = jiffies;
- while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0)
- {
- if( (jiffies - starttime) > TIMEOUT_TICKS)
- {
+ while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) {
+ if( (jiffies - starttime) > TX_TIMEOUT) {
+
if(eth16i_debug > 1)
- printk("Timeout occurred waiting transmit packet received\n");
+ printk(KERN_DEBUG "Timeout occured waiting transmit packet received\n");
starttime = jiffies;
- while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0)
- {
- if( (jiffies - starttime) > TIMEOUT_TICKS)
- {
+ while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) {
+ if( (jiffies - starttime) > TX_TIMEOUT) {
if(eth16i_debug > 1)
- printk("Timeout occurred waiting receive packet\n");
+ printk(KERN_DEBUG "Timeout occured waiting receive packet\n");
return -1;
}
}
if(eth16i_debug > 1)
- printk("RECEIVE_PACKET\n");
+ printk(KERN_DEBUG "RECEIVE_PACKET\n");
return(0); /* Found receive packet */
}
}
if(eth16i_debug > 1) {
- printk("TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
- printk("RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
+ printk(KERN_DEBUG "TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
+ printk(KERN_DEBUG "RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
}
return(0); /* Return success */
}
-static int eth16i_get_irq(short ioaddr)
+#if 0
+static int eth16i_set_irq(struct device* dev)
+{
+ const int ioaddr = dev->base_addr;
+ const int irq = dev->irq;
+ int i = 0;
+
+ if(ioaddr < 0x1000) {
+ while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq)
+ i++;
+
+ if(i < NUM_OF_ISA_IRQS) {
+ u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
+ cbyte = (cbyte & 0x3F) | (i << 6);
+ outb(cbyte, ioaddr + JUMPERLESS_CONFIG);
+ return 0;
+ }
+ }
+ else {
+ printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name);
+ }
+
+ return -1;
+
+}
+#endif
+
+static int eth16i_get_irq(int ioaddr)
{
unsigned char cbyte;
if( ioaddr < 0x1000) {
cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
- return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] );
- } else { /* Oh..the card is EISA so method getting IRQ different */
- unsigned short index = 0;
- cbyte = inb(ioaddr + EISA_IRQ_REG);
- while( (cbyte & 0x01) == 0) {
- cbyte = cbyte >> 1;
- index++;
- }
- return( eth32i_irqmap[ index ] );
+ return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] );
+ } else { /* Oh..the card is EISA so method getting IRQ different */
+ unsigned short index = 0;
+ cbyte = inb(ioaddr + EISA_IRQ_REG);
+ while( (cbyte & 0x01) == 0) {
+ cbyte = cbyte >> 1;
+ index++;
+ }
+ return( eth32i_irqmap[ index ] );
}
}
-static int eth16i_check_signature(short ioaddr)
+static int eth16i_check_signature(int ioaddr)
{
int i;
unsigned char creg[4] = { 0 };
creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
if(eth16i_debug > 1)
- printk("eth16i: read signature byte %x at %x\n", creg[i],
- ioaddr + TRANSMIT_MODE_REG + i);
+ printk("eth16i: read signature byte %x at %x\n",
+ creg[i],
+ ioaddr + TRANSMIT_MODE_REG + i);
}
creg[0] &= 0x0F; /* Mask collision cnr */
creg[2] &= 0x7F; /* Mask DCLEN bit */
-#if 0
-/*
- This was removed because the card was sometimes left to state
- from which it couldn't be find anymore. If there is need
- to have a more strict check still this have to be fixed.
-*/
- if( !( (creg[0] == 0x06) && (creg[1] == 0x41)) ) {
+#ifdef 0
+ /*
+ This was removed because the card was sometimes left to state
+ from which it couldn't be find anymore. If there is need
+ to more strict check still this have to be fixed.
+ */
+ if( ! ((creg[0] == 0x06) && (creg[1] == 0x41)) ) {
if(creg[1] != 0x42)
return -1;
}
#endif
- if( !( (creg[2] == 0x36) && (creg[3] == 0xE0)) )
- {
- creg[2] &= 0x42;
+ if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) {
+ creg[2] &= 0x40;
creg[3] &= 0x03;
-
- if( !( (creg[2] == 0x42) && (creg[3] == 0x00)) )
+
+ if( !((creg[2] == 0x40) && (creg[3] == 0x00)) )
return -1;
}
-
+
if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
return -1;
+
if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
return -1;
data = eth16i_read_eeprom_word(ioaddr);
outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
- return(data);
+ return(data);
}
static int eth16i_read_eeprom_word(int ioaddr)
{
int i;
int data = 0;
-
+
for(i = 16; i > 0; i--) {
outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
eeprom_slow_io();
outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
eeprom_slow_io();
- data = (data << 1) | ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
+ data = (data << 1) |
+ ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
+
eeprom_slow_io();
}
eeprom_slow_io();
outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
eeprom_slow_io();
- }
+ }
}
static int eth16i_open(struct device *dev)
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
int ioaddr = dev->base_addr;
-
+
/* Powerup the chip */
outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
/* Initialize the chip */
- eth16i_initialize(dev);
+ eth16i_initialize(dev);
/* Set the transmit buffer size */
lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
- if(eth16i_debug > 3)
- printk("%s: transmit buffer size %d\n", dev->name, lp->tx_buf_size);
+ if(eth16i_debug > 0)
+ printk(KERN_DEBUG "%s: transmit buffer size %d\n",
+ dev->name, lp->tx_buf_size);
/* Now enable Transmitter and Receiver sections */
BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
lp->tx_queue_len = 0;
/* Turn on interrupts*/
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
-#ifdef MODULE
MOD_INC_USE_COUNT;
-#endif
return 0;
}
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
int ioaddr = dev->base_addr;
- lp->open_time = 0;
+ eth16i_reset(dev);
+
+ /* Turn off interrupts*/
+ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- dev->tbusy = 1;
dev->start = 0;
+ dev->tbusy = 1;
+
+ lp->open_time = 0;
/* Disable transmit and receive */
BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
/* Reset the chip */
- outb(0xff, ioaddr + RESET);
-
- /* Save some energy by switching off power */
- BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
+ /* outb(0xff, ioaddr + RESET); */
+ /* outw(0xffff, ioaddr + TX_STATUS_REG); */
+
+ outb(0x00, ioaddr + CONFIG_REG_1);
-#ifdef MODULE
MOD_DEC_USE_COUNT;
-#endif
return 0;
}
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
int ioaddr = dev->base_addr;
+ int status = 0;
if(dev->tbusy) {
- /*
- If we get here, some higher level has decided that we are broken.
- There should really be a "kick me" function call instead.
- */
+
+ /*
+ If we get here, some higher level has decided that
+ we are broken. There should really be a "kick me"
+ function call instead.
+ */
int tickssofar = jiffies - dev->trans_start;
- if(tickssofar < TIMEOUT_TICKS) /* Let's not rush with our timeout, */
- return 1; /* wait a couple of ticks first */
+ if(tickssofar < TX_TIMEOUT)
+ return 1;
- printk("%s: transmit timed out with status %04x, %s ?\n", dev->name,
- inw(ioaddr + TX_STATUS_REG),
- (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
- "IRQ conflict" : "network cable problem");
+ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- /* Let's dump all registers */
- if(eth16i_debug > 0) {
- printk("%s: timeout regs: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
- dev->name, inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2),
- inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5),
- inb(ioaddr + 6), inb(ioaddr + 7));
+ printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
+ dev->name,
+ inw(ioaddr + TX_STATUS_REG),
+ (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
+ "IRQ conflict" : "network cable problem");
+ dev->trans_start = jiffies;
- printk("lp->tx_queue = %d\n", lp->tx_queue);
- printk("lp->tx_queue_len = %d\n", lp->tx_queue_len);
- printk("lp->tx_started = %d\n", lp->tx_started);
+ /* Let's dump all registers */
+ if(eth16i_debug > 0) {
+ printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+ dev->name, inb(ioaddr + 0),
+ inb(ioaddr + 1), inb(ioaddr + 2),
+ inb(ioaddr + 3), inb(ioaddr + 4),
+ inb(ioaddr + 5),
+ inb(ioaddr + 6), inb(ioaddr + 7));
+
+ printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
+ dev->name, inb(ioaddr + TRANSMIT_START_REG),
+ inb(ioaddr + COL_16_REG));
+
+ printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);
+ printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
+ printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
}
lp->stats.tx_errors++;
- /* Now let's try to restart the adaptor */
-
- BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
- outw(0xffff, ioaddr + RESET);
- eth16i_initialize(dev);
- outw(0xffff, ioaddr + TX_STATUS_REG);
- BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+ eth16i_reset(dev);
- lp->tx_started = 0;
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
+ dev->trans_start = jiffies;
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
- dev->tbusy = 0;
- dev->trans_start = jiffies;
}
- /* Block a timer based transmitter from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+ /*
+ If some higher layer thinks we've missed an tx-done interrupt
+ we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+ itself
+ */
+
+ if(skb == NULL) {
+#if LINUX_VERSION_CODE < 0x020100
+ dev_tint(dev);
+#endif
+ if(eth16i_debug > 0)
+ printk(KERN_WARNING "%s: Missed tx-done interrupt.\n", dev->name);
+ return 0;
+ }
+
+ /* Block a timer based transmitter from overlapping.
+ This could better be done with atomic_swap(1, dev->tbusy),
+ but set_bit() works as well. */
+ set_bit(0, (void *)&lp->tx_buf_busy);
+
/* Turn off TX interrupts */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
+ if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) {
+ printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
+ status = -1;
+ }
else {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data;
- outw(length, ioaddr + DATAPORT);
+ if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
+ if(eth16i_debug > 0)
+ printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
+ }
+ else {
+ outw(length, ioaddr + DATAPORT);
- if( ioaddr < 0x1000 )
- outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
- else
- {
- unsigned char frag = length % 4;
+ if( ioaddr < 0x1000 )
+ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+ else {
+ unsigned char frag = length % 4;
- outsl(ioaddr + DATAPORT, buf, length >> 2);
+ outsl(ioaddr + DATAPORT, buf, length >> 2);
- if( frag != 0 )
- {
- outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
- if( frag == 3 )
- outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC) + 2), 1);
+ if( frag != 0 ) {
+ outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
+ if( frag == 3 )
+ outsw(ioaddr + DATAPORT,
+ (buf + (length & 0xFFFC) + 2), 1);
+ }
}
- }
- lp->tx_queue++;
- lp->tx_queue_len += length + 2;
+ lp->tx_buffered_packets++;
+ lp->tx_queue++;
+ lp->tx_queue_len += length + 2;
+
+ }
+
+ lp->tx_buf_busy = 0;
if(lp->tx_started == 0) {
/* If the transmitter is idle..always trigger a transmit */
/* There is still more room for one more packet in tx buffer */
dev->tbusy = 0;
}
-
+
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
+
/* Turn TX interrupts back on */
/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
- }
+ status = 0;
+ }
+
+#if LINUX_VERSION_CODE >= 0x020100
dev_kfree_skb(skb);
+#else
+ dev_kfree_skb(skb, FREE_WRITE);
+#endif
- return 0;
+ return status;
}
static void eth16i_rx(struct device *dev)
int boguscount = MAX_RX_LOOP;
/* Loop until all packets have been read */
- while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0)
- {
- /* Read status byte from receive buffer */
+ while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {
+
+ /* Read status byte from receive buffer */
ushort status = inw(ioaddr + DATAPORT);
- if(eth16i_debug > 4)
- printk("%s: Receiving packet mode %02x status %04x.\n",
- dev->name, inb(ioaddr + RECEIVE_MODE_REG), status);
+ /* Get the size of the packet from receive buffer */
+ ushort pkt_len = inw(ioaddr + DATAPORT);
- if( !(status & PKT_GOOD) )
- {
- /* Hmm..something went wrong. Let's check what error occurred */
+ if(eth16i_debug > 4)
+ printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n",
+ dev->name,
+ inb(ioaddr + RECEIVE_MODE_REG), status);
+
+ if( !(status & PKT_GOOD) ) {
lp->stats.rx_errors++;
- if( status & PKT_SHORT)
+
+ if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
lp->stats.rx_length_errors++;
- if( status & PKT_ALIGN_ERR )
- lp->stats.rx_frame_errors++;
- if( status & PKT_CRC_ERR )
- lp->stats.rx_crc_errors++;
- if( status & PKT_RX_BUF_OVERFLOW)
- lp->stats.rx_over_errors++;
+ eth16i_reset(dev);
+ return;
+ }
+ else {
+ eth16i_skip_packet(dev);
+ lp->stats.rx_dropped++;
+ }
}
- else
- { /* Ok so now we should have a good packet */
+ else { /* Ok so now we should have a good packet */
struct sk_buff *skb;
- /* Get the size of the packet from receive buffer */
- ushort pkt_len = inw(ioaddr + DATAPORT);
-
- if(pkt_len > ETH_FRAME_LEN)
- {
- printk("%s: %s claimed a very large packet, size of %d bytes.\n",
- dev->name, cardname, pkt_len);
- outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
- lp->stats.rx_dropped++;
- break;
- }
skb = dev_alloc_skb(pkt_len + 3);
- if( skb == NULL )
- {
- printk("%s: Couldn't allocate memory for packet (len %d)\n",
- dev->name, pkt_len);
- outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
+ if( skb == NULL ) {
+ printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
+ dev->name, pkt_len);
+ eth16i_skip_packet(dev);
lp->stats.rx_dropped++;
break;
}
+
skb->dev = dev;
skb_reserve(skb,2);
- /*
- Now let's get the packet out of buffer.
- size is (pkt_len + 1) >> 1, cause we are now reading words
- and it has to be even aligned.
- */
-
- if( ioaddr < 0x1000)
- insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), (pkt_len + 1) >> 1);
- else
- {
+
+ /*
+ Now let's get the packet out of buffer.
+ size is (pkt_len + 1) >> 1, cause we are now reading words
+ and it have to be even aligned.
+ */
+
+ if(ioaddr < 0x1000)
+ insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
+ (pkt_len + 1) >> 1);
+ else {
unsigned char *buf = skb_put(skb, pkt_len);
unsigned char frag = pkt_len % 4;
insl(ioaddr + DATAPORT, buf, pkt_len >> 2);
- if(frag != 0)
- {
+ if(frag != 0) {
unsigned short rest[2];
rest[0] = inw( ioaddr + DATAPORT );
if(frag == 3)
netif_rx(skb);
lp->stats.rx_packets++;
- if( eth16i_debug > 5 )
- {
+ if( eth16i_debug > 5 ) {
int i;
- printk("%s: Received packet of length %d.\n", dev->name, pkt_len);
- for(i = 0; i < 14; i++)
- printk(" %02x", skb->data[i]);
- printk(".\n");
+ printk(KERN_DEBUG "%s: Received packet of length %d.\n",
+ dev->name, pkt_len);
+ for(i = 0; i < 14; i++)
+ printk(KERN_DEBUG " %02x", skb->data[i]);
+ printk(KERN_DEBUG ".\n");
}
} /* else */
{
int i;
- for(i = 0; i < 20; i++)
- {
- if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == RX_BUFFER_EMPTY)
+ for(i = 0; i < 20; i++) {
+ if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) ==
+ RX_BUFFER_EMPTY)
break;
inw(ioaddr + DATAPORT);
- outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
+ outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
}
if(eth16i_debug > 1)
- printk("%s: Flushed receive buffer.\n", dev->name);
+ printk(KERN_DEBUG "%s: Flushed receive buffer.\n", dev->name);
}
#endif
struct device *dev = dev_id;
struct eth16i_local *lp;
int ioaddr = 0,
- status;
+ status;
if(dev == NULL) {
- printk("eth16i_interrupt(): irq %d for unknown device. \n", irq);
+ printk(KERN_WARNING "eth16i_interrupt(): irq %d for unknown device. \n", irq);
return;
}
/* Turn off all interrupts from adapter */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+ set_bit(0, (void *)&dev->tbusy); /* Set the device busy so that */
+ /* eth16i_tx wont be called */
+
+ if(dev->interrupt)
+ printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);
dev->interrupt = 1;
ioaddr = dev->base_addr;
lp = (struct eth16i_local *)dev->priv;
- status = inw(ioaddr + TX_STATUS_REG); /* Get the status */
- outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */
+ status = inw(ioaddr + TX_STATUS_REG); /* Get the status */
+ outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */
if(eth16i_debug > 3)
- printk("%s: Interrupt with status %04x.\n", dev->name, status);
-
- if( status & 0x00ff ) { /* Let's check the transmit status reg */
- if(status & TX_DONE)
- { /* The transmit has been done */
- lp->stats.tx_packets++;
- if(lp->tx_queue)
- { /* Are there still packets ? */
+ printk(KERN_DEBUG "%s: Interrupt with status %04x.\n", dev->name, status);
+
+ if( status & 0x7f00 ) {
+
+ lp->stats.rx_errors++;
+
+ if(status & (BUS_RD_ERR << 8) )
+ printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
+ if(status & (SHORT_PKT_ERR << 8) ) lp->stats.rx_length_errors++;
+ if(status & (ALIGN_ERR << 8) ) lp->stats.rx_frame_errors++;
+ if(status & (CRC_ERR << 8) ) lp->stats.rx_crc_errors++;
+ if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++;
+ }
+ if( status & 0x001a) {
+
+ lp->stats.tx_errors++;
+
+ if(status & CR_LOST) lp->stats.tx_carrier_errors++;
+ if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++;
+
+#if 0
+ if(status & COLLISION) {
+ lp->stats.collisions +=
+ ((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
+ }
+#endif
+ if(status & COLLISIONS_16) {
+ if(lp->col_16 < MAX_COL_16) {
+ lp->col_16++;
+ lp->stats.collisions++;
+ /* Resume transmitting, skip failed packet */
+ outb(0x02, ioaddr + COL_16_REG);
+ }
+ else {
+ printk(KERN_WARNING "%s: bailing out due to many consecutive 16-in-a-row collisions. Network cable problem?\n", dev->name);
+ }
+ }
+ }
+
+ if( status & 0x00ff ) { /* Let's check the transmit status reg */
+
+ if(status & TX_DONE) { /* The transmit has been done */
+ lp->stats.tx_packets = lp->tx_buffered_packets;
+ lp->col_16 = 0;
+
+ if(lp->tx_queue) { /* Is there still packets ? */
/* There was packet(s) so start transmitting and write also
- how many packets there is to be sent */
+ how many packets there is to be sended */
outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
+ lp->tx_started = 1;
dev->trans_start = jiffies;
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ mark_bh(NET_BH);
}
- else
- {
+ else {
lp->tx_started = 0;
- dev->tbusy = 0;
mark_bh(NET_BH);
}
}
}
- if( ( status & 0xff00 ) ||
- ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
- eth16i_rx(dev); /* We have packet in receive buffer */
- }
-
+ if( ( status & 0x8000 ) ||
+ ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
+ eth16i_rx(dev); /* We have packet in receive buffer */
+ }
+
dev->interrupt = 0;
-
+
/* Turn interrupts back on */
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
+
+ if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+ /* There is still more room for one more packet in tx buffer */
+ dev->tbusy = 0;
+ }
+
return;
}
-static void eth16i_multicast(struct device *dev)
+static void eth16i_skip_packet(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ inw(ioaddr + DATAPORT);
+ inw(ioaddr + DATAPORT);
+ inw(ioaddr + DATAPORT);
+
+ outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
+ while( inb( ioaddr + FILTER_SELF_RX_REG ) != 0);
+}
+
+static void eth16i_reset(struct device *dev)
{
- short ioaddr = dev->base_addr;
+ struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ if(eth16i_debug > 1)
+ printk(KERN_DEBUG "%s: Resetting device.\n", dev->name);
+
+ BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+ outw(0xffff, ioaddr + TX_STATUS_REG);
+ eth16i_select_regbank(2, ioaddr);
+
+ lp->tx_started = 0;
+ lp->tx_buf_busy = 0;
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+
+ dev->interrupt = 0;
+ dev->start = 1;
+ dev->tbusy = 0;
+ BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+}
- if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
+static void eth16i_multicast(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
{
dev->flags|=IFF_PROMISC; /* Must do this */
- outb(3, ioaddr + RECEIVE_MODE_REG);
+ outb(3, ioaddr + RECEIVE_MODE_REG);
} else {
outb(2, ioaddr + RECEIVE_MODE_REG);
}
}
-static struct net_device_stats *eth16i_get_stats(struct device *dev)
+static struct enet_statistics *eth16i_get_stats(struct device *dev)
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
return &lp->stats;
}
-static void eth16i_select_regbank(unsigned char banknbr, short ioaddr)
+static void eth16i_select_regbank(unsigned char banknbr, int ioaddr)
{
unsigned char data;
data = inb(ioaddr + CONFIG_REG_1);
- outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
+ outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
}
#ifdef MODULE
-static char devicename[9] = { 0, };
-static struct device dev_eth16i = {
- devicename,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, NULL, eth16i_probe
+
+static ushort eth16i_parse_mediatype(const char* s)
+{
+ if(!s)
+ return E_PORT_FROM_EPROM;
+
+ if (!strncmp(s, "bnc", 3))
+ return E_PORT_BNC;
+ else if (!strncmp(s, "tp", 2))
+ return E_PORT_TP;
+ else if (!strncmp(s, "dix", 3))
+ return E_PORT_DIX;
+ else if (!strncmp(s, "auto", 4))
+ return E_PORT_AUTO;
+ else
+ return E_PORT_FROM_EPROM;
+}
+
+#define MAX_ETH16I_CARDS 4 /* Max number of Eth16i cards per module */
+#define NAMELEN 8 /* number of chars for storing dev->name */
+
+static char namelist[NAMELEN * MAX_ETH16I_CARDS] = { 0, };
+static struct device dev_eth16i[MAX_ETH16I_CARDS] = {
+ {
+ NULL,
+ 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, NULL, NULL
+ },
};
-int io = 0x2a0;
-int irq = 0;
+static int ioaddr[MAX_ETH16I_CARDS] = { 0, };
+#if 0
+static int irq[MAX_ETH16I_CARDS] = { 0, };
+#endif
+static char* mediatype[MAX_ETH16I_CARDS] = { 0, };
+static int debug = -1;
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
+#if (LINUX_VERSION_CODE >= 0x20115)
+MODULE_AUTHOR("Mika Kuoppala <miku@iki.fi>");
+MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver");
+
+MODULE_PARM(ioaddr, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
+MODULE_PARM_DESC(ioaddr, "eth16i io base address");
+
+#if 0
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
+MODULE_PARM_DESC(irq, "eth16i interrupt request number");
+#endif
+
+MODULE_PARM(mediatype, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "s");
+MODULE_PARM_DESC(mediatype, "eth16i interfaceport mediatype");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "eth16i debug level (0-4)");
+#endif
int init_module(void)
{
- if(io == 0)
- printk("eth16i: You should not use auto-probing with insmod!\n");
-
- dev_eth16i.base_addr = io;
- dev_eth16i.irq = irq;
- if( register_netdev( &dev_eth16i ) != 0 ) {
- printk("eth16i: register_netdev() returned non-zero.\n");
- return -EIO;
- }
+ int this_dev, found = 0;
+
+ for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++)
+ {
+ struct device *dev = &dev_eth16i[this_dev];
+
+ dev->name = namelist + (NAMELEN*this_dev);
+ dev->irq = 0; /* irq[this_dev]; */
+ dev->base_addr = ioaddr[this_dev];
+ dev->init = eth16i_probe;
+
+ if(debug != -1)
+ eth16i_debug = debug;
+
+ if(eth16i_debug > 1)
+ printk(KERN_NOTICE "eth16i(%d): interface type %s\n", this_dev, mediatype[this_dev] ? mediatype[this_dev] : "none" );
+
+ dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);
+
+ if(ioaddr[this_dev] == 0)
+ {
+ if(this_dev != 0) break; /* Only autoprobe 1st one */
+ printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n");
+ }
+
+ if(register_netdev(dev) != 0)
+ {
+ printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",
+ ioaddr[this_dev]);
+
+ if(found != 0) return 0;
+ return -ENXIO;
+ }
+
+ found++;
+ }
return 0;
}
-
+
void cleanup_module(void)
{
- unregister_netdev( &dev_eth16i );
- free_irq( dev_eth16i.irq, &dev_eth16i );
- release_region( dev_eth16i.base_addr, ETH16I_IO_EXTENT );
-}
+ int this_dev;
+ for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++)
+ {
+ struct device* dev = &dev_eth16i[this_dev];
+
+ if(dev->priv != NULL)
+ {
+ unregister_netdev(dev);
+ kfree(dev->priv);
+ dev->priv = NULL;
+
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, ETH16I_IO_EXTENT);
+
+ }
+ }
+}
#endif /* MODULE */
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eth16i.c"
+ * alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict -prototypes -O6 -c eth16i.c"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * c-indent-level: 8
+ * End:
+ */
+
+/* End of file eth16i.c */
/* --------------------------------------------------------------------- */
-static int epp_preempt(void *handle)
-{
- /* we cannot relinquish the port in the middle of an operation */
- return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
static void epp_wakeup(void *handle)
{
struct device *dev = (struct device *)handle;
}
#endif
memset(&bc->modem, 0, sizeof(bc->modem));
- if (!(bc->pdev = parport_register_device(pp, dev->name, epp_preempt, epp_wakeup,
- epp_interrupt, PARPORT_DEV_LURK, dev))) {
+ if (!(bc->pdev = parport_register_device(pp, dev->name, NULL, epp_wakeup,
+ epp_interrupt, PARPORT_DEV_EXCL, dev))) {
printk(KERN_ERR "%s: cannot register parport at 0x%lx\n", bc_drvname, pp->base);
return -ENXIO;
}
/* --------------------------------------------------------------------- */
-static int par96_preempt(void *handle)
-{
- /* we cannot relinquish the port in the middle of an operation */
- return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
static void par96_wakeup(void *handle)
{
struct device *dev = (struct device *)handle;
}
memset(&bc->modem, 0, sizeof(bc->modem));
bc->hdrv.par.bitrate = 9600;
- if (!(bc->pdev = parport_register_device(pp, dev->name, par96_preempt, par96_wakeup,
- par96_interrupt, PARPORT_DEV_LURK, dev))) {
+ if (!(bc->pdev = parport_register_device(pp, dev->name, NULL, par96_wakeup,
+ par96_interrupt, PARPORT_DEV_EXCL, dev))) {
printk(KERN_ERR "baycom_par: cannot register parport at 0x%lx\n", pp->base);
return -ENXIO;
}
{
struct scc_priv *priv = dev->priv;
int cb, cmd = priv->cmd;
+ unsigned long flags;
/* See Figure 2-15. Only overrun and EOF need to be checked. */
} else if (rc & END_FR) {
/* End of frame. Get byte count */
if (dev->dma) {
+ flags=claim_dma_lock();
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
cb = BUF_SIZE - get_dma_residue(dev->dma) - 2;
+ release_dma_lock(flags);
+
} else {
cb = priv->rx_ptr - 2;
}
}
/* Get ready for new frame */
if (dev->dma) {
+
+ flags=claim_dma_lock();
set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
set_dma_count(dev->dma, BUF_SIZE);
enable_dma(dev->dma);
+ release_dma_lock(flags);
+
} else {
priv->rx_ptr = 0;
}
struct scc_info *info = priv->info;
int i, cmd = priv->cmd;
int st, dst, res;
+ unsigned long flags;
/* Read status and reset interrupt bit */
st = read_scc(cmd, R0);
/* Get remaining bytes */
i = priv->tx_tail;
if (dev->dma) {
+ flags=claim_dma_lock();
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
res = get_dma_residue(dev->dma);
+ release_dma_lock(flags);
} else {
res = priv->tx_len[i] - priv->tx_ptr;
if (res) write_scc(cmd, R0, RES_Tx_P);
/* Check if another frame is available and we are allowed to transmit */
if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) {
if (dev->dma) {
+ flags=claim_dma_lock();
set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]);
set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]);
enable_dma(dev->dma);
+ release_dma_lock(flags);
} else {
/* If we have an ESCC, we are allowed to write data bytes
immediately. Otherwise we have to wait for the next
if (st & DCD) {
if (dev->dma) {
/* Program DMA controller */
+ flags=claim_dma_lock();
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
set_dma_mode(dev->dma, DMA_MODE_READ);
set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
set_dma_count(dev->dma, BUF_SIZE);
enable_dma(dev->dma);
+ release_dma_lock(flags);
/* Configure PackeTwin DMA */
if (info->type == TYPE_TWIN) {
outb_p((dev->dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3,
}
} else {
/* Disable DMA */
- if (dev->dma) disable_dma(dev->dma);
+ if (dev->dma)
+ {
+ flags=claim_dma_lock();
+ disable_dma(dev->dma);
+ release_dma_lock(flags);
+ }
/* Disable receiver */
write_scc(cmd, R3, Rx8);
/* DMA disable, RX int disable, Ext int enable */
while (read_scc(cmd, R0) & Rx_CH_AV) read_scc(cmd, R8);
priv->rx_over = 0;
if (dev->dma) {
+ flags=claim_dma_lock();
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
set_dma_count(dev->dma, BUF_SIZE);
enable_dma(dev->dma);
+ release_dma_lock(flags);
} else {
priv->rx_ptr = 0;
}
struct scc_priv *priv = dev->priv;
struct scc_info *info = priv->info;
int cmd = priv->cmd;
+ unsigned long flags;
switch (priv->tx_state) {
case TX_OFF:
priv->tx_state = TX_ACTIVE;
if (dev->dma) {
/* Program DMA controller */
+
+ flags=claim_dma_lock();
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
set_dma_mode(dev->dma, DMA_MODE_WRITE);
set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]);
set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]);
enable_dma(dev->dma);
+ release_dma_lock(flags);
+
/* Configure PackeTwin DMA */
if (info->type == TYPE_TWIN) {
outb_p((dev->dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3,
+#define LINUX_21
+
/*
* Comtrol SV11 card driver
*
* Its a genuine Z85230
*
* It supports DMA using two DMA channels in SYNC mode. The driver doesn't
- * use these facilities (yet).
+ * use these facilities
*
* The control port is at io+1, the data at io+3 and turning off the DMA
* is done by writing 0 to io+4
*/
#include <linux/module.h>
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/net.h>
/*
* Frame receive. Simple for our card as we do sync ppp and there
- * is no funny garbage involved. This is very timing sensitive.
+ * is no funny garbage involved
*/
static void hostess_input(struct z8530_channel *c, struct sk_buff *skb)
/* Drop the CRC - its not a good idea to try and negotiate it ;) */
skb_trim(skb, skb->len-2);
skb->protocol=htons(ETH_P_WAN_PPP);
+ skb->mac.raw=skb->data;
skb->dev=c->netdevice;
/*
* Send it to the PPP layer. We dont have time to process
* it right now.
*/
- skb->mac.raw = skb->data;
-
netif_rx(skb);
}
static int hostess_open(struct device *d)
{
struct sv11_device *sv11=d->priv;
- int err;
+ int err = -1;
/*
* Link layer up
*/
- if(dma)
- err=z8530_sync_dma_open(d, &sv11->sync.chanA);
- else
- err=z8530_sync_open(d, &sv11->sync.chanA);
+ switch(dma)
+ {
+ case 0:
+ err=z8530_sync_open(d, &sv11->sync.chanA);
+ break;
+ case 1:
+ err=z8530_sync_dma_open(d, &sv11->sync.chanA);
+ break;
+ case 2:
+ err=z8530_sync_txdma_open(d, &sv11->sync.chanA);
+ break;
+ }
+
if(err)
return err;
/*
err=sppp_open(d);
if(err)
{
- if(dma)
- z8530_sync_dma_close(d, &sv11->sync.chanA);
- else
- z8530_sync_close(d, &sv11->sync.chanA);
+ switch(dma)
+ {
+ case 0:
+ z8530_sync_close(d, &sv11->sync.chanA);
+ break;
+ case 1:
+ z8530_sync_dma_close(d, &sv11->sync.chanA);
+ break;
+ case 2:
+ z8530_sync_txdma_close(d, &sv11->sync.chanA);
+ break;
+ }
return err;
}
sv11->sync.chanA.rx_function=hostess_input;
* Link layer down
*/
d->tbusy=1;
- if(dma)
- z8530_sync_dma_close(d, &sv11->sync.chanA);
- else
- z8530_sync_close(d, &sv11->sync.chanA);
+
+ switch(dma)
+ {
+ case 0:
+ z8530_sync_close(d, &sv11->sync.chanA);
+ break;
+ case 1:
+ z8530_sync_dma_close(d, &sv11->sync.chanA);
+ break;
+ case 2:
+ z8530_sync_txdma_close(d, &sv11->sync.chanA);
+ break;
+ }
MOD_DEC_USE_COUNT;
return 0;
}
{
struct sv11_device *sv11=d->priv;
/* z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
- return sppp_do_ioctl(d, ifr, cmd);
+ return sppp_do_ioctl(d, ifr,cmd);
}
-static struct net_device_stats *hostess_get_stats(struct device *d)
+static struct enet_statistics *hostess_get_stats(struct device *d)
{
struct sv11_device *sv11=d->priv;
if(sv11)
return z8530_queue_xmit(&sv11->sync.chanA, skb);
}
+#ifdef LINUX_21
static int hostess_neigh_setup(struct neighbour *n)
{
if (n->nud_state == NUD_NONE) {
return 0;
}
+#else
+
+static int return_0(struct device *d)
+{
+ return 0;
+}
+
+#endif
+
/*
* Description block for a Comtrol Hostess SV11 card
*/
* You can have DMA off or 1 and 3 thats the lot
* on the Comtrol.
*/
- dev->chanA.txdma=1;
- dev->chanA.rxdma=3;
- outb(14, iobase+4); /* DMA on */
+ dev->chanA.txdma=3;
+ dev->chanA.rxdma=1;
+ outb(0x03|0x08, iobase+4); /* DMA on */
if(request_dma(dev->chanA.txdma, "Hostess SV/11 (TX)")!=0)
goto fail;
- if(request_dma(dev->chanA.rxdma, "Hostess SV/11 (RX)")!=0)
- goto dmafail;
+
+ if(dma==1)
+ {
+ if(request_dma(dev->chanA.rxdma, "Hostess SV/11 (RX)")!=0)
+ goto dmafail;
+ }
}
save_flags(flags);
cli();
*/
if(z8530_init(dev)!=0)
+ {
+ printk(KERN_ERR "Z8530 series device not found.\n");
goto dmafail2;
+ }
z8530_channel_load(&dev->chanB, z8530_dead_port);
if(dev->type==Z85C30)
z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream);
restore_flags(flags);
- printk(KERN_INFO "begin loading hdlc\n");
-
/*
* Now we can take the IRQ
*/
* Local fields
*/
sprintf(sv->name,"hdlc%d", i);
- printk("Filling in device '%s' at %p\n", sv->name, d);
d->name = sv->name;
d->base_addr = iobase;
d->get_stats = hostess_get_stats;
d->set_multicast_list = NULL;
d->do_ioctl = hostess_ioctl;
+#ifdef LINUX_21
d->neigh_setup = hostess_neigh_setup_dev;
dev_init_buffers(d);
+#else
+ d->init = return_0;
+#endif
d->set_mac_address = NULL;
if(register_netdev(d)==-1)
}
}
dmafail2:
- if(!dma)
- goto fail;
- free_dma(dev->chanA.rxdma);
+ if(dma==1)
+ free_dma(dev->chanA.rxdma);
dmafail:
- free_dma(dev->chanA.txdma);
+ if(dma)
+ free_dma(dev->chanA.txdma);
fail:
free_irq(irq, dev);
fail2:
z8530_shutdown(&dev->sync);
unregister_netdev(&dev->netdev.dev);
free_irq(dev->sync.irq, dev);
- free_dma(dev->sync.chanA.rxdma);
- free_dma(dev->sync.chanA.txdma);
+ if(dma)
+ {
+ free_dma(dev->sync.chanA.rxdma);
+ free_dma(dev->sync.chanA.txdma);
+ }
release_region(dev->sync.chanA.ctrlio-1, 8);
}
static int io=0x200;
static int irq=9;
+#ifdef LINUX_21
MODULE_PARM(io,"i");
MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card");
MODULE_PARM(dma,"i");
MODULE_AUTHOR("Bulding Number Three Ltd");
MODULE_DESCRIPTION("Modular driver for the Comtrol Hostess SV11");
+#endif
static struct sv11_device *sv11_unit;
int init_module(void)
{
- printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.02.\n");
+ printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.01.\n");
printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n");
if(dma)
printk(KERN_WARNING "DMA mode probably wont work right now.\n");
unsigned char hpJ2405A = 0; /* HP ISA adaptor */
int hp_builtin = 0; /* HP on-board ethernet. */
static int did_version = 0; /* Already printed version info. */
+ unsigned long flags;
/* First we look for special cases.
Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */
if (request_dma(dma, chipname))
continue;
+
+ flags=claim_dma_lock();
set_dma_mode(dma, DMA_MODE_CASCADE);
enable_dma(dma);
+ release_dma_lock(flags);
/* Trigger an initialization. */
outw(0x0001, ioaddr+LANCE_DATA);
printk(", DMA %d.\n", dev->dma);
break;
} else {
+ flags=claim_dma_lock();
disable_dma(dma);
+ release_dma_lock(flags);
free_dma(dma);
}
}
/* The DMA controller is used as a no-operation slave, "cascade mode". */
if (dev->dma != 4) {
+ unsigned long flags=claim_dma_lock();
enable_dma(dev->dma);
set_dma_mode(dev->dma, DMA_MODE_CASCADE);
+ release_dma_lock(flags);
}
/* Un-Reset the LANCE, needed only for the NE2100. */
outw(0x0004, ioaddr+LANCE_DATA);
if (dev->dma != 4)
+ {
+ unsigned long flags=claim_dma_lock();
disable_dma(dev->dma);
+ release_dma_lock(flags);
+ }
free_irq(dev->irq, dev);
/* called *only* from idle, non-reentrant */
int dma = dev->dma;
int base = dev->base_addr;
+ unsigned long flags;
+
+ flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma,DMA_MODE_READ);
set_dma_addr(dma,virt_to_bus(ltdmacbuf));
set_dma_count(dma,50);
enable_dma(dma);
+ release_dma_lock(flags);
inb_p(base+3);
inb_p(base+2);
{
int dma = dev->dma;
int base = dev->base_addr;
+ unsigned long flags;
+ flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma,DMA_MODE_READ);
set_dma_addr(dma,virt_to_bus(ltdmabuf));
set_dma_count(dma,800);
enable_dma(dma);
+ release_dma_lock(flags);
inb_p(base+3);
inb_p(base+2);
/* on entry, 0xfb and ltdmabuf holds data */
int dma = dev->dma;
int base = dev->base_addr;
-
-
+ unsigned long flags;
+
+ flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma,DMA_MODE_WRITE);
set_dma_addr(dma,virt_to_bus(ltdmabuf));
set_dma_count(dma,800);
enable_dma(dma);
-
+ release_dma_lock(flags);
+
inb_p(base+3);
inb_p(base+2);
if ( wait_timeout(dev,0xfb) ) {
+ flags=claim_dma_lock();
printk("timed out in handlewrite, dma res %d\n",
get_dma_residue(dev->dma) );
+ release_dma_lock(flags);
}
}
/* on exit, ltdmabuf holds data */
int dma = dev->dma;
int base = dev->base_addr;
+ unsigned long flags;
-
-
+
+ flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma,DMA_MODE_READ);
set_dma_addr(dma,virt_to_bus(ltdmabuf));
set_dma_count(dma,800);
enable_dma(dma);
+ release_dma_lock(flags);
inb_p(base+3);
inb_p(base+2);
/* on entry, 0xfa and ltdmacbuf holds command */
int dma = dev->dma;
int base = dev->base_addr;
+ unsigned long flags;
+ flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma,DMA_MODE_WRITE);
set_dma_addr(dma,virt_to_bus(ltdmacbuf));
set_dma_count(dma,50);
enable_dma(dma);
-
+ release_dma_lock(flags);
inb_p(base+3);
inb_p(base+2);
if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
int probe3, probe4, probe9;
unsigned short straymask;
unsigned long flags;
+ unsigned long f;
err = ltpc_init(dev);
if (err) return err;
inb_p(base+6); /* tri-state interrupt line */
timeout = jiffies+100;
+
while(timeout>jiffies) {
/* wait for the card to complete initialization */
}
/* set up both dma 1 and 3 for read call */
if (!request_dma(1,"ltpc")) {
+
+ f=claim_dma_lock();
disable_dma(1);
clear_dma_ff(1);
set_dma_mode(1,DMA_MODE_WRITE);
set_dma_addr(1,virt_to_bus(ltdmabuf));
set_dma_count(1,sizeof(struct lt_mem));
enable_dma(1);
+ release_dma_lock(f);
dma|=1;
}
if (!request_dma(3,"ltpc")) {
+ f=claim_dma_lock();
disable_dma(3);
clear_dma_ff(3);
set_dma_mode(3,DMA_MODE_WRITE);
set_dma_addr(3,virt_to_bus(ltdmabuf));
set_dma_count(3,sizeof(struct lt_mem));
enable_dma(3);
+ release_dma_lock(f);
dma|=2;
}
if(debug&DEBUG_VERBOSE) {
printk("finishing up transfer\n");
}
-
+
+ f=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
set_dma_mode(dma,DMA_MODE_READ);
set_dma_addr(dma,virt_to_bus(ltdmabuf));
set_dma_count(dma,0x100);
enable_dma(dma);
+ release_dma_lock(f);
(void) inb_p(base+3);
(void) inb_p(base+2);
{
int i,j;
struct priv *p;
+ unsigned long flags;
for(i=0;i<NUM_CARDS;i++) {
if(check_region(ioaddr, cards[i].total_size))
int dma = dmatab[i];
if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510"))
continue;
+
+ flags=claim_dma_lock();
disable_dma(dma);
set_dma_mode(dma,DMA_MODE_CASCADE);
enable_dma(dma);
+ release_dma_lock(flags);
+
ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */
+
+ flags=claim_dma_lock();
disable_dma(dma);
free_dma(dma);
+ release_dma_lock(flags);
+
if(readreg(CSR0) & CSR0_IDON)
break;
}
{
int i;
struct priv *p = (struct priv *) dev->priv;
+ unsigned long flags;
p->lock = 0;
p->xmit_queued = 0;
+ flags=claim_dma_lock();
disable_dma(dev->dma); /* I've never worked with dma, but we do it like the packetdriver */
set_dma_mode(dev->dma,DMA_MODE_CASCADE);
enable_dma(dev->dma);
+ release_dma_lock(flags);
outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
if( (i=readreg(CSR0) ) != 0x4)
{
printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name,
cards[p->cardno].cardname,(int) i);
+ flags=claim_dma_lock();
disable_dma(dev->dma);
+ release_dma_lock(flags);
return 0;
}
return 1; /* ->OK */
}
printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
+ flags=claim_dma_lock();
disable_dma(dev->dma);
+ release_dma_lock(flags);
return 0; /* ->Error */
}
}
#ifdef MODULE
+static char devicename[9] = { 0, };
+
static struct device dev_ni65 = {
- " ", /* "ni6510": device name inserted by net_init.c */
+ devicename, /* "ni6510": device name inserted by net_init.c */
0, 0, 0, 0,
0x360, 9, /* I/O address, IRQ */
0, 0, 0, NULL, ni65_probe };
pardev = parport_register_device(pb, dev->name, plip_preempt,
plip_wakeup, plip_interrupt,
- PARPORT_DEV_LURK, dev);
+ 0, dev);
+
+ if (!pardev)
+ return -ENODEV;
printk(KERN_INFO "%s", version);
printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d\n", dev->name,
dev->irq = wandev->irq;
dev->dma = wandev->dma;
dev->base_addr = wandev->ioport;
- dev->mem_start = wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
+ dev->mem_start = (unsigned long)wandev->maddr;
+ dev->mem_end = dev->mem_start + wandev->msize - 1;
/* Set transmit buffer queue length */
dev->tx_queue_len = 10;
/* Initialize socket buffers */
dev->irq = wandev->irq;
dev->dma = wandev->dma;
dev->base_addr = wandev->ioport;
- dev->mem_start = wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
+ dev->mem_start = (unsigned long)wandev->maddr;
+ dev->mem_end = dev->mem_start + wandev->msize - 1;
/* Set transmit buffer queue length */
dev->tx_queue_len = 100;
/* Initialize socket buffers */
dev->irq = wandev->irq;
dev->dma = wandev->dma;
dev->base_addr = wandev->ioport;
- dev->mem_start = wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
+ dev->mem_start = (unsigned long)wandev->maddr;
+ dev->mem_end = dev->mem_end + wandev->msize - 1;
/* Set transmit buffer queue length */
dev->tx_queue_len = 10;
return err;
}
}
- else if (!get_option_index(dpmbase_opt, virt_to_phys((void *)hw->dpmbase)))
+ else if (!get_option_index(dpmbase_opt, virt_to_phys(hw->dpmbase)))
{
printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n",
- modname, hw->dpmbase)
+ modname, virt_to_phys(hw->dpmbase))
;
return -EINVAL;
}
{
printk(KERN_ERR
"%s: 8K memory region at 0x%lX is not available!\n",
- modname, hw->dpmbase)
- ;
+ modname, virt_to_phys(hw->dpmbase));
return -EINVAL;
}
printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n",
- modname, virt_to_phys((void *)hw->dpmbase))
- ;
+ modname, virt_to_phys(hw->dpmbase));
+
printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n",
- modname, hw->memory / 1024)
- ;
+ modname, hw->memory / 1024);
/* Load firmware. If loader fails then shut down adapter */
err = sdla_load(hw, sfm, len);
/* Relocate window and copy block of data */
err = sdla_mapmem(hw, curvec);
- memcpy((void*)buf, (void*)(hw->dpmbase + curpos), curlen);
+ memcpy(buf, (void *)((u8 *)hw->dpmbase + curpos), curlen);
addr += curlen;
(char*)buf += curlen;
len -= curlen;
/* Relocate window and copy block of data */
sdla_mapmem(hw, curvec);
- memcpy((void*)(hw->dpmbase + curpos), (void*)buf, curlen);
+ memcpy((void*)((u8 *)hw->dpmbase + curpos), buf, curlen);
addr += curlen;
(char*)buf += curlen;
len -= curlen;
for (i = opt[0]; i && err; --i)
{
- hw->dpmbase = (unsigned long )(phys_to_virt(opt[i]));
+ hw->dpmbase = phys_to_virt(opt[i]);
err = sdla_setdpm(hw);
}
return err;
/* Shut down card and verify memory region */
sdla_down(hw);
- if (check_memregion((void*)hw->dpmbase, hw->dpmsize))
+ if (check_memregion(hw->dpmbase, hw->dpmsize))
return -EINVAL
;
for (memsize = 0, winsize = hw->dpmsize;
!sdla_mapmem(hw, memsize) &&
- (test_memregion((void*)hw->dpmbase, winsize) == winsize)
+ (test_memregion(hw->dpmbase, winsize) == winsize)
;
memsize += winsize)
;
if (sdla_mapmem(hw, sfminfo->dataoffs) != 0)
return -EIO
;
- data = (void*)(hw->dpmbase + (sfminfo->dataoffs - hw->vector));
+ data = (void*)((u8 *)hw->dpmbase + (sfminfo->dataoffs - hw->vector));
memset(data, 0, sfminfo->datasize);
data[0x00] = make_config_byte(hw);
static int sdla_start (sdlahw_t* hw, unsigned addr)
{
unsigned port = hw->port;
- unsigned char* bootp;
+ unsigned char *bootp;
int err, tmp, i;
if (!port) return -EFAULT;
switch (hw->type)
{
case SDLA_S502A:
- bootp = (void*)(hw->dpmbase + 0x66);
+ bootp = hw->dpmbase;
+ bootp += 0x66;
break;
case SDLA_S502E:
case SDLA_S503:
case SDLA_S507:
case SDLA_S508:
- bootp = (void*)hw->dpmbase;
+ bootp = hw->dpmbase;
break;
default:
hw->regs[1] = 0xFF;
/* Verify configuration options */
- i = get_option_index(s502a_dpmbase_options, virt_to_phys((void *)hw->dpmbase));
+ i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase));
if (i == 0)
return -EINVAL
;
;
/* Verify configuration options */
- i = get_option_index(s508_dpmbase_options, virt_to_phys((void *)hw->dpmbase));
+ i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
if (i == 0)
return -EINVAL
;
;
/* Verify configuration options */
- i = get_option_index(s508_dpmbase_options, virt_to_phys((void *)hw->dpmbase));
+ i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
if (i == 0)
return -EINVAL
;
;
/* Verify configuration options */
- i = get_option_index(s507_dpmbase_options, virt_to_phys((void *)hw->dpmbase));
+ i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase));
if (i == 0)
return -EINVAL
;
;
/* Verify configuration options */
- i = get_option_index(s508_dpmbase_options, virt_to_phys((void *)hw->dpmbase));
+ i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
if (i == 0)
return -EINVAL
;
card->hw.irq = (conf->irq == 9) ? 2 : conf->irq;
/* Compute the virtual address of the card in kernel space */
if(conf->maddr)
- card->hw.dpmbase = (unsigned long)phys_to_virt(conf->maddr);
+ card->hw.dpmbase = phys_to_virt(conf->maddr);
else /* But 0 means NULL */
- card->hw.dpmbase = conf->maddr;
+ card->hw.dpmbase = (void *)conf->maddr;
card->hw.dpmsize = SDLA_WINDOWSIZE;
card->hw.type = conf->hw_opt[0];
}
/* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */
sti(); /* Not ideal but tough we have to do this */
- if(copy_to_user((void*)(dump.ptr),
- (void*)(card->hw.dpmbase + pos), len))
+ if(copy_to_user((void *)dump.ptr,
+ (u8 *)card->hw.dpmbase + pos, len))
return -EFAULT;
cli();
dump.length -= len;
__initfunc(static int sktr_isa_chk_card(struct device *dev, int ioaddr))
{
int i, err;
+ unsigned long flags;
err = sktr_isa_chk_ioaddr(ioaddr);
if(err < 0)
}
}
+ flags=claim_dma_lock();
disable_dma(dev->dma);
set_dma_mode(dev->dma, DMA_MODE_CASCADE);
enable_dma(dev->dma);
+ release_dma_lock(flags);
printk("%s: %s found at %#4x, using IRQ %d and DMA %d.\n",
dev->name, AdapterName, ioaddr, dev->irq, dev->dma);
sktr_disable_interrupts(dev);
if(dev->dma > 0)
+ {
+ unsigned long flags=claim_dma_lock();
disable_dma(dev->dma);
+ release_dma_lock(flags);
+ }
+
outw(0xFF00, dev->base_addr + SIFCMD);
if(dev->dma > 0)
outb(0xff, dev->base_addr + POSREG);
sp->obytes += skb->len;
/* Control is high priority so it doesnt get queued behind data */
skb->priority=1;
+ skb->dev = dev;
dev_queue_xmit(skb);
}
ch->par2, ch->rel, ch->time0, ch->time1);
sp->obytes += skb->len;
skb->priority=1;
+ skb->dev = dev;
dev_queue_xmit(skb);
}
{
case SPPPIOCCISCO:
sp->pp_flags|=PP_CISCO;
+ dev->type = ARPHRD_HDLC;
break;
case SPPPIOCPPP:
sp->pp_flags&=~PP_CISCO;
+ dev->type = ARPHRD_PPP;
break;
default:
return -EINVAL;
dev->hard_header = sppp_hard_header;
dev->rebuild_header = sppp_rebuild_header;
dev->tx_queue_len = 10;
- dev->type = ARPHRD_PPP;
+ dev->type = ARPHRD_HDLC;
dev->addr_len = 0;
dev->hard_header_len = sizeof(struct ppp_header);
dev->mtu = PPP_MTU;
dev->change_mtu = sppp_change_mtu;
dev->hard_header_cache = NULL;
dev->header_cache_update = NULL;
- dev->flags = IFF_MULTICAST;
+ dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
dev_init_buffers(dev);
}
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
/* Include files, designed to support most kernel versions 2.0.0 and later. */
-#include <linux/config.h>
#include <linux/version.h>
#ifdef MODULE
#ifdef MODVERSIONS
3, ENT_HM|RxCRC_ENAB|Rx8,
5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
9, 0, /* Disable interrupts */
+ 6, 0xFF,
7, FLAG,
- 10, ABUNDER|MARKIDLE|NRZ|CRCPS,
+ 10, ABUNDER|NRZ|CRCPS,/*MARKIDLE ??*/
11, TCTRxCP,
14, DISDPLL,
15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
3, ENT_HM|RxCRC_ENAB|Rx8,
5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
9, 0, /* Disable interrupts */
+ 6, 0xFF,
7, FLAG,
- 10, ABUNDER|MARKIDLE|NRZ|CRCPS,
+ 10, ABUNDER|NRZ|CRCPS, /* MARKIDLE?? */
11, TCTRxCP,
14, DISDPLL,
15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
if(chan->rxdma_on)
{
/* Special condition check only */
+ u8 r7=read_zsreg(chan, R7);
+ u8 r6=read_zsreg(chan, R6);
u8 status=read_zsreg(chan, R1);
if(status&END_FR)
{
static void z8530_dma_status(struct z8530_channel *chan)
{
+ unsigned long flags;
u8 status=read_zsreg(chan, R0);
u8 altered=chan->status^status;
{
if(status&TxEOM)
{
+ flags=claim_dma_lock();
/* Transmit underrun */
disable_dma(chan->txdma);
clear_dma_ff(chan->txdma);
chan->txdma_on=0;
+ release_dma_lock(flags);
z8530_tx_done(chan);
}
}
EXPORT_SYMBOL(z8530_dma_sync);
+struct z8530_irqhandler z8530_txdma_sync=
+{
+ z8530_rx,
+ z8530_dma_tx,
+ z8530_dma_status
+};
+
+EXPORT_SYMBOL(z8530_txdma_sync);
+
/*
* Interrupt vectors for a Z8530 that is in 'parked' mode.
* For machines with PCI Z85x30 cards, or level triggered interrupts
irqs->status(&dev->chanB);
}
}
- if(work==200)
+ if(work==5000)
printk(KERN_ERR "%s: interrupt jammed - abort(0x%X)!\n", dev->name, intr);
/* Ok all done */
locker=0;
int z8530_sync_dma_open(struct device *dev, struct z8530_channel *c)
{
+ unsigned long flags;
+
c->sync = 1;
c->mtu = dev->mtu;
c->count = 0;
return -ENOBUFS;
}
c->tx_dma_used=0;
+ c->dma_tx = 1;
c->dma_num=0;
c->dma_ready=1;
* Enable DMA control mode
*/
- c->regs[R1]|= WT_RDY_RT|WT_FN_RDYFN;
+ /*
+ * TX DMA via DIR/REQ
+ */
+
+ c->regs[R14]|= DTRREQ;
+ write_zsreg(c, R14, c->regs[R14]);
+
+ /*
+ * RX DMA via W/Req
+ */
+
+ c->regs[R1]|= WT_FN_RDYFN;
+ c->regs[R1]|= WT_RDY_RT;
c->regs[R1]|= INT_ERR_Rx;
write_zsreg(c, R1, c->regs[R1]);
c->regs[R1]|= WT_RDY_ENAB;
write_zsreg(c, R1, c->regs[R1]);
- c->regs[R14]|= DTRREQ;
- write_zsreg(c, R14, c->regs[R14]);
/*
* DMA interrupts
* Set up the DMA configuration
*/
+ flags=claim_dma_lock();
+
disable_dma(c->rxdma);
clear_dma_ff(c->rxdma);
- set_dma_mode(c->rxdma, DMA_MODE_READ);
+ set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);
set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0]));
set_dma_count(c->rxdma, c->mtu);
enable_dma(c->rxdma);
set_dma_mode(c->txdma, DMA_MODE_WRITE);
disable_dma(c->txdma);
+ release_dma_lock(flags);
+
/*
* Select the DMA interrupt handlers
*/
int z8530_sync_dma_close(struct device *dev, struct z8530_channel *c)
{
u8 chk;
+ unsigned long flags;
+
c->irqs = &z8530_nop;
c->max = 0;
c->sync = 0;
/*
* Disable the PC DMA channels
*/
-
+
+ flags=claim_dma_lock();
disable_dma(c->rxdma);
clear_dma_ff(c->rxdma);
+
c->rxdma_on = 0;
+
disable_dma(c->txdma);
clear_dma_ff(c->txdma);
+ release_dma_lock(flags);
+
c->txdma_on = 0;
c->tx_dma_used = 0;
EXPORT_SYMBOL(z8530_sync_dma_close);
+int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c)
+{
+ printk("Opening sync interface for TX-DMA\n");
+ c->sync = 1;
+ c->mtu = dev->mtu;
+ c->count = 0;
+ c->skb = NULL;
+ c->skb2 = NULL;
+
+ /*
+ * Load the PIO receive ring
+ */
+
+ z8530_rx_done(c);
+ z8530_rx_done(c);
+
+ /*
+ * Load the DMA interfaces up
+ */
+
+ c->rxdma_on = 0;
+ c->txdma_on = 0;
+
+ c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+ if(c->tx_dma_buf[0]==NULL)
+ {
+ kfree(c->rx_buf[0]);
+ kfree(c->rx_buf[1]);
+ c->rx_buf[0]=NULL;
+ return -ENOBUFS;
+ }
+ c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+ if(c->tx_dma_buf[1]==NULL)
+ {
+ kfree(c->tx_dma_buf[0]);
+ kfree(c->rx_buf[0]);
+ kfree(c->rx_buf[1]);
+ c->rx_buf[0]=NULL;
+ c->rx_buf[1]=NULL;
+ c->tx_dma_buf[0]=NULL;
+ return -ENOBUFS;
+ }
+ c->tx_dma_used=0;
+ c->dma_num=0;
+ c->dma_ready=1;
+ c->dma_tx = 1;
+
+ /*
+ * Enable DMA control mode
+ */
+
+ /*
+ * TX DMA via DIR/REQ
+ */
+ c->regs[R14]|= DTRREQ;
+ write_zsreg(c, R14, c->regs[R14]);
+
+ /*
+ * Set up the DMA configuration
+ */
+
+ disable_dma(c->txdma);
+ clear_dma_ff(c->txdma);
+ set_dma_mode(c->txdma, DMA_MODE_WRITE);
+ disable_dma(c->txdma);
+
+ /*
+ * Select the DMA interrupt handlers
+ */
+
+ c->rxdma_on = 0;
+ c->txdma_on = 1;
+ c->tx_dma_used = 1;
+
+ c->irqs = &z8530_txdma_sync;
+ printk("Loading RX\n");
+ z8530_rtsdtr(c,1);
+ printk("Rx interrupts ON\n");
+ write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+ return 0;
+}
+
+EXPORT_SYMBOL(z8530_sync_txdma_open);
+
+int z8530_sync_txdma_close(struct device *dev, struct z8530_channel *c)
+{
+ u8 chk;
+ c->irqs = &z8530_nop;
+ c->max = 0;
+ c->sync = 0;
+
+ /*
+ * Disable the PC DMA channels
+ */
+
+ disable_dma(c->txdma);
+ clear_dma_ff(c->txdma);
+ c->txdma_on = 0;
+ c->tx_dma_used = 0;
+
+ /*
+ * Disable DMA control mode
+ */
+
+ c->regs[R1]&= ~WT_RDY_ENAB;
+ write_zsreg(c, R1, c->regs[R1]);
+ c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);
+ c->regs[R1]|= INT_ALL_Rx;
+ write_zsreg(c, R1, c->regs[R1]);
+ c->regs[R14]&= ~DTRREQ;
+ write_zsreg(c, R14, c->regs[R14]);
+
+ if(c->tx_dma_buf[0])
+ {
+ kfree(c->tx_dma_buf[0]);
+ c->tx_dma_buf[0]=NULL;
+ }
+ if(c->tx_dma_buf[1])
+ {
+ kfree(c->tx_dma_buf[1]);
+ c->tx_dma_buf[1]=NULL;
+ }
+ chk=read_zsreg(c,R0);
+ write_zsreg(c, R3, c->regs[R3]);
+ z8530_rtsdtr(c,0);
+ return 0;
+}
+
+
+EXPORT_SYMBOL(z8530_sync_txdma_close);
+
/*
* Describe a Z8530 in a standard format. We must pass the I/O as
* the port offset isnt predictable. The main reason for this function
if(c->tx_skb==NULL)
{
/* Idle on */
- disable_dma(c->txdma);
+ if(c->txdma)
+ {
+ flags=claim_dma_lock();
+ disable_dma(c->txdma);
+ release_dma_lock(flags);
+ }
c->txcount=0;
}
else
c->txcount=c->tx_skb->len;
- if(c->tx_dma_used)
+ if(c->dma_tx)
{
/*
- * FIXME. DMA is broken for the non 85230,
+ * FIXME. DMA is broken for the original 8530,
* on the older parts we need to set a flag and
* wait for a further TX interrupt to fire this
* stage off
*/
+
+ flags=claim_dma_lock();
disable_dma(c->txdma);
clear_dma_ff(c->txdma);
set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr));
set_dma_count(c->txdma, c->txcount);
enable_dma(c->txdma);
+ release_dma_lock(flags);
write_zsreg(c, R5, c->regs[R5]|TxENAB);
}
else
* Save the ready state and the buffer currently
* being used as the DMA target
*/
+
int ready=c->dma_ready;
- char *rxb=c->rx_buf[c->dma_num];
+ unsigned char *rxb=c->rx_buf[c->dma_num];
+ unsigned long flags;
/*
* Complete this DMA. Neccessary to find the length
*/
+
+ flags=claim_dma_lock();
+
disable_dma(c->rxdma);
clear_dma_ff(c->rxdma);
c->rxdma_on=0;
if(ready)
{
c->dma_num^=1;
- set_dma_mode(c->rxdma, DMA_MODE_READ);
+ set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);
set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num]));
set_dma_count(c->rxdma, c->mtu);
c->rxdma_on = 1;
enable_dma(c->rxdma);
+ /* Stop any frames that we missed the head of
+ from passing */
+ write_zsreg(c, R0, RES_Rx_CRC);
}
else
/* Can't occur as we dont reenable the DMA irq until
after the flip is done */
printk("DMA flip overrun!\n");
+
+ release_dma_lock(flags);
/*
* Shove the old buffer into an sk_buff. We can't DMA
printk("Lost a frame\n");
}
+/*
+ * Cannot DMA over a 64K boundary on a PC
+ */
+
+extern inline int spans_boundary(struct sk_buff *skb)
+{
+ unsigned long a=(unsigned long)skb->data;
+ a^=(a+skb->len);
+ if(a&0x00010000) /* If the 64K bit is different.. */
+ {
+ printk("spanner\n");
+ return 1;
+ }
+ return 0;
+}
/*
* Queue a packet for transmission. Because we have rather
* limit, then copy to the flip buffer
*/
- if(c->dma_tx && (unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024)
+ if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb)))
{
/*
* Send the flip buffer, and flip the flippy bit.
extern int z8530_sync_close(struct device *, struct z8530_channel *);
extern int z8530_sync_dma_open(struct device *, struct z8530_channel *);
extern int z8530_sync_dma_close(struct device *, struct z8530_channel *);
+extern int z8530_sync_txdma_open(struct device *, struct z8530_channel *);
+extern int z8530_sync_txdma_close(struct device *, struct z8530_channel *);
extern int z8530_channel_load(struct z8530_channel *, u8 *);
extern int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb);
extern struct net_device_stats *z8530_get_stats(struct z8530_channel *c);
/* The inverse routine to znet_open(). */
static int znet_close(struct device *dev)
{
+ unsigned long flags;
int ioaddr = dev->base_addr;
dev->tbusy = 1;
outb(CMD0_RESET, ioaddr); /* CMD0_RESET */
+ flags=claim_dma_lock();
disable_dma(zn.rx_dma);
disable_dma(zn.tx_dma);
+ release_dma_lock(flags);
free_irq(dev->irq, dev);
void show_dma(void)
{
+ unsigned long flags;
short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;
unsigned addr = inb(dma_port);
addr |= inb(dma_port) << 8;
+
+ flags=claim_dma_lock();
printk("Addr: %04x cnt:%3x...", addr<<1, get_dma_residue(zn.tx_dma));
+ release_dma_lock(flags);
}
/* Initialize the hardware. We have to do this when the board is open()ed
/* Reset the chip, and start it up. */
outb(CMD0_RESET, ioaddr);
- cli(); { /* Protect against a DMA flip-flop */
- disable_dma(zn.rx_dma); /* reset by an interrupting task. */
- clear_dma_ff(zn.rx_dma);
- set_dma_mode(zn.rx_dma, DMA_RX_MODE);
- set_dma_addr(zn.rx_dma, (unsigned int) zn.rx_start);
- set_dma_count(zn.rx_dma, RX_BUF_SIZE);
- enable_dma(zn.rx_dma);
- /* Now set up the Tx channel. */
- disable_dma(zn.tx_dma);
- clear_dma_ff(zn.tx_dma);
- set_dma_mode(zn.tx_dma, DMA_TX_MODE);
- set_dma_addr(zn.tx_dma, (unsigned int) zn.tx_start);
- set_dma_count(zn.tx_dma, zn.tx_buf_len<<1);
- enable_dma(zn.tx_dma);
- } sti();
-
+ flags=claim_dma_lock();
+ disable_dma(zn.rx_dma); /* reset by an interrupting task. */
+ clear_dma_ff(zn.rx_dma);
+ set_dma_mode(zn.rx_dma, DMA_RX_MODE);
+ set_dma_addr(zn.rx_dma, (unsigned int) zn.rx_start);
+ set_dma_count(zn.rx_dma, RX_BUF_SIZE);
+ enable_dma(zn.rx_dma);
+ /* Now set up the Tx channel. */
+ disable_dma(zn.tx_dma);
+ clear_dma_ff(zn.tx_dma);
+ set_dma_mode(zn.tx_dma, DMA_TX_MODE);
+ set_dma_addr(zn.tx_dma, (unsigned int) zn.tx_start);
+ set_dma_count(zn.tx_dma, zn.tx_buf_len<<1);
+ enable_dma(zn.tx_dma);
+ release_dma_lock(flags);
+
if (znet_debug > 1)
printk(KERN_DEBUG "%s: Initializing the i82593, tx buf %p... ", dev->name,
zn.tx_start);
/*
- * $Id: oldproc.c,v 1.20 1998/08/23 12:12:01 mj Exp $
+ * $Id: oldproc.c,v 1.24 1998/10/11 15:13:04 mj Exp $
*
* Backward-compatible procfs interface for PCI.
*
DEVICE( PROMISE, PROMISE_5300, "DC5030"),
DEVICE( N9, N9_I128, "Imagine 128"),
DEVICE( N9, N9_I128_2, "Imagine 128v2"),
+ DEVICE( N9, N9_I128_T2R, "Revolution 3D"),
DEVICE( UMC, UMC_UM8673F, "UM8673F"),
DEVICE( UMC, UMC_UM8891A, "UM8891A"),
DEVICE( UMC, UMC_UM8886BF, "UM8886BF"),
DEVICE( ADAPTEC, ADAPTEC_7883, "AIC-7883U"),
DEVICE( ADAPTEC, ADAPTEC_7884, "AIC-7884U"),
DEVICE( ADAPTEC, ADAPTEC_1030, "ABA-1030 DVB receiver"),
- DEVICE( ADAPTEC2, ADAPTEC2_2940U2, "AHA-2940U2"),
- DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"),
- DEVICE( ADAPTEC2, ADAPTEC2_3940U2, "AHA-3940U2"),
- DEVICE( ADAPTEC2, ADAPTEC2_7896, "AIC-7896/7"),
+ DEVICE( ADAPTEC2, ADAPTEC2_2940U2,"AHA-2940U2"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"),
+ DEVICE( ADAPTEC2, ADAPTEC2_3940U2,"AHA-3940U2"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7896, "AIC-7896/7"),
DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL"),
DEVICE( TIGERJET, TIGERJET_300, "Tiger300 ISDN"),
DEVICE( ARK, ARK_STING, "Stingray"),
int parport_probe(struct parport *port, char *buffer, int len)
{
- struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, PARPORT_DEV_TRAN, &dev);
+ struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, 0, &dev);
int result = 0;
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
if [ "$CONFIG_SCSI_PPA" != "n" ]; then
- int ' Pedantic EPP-checking' CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3
+ bool ' Pedantic EPP-checking' CONFIG_SCSI_PPA_HAVE_PEDANTIC
fi
dep_tristate 'IOMEGA ZIP Plus drive SCSI support' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT
fi
if ((count & 1) || (((unsigned) ptr) & 1))
panic ("NCR53c406a: attempted unaligned DMA transfer\n");
- save_flags(flags);
- cli();
+ flags=claim_dma_lock();
disable_dma(dma_chan);
clear_dma_ff(dma_chan);
set_dma_addr(dma_chan, (long) ptr);
set_dma_count(dma_chan, count);
set_dma_mode(dma_chan, mode);
enable_dma(dma_chan);
- restore_flags(flags);
+ release_dma_lock(flags);
return count;
}
static __inline__ int
NCR53c406a_dma_residual (void) {
register int tmp;
- unsigned long flags = 0;
- save_flags(flags);
- cli();
+ unsigned long flags;
+
+ flags=claim_dma_lock();
clear_dma_ff(dma_chan);
tmp = get_dma_residue(dma_chan);
- restore_flags(flags);
+ release_dma_lock(flags);
return tmp;
}
the system. Each file presents the current configuration and transfer
statistics (enabled with #define in aic7xxx.c) for each controller.
- Thanks to Michael Neuffer for for his upper-level SCSI help, and
+ Thanks to Michael Neuffer for his upper-level SCSI help, and
Matthew Jacob for statistics support.
Debugging the driver
/* set by aha152x_setup according to the command line */
static int setup_count=0;
+static int registered_count=0;
static struct aha152x_setup {
int io_port;
int irq;
shpnt = aha152x_host[setup[i].irq-IRQ_MIN] =
scsi_register(tpnt, sizeof(struct aha152x_hostdata));
+ registered_count++;
shpnt->io_port = setup[i].io_port;
shpnt->n_io_port = IO_RANGE;
SETBITS(DMACNTRL0, INTEN);
- ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", NULL);
+ ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt);
if(ok<0) {
if(ok == -EINVAL)
printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq);
printk("aha152x: driver needs an IRQ.\n");
scsi_unregister(shpnt);
+ registered_count--;
+ release_region(shpnt->io_port, IO_RANGE);
shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0;
continue;
}
while(!HOSTDATA(shpnt)->swint && jiffies<the_time)
barrier();
- free_irq(shpnt->irq,0);
+ free_irq(shpnt->irq,shpnt);
if(!HOSTDATA(shpnt)->swint) {
if(TESTHI(DMASTAT, INTSTAT)) {
printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq);
scsi_unregister(shpnt);
+ registered_count--;
+ release_region(shpnt->io_port, IO_RANGE);
shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0;
continue;
}
SETPORT(SSTAT0, 0x7f);
SETPORT(SSTAT1, 0xef);
- if(request_irq(shpnt->irq,aha152x_intr,SA_INTERRUPT,"aha152x",NULL)<0) {
+ if(request_irq(shpnt->irq,aha152x_intr,SA_INTERRUPT,"aha152x",shpnt)<0) {
printk("aha152x: failed to reassign interrupt.\n");
}
}
- return (setup_count>0);
+ return (registered_count>0);
+}
+
+
+int aha152x_release(struct Scsi_Host *shpnt)
+{
+ if (shpnt->irq)
+ free_irq(shpnt->irq, shpnt);
+ if (shpnt->io_port)
+ release_region(shpnt->io_port, IO_RANGE);
+
+ return 0;
}
/*
queuecommand: aha152x_queue, \
abort: aha152x_abort, \
reset: aha152x_reset, \
+ release: aha152x_release, \
slave_attach: 0, \
bios_param: aha152x_biosparam, \
can_queue: 1, \
#include "hosts.h"
#include "aic7xxx.h"
-#include "aic7xxx/bsd_q.h"
#include "aic7xxx/sequencer.h"
#include "aic7xxx/scsi_message.h"
#include "aic7xxx_reg.h"
0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "5.1.0"
+#define AIC7XXX_C_VERSION "5.1.2"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
(((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0)));
if (aic7xxx_panic_on_abort)
aic7xxx_panic_abort(p, NULL);
+#ifdef CONFIG_PCI
if (errno & PCIERRSTAT)
aic7xxx_pci_intr(p);
+#endif
if (errno & (SQPARERR | ILLOPCODE | ILLSADDR))
{
sti();
+++ /dev/null
-/*
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)queue.h 8.5 (Berkeley) 8/20/94
- * $Id: queue.h,v 1.21 1998/05/12 03:55:25 gibbs Exp $
- */
-
-#ifndef _SYS_QUEUE_H_
-#define _SYS_QUEUE_H_
-
-/*
- * This file defines five types of data structures: singly-linked lists,
- * slingly-linked tail queues, lists, tail queues, and circular queues.
- *
- * A singly-linked list is headed by a single forward pointer. The elements
- * are singly linked for minimum space and pointer manipulation overhead at
- * the expense of O(n) removal for arbitrary elements. New elements can be
- * added to the list after an existing element or at the head of the list.
- * Elements being removed from the head of the list should use the explicit
- * macro for this purpose for optimum efficiency. A singly-linked list may
- * only be traversed in the forward direction. Singly-linked lists are ideal
- * for applications with large datasets and few or no removals or for
- * implementing a LIFO queue.
- *
- * A singly-linked tail queue is headed by a pair of pointers, one to the
- * head of the list and the other to the tail of the list. The elements are
- * singly linked for minimum space and pointer manipulation overhead at the
- * expense of O(n) removal for arbitrary elements. New elements can be added
- * to the list after an existing element, at the head of the list, or at the
- * end of the list. Elements being removed from the head of the tail queue
- * should use the explicit macro for this purpose for optimum efficiency.
- * A singly-linked tail queue may only be traversed in the forward direction.
- * Singly-linked tail queues are ideal for applications with large datasets
- * and few or no removals or for implementing a FIFO queue.
- *
- * A list is headed by a single forward pointer (or an array of forward
- * pointers for a hash table header). The elements are doubly linked
- * so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before
- * or after an existing element or at the head of the list. A list
- * may only be traversed in the forward direction.
- *
- * A tail queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or
- * after an existing element, at the head of the list, or at the end of
- * the list. A tail queue may only be traversed in the forward direction.
- *
- * A circle queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or after
- * an existing element, at the head of the list, or at the end of the list.
- * A circle queue may be traversed in either direction, but has a more
- * complex end of list detection.
- *
- * For details on the use of these macros, see the queue(3) manual page.
- *
- *
- * SLIST LIST STAILQ TAILQ CIRCLEQ
- * _HEAD + + + + +
- * _ENTRY + + + + +
- * _INIT + + + + +
- * _EMPTY + + + + +
- * _FIRST + + - + +
- * _NEXT + + - + +
- * _PREV - - - + +
- * _LAST - - - + +
- * _FOREACH + + - + -
- * _INSERT_HEAD + + + + +
- * _INSERT_BEFORE - + - + +
- * _INSERT_AFTER + + + + +
- * _INSERT_TAIL - - + + +
- * _REMOVE_HEAD + - + - -
- * _REMOVE + + + + +
- *
- */
-
-/*
- * Singly-linked List definitions.
- */
-#define SLIST_HEAD(name, type) \
-struct name { \
- struct type *slh_first; /* first element */ \
-}
-
-#define SLIST_ENTRY(type) \
-struct { \
- struct type *sle_next; /* next element */ \
-}
-
-/*
- * Singly-linked List functions.
- */
-#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
-
-#define SLIST_FIRST(head) ((head)->slh_first)
-
-#define SLIST_FOREACH(var, head, field) \
- for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
-
-#define SLIST_INIT(head) { \
- (head)->slh_first = NULL; \
-}
-
-#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
- (elm)->field.sle_next = (slistelm)->field.sle_next; \
- (slistelm)->field.sle_next = (elm); \
-} while (0)
-
-#define SLIST_INSERT_HEAD(head, elm, field) do { \
- (elm)->field.sle_next = (head)->slh_first; \
- (head)->slh_first = (elm); \
-} while (0)
-
-#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
-
-#define SLIST_REMOVE_HEAD(head, field) do { \
- (head)->slh_first = (head)->slh_first->field.sle_next; \
-} while (0)
-
-#define SLIST_REMOVE(head, elm, type, field) do { \
- if ((head)->slh_first == (elm)) { \
- SLIST_REMOVE_HEAD((head), field); \
- } \
- else { \
- struct type *curelm = (head)->slh_first; \
- while( curelm->field.sle_next != (elm) ) \
- curelm = curelm->field.sle_next; \
- curelm->field.sle_next = \
- curelm->field.sle_next->field.sle_next; \
- } \
-} while (0)
-
-/*
- * Singly-linked Tail queue definitions.
- */
-#define STAILQ_HEAD(name, type) \
-struct name { \
- struct type *stqh_first;/* first element */ \
- struct type **stqh_last;/* addr of last next element */ \
-}
-
-#define STAILQ_ENTRY(type) \
-struct { \
- struct type *stqe_next; /* next element */ \
-}
-
-/*
- * Singly-linked Tail queue functions.
- */
-#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
-
-#define STAILQ_INIT(head) do { \
- (head)->stqh_first = NULL; \
- (head)->stqh_last = &(head)->stqh_first; \
-} while (0)
-
-#define STAILQ_FIRST(head) ((head)->stqh_first)
-#define STAILQ_LAST(head) (*(head)->stqh_last)
-
-#define STAILQ_INSERT_HEAD(head, elm, field) do { \
- if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
- (head)->stqh_last = &(elm)->field.stqe_next; \
- (head)->stqh_first = (elm); \
-} while (0)
-
-#define STAILQ_INSERT_TAIL(head, elm, field) do { \
- (elm)->field.stqe_next = NULL; \
- *(head)->stqh_last = (elm); \
- (head)->stqh_last = &(elm)->field.stqe_next; \
-} while (0)
-
-#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
- if (((elm)->field.stqe_next = (tqelm)->field.stqe_next) == NULL)\
- (head)->stqh_last = &(elm)->field.stqe_next; \
- (tqelm)->field.stqe_next = (elm); \
-} while (0)
-
-#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
-
-#define STAILQ_REMOVE_HEAD(head, field) do { \
- if (((head)->stqh_first = \
- (head)->stqh_first->field.stqe_next) == NULL) \
- (head)->stqh_last = &(head)->stqh_first; \
-} while (0)
-
-#define STAILQ_REMOVE(head, elm, type, field) do { \
- if ((head)->stqh_first == (elm)) { \
- STAILQ_REMOVE_HEAD(head, field); \
- } \
- else { \
- struct type *curelm = (head)->stqh_first; \
- while( curelm->field.stqe_next != (elm) ) \
- curelm = curelm->field.stqe_next; \
- if((curelm->field.stqe_next = \
- curelm->field.stqe_next->field.stqe_next) == NULL) \
- (head)->stqh_last = &(curelm)->field.stqe_next; \
- } \
-} while (0)
-
-/*
- * List definitions.
- */
-
-#define LIST_ENTRY(type) \
-struct { \
- struct type *le_next; /* next element */ \
- struct type **le_prev; /* address of previous next element */ \
-}
-
-/*
- * List functions.
- */
-
-#define LIST_EMPTY(head) ((head)->lh_first == NULL)
-
-#define LIST_FIRST(head) ((head)->lh_first)
-
-#define LIST_FOREACH(var, head, field) \
- for((var) = (head)->lh_first; (var); (var) = (var)->field.le_next)
-
-#define LIST_INIT(head) do { \
- (head)->lh_first = NULL; \
-} while (0)
-
-#define LIST_INSERT_AFTER(listelm, elm, field) do { \
- if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
- (listelm)->field.le_next->field.le_prev = \
- &(elm)->field.le_next; \
- (listelm)->field.le_next = (elm); \
- (elm)->field.le_prev = &(listelm)->field.le_next; \
-} while (0)
-
-#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
- (elm)->field.le_prev = (listelm)->field.le_prev; \
- (elm)->field.le_next = (listelm); \
- *(listelm)->field.le_prev = (elm); \
- (listelm)->field.le_prev = &(elm)->field.le_next; \
-} while (0)
-
-#define LIST_INSERT_HEAD(head, elm, field) do { \
- if (((elm)->field.le_next = (head)->lh_first) != NULL) \
- (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
- (head)->lh_first = (elm); \
- (elm)->field.le_prev = &(head)->lh_first; \
-} while (0)
-
-#define LIST_NEXT(elm, field) ((elm)->field.le_next)
-
-#define LIST_REMOVE(elm, field) do { \
- if ((elm)->field.le_next != NULL) \
- (elm)->field.le_next->field.le_prev = \
- (elm)->field.le_prev; \
- *(elm)->field.le_prev = (elm)->field.le_next; \
-} while (0)
-
-/*
- * Tail queue definitions.
- */
-#define TAILQ_HEAD(name, type) \
-struct name { \
- struct type *tqh_first; /* first element */ \
- struct type **tqh_last; /* addr of last next element */ \
-}
-
-#define TAILQ_HEAD_INITIALIZER(head) \
- { NULL, &(head).tqh_first }
-
-#define TAILQ_ENTRY(type) \
-struct { \
- struct type *tqe_next; /* next element */ \
- struct type **tqe_prev; /* address of previous next element */ \
-}
-
-/*
- * Tail queue functions.
- */
-#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
-
-#define TAILQ_FOREACH(var, head, field) \
- for (var = TAILQ_FIRST(head); var; var = TAILQ_NEXT(var, field))
-
-#define TAILQ_FIRST(head) ((head)->tqh_first)
-
-#define TAILQ_LAST(head, headname) \
- (*(((struct headname *)((head)->tqh_last))->tqh_last))
-
-#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
-
-#define TAILQ_PREV(elm, headname, field) \
- (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
-
-#define TAILQ_INIT(head) do { \
- (head)->tqh_first = NULL; \
- (head)->tqh_last = &(head)->tqh_first; \
-} while (0)
-
-#define TAILQ_INSERT_HEAD(head, elm, field) do { \
- if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
- (head)->tqh_first->field.tqe_prev = \
- &(elm)->field.tqe_next; \
- else \
- (head)->tqh_last = &(elm)->field.tqe_next; \
- (head)->tqh_first = (elm); \
- (elm)->field.tqe_prev = &(head)->tqh_first; \
-} while (0)
-
-#define TAILQ_INSERT_TAIL(head, elm, field) do { \
- (elm)->field.tqe_next = NULL; \
- (elm)->field.tqe_prev = (head)->tqh_last; \
- *(head)->tqh_last = (elm); \
- (head)->tqh_last = &(elm)->field.tqe_next; \
-} while (0)
-
-#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
- if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
- (elm)->field.tqe_next->field.tqe_prev = \
- &(elm)->field.tqe_next; \
- else \
- (head)->tqh_last = &(elm)->field.tqe_next; \
- (listelm)->field.tqe_next = (elm); \
- (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
-} while (0)
-
-#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
- (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
- (elm)->field.tqe_next = (listelm); \
- *(listelm)->field.tqe_prev = (elm); \
- (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
-} while (0)
-
-#define TAILQ_REMOVE(head, elm, field) do { \
- if (((elm)->field.tqe_next) != NULL) \
- (elm)->field.tqe_next->field.tqe_prev = \
- (elm)->field.tqe_prev; \
- else \
- (head)->tqh_last = (elm)->field.tqe_prev; \
- *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
-} while (0)
-
-/*
- * Circular queue definitions.
- */
-#define CIRCLEQ_HEAD(name, type) \
-struct name { \
- struct type *cqh_first; /* first element */ \
- struct type *cqh_last; /* last element */ \
-}
-
-#define CIRCLEQ_ENTRY(type) \
-struct { \
- struct type *cqe_next; /* next element */ \
- struct type *cqe_prev; /* previous element */ \
-}
-
-/*
- * Circular queue functions.
- */
-#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
-
-#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
-
-#define CIRCLEQ_FOREACH(var, head, field) \
- for((var) = (head)->cqh_first; \
- (var) != (void *)(head); \
- (var) = (var)->field.cqe_next)
-
-#define CIRCLEQ_INIT(head) do { \
- (head)->cqh_first = (void *)(head); \
- (head)->cqh_last = (void *)(head); \
-} while (0)
-
-#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
- (elm)->field.cqe_next = (listelm)->field.cqe_next; \
- (elm)->field.cqe_prev = (listelm); \
- if ((listelm)->field.cqe_next == (void *)(head)) \
- (head)->cqh_last = (elm); \
- else \
- (listelm)->field.cqe_next->field.cqe_prev = (elm); \
- (listelm)->field.cqe_next = (elm); \
-} while (0)
-
-#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
- (elm)->field.cqe_next = (listelm); \
- (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
- if ((listelm)->field.cqe_prev == (void *)(head)) \
- (head)->cqh_first = (elm); \
- else \
- (listelm)->field.cqe_prev->field.cqe_next = (elm); \
- (listelm)->field.cqe_prev = (elm); \
-} while (0)
-
-#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
- (elm)->field.cqe_next = (head)->cqh_first; \
- (elm)->field.cqe_prev = (void *)(head); \
- if ((head)->cqh_last == (void *)(head)) \
- (head)->cqh_last = (elm); \
- else \
- (head)->cqh_first->field.cqe_prev = (elm); \
- (head)->cqh_first = (elm); \
-} while (0)
-
-#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
- (elm)->field.cqe_next = (void *)(head); \
- (elm)->field.cqe_prev = (head)->cqh_last; \
- if ((head)->cqh_first == (void *)(head)) \
- (head)->cqh_first = (elm); \
- else \
- (head)->cqh_last->field.cqe_next = (elm); \
- (head)->cqh_last = (elm); \
-} while (0)
-
-#define CIRCLEQ_LAST(head) ((head)->cqh_last)
-
-#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next)
-
-#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev)
-
-#define CIRCLEQ_REMOVE(head, elm, field) do { \
- if ((elm)->field.cqe_next == (void *)(head)) \
- (head)->cqh_last = (elm)->field.cqe_prev; \
- else \
- (elm)->field.cqe_next->field.cqe_prev = \
- (elm)->field.cqe_prev; \
- if ((elm)->field.cqe_prev == (void *)(head)) \
- (head)->cqh_first = (elm)->field.cqe_next; \
- else \
- (elm)->field.cqe_prev->field.cqe_next = \
- (elm)->field.cqe_next; \
-} while (0)
-
-#ifdef KERNEL
-
-/*
- * XXX insque() and remque() are an old way of handling certain queues.
- * They bogusly assumes that all queue heads look alike.
- */
-
-struct quehead {
- struct quehead *qh_link;
- struct quehead *qh_rlink;
-};
-
-#ifdef __GNUC__
-
-static __inline void
-insque(void *a, void *b)
-{
- struct quehead *element = a, *head = b;
-
- element->qh_link = head->qh_link;
- element->qh_rlink = head;
- head->qh_link = element;
- element->qh_link->qh_rlink = element;
-}
-
-static __inline void
-remque(void *a)
-{
- struct quehead *element = a;
-
- element->qh_link->qh_rlink = element->qh_rlink;
- element->qh_rlink->qh_link = element->qh_link;
- element->qh_rlink = 0;
-}
-
-#else /* !__GNUC__ */
-
-void insque __P((void *a, void *b));
-void remque __P((void *a));
-
-#endif /* __GNUC__ */
-
-#endif /* KERNEL */
-
-#endif /* !_SYS_QUEUE_H_ */
union ins_formats format;
unsigned int srcline;
struct symbol *patch_label;
- STAILQ_ENTRY(instruction) links;
+ struct {
+ struct instruction *stqe_next;
+ } links;
};
#define AIC_OP_OR 0x0
if (HD(j)->subversion == ESA)
sh[j]->unchecked_isa_dma = FALSE;
else {
+ unsigned long flags;
sh[j]->wish_block = TRUE;
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);
2.0.12 5.44 8 Aug 1996 Use ID 7 for all PCI cards
2.1.1 5.45 2 Oct 1996 Update ROM accesses for 2.1.x
2.1.97 5.46 23 Apr 1998 Rewritten PCI detection routines [mj]
+ 2.1.11x 5.47 9 Aug 1998 Touched for 8 SCSI disk majors support
0x0a bytes long. Heads are one less than we need to report.
*/
- drive = MINOR(dev) / 16;
+ if (MAJOR(dev) != SCSI_DISK0_MAJOR) {
+ printk("fdomain_16x0_biosparam: too many disks");
+ return 0;
+ }
+ drive = MINOR(dev) >> 4;
if (bios_major == 2) {
switch (Quantum) {
imm_hosts[i].dev =
parport_register_device(pb, "imm", NULL, imm_wakeup,
- NULL, PARPORT_DEV_TRAN, (void *) &imm_hosts[i]);
+ NULL, 0, (void *) &imm_hosts[i]);
+
+ if (!imm_hosts[i].dev)
+ continue;
/* Claim the bus so it remembers what we do to the control
* registers. [ CTR and ECP ]
*/
- if (imm_pb_claim(i))
- while (imm_hosts[i].p_busy)
- schedule(); /* We are safe to schedule here */
+ if (imm_pb_claim(i))
+ {
+ unsigned long now = jiffies;
+ while (imm_hosts[i].p_busy)
+ {
+ schedule(); /* We are safe to schedule here */
+ if (jiffies > now + 3*HZ)
+ {
+ printk(KERN_ERR "imm%d: failed to claim parport because a "
+ "pardevice is owning the port for too longtime!\n",
+ i);
+ return 0;
+ }
+ }
+ }
ppb = IMM_BASE(i) = imm_hosts[i].dev->port->base;
w_ctr(ppb, 0x0c);
ppa_hosts[i].dev =
parport_register_device(pb, "ppa", NULL, ppa_wakeup,
- NULL, PARPORT_DEV_TRAN, (void *) &ppa_hosts[i]);
+ NULL, 0, (void *) &ppa_hosts[i]);
+
+ if (!ppa_hosts[i].dev)
+ continue;
/* Claim the bus so it remembers what we do to the control
* registers. [ CTR and ECP ]
*/
if (ppa_pb_claim(i))
+ {
+ unsigned long now = jiffies;
while (ppa_hosts[i].p_busy)
+ {
schedule(); /* We are safe to schedule here */
+ if (jiffies > now + 3*HZ)
+ {
+ printk(KERN_ERR "ppa%d: failed to claim parport because a "
+ "pardevice is owning the port for too longtime!\n",
+ i);
+ return 0;
+ }
+ }
+ }
ppb = PPA_BASE(i) = ppa_hosts[i].dev->port->base;
w_ctr(ppb, 0x0c);
host_active = NULL;
/* For block devices "wake_up" is done in end_scsi_request */
- if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
- MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
+ if (!SCSI_BLK_MAJOR(SCpnt->request.rq_dev)) {
struct Scsi_Host * next;
for (next = host->block; next != host; next = next->block)
* that an interrupt may start another request, so we run this with interrupts
* turned off
*/
-#define INIT_SCSI_REQUEST \
- if (!CURRENT) { \
- CLEAR_INTR; \
- return; \
- } \
- 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"); \
+#if MAJOR_NR == SCSI_DISK0_MAJOR
+#define CHECK_INITREQ_SD_MAJOR(major) SCSI_DISK_MAJOR(major)
+#else
+#define CHECK_INITREQ_SD_MAJOR(major) ((major) == MAJOR_NR)
+#endif
+
+#define INIT_SCSI_REQUEST \
+ if (!CURRENT) { \
+ CLEAR_INTR; \
+ return; \
+ } \
+ if (!CHECK_INITREQ_SD_MAJOR(MAJOR(CURRENT->rq_dev)))\
+ panic(DEVICE_NAME ": request list destroyed"); \
+ if (CURRENT->bh) { \
+ if (!buffer_locked(CURRENT->bh)) \
+ panic(DEVICE_NAME ": block not locked"); \
}
#endif
/* A few options that we want selected */
-#define NR_HOSTS_PRESENT 1
-#define NR_FAKE_DISKS 3
+#define NR_HOSTS_PRESENT 20
+#define NR_FAKE_DISKS 6
#define N_HEAD 32
#define N_SECTOR 64
#define DISK_READONLY(TGT) (1)
/* 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;
#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
{
int delay = SCSI_SETUP_LATENCY;
- double usec;
- usec = 0.0;
- usec = (SCpnt->request.nr_sectors << 9) * 1.0e6 / SCSI_DATARATE;
- delay += usec;
+ delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
if(delay) usleep(delay);
};
#endif
do{
VERIFY1_DEBUG(READ);
/* For the speedy test, we do not even want to fill the buffer with anything */
-#ifndef SPEEDY
+#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 && target == 0) {
+ if(block == 0) {
+ int i;
memset(buff, 0, bufflen);
*((unsigned short *) (buff+510)) = 0xAA55;
p = (struct partition* ) (buff + 0x1be);
- npart = 0;
- while(starts[npart+1]){
- p->start_sect = starts[npart];
- p->nr_sects = starts[npart+1] - starts [npart];
+ i = 0;
+ while(starts[i+1]){
+ p->start_sect = starts[i];
+ p->nr_sects = starts[i+1] - starts [i];
p->sys_ind = 0x81; /* Linux partition */
- p->head = (npart == 0 ? 1 : 0);
+ p->head = (i == 0 ? 1 : 0);
p->sector = 1;
- p->cyl = starts[npart] / N_HEAD / N_SECTOR;
+ p->cyl = starts[i] / N_HEAD / N_SECTOR;
p->end_head = N_HEAD - 1;
p->end_sector = N_SECTOR;
- p->end_cyl = starts[npart + 1] / N_HEAD / N_SECTOR;
+ p->end_cyl = starts[i + 1] / N_HEAD / N_SECTOR;
p++;
- npart++;
+ i++;
};
+ if (!npart) npart = i;
scsi_debug_errsts = 0;
break;
};
} /* End phony disk change code */
#endif
-#ifndef SPEEDY
+#ifdef CLEAR
memcpy(buff, &target, sizeof(target));
memcpy(buff+sizeof(target), cmd, 24);
memcpy(buff+60, &block, sizeof(block));
#endif
nbytes -= bufflen;
if(SCpnt->use_sg){
-#ifndef SPEEDY
+#ifdef CLEAR
memcpy(buff+128, bh, sizeof(struct buffer_head));
#endif
block += bufflen >> 9;
host_active = NULL;
/* For block devices "wake_up" is done in end_scsi_request */
- if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
- MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
+ if (!SCSI_BLK_MAJOR(SCpnt->request.rq_dev)) {
struct Scsi_Host * next;
for (next = host->block; next != host; next = next->block)
*
* Modified by Eric Youngdale eric@aib.com to support loadable
* low-level scsi drivers.
+ *
+ * Modified by Jirka Hanika geo@ff.cuni.cz to support more
+ * scsi disks using eight major numbers.
*/
-
+
#include <linux/module.h>
#ifdef MODULE
/*
#include <asm/system.h>
#include <asm/io.h>
-#define MAJOR_NR SCSI_DISK_MAJOR
+#define MAJOR_NR SCSI_DISK0_MAJOR
#include <linux/blk.h>
#include "scsi.h"
#include "hosts.h"
/*
* static const char RCSid[] = "$Header:";
*/
+
+#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))
+
+#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(index) MKDEV_SD_PARTITION((index) << 4)
+#define N_USED_SD_MAJORS ((sd_template.dev_max + SCSI_DISKS_PER_MAJOR - 1) / SCSI_DISKS_PER_MAJOR)
#define MAX_RETRIES 5
static void sd_devname(unsigned int disknum, char * buffer)
{
- if( disknum <= 26 )
- {
+ if( disknum < 26 )
sprintf(buffer, "sd%c", 'a' + disknum);
- }
- else
- {
+ else {
unsigned int min1;
unsigned int min2;
/*
*/
min1 = disknum / 26;
min2 = disknum % 26;
- sprintf(buffer, "sd%c%c", 'a' + min1, 'a' + min2);
+ sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
}
}
struct Scsi_Device_Template sd_template =
{ NULL, "disk", "sd", NULL, TYPE_DISK,
- SCSI_DISK_MAJOR, 0, 0, 0, 1,
+ SCSI_DISK0_MAJOR, 0, 0, 0, 1,
sd_detect, sd_init,
sd_finish, sd_attach, sd_detach
};
* See if we are requesting a non-existent partition. Do this
* after checking for disk change.
*/
- if(sd_sizes[MINOR(inode->i_rdev)] == 0)
+ if(sd_sizes[SD_PARTITION(inode->i_rdev)] == 0)
return -ENXIO;
if(rscsi_disks[target].device->removable)
fop_revalidate_scsidisk /* revalidate */
};
+/*
+ * If we need more than one SCSI disk major (i.e. more than
+ * 16 SCSI disks), we'll have to kmalloc() more gendisks later.
+ */
+
static struct gendisk sd_gendisk = {
- MAJOR_NR, /* Major number */
+ SCSI_DISK0_MAJOR, /* Major number */
"sd", /* Major name */
4, /* Bits to shift to get real from partition */
1 << 4, /* Number of partitions per real */
0, /* number */
NULL, /* internal */
NULL /* next */
-};
+};
+
+static struct gendisk *sd_gendisks = &sd_gendisk;
+
+#define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR]
+#define LAST_SD_GENDISK sd_gendisks[N_USED_SD_MAJORS - 1]
static void sd_geninit (struct gendisk *ignored)
{
for (i = 0; i < sd_template.dev_max; ++i)
if(rscsi_disks[i].device)
sd[i << 4].nr_sects = rscsi_disks[i].capacity;
-#if 0
- /* No longer needed - we keep track of this as we attach/detach */
- sd_gendisk.nr_real = sd_template.dev_max;
-#endif
}
/*
int good_sectors = (result == 0 ? this_count : 0);
int block_sectors = 1;
- sd_devname(MINOR(SCpnt->request.rq_dev) >> 4, nbuff);
+ sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff);
SCSI_LOG_HLCOMPLETE(1,printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff,
SCpnt->host->host_no,
}
else if (sector_size == 256)
error_sector >>= 1;
- error_sector -= sd[MINOR(SCpnt->request.rq_dev)].start_sect;
+ error_sector -= sd[SD_PARTITION(SCpnt->request.rq_dev)].start_sect;
error_sector &= ~ (block_sectors - 1);
good_sectors = error_sector - SCpnt->request.sector;
if (good_sectors < 0 || good_sectors >= this_count)
}
INIT_SCSI_REQUEST;
- SDev = rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device;
+ SDev = rscsi_disks[CURRENT_DEV].device;
/*
* If the host for this device is in error recovery mode, don't
if (flag++ == 0)
SCpnt = scsi_allocate_device(&CURRENT,
- rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0);
+ rscsi_disks[CURRENT_DEV].device, 0);
else SCpnt = NULL;
/*
return;
}
- devm = MINOR(SCpnt->request.rq_dev);
+ devm = SD_PARTITION(SCpnt->request.rq_dev);
dev = DEVICE_NR(SCpnt->request.rq_dev);
block = SCpnt->request.sector;
printk ("scsi : deleting disk entry.\n");
rscsi_disks[i].device = NULL;
sd_template.nr_dev--;
- sd_gendisk.nr_real--;
+ SD_GENDISK(i).nr_real--;
/* Wake up a process waiting for device */
wake_up(&SCpnt->device->device_wait);
if (sd_template.dev_noticed == 0) return 0;
+ if (!rscsi_disks)
+ sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
+
+ /* 128 disks is our current limit (8 majors, 16 disks per major) */
+ if(sd_template.dev_max > 128)
+ sd_template.dev_max = 128;
+
if(!sd_registered) {
- if (register_blkdev(MAJOR_NR,"sd",&sd_fops)) {
- printk("Unable to get major %d for SCSI disk\n",MAJOR_NR);
- return 1;
- }
- sd_registered++;
- }
+ for (i=0; i <= sd_template.dev_max / SCSI_DISKS_PER_MAJOR; i++) {
+ if (register_blkdev(SD_MAJOR(i),"sd",&sd_fops)) {
+ printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i));
+ return 1;
+ }
+ }
+ sd_registered++;
+ }
/* We do not support attaching loadable devices yet. */
if(rscsi_disks) return 0;
- sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
-
rscsi_disks = (Scsi_Disk *)
scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
-
- sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
- sizeof(int), GFP_ATOMIC);
+
+ /* for every (necessary) major: */
+ sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
- sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
- sizeof(int), GFP_ATOMIC);
-
- sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
- sizeof(int), GFP_ATOMIC);
+ sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+ sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
- for(i=0;i<(sd_template.dev_max << 4);i++)
- {
- sd_blocksizes[i] = 1024;
- sd_hardsizes[i] = 512;
- }
+ for(i=0; i < sd_template.dev_max << 4; i++) {
+ sd_blocksizes[i] = 1024;
+ sd_hardsizes[i] = 512;
+ }
- blksize_size[MAJOR_NR] = sd_blocksizes;
- hardsect_size[MAJOR_NR] = sd_hardsizes;
+ for (i=0; i < N_USED_SD_MAJORS; i++) {
+ blksize_size[SD_MAJOR(i)] = sd_blocksizes + i * (SCSI_DISKS_PER_MAJOR << 4);
+ hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4);
+ }
sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(struct hd_struct),
GFP_ATOMIC);
-
- sd_gendisk.max_nr = sd_template.dev_max;
- sd_gendisk.part = sd;
- sd_gendisk.sizes = sd_sizes;
- sd_gendisk.real_devices = (void *) rscsi_disks;
+ if (N_USED_SD_MAJORS > 1)
+ sd_gendisks = (struct gendisk *)
+ kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC);
+ for (i=0; i < N_USED_SD_MAJORS; i++) {
+ 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].max_nr = SCSI_DISKS_PER_MAJOR;
+ sd_gendisks[i].init = sd_geninit;
+ sd_gendisks[i].part = sd + (i * SCSI_DISKS_PER_MAJOR << 4);
+ sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4);
+ sd_gendisks[i].nr_real = 0;
+ sd_gendisks[i].next = sd_gendisks + i + 1;
+ sd_gendisks[i].real_devices =
+ (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR);
+ }
+ LAST_SD_GENDISK.max_nr =
+ sd_template.dev_max % SCSI_DISKS_PER_MAJOR;
+ LAST_SD_GENDISK.next = NULL;
return 0;
}
+/*
+ * sd_get_queue() returns the queue which corresponds to a given device.
+ */
+static struct request **sd_get_queue (kdev_t dev)
+{
+ return &blk_dev[MAJOR_NR].current_request;
+}
+
static void sd_finish()
{
struct gendisk *gendisk;
int i;
- blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ for (i=0; i <= sd_template.dev_max / SCSI_DISKS_PER_MAJOR; i++) {
+ /* FIXME: After 2.2 we should implement multiple sd queues */
+ blk_dev[SD_MAJOR(i)].request_fn = DEVICE_REQUEST;
+ if (i) blk_dev[SD_MAJOR(i)].queue = sd_get_queue;
+ }
for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next)
- if (gendisk == &sd_gendisk)
+ if (gendisk == sd_gendisks)
break;
if (gendisk == NULL)
{
- sd_gendisk.next = gendisk_head;
- gendisk_head = &sd_gendisk;
+ LAST_SD_GENDISK.next = gendisk_head;
+ gendisk_head = sd_gendisks;
}
for (i = 0; i < sd_template.dev_max; ++i)
&& !rscsi_disks[i].has_part_table) {
sd_sizes[i << 4] = rscsi_disks[i].capacity;
/* revalidate does sd_init_onedisk via MAYBE_REINIT*/
- revalidate_scsidisk(MKDEV(MAJOR_NR, i << 4), 0);
+ revalidate_scsidisk(MKDEV_SD(i), 0);
}
else
i=sd_init_onedisk(i);
}
/* If our host adapter is capable of scatter-gather, then we increase
- * the read-ahead to 16 blocks (32 sectors). If not, we use
- * a two block (4 sector) read ahead.
+ * the read-ahead to 60 blocks (120 sectors). If not, we use
+ * a two block (4 sector) read ahead. We can only respect this with the
+ * granularity of every 16 disks (one device major).
*/
- if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize)
- read_ahead[MAJOR_NR] = 120; /* 120 sector read-ahead */
- else
- read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
+ for (i=0; i < N_USED_SD_MAJORS; i++) {
+ read_ahead[SD_MAJOR(i)] =
+ (rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device
+ && rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device->host->sg_tablesize)
+ ? 120 /* 120 sector read-ahead */
+ : 4; /* 4 sector read-ahead */
+ }
return;
}
rscsi_disks[i].device = SDp;
rscsi_disks[i].has_part_table = 0;
sd_template.nr_dev++;
- sd_gendisk.nr_real++;
+ SD_GENDISK(i).nr_real++;
return 0;
}
#define USAGE rscsi_disks[target].device->access_count
#define CAPACITY rscsi_disks[target].capacity
#define MAYBE_REINIT sd_init_onedisk(target)
-#define GENDISK_STRUCT sd_gendisk
/* This routine is called to flush all partitions and partition tables
* for a changed scsi disk, and then re-read the new partition table.
* usage == 1 (we need an open channel to use an ioctl :-), so this
* is our limit.
*/
-int revalidate_scsidisk(kdev_t dev, int maxusage){
+int revalidate_scsidisk(kdev_t dev, int maxusage) {
int target;
- struct gendisk * gdev;
int max_p;
int start;
int i;
target = DEVICE_NR(dev);
- gdev = &GENDISK_STRUCT;
if (DEVICE_BUSY || USAGE > maxusage) {
printk("Device busy for revalidation (usage=%d)\n", USAGE);
}
DEVICE_BUSY = 1;
- max_p = gdev->max_p;
- start = target << gdev->minor_shift;
+ max_p = sd_gendisks->max_p;
+ start = target << sd_gendisks->minor_shift;
for (i=max_p - 1; i >=0 ; i--) {
- int minor = start+i;
- kdev_t devi = MKDEV(MAJOR_NR, minor);
+ int index = start+i;
+ kdev_t devi = MKDEV_SD_PARTITION(index);
struct super_block *sb = get_super(devi);
sync_dev(devi);
if (sb) invalidate_inodes(sb);
invalidate_buffers(devi);
- gdev->part[minor].start_sect = 0;
- gdev->part[minor].nr_sects = 0;
+ sd_gendisks->part[index].start_sect = 0;
+ sd_gendisks->part[index].nr_sects = 0;
/*
* Reset the blocksize for everything so that we can read
* the partition table. Technically we will determine the
* correct block size when we revalidate, but we do this just
* to make sure that everything remains consistent.
*/
- blksize_size[MAJOR_NR][minor] = 1024;
+ sd_blocksizes[index] = 1024;
if( rscsi_disks[target].sector_size == 2048 )
- blksize_size[MAJOR_NR][minor] = 2048;
+ sd_blocksizes[index] = 2048;
else
- blksize_size[MAJOR_NR][minor] = 1024;
+ sd_blocksizes[index] = 1024;
}
#ifdef MAYBE_REINIT
MAYBE_REINIT;
#endif
- gdev->part[start].nr_sects = CAPACITY;
- resetup_one_dev(gdev, target);
+ sd_gendisks->part[start].nr_sects = CAPACITY;
+ resetup_one_dev(&SD_GENDISK(target),
+ target % SCSI_DISKS_PER_MAJOR);
DEVICE_BUSY = 0;
return 0;
start = i << sd_gendisk.minor_shift;
for (i=max_p - 1; i >=0 ; i--) {
- int minor = start+i;
- kdev_t devi = MKDEV(MAJOR_NR, minor);
+ int index = start+i;
+ kdev_t devi = MKDEV_SD_PARTITION(index);
struct super_block *sb = get_super(devi);
sync_dev(devi);
if (sb) invalidate_inodes(sb);
invalidate_buffers(devi);
- sd_gendisk.part[minor].start_sect = 0;
- sd_gendisk.part[minor].nr_sects = 0;
- sd_sizes[minor] = 0;
+ sd_gendisks->part[index].start_sect = 0;
+ sd_gendisks->part[index].nr_sects = 0;
+ sd_sizes[index] = 0;
}
dpnt->has_part_table = 0;
SDp->attached--;
sd_template.dev_noticed--;
sd_template.nr_dev--;
- sd_gendisk.nr_real--;
+ SD_GENDISK(start).nr_real--;
return;
}
return;
{
struct gendisk * prev_sdgd;
struct gendisk * sdgd;
+ int i;
+ int removed = 0;
scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
- unregister_blkdev(SCSI_DISK_MAJOR, "sd");
+
+ for (i=0; i <= sd_template.dev_max / SCSI_DISKS_PER_MAJOR; i++)
+ unregister_blkdev(SD_MAJOR(i),"sd");
+
sd_registered--;
if( rscsi_disks != NULL )
{
- scsi_init_free((char *) rscsi_disks,
- (sd_template.dev_noticed + SD_EXTRA_DEVS)
- * sizeof(Scsi_Disk));
-
+ scsi_init_free((char *) rscsi_disks,
+ sd_template.dev_max * sizeof(Scsi_Disk));
scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int));
scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int));
scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int));
scsi_init_free((char *) sd,
(sd_template.dev_max << 4) * sizeof(struct hd_struct));
/*
- * Now remove sd_gendisk from the linked list
+ * Now remove sd_gendisks from the linked list
*/
- sdgd = gendisk_head;
- prev_sdgd = NULL;
- while(sdgd != &sd_gendisk)
- {
- prev_sdgd = sdgd;
- sdgd = sdgd->next;
- }
- if(sdgd != &sd_gendisk)
- printk("sd_gendisk not in disk chain.\n");
- else {
- if(prev_sdgd != NULL)
- prev_sdgd->next = sdgd->next;
- else
- gendisk_head = sdgd->next;
+ for (sdgd = gendisk_head; sdgd; sdgd = sdgd->next)
+ {
+ if (sdgd->next >= sd_gendisks && sdgd->next <= LAST_SD_GENDISK)
+ removed++, sdgd->next = sdgd->next->next;
+ else sdgd = sdgd->next;
}
+ if (removed != N_USED_SCSI_DISKS)
+ printk("%s %d sd_gendisks in disk chain",
+ removed > N_USED_SCSI_DISKS ? "total" : "just", removed);
+
}
- blksize_size[MAJOR_NR] = NULL;
- blk_dev[MAJOR_NR].request_fn = NULL;
- blk_size[MAJOR_NR] = NULL;
- hardsect_size[MAJOR_NR] = NULL;
- read_ahead[MAJOR_NR] = 0;
+ for (i=0; i <= sd_template.dev_max / SCSI_DISKS_PER_MAJOR; i++) {
+ blk_dev[SD_MAJOR(i)].request_fn = NULL;
+ blk_size[SD_MAJOR(i)] = NULL;
+ hardsect_size[SD_MAJOR(i)] = NULL;
+ read_ahead[SD_MAJOR(i)] = 0;
+ }
sd_template.dev_max = 0;
+ if (sd_gendisks != &sd_gendisk) kfree(sd_gendisks);
}
#endif /* MODULE */
extern int revalidate_scsidisk(kdev_t dev, int maxusage);
+#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))
+
#endif
/*
#include <asm/uaccess.h>
+#define MAJOR_NR SCSI_DISK0_MAJOR
#include <linux/blk.h>
#include "scsi.h"
#include <scsi/scsi_ioctl.h>
int diskinfo[4];
struct hd_geometry *loc = (struct hd_geometry *) arg;
- SDev = rscsi_disks[MINOR(dev) >> 4].device;
+ SDev = rscsi_disks[DEVICE_NR(dev)].device;
/*
* If we are in the middle of error recovery, don't let anyone
* else try and use this device. Also, if error recovery fails, it
error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
if (error)
return error;
- host = rscsi_disks[MINOR(dev) >> 4].device->host;
+ host = rscsi_disks[DEVICE_NR(dev)].device->host;
/* default to most commonly used values */
diskinfo[0] = 0x40;
diskinfo[1] = 0x20;
- diskinfo[2] = rscsi_disks[MINOR(dev) >> 4].capacity >> 11;
+ diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11;
/* override with calculated, extended default, or driver values */
if(host->hostt->bios_param != NULL)
- host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4],
+ host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)],
dev,
&diskinfo[0]);
- else scsicam_bios_param(&rscsi_disks[MINOR(dev) >> 4],
+ else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)],
dev, &diskinfo[0]);
put_user(diskinfo[0], &loc->heads);
put_user(diskinfo[1], &loc->sectors);
put_user(diskinfo[2], &loc->cylinders);
- put_user(sd[MINOR(inode->i_rdev)].start_sect, &loc->start);
+ put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start);
return 0;
case BLKGETSIZE: /* Return device size */
if (!arg) return -EINVAL;
error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
if (error)
return error;
- put_user(sd[MINOR(inode->i_rdev)].nr_sects,
+ put_user(sd[SD_PARTITION(inode->i_rdev)].nr_sects,
(long *) arg);
return 0;
RO_IOCTLS(dev, arg);
default:
- return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg);
+ return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg);
}
}
bus_type = "VESA";
}
else {
+ unsigned long flags;
sh[j]->wish_block = TRUE;
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";
static inline void wd7000_enable_dma (Adapter *host)
{
+ unsigned long flags;
host->control |= DMA_EN;
outb (host->control, host->iobase + ASC_CONTROL);
+
+ flags = claim_dma_lock();
set_dma_mode (host->dma, DMA_MODE_CASCADE);
enable_dma (host->dma);
+ release_dma_lock(flags);
+
}
if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
comment 'Compiled-in MSND Classic support requires firmware during compilation.'
define_bool CONFIG_MSNDCLAS_HAVE_BOOT y
- string ' Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE "/etc/sound/msndinit.bin"
- string ' Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE "/etc/sound/msndperm.bin"
else
define_bool CONFIG_MSNDCLAS_HAVE_BOOT n
fi
+ string ' Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE "/etc/sound/msndinit.bin"
+ string ' Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE "/etc/sound/msndperm.bin"
fi
if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
int 'MSND Classic IRQ 5,7,9,10,11,12' CONFIG_MSNDCLAS_IRQ 5
if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDPIN" = "m" ]; then
if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then
comment 'Compiled-in MSND Pinnacle support requires firmware during compilation.'
- string ' Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE "/etc/sound/pndspini.bin"
- string ' Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE "/etc/sound/pndsperm.bin"
define_bool CONFIG_MSNDPIN_HAVE_BOOT y
else
define_bool CONFIG_MSNDPIN_HAVE_BOOT n
fi
+ string ' Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE "/etc/sound/pndspini.bin"
+ string ' Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE "/etc/sound/pndsperm.bin"
fi
if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then
int 'MSND Pinnacle IRQ 5,7,9,10,11,12' CONFIG_MSNDPIN_IRQ 5
hex 'MSND Pinnacle memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDPIN_MEM D0000
hex 'MSND Pinnacle I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDPIN_IO 290
bool 'MSND Pinnacle has S/PDIF I/O' CONFIG_MSNDPIN_DIGITAL
- bool 'MSND Pinnacle Non-PnP Mode' CONFIG_MSNDPIN_NONPNP
+ bool 'MSND Pinnacle non-PnP Mode' CONFIG_MSNDPIN_NONPNP
if [ "$CONFIG_MSNDPIN_NONPNP" = "y" ]; then
comment 'MSND Pinnacle DSP section will be configured to above parameters.'
- hex 'MSDN Pinnacle config port 250,260,270' CONFIG_MSNDPIN_CFG 250
+ hex 'MSND Pinnacle config port 250,260,270' CONFIG_MSNDPIN_CFG 250
comment 'Pinnacle-specific Device Configuration (0 disables)'
hex 'MSND Pinnacle MPU I/O (e.g. 330)' CONFIG_MSNDPIN_MPU_IO 0
int 'MSND Pinnacle MPU IRQ (e.g. 9)' CONFIG_MSNDPIN_MPU_IRQ 0
hex 'MSND Pinnacle IDE I/O 0 (e.g. 170)' CONFIG_MSNDPIN_IDE_IO0 0
hex 'MSND Pinnacle IDE I/O 1 (e.g. 376)' CONFIG_MSNDPIN_IDE_IO1 0
int 'MSND Pinnacle IDE IRQ (e.g. 15)' CONFIG_MSNDPIN_IDE_IRQ 0
- hex 'MSDN Pinnacle joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0
+ hex 'MSND Pinnacle joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0
fi
fi
if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_MPU_IRQ 9
fi
+ dep_tristate 'Support for Yamaha OPL3-SA[2,3,x] based (PnP) cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
+ if [ "$CONFIG_SOUND_OPL3SA2" = "y" ]; then
+ hex 'OPL3SA2 audio I/O base 530, 604, E80 or F40' CONFIG_OPL3SA2_BASE 530
+ int 'OPL3SA2 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_IRQ 11
+ int 'OPL3SA2 audio DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA 0
+ int 'OPL3SA2 second (duplex) DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA2 1
+ hex 'OPL3SA2 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_OPL3SA2_MPU_BASE 330
+ int 'OPL3SA2 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_MPU_IRQ 9
+ fi
+
dep_tristate 'Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND_OSS
if [ "$CONFIG_SOUND_MAUI" = "y" ]; then
hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_MAUI_BASE 330
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_MSS) += ad1848.o
obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o
+obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o uart401.o mpu401.o
obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o uart401.o
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_SB) += sb.o uart401.o
ifeq ($(CONFIG_MAUI_HAVE_BOOT),y)
maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) bin2hex
- bin2hex -i maui_os < $(CONFIG_MAUI_BOOT_FILE) > $@
+ ./bin2hex -i maui_os < $(CONFIG_MAUI_BOOT_FILE) > $@
else
maui_boot.h:
( \
with impossible parameters. Check that the application is
for sound driver version 2.X or later.
-In general the printout of of /dev/sndstat should tell what is the problem.
+In general the printout of /dev/sndstat should tell what is the problem.
It's possible that there are bugs in the sound driver but 99% of the problems
reported to me are caused by somehow incorrect setup during "make config".
return;
timeout = 80000;
- while (timeout > 0 && ad_read(devc, 11) & 0x20)
+ while (timeout > 0 && (ad_read(devc, 11) & 0x20))
timeout--;
if (ad_read(devc, 11) & 0x20)
if (devc->model != MD_1845)
cnt >>= 1;
cnt--;
- if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
+ if ((devc->audio_mode & PCM_ENABLE_OUTPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) &&
intrflag &&
cnt == devc->xfer_count)
{
cnt >>= 1;
cnt--;
- if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
+ if ((devc->audio_mode & PCM_ENABLE_INPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) &&
intrflag &&
cnt == devc->xfer_count)
{
unsigned char bits = ad_read(devc, 9);
- if (bits & 0x01 && portc->open_mode & OPEN_WRITE)
+ if (bits & 0x01 && (portc->open_mode & OPEN_WRITE))
ad1848_halt_output(dev);
- if (bits & 0x02 && portc->open_mode & OPEN_READ)
+ if (bits & 0x02 && (portc->open_mode & OPEN_READ))
ad1848_halt_input(dev);
devc->audio_mode = 0;
}
0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
/* Positions 16 to 31 just for CS4231/2 and ad1845 */
- 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x1f, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */
}
- if (devc->open_mode & OPEN_READ && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
+ if ((devc->open_mode & OPEN_READ) && (devc->audio_mode & PCM_ENABLE_INPUT) && (alt_stat & 0x20))
{
DMAbuf_inputintr(devc->record_dev);
}
- if (devc->open_mode & OPEN_WRITE && devc->audio_mode & PCM_ENABLE_OUTPUT &&
- alt_stat & 0x10)
+ if ((devc->open_mode & OPEN_WRITE) && (devc->audio_mode & PCM_ENABLE_OUTPUT) &&
+ (alt_stat & 0x10))
{
DMAbuf_outputintr(devc->playback_dev, 1);
}
- if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */
+ if (devc->model != MD_1848 && (alt_stat & 0x40)) /* Timer interrupt */
{
devc->timer_ticks++;
#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
* The AD1848 codec has generic input lines called Line, Aux1 and Aux2.
* Sound card manufacturers have connected actual inputs (CD, synth, line,
* etc) to these inputs in different order. Therefore it's difficult
- * to assign mixer channels to to these inputs correctly. The following
+ * to assign mixer channels to these inputs correctly. The following
* contains two alternative mappings. The first one is for GUS MAX and
* the second is just a generic one (line1, line2 and line3).
* (Actually this is not a mapping but rather some kind of interleaving
* Nonblocking mode handling. Return current # of bytes
*/
- if (file->f_flags & O_NONBLOCK && buf_no == -EAGAIN)
+ if ((file->f_flags & O_NONBLOCK) && buf_no == -EAGAIN)
return p;
if (p > 0) /* Avoid throwing away data */
#define SNDCARD_SOFTOSS 36
#define SNDCARD_VMIDI 37
#define SNDCARD_WAVEFRONT 41
+#define SNDCARD_OPL3SA2 42
+#define SNDCARD_OPL3SA2_MPU 43
void attach_opl3sa_wss (struct address_info *hw_config);
int probe_opl3sa_wss (struct address_info *hw_config);
{"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu},
#endif
+#ifdef CONFIG_SOUND_OPL3SA2
+ {"OPL3SA2", 0, SNDCARD_OPL3SA2, "OPL3SA2", attach_opl3sa2, probe_opl3sa2, unload_opl3sa2},
+ {"OPL3SA2MPU", 0, SNDCARD_OPL3SA2_MPU, "OPL3SA2 MIDI", attach_opl3sa2_mpu, probe_opl3sa2_mpu, unload_opl3sa2_mpu},
+#endif
+
#ifdef CONFIG_SGALAXY
{"SGALAXY", 0, SNDCARD_SGALAXY, "Sound Galaxy WSS", attach_sgalaxy, probe_sgalaxy, unload_sgalaxy},
#endif
{SNDCARD_CS4232, {CONFIG_CS4232_BASE, CONFIG_CS4232_IRQ, CONFIG_CS4232_DMA, CONFIG_CS4232_DMA2}, SND_DEFAULT_ENABLE},
#endif
+#ifdef CONFIG_SOUND_OPL3SA2
+#ifndef CONFIG_OPL3SA2_DMA2
+#define CONFIG_OPL3SA2_DMA2 CONFIG_OPL3SA2_DMA
+#endif
+#ifdef CONFIG_OPL3SA2_MPU_BASE
+ {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+ {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE},
+#endif
+
#ifdef CONFIG_SGALAXY
#ifndef CONFIG_SGALAXY_DMA2
#define CONFIG_SGALAXY_DMA2 CONFIG_SGALAXY_DMA
int chan = dmap->dma;
/* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */
- save_flags(flags);
- cli();
+
+ flags = claim_dma_lock();
disable_dma(chan);
clear_dma_ff(chan);
set_dma_mode(chan, dma_mode);
set_dma_addr(chan, physaddr);
set_dma_count(chan, count);
enable_dma(chan);
- restore_flags(flags);
+ release_dma_lock(flags);
return 0;
}
static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap)
{
+ unsigned long flags;
+
sound_close_dma(dmap->dma);
if (dmap->flags & DMA_BUSY)
dmap->dma_mode = DMODE_NONE;
dmap->flags &= ~DMA_BUSY;
+
+ flags=claim_dma_lock();
disable_dma(dmap->dma);
+ release_dma_lock(flags);
+
sound_free_dmap(dmap);
}
}
adev->enable_bits = mode;
- if (mode == OPEN_READ || (mode != OPEN_WRITE && adev->flags & DMA_DUPLEX)) {
+ if (mode == OPEN_READ || (mode != OPEN_WRITE && (adev->flags & DMA_DUPLEX))) {
if ((retval = open_dmap(adev, mode, dmap_in)) < 0) {
adev->d->close(dev);
if (mode & OPEN_WRITE)
static void dma_reset_output(int dev)
{
struct audio_operations *adev = audio_devs[dev];
- unsigned long flags;
+ unsigned long flags,f ;
struct dma_buffparms *dmap = adev->dmap_out;
if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */
else
adev->d->halt_output(dev);
adev->dmap_out->flags &= ~DMA_STARTED;
+
+ f=claim_dma_lock();
clear_dma_ff(dmap->dma);
disable_dma(dmap->dma);
+ release_dma_lock(f);
+
restore_flags(flags);
dmap->byte_counter = 0;
reorganize_buffers(dev, adev->dmap_out, 0);
return; /* Don't start DMA yet */
dmap->dma_mode = DMODE_OUTPUT;
- if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) {
+ if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) {
if (!(dmap->flags & DMA_STARTED)) {
reorganize_buffers(dev, dmap, 0);
if (adev->d->prepare_for_output(dev, dmap->fragment_size, dmap->nbufs))
int n = 0;
struct dma_buffparms *dmap;
- if (!adev->go && (!adev->enable_bits & PCM_ENABLE_OUTPUT))
+ if (!adev->go && !(adev->enable_bits & PCM_ENABLE_OUTPUT))
return 0;
if (adev->dmap_out->dma_mode == DMODE_OUTPUT) {
if (adev->open_mode == OPEN_READ ||
(adev->open_mode != OPEN_WRITE &&
- adev->flags & DMA_DUPLEX))
+ (adev->flags & DMA_DUPLEX)))
close_dmap(adev, adev->dmap_in);
adev->open_mode = 0;
restore_flags(flags);
int pos;
unsigned long flags;
+ unsigned long f;
save_flags(flags);
cli();
pos = 0;
else {
int chan = dmap->dma;
+
+ f=claim_dma_lock();
clear_dma_ff(chan);
disable_dma(dmap->dma);
pos = get_dma_residue(chan);
+
pos = dmap->bytes_in_use - pos;
if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) {
if (pos >= dmap->bytes_in_use)
pos = 0;
enable_dma(dmap->dma);
+ release_dma_lock(f);
}
restore_flags(flags);
/* printk( "%04x ", pos); */
}
if (!(adev->flags & DMA_AUTOMODE))
dmap->flags &= ~DMA_ACTIVE;
- while (dmap->qlen <= 0) {
+
+ /*
+ * This is dmap->qlen <= 0 except when closing when
+ * dmap->qlen < 0
+ */
+
+ while (dmap->qlen <= -dmap->closing) {
dmap->underrun_count++;
dmap->qlen++;
- if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) {
+ if ((dmap->flags & DMA_DIRTY) && dmap->applic_profile != APF_CPUINTENS) {
dmap->flags &= ~DMA_DIRTY;
memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte,
adev->dmap_out->buffsize);
cli();
if (!(dmap->flags & DMA_NODMA)) {
int chan = dmap->dma, pos, n;
+ unsigned long f;
+
+ f=claim_dma_lock();
clear_dma_ff(chan);
disable_dma(dmap->dma);
pos = dmap->bytes_in_use - get_dma_residue(chan);
enable_dma(dmap->dma);
+ release_dma_lock(f);
+
pos = pos / dmap->fragment_size; /* Actual qhead */
if (pos < 0 || pos >= dmap->nbufs)
pos = 0;
}
}
}
- if (!(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) {
+ if (!(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) {
local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ);
adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1);
if (adev->d->trigger)
if (!(dmap->flags & DMA_NODMA)) {
int chan = dmap->dma, pos, n;
+ unsigned long f;
+
+ f=claim_dma_lock();
clear_dma_ff(chan);
disable_dma(dmap->dma);
pos = dmap->bytes_in_use - get_dma_residue(chan);
enable_dma(dmap->dma);
+ release_dma_lock(f);
pos = pos / dmap->fragment_size; /* Actual qhead */
if (pos < 0 || pos >= dmap->nbufs)
if (adev->dmap_out->dma >= 0) {
unsigned long flags;
- save_flags(flags);
- cli();
+ flags=claim_dma_lock();
clear_dma_ff(adev->dmap_out->dma);
disable_dma(adev->dmap_out->dma);
- restore_flags(flags);
+ release_dma_lock(flags);
}
return 0;
}
#define CONFIG_MPU401
#define CONFIG_MSS
#define CONFIG_OPL3SA1
+#define CONFIG_OPL3SA2
#define CONFIG_PAS
#define CONFIG_PSS
#define CONFIG_SB
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: msnd_pinnacle.c,v 1.63 1998/09/10 18:37:19 andrewtv Exp $
+ * $Id: msnd_pinnacle.c,v 1.65 1998/09/18 19:13:03 andrewtv Exp $
*
********************************************************************/
dev_ioctl, /* ioctl */
NULL, /* mmap */
dev_open, /* open */
+#ifndef LINUX20
NULL, /* flush */
+#endif
dev_release, /* release */
NULL, /* fsync */
NULL, /* fasync */
--- /dev/null
+/*
+ * sound/opl3sa2.c
+ *
+ * A low level driver for Yamaha OPL3-SA[2,3,x] based cards.
+ *
+ * Scott Murray, Jun 14, 1998
+ *
+ */
+
+/* Based on the CS4232 driver:
+ *
+ * Copyright (C) by Hannu Savolainen 1993-1997
+ *
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include "sound_config.h"
+#include "soundmodule.h"
+
+#ifdef CONFIG_OPL3SA2
+
+int probe_opl3sa2_mpu(struct address_info *hw_config)
+{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ return probe_mpu401(hw_config);
+#else
+ return 0;
+#endif
+}
+
+
+void attach_opl3sa2_mpu(struct address_info *hw_config)
+{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ attach_mpu401(hw_config);
+#endif
+}
+
+
+void unload_opl3sa2_mpu(struct address_info *hw_config)
+{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ unload_mpu401(hw_config);
+#endif
+}
+
+
+int probe_opl3sa2_mss(struct address_info *hw_config)
+{
+ return probe_ms_sound(hw_config);
+}
+
+
+void attach_opl3sa2_mss(struct address_info *hw_config)
+{
+ printk(KERN_INFO "opl3sa2.c: trying to init WSS\n");
+
+ attach_ms_sound(hw_config);
+
+ /* request_region(hw_config->io_base, 4, "Yamaha 7xx WSS Config"); */
+
+ if (hw_config->slots[0] != -1 &&
+ audio_devs[hw_config->slots[0]]->mixer_dev != -1)
+ {
+ AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
+ AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
+ /* GSM! test the following: */
+ AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
+ }
+}
+
+
+void unload_opl3sa2_mss(struct address_info *hw_config)
+{
+ int mixer;
+
+ /* Find mixer */
+ mixer = audio_devs[hw_config->slots[0]]->mixer_dev;
+
+ /* Unload MSS audio codec */
+ unload_ms_sound(hw_config);
+
+ sound_unload_audiodev(hw_config->slots[0]);
+
+ /* Unload mixer if there */
+ if(mixer >= 0)
+ {
+ sound_unload_mixerdev(mixer);
+ }
+
+ /* Release MSS config ports */
+ release_region(hw_config->io_base, 4);
+}
+
+
+int probe_opl3sa2(struct address_info *hw_config)
+{
+ /*
+ * Verify that the I/O port range is free.
+ */
+
+ printk(KERN_INFO "opl3sa2.c: Control using I/O port 0x%03x\n", hw_config->io_base);
+
+ if (check_region(hw_config->io_base, 2))
+ {
+ printk(KERN_ERR "opl3sa2.c: Control I/O port 0x%03x not free\n", hw_config->io_base);
+ return 0;
+ }
+
+ /* GSM!: Add some kind of other test here... */
+
+ return 1;
+}
+
+
+void attach_opl3sa2(struct address_info *hw_config)
+{
+ printk(KERN_INFO "opl3sa2.c: trying to init!\n");
+
+ request_region(hw_config->io_base, 2, "Yamaha 7xx Control");
+
+ /* GSM! Mixer stuff should go here... */
+}
+
+
+void unload_opl3sa2(struct address_info *hw_config)
+{
+ /* Release control ports */
+ release_region(hw_config->io_base, 2);
+
+ /* GSM! Mixer stuff should go here... */
+}
+
+
+#ifdef MODULE
+
+int io = -1;
+int mss_io = -1;
+int mpu_io = -1;
+int irq = -1;
+int dma = -1;
+int dma2 = -1;
+
+MODULE_PARM(io,"i");
+MODULE_PARM(mss_io,"i");
+MODULE_PARM(mpu_io,"i");
+MODULE_PARM(irq,"i");
+MODULE_PARM(dma,"i");
+MODULE_PARM(dma2,"i");
+
+EXPORT_NO_SYMBOLS;
+
+struct address_info cfg;
+struct address_info mss_cfg;
+struct address_info mpu_cfg;
+
+/*
+ * Install a OPL3SA2 based card. Need to have ad1848 and mpu401
+ * loaded ready.
+ */
+int init_module(void)
+{
+ int i;
+
+ if (io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1)
+ {
+ printk(KERN_ERR "opl3sa2: io, mss_io, irq, dma, and dma2 must be set.\n");
+ return -EINVAL;
+ }
+
+ /* Our own config: */
+ cfg.io_base = io;
+ cfg.irq = irq;
+ cfg.dma = dma;
+ cfg.dma2 = dma2;
+
+ /* The MSS config: */
+ mss_cfg.io_base = mss_io;
+ mss_cfg.irq = irq;
+ mss_cfg.dma = dma;
+ mss_cfg.dma2 = dma2;
+ mss_cfg.card_subtype = 1; /* No IRQ or DMA setup */
+
+ /* Call me paranoid: */
+ for(i = 0; i < 6; i++)
+ {
+ cfg.slots[i] = mss_cfg.slots[i] = mpu_cfg.slots[i] = -1;
+ }
+
+ if (probe_opl3sa2(&cfg) == 0)
+ {
+ return -ENODEV;
+ }
+ attach_opl3sa2(&cfg);
+
+ if (probe_opl3sa2_mss(&mss_cfg) == 0)
+ {
+ return -ENODEV;
+ }
+ attach_opl3sa2_mss(&mss_cfg);
+
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ if(mpu_io != -1)
+ {
+ /* MPU config: */
+ mpu_cfg.io_base = mpu_io;
+ mpu_cfg.irq = irq;
+ mpu_cfg.dma = dma;
+ mpu_cfg.always_detect = 1; /* It's there, so use shared IRQs */
+
+ if (probe_opl3sa2_mpu(&mpu_cfg))
+ {
+ attach_opl3sa2_mpu(&mpu_cfg);
+ }
+ }
+#endif
+ SOUND_LOCK;
+ return 0;
+}
+
+
+void cleanup_module(void)
+{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ if(mpu_cfg.slots[1] != -1)
+ {
+ unload_opl3sa2_mpu(&mpu_cfg);
+ }
+#endif
+ unload_opl3sa2_mss(&mss_cfg);
+ unload_opl3sa2(&cfg);
+ SOUND_LOCK_END;
+}
+
+#endif
+#endif
if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && devc->irq > 0)
{
free_irq(devc->irq, devc);
- if (devc->my_mixerdev)
- sound_unload_mixerdev(devc->my_mixerdev);
+ sound_unload_mixerdev(devc->my_mixerdev);
/* We don't have to do this bit any more the UART401 is its own
master -- Krzysztof Halasa */
/* But we have to do it, if UART401 is not detected */
void unload_trix_mpu(struct address_info *hw_info);
void unload_cs4232(struct address_info *hw_info);
void unload_cs4232_mpu(struct address_info *hw_info);
+void unload_opl3sa2(struct address_info *hw_info);
+void unload_opl3sa2_mpu(struct address_info *hw_info);
/* From cs4232.c */
int probe_cs4232_mpu (struct address_info *hw_config);
void attach_cs4232_mpu (struct address_info *hw_config);
+/* From opl3sa2.c */
+int probe_opl3sa2 (struct address_info *hw_config);
+void attach_opl3sa2 (struct address_info *hw_config);
+int probe_opl3sa2_mpu (struct address_info *hw_config);
+void attach_opl3sa2_mpu (struct address_info *hw_config);
+
/* From maui.c */
void attach_maui(struct address_info * hw_config);
int probe_maui(struct address_info *hw_config);
bool ' Leo (ZX) support' CONFIG_FB_LEO
fi
fi
+ if [ "$ARCH" = "sparc" ]; then
+ if [ "$CONFIG_PCI" != "n" ]; then
+ bool 'PCI framebuffers' CONFIG_FB_PCI
+ if [ "$CONFIG_FB_PCI" != "n" ]; then
+ bool ' IGA 168x display support' CONFIG_FB_IGA
+ fi
+ fi
+ fi
if [ "$ARCH" = "sparc64" ]; then
if [ "$CONFIG_PCI" != "n" ]; then
bool 'PCI framebuffers' CONFIG_FB_PCI
"$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
"$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
"$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
- "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" ]; then
+ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+ "$CONFIG_FB_IGA" = "y" ]; then
define_bool CONFIG_FBCON_CFB8 y
else
if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
"$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
"$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
"$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \
- "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" ]; then
+ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+ "$CONFIG_FB_IGA" = "y" ]; then
define_bool CONFIG_FBCON_CFB8 m
fi
fi
L_OBJS += atyfb.o
endif
+ifeq ($(CONFIG_FB_IGA),y)
+L_OBJS += igafb.o
+endif
+
ifeq ($(CONFIG_FB_CONTROL),y)
L_OBJS += controlfb.o
endif
include $(TOPDIR)/Rules.make
-promcon_tbl.c: prom.uni
+promcon_tbl.c: prom.uni ../char/conmakehash
../char/conmakehash prom.uni | \
sed -e '/#include <[^>]*>/p' -e 's/types/init/' \
-e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c
-/* $Id: atyfb.c,v 1.77 1998/09/14 08:01:46 jj Exp $
+/* $Id: atyfb.c,v 1.81 1998/10/14 16:45:38 ecd Exp $
* linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
*
* Copyright (C) 1997-1998 Geert Uytterhoeven
- cursor support on all cards and all ramdacs.
- cursor parameters controlable via ioctl()s.
+ - guess PLL and MCLK based on the original PLL register values initialized
+ by the BIOS or Open Firmware (if they are initialized).
(Anyone to help with this?)
#include <asm/io.h>
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+#if defined(CONFIG_PPC)
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <video/macmodes.h>
/*
* Debug flags.
*/
-#undef PLL_DEBUG
+#undef DEBUG
#define GUI_RESERVE 0x00001000
const struct fb_info_aty *info);
static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info);
static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
-#ifdef PLL_DEBUG
+#if defined(__sparc__) || defined(DEBUG)
static u8 aty_ld_pll(int offset, const struct fb_info_aty *info);
#endif
static void aty_set_crtc(const struct fb_info_aty *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 void do_install_cmap(int con, struct fb_info *info);
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+#if defined(CONFIG_PPC)
static int read_aty_sense(const struct fb_info_aty *info);
#endif
static const u32 ref_clk_per = 1000000000000ULL/14318180;
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+#if defined(CONFIG_PPC)
static int default_vmode = VMODE_NVRAM;
static int default_cmode = CMODE_NVRAM;
#endif
{ 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" },
};
+static const char *aty_gx_ram[8] __initdata = {
+ "DRAM", "VRAM", "VRAM", "DRAM", "GDRAM", "EVRAM", "EVRAM", "RESV"
+};
+
+static const char *aty_ct_ram[8] __initdata = {
+ "OFF", "DRAM", "EDO", "HPDRAM", "SDRAM", "SGRAM", "WRAM", "RESV"
+};
+
static inline u32 aty_ld_le32(volatile unsigned int regindex,
const struct fb_info_aty *info)
aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);
}
-#ifdef PLL_DEBUG
+#if defined(__sparc__) || defined(DEBUG)
static u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
{
u8 res;
}
#endif
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+#if defined(CONFIG_PPC)
/*
* Apple monitor sense
return sense;
}
-#endif /* defined(CONFIG_PMAC) || defined(CONFIG_CHRP) */
+#endif /* defined(CONFIG_PPC) */
/* ------------------------------------------------------------------------- */
}
return 0;
}
+
+static struct {
+ u32 yoffset;
+ u8 r[2][256];
+ u8 g[2][256];
+ u8 b[2][256];
+} atyfb_save;
+
+static void atyfb_save_palette(struct fb_info *fb, int enter)
+{
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
+ int i, tmp, scale;
+
+ for (i = 0; i < 256; i++) {
+ tmp = aty_ld_8(DAC_CNTL, info) & 0xfc;
+ if ((Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) ||
+ (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) ||
+ (Gx == GD_CHIP_ID) || (Gx == GI_CHIP_ID) ||
+ (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID))
+ tmp |= 0x2;
+ aty_st_8(DAC_CNTL, tmp, info);
+ aty_st_8(DAC_REGS + DAC_MASK, 0xff, info);
+ eieio();
+ scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) &&
+ (info->current_par.crtc.bpp == 16)) ? 3 : 0;
+ info->aty_cmap_regs->rindex = i << scale;
+ eieio();
+ atyfb_save.r[enter][i] = info->aty_cmap_regs->lut;
+ eieio();
+ atyfb_save.g[enter][i] = info->aty_cmap_regs->lut;
+ eieio();
+ atyfb_save.b[enter][i] = info->aty_cmap_regs->lut;
+ eieio();
+ info->aty_cmap_regs->windex = i << scale;
+ eieio();
+ info->aty_cmap_regs->lut = atyfb_save.r[1-enter][i];
+ eieio();
+ info->aty_cmap_regs->lut = atyfb_save.g[1-enter][i];
+ eieio();
+ info->aty_cmap_regs->lut = atyfb_save.b[1-enter][i];
+ eieio();
+ }
+}
+
+static void atyfb_palette(int enter)
+{
+ struct fb_info_aty *info;
+ struct atyfb_par *par;
+ struct display *d;
+ int i;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ d = &fb_display[i];
+ if (d->fb_info &&
+ d->fb_info->fbops == &atyfb_ops &&
+ d->fb_info->display_fg &&
+ d->fb_info->display_fg->vc_num == i) {
+ atyfb_save_palette(d->fb_info, enter);
+ info = (struct fb_info_aty *)d->fb_info;
+ par = &info->current_par;
+ if (enter) {
+ atyfb_save.yoffset = par->crtc.yoffset;
+ par->crtc.yoffset = 0;
+ set_off_pitch(par, info);
+ } else {
+ par->crtc.yoffset = atyfb_save.yoffset;
+ set_off_pitch(par, info);
+ }
+ break;
+ }
+ }
+}
#endif /* __sparc__ */
/*
int j, k;
struct fb_var_screeninfo var;
struct display *disp;
- const char *chipname = NULL;
+ const char *chipname = NULL, *ramname = NULL;
int pll, mclk;
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+#if defined(CONFIG_PPC)
int sense;
#endif
if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
info->bus_type = (aty_ld_le32(CONFIG_STAT0, info) >> 0) & 0x07;
info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) >> 3) & 0x07;
+ ramname = aty_gx_ram[info->ram_type];
/* FIXME: clockchip/RAMDAC probing? */
#ifdef CONFIG_ATARI
info->dac_type = DAC_ATI68860_B;
} else {
info->bus_type = PCI;
info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07);
+ ramname = aty_ct_ram[info->ram_type];
info->dac_type = DAC_INTERNAL;
info->clk_type = CLK_INTERNAL;
if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
info->total_vram += 0x400000;
}
- printk("%d%c %d MHz PLL, %d Mhz MCLK\n",
+ printk("%d%c %s, %d MHz PLL, %d Mhz MCLK\n",
info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20),
- info->total_vram == 0x80000 ? 'K' : 'M', pll, mclk);
-
+ info->total_vram == 0x80000 ? 'K' : 'M', ramname, pll, mclk);
+
+#ifdef DEBUG
+ if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
+ int i;
+ printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL "
+ "DSP_CONFIG DSP_ON_OFF\n"
+ "%08x %08x %08x %08x %08x %08x %08x\n"
+ "PLL",
+ aty_ld_le32(BUS_CNTL, info), aty_ld_le32(DAC_CNTL, info),
+ aty_ld_le32(MEM_CNTL, info), aty_ld_le32(EXT_MEM_CNTL, info),
+ aty_ld_le32(CRTC_GEN_CNTL, info), aty_ld_le32(DSP_CONFIG, info),
+ aty_ld_le32(DSP_ON_OFF, info));
+ for (i = 0; i < 16; i++)
+ printk(" %02x", aty_ld_pll(i, info));
+ printk("\n");
+ }
+#endif
+
if (info->bus_type == ISA)
if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) {
/* protect GUI-regs if complete Aperture is VRAM */
info->total_vram -= GUI_RESERVE;
}
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+#if defined(CONFIG_PPC)
if (default_vmode == VMODE_NVRAM) {
default_vmode = nvram_read_byte(NV_VMODE);
if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_cmode = CMODE_8;
if (mac_vmode_to_var(default_vmode, default_cmode, &var))
var = default_var;
-#else /* !CONFIG_PMAC && !CONFIG_CHRP */
+#else /* !CONFIG_PPC */
var = default_var;
-#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
+#endif /* !CONFIG_PPC */
if (noaccel)
var.accel_flags &= ~FB_ACCELF_TEXT;
else
info->fb_info.blank = &atyfbcon_blank;
info->fb_info.flags = FBINFO_FLAG_DEFAULT;
+#ifdef __sparc__
+ atyfb_save_palette(&info->fb_info, 0);
+#endif
for (j = 0; j < 16; j++) {
k = color_table[j];
info->palette[j].red = default_red[k];
struct fb_info_aty *info;
unsigned long addr;
#ifdef __sparc__
+ extern void (*prom_palette) (int);
extern int con_is_present(void);
struct pcidev_cookie *pcp;
char prop[128];
struct fb_var_screeninfo *var = &default_var;
u32 v_total, h_total;
struct crtc crtc;
+ u8 pll_regs[16];
+ u8 clock_cntl;
+ unsigned int N, P, Q, M, T;
crtc.vxres = prom_getintdefault(node, "width", 1024);
crtc.vyres = prom_getintdefault(node, "height", 768);
crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, info);
aty_crtc_to_var(&crtc, var);
- /*
- * FIXME: Read the PLL to figure actual Refresh Rate.
- * Default to 66Hz for now.
- */
h_total = var->xres + var->right_margin +
var->hsync_len + var->left_margin;
v_total = var->yres + var->lower_margin +
var->vsync_len + var->upper_margin;
- default_var.pixclock = 1000000000000ULL/(66*h_total*v_total);
+
+ /*
+ * Read the PLL to figure actual Refresh Rate.
+ */
+ clock_cntl = aty_ld_8(CLOCK_CNTL, info);
+ /* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */
+ for (i = 0; i < 16; i++) {
+ pll_regs[i] = aty_ld_pll(i, info);
+ /* printk("atyfb: PLL %2d: %02x\n", i, pll_regs[i]); */
+ }
+ /*
+ * PLL Reference Devider M:
+ */
+ M = pll_regs[2];
+ /* printk("atyfb: M: %02x\n", M); */
+
+ /*
+ * PLL Feedback Devider N (Dependant on CLOCK_CNTL):
+ */
+ N = pll_regs[7 + (clock_cntl & 3)];
+ /* printk("atyfb: N: %02x\n", N); */
+
+ /*
+ * PLL Post Devider P (Dependant on CLOCK_CNTL):
+ */
+ P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1));
+ /* printk("atyfb: P: %2d\n", P); */
+
+ /*
+ * PLL Devider Q:
+ */
+ Q = N / P;
+ /* printk("atyfb: Q: %d\n", Q); */
+
+ /*
+ * Target Frequency:
+ *
+ * T * M
+ * Q = -------
+ * 2 * R
+ *
+ * where R is XTALIN (= 14318 kHz).
+ */
+ T = 2 * Q * 14318 / M;
+ /* printk("atyfb: T: %d\n", T); */
+
+ default_var.pixclock =
+ ((1000000000000ULL / v_total) * 1000) / (T * h_total);
+ /* printk("atyfb: pixclock: %d\n", default_var.pixclock); */
}
#else /* __sparc__ */
}
#ifdef __sparc__
+ if (!prom_palette)
+ prom_palette = atyfb_palette;
+
/*
* Add /dev/fb mmap values.
*/
} else if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
}
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+#if defined(CONFIG_PPC)
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
if (vmode > 0 && vmode <= VMODE_MAX)
if (resize) {
/* reset wrap/pan */
p->var.xoffset = p->var.yoffset = p->yscroll = 0;
- if (!p->dispsw->set_font ||
- !p->dispsw->set_font(p, fontwidth(p), fontheight(p))) {
- /* Adjust the virtual screen-size to fontheight*rows */
- p->var.yres_virtual = (p->var.yres/h)*h;
- }
p->vrows = p->var.yres_virtual/h;
updatescrollmode(p);
vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
extern void offb_setup(char *options, int *ints);
extern void atyfb_init(void);
extern void atyfb_setup(char *options, int *ints);
+extern void igafb_init(void);
+extern void igafb_setup(char *options, int *ints);
extern void imsttfb_init(void);
extern void dnfb_init(void);
extern void tgafb_init(void);
#ifdef CONFIG_FB_ATY
{ "atyfb", atyfb_init, atyfb_setup },
#endif
+#ifdef CONFIG_FB_IGA
+ { "igafb", igafb_init, igafb_setup },
+#endif
#ifdef CONFIG_FB_IMSTT
{ "imsttfb", imsttfb_init, NULL },
#endif
--- /dev/null
+/* $Id: iga.h,v 1.1 1998/10/07 11:36:07 jj Exp $
+ * iga1682.h: Sparc/PCI iga1682 driver constants etc.
+ *
+ * Copyleft 1998 V. Roganov and G. Raiko
+ */
+
+#ifndef _IGA1682_H
+#define _IGA1682_H 1
+
+struct iga1682_info
+{
+ unsigned int total_vram;
+};
+
+#define DAC_W_INDEX 0x03C8
+#define DAC_DATA 0x03C9
+#define IGA_EXT_CNTRL 0x3CE
+#define IGA_IDX_EXT_BUS_CNTL 0x30
+#define MEM_SIZE_ALIAS 0x3
+#define MEM_SIZE_1M 0x0
+#define MEM_SIZE_2M 0x1
+#define MEM_SIZE_4M 0x2
+#define MEM_SIZE_RESERVED 0x3
+#define IGA_IDX_OVERSCAN_COLOR 0x58
+#define IGA_IDX_EXT_MEM_2 0x72
+
+#endif /* !(_IGA1682_H) */
--- /dev/null
+/*
+ * linux/drivers/video/igafb.c -- Frame buffer device for IGA 1682
+ *
+ * Copyright (C) 1998 Vladimir Roganov and Gleb Raiko
+ *
+ * This driver is partly based on the Frame buffer device for ATI Mach64
+ * and partially on VESA-related code.
+ *
+ * Copyright (C) 1997-1998 Geert Uytterhoeven
+ * Copyright (C) 1998 Bernd Harries
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+/******************************************************************************
+
+ TODO:
+ Despite of IGA Card has advanced graphic acceleration,
+ initial version is almost dummy and does not support it.
+ Support for video modes and acceleration must be added
+ together with accelerated X-Windows driver implementation.
+
+ (Anyone to help with this?)
+
+ Most important thing at this moment is that we have working
+ JavaEngine1 console & X with new console interface.
+
+******************************************************************************/
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+
+#include <asm/io.h>
+
+#ifdef __sparc__
+#include <asm/pbm.h>
+#include <asm/pcic.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "iga.h"
+
+static char igafb_name[16] = "IGA 1682";
+static char fontname[40] __initdata = { 0 };
+
+struct pci_mmap_map {
+ unsigned long voff;
+ unsigned long poff;
+ unsigned long size;
+ unsigned long prot_flag;
+ unsigned long prot_mask;
+};
+
+struct fb_info_iga {
+ struct fb_info fb_info;
+ unsigned long frame_buffer_phys;
+ unsigned long frame_buffer;
+ unsigned long io_base_phys;
+ unsigned long io_base;
+ u32 total_vram;
+ struct pci_mmap_map *mmap_map;
+ struct { u_short blue, green, red, pad; } palette[256];
+ int video_cmap_len;
+ int currcon;
+ struct display disp;
+ struct display_switch dispsw;
+ union {
+#ifdef FBCON_HAS_CFB16
+ u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+ u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cfb32[16];
+#endif
+ } fbcon_cmap;
+#ifdef __sparc__
+ u8 open;
+ u8 mmaped;
+ int vtconsole;
+ int consolecnt;
+#endif
+};
+
+struct fb_var_screeninfo default_var = {
+ /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+ 640, 480, 640, 480, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+};
+
+#ifdef __sparc__
+struct fb_var_screeninfo default_var_1024x768 __initdata = {
+ /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
+ 1024, 768, 1024, 768, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+struct fb_var_screeninfo default_var_1152x900 __initdata = {
+ /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
+ 1152, 900, 1152, 900, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+struct fb_var_screeninfo default_var_1280x1024 __initdata = {
+ /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
+ 1280, 1024, 1280, 1024, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+/*
+ * Memory-mapped I/O functions for Sparc PCI
+ */
+static inline unsigned char pci_inb (struct fb_info_iga *info,
+ unsigned int reg)
+{
+ return *(volatile unsigned char*)(info->io_base + reg);
+}
+static inline void pci_outb (struct fb_info_iga *info, unsigned char c,
+ unsigned int reg)
+{
+ *(volatile unsigned char*)(info->io_base + reg) = c;
+}
+static inline unsigned int iga_inb(struct fb_info_iga *info,
+ unsigned int reg, unsigned int idx )
+{
+ pci_outb(info, idx, reg);
+ return pci_inb(info, reg + 1);
+}
+static inline void iga_outb(struct fb_info_iga *info, unsigned char val,
+ unsigned int reg, unsigned int idx )
+{
+ pci_outb(info, idx, reg);
+ pci_outb(info, val, reg+1);
+}
+
+#endif /* __sparc__ */
+
+/*
+ * Very important functionality for the JavaEngine1 computer:
+ * make screen border black (usign special IGA registers)
+ */
+static void iga_blank_border(struct fb_info_iga *info)
+{
+ int i;
+
+ for (i=0; i < 3; i++)
+ iga_outb(info, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i);
+}
+
+
+/*
+ * Frame buffer device API
+ */
+
+/*
+ * Open/Release the frame buffer device
+ */
+
+static int igafb_open(struct fb_info *info, int user)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int igafb_release(struct fb_info *info, int user)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+static int igafb_update_var(int con, struct fb_info *info)
+{
+ return 0;
+}
+
+static int igafb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct fb_info_iga *fb = (struct fb_info_iga*)info;
+
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, igafb_name);
+
+ fix->smem_start = (char *)fb->frame_buffer;
+ fix->smem_len = fb->total_vram;
+ fix->xpanstep = 0;
+ fix->ypanstep = 0;
+ fix->ywrapstep = 0;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ fix->line_length = default_var.xres * (default_var.bits_per_pixel/8);
+ fix->visual = default_var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_DIRECTCOLOR;
+ return 0;
+}
+
+static int igafb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ if(con == -1)
+ memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
+ else
+ *var = fb_display[con].var;
+ return 0;
+}
+
+static int igafb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
+ return 0;
+}
+
+#ifdef __sparc__
+static int igafb_mmap(struct fb_info *info, struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fb_info_iga *fb = (struct fb_info_iga *)info;
+ unsigned int size, page, map_size = 0;
+ unsigned long map_offset = 0;
+ int i;
+
+ if (!fb->mmap_map)
+ return -ENXIO;
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* To stop the swapper from even considering these pages. */
+ vma->vm_flags |= (VM_SHM | VM_LOCKED);
+
+ /* Each page, see which map applies */
+ for (page = 0; page < size; ) {
+ map_size = 0;
+ for (i = 0; fb->mmap_map[i].size; i++) {
+ unsigned long start = fb->mmap_map[i].voff;
+ unsigned long end = start + fb->mmap_map[i].size;
+ unsigned long offset = vma->vm_offset + page;
+
+ if (start > offset)
+ continue;
+ if (offset >= end)
+ continue;
+
+ map_size = fb->mmap_map[i].size - (offset - start);
+ map_offset = fb->mmap_map[i].poff + (offset - start);
+ break;
+ }
+ if (!map_size) {
+ page += PAGE_SIZE;
+ continue;
+ }
+ if (page + map_size > size)
+ map_size = size - page;
+
+ pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
+ pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
+
+ if (remap_page_range(vma->vm_start + page, map_offset,
+ map_size, vma->vm_page_prot))
+ return -EAGAIN;
+
+ page += map_size;
+ }
+
+ if (!map_size)
+ return -EINVAL;
+
+ vma->vm_file = file;
+ file->f_count++;
+ vma->vm_flags |= VM_IO;
+
+ if (!fb->mmaped) {
+ int lastconsole = 0;
+
+ if (info->display_fg)
+ lastconsole = info->display_fg->vc_num;
+ fb->mmaped = 1;
+ if (fb->consolecnt && fb_display[lastconsole].fb_info ==info) {
+ fb->vtconsole = lastconsole;
+ vt_cons[lastconsole]->vc_mode = KD_GRAPHICS;
+ }
+ }
+ return 0;
+}
+#endif /* __sparc__ */
+
+
+static int iga_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *fb_info)
+{
+ /*
+ * Read a single color register and split it into colors/transparent.
+ * Return != 0 for invalid regno.
+ */
+ struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
+
+ if (regno >= info->video_cmap_len)
+ return 1;
+
+ *red = info->palette[regno].red;
+ *green = info->palette[regno].green;
+ *blue = info->palette[regno].blue;
+ *transp = 0;
+ return 0;
+}
+
+static int iga_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
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure). Return
+ * != 0 for invalid regno.
+ */
+
+ struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
+
+ if (regno >= info->video_cmap_len)
+ return 1;
+
+ info->palette[regno].red = red;
+ info->palette[regno].green = green;
+ info->palette[regno].blue = blue;
+
+ pci_outb(info, regno, DAC_W_INDEX);
+ pci_outb(info, red, DAC_DATA);
+ pci_outb(info, green, DAC_DATA);
+ pci_outb(info, blue, DAC_DATA);
+
+ if (regno << 16)
+ switch (default_var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ info->fbcon_cmap.cfb16[regno] =
+ (regno << 10) | (regno << 5) | regno;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ info->fbcon_cmap.cfb24[regno] =
+ (regno << 16) | (regno << 8) | regno;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ i = (regno << 8) | regno;
+ info->fbcon_cmap.cfb32[regno] = (i << 16) | i;
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *fb_info)
+{
+ struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
+
+ if (con != info->currcon)
+ return;
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, 1,
+ iga_setcolreg, &info->fb_info);
+ else
+ fb_set_cmap(fb_default_cmap(info->video_cmap_len), 1,
+ iga_setcolreg, &info->fb_info);
+}
+
+static int igafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *fb_info)
+{
+ struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
+
+ if (con == info->currcon) /* current console? */
+ return fb_get_cmap(cmap, kspc, iga_getcolreg, &info->fb_info);
+ else if (fb_display[con].cmap.len) /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(info->video_cmap_len),
+ cmap, kspc ? 0 : 2);
+ return 0;
+}
+
+static int igafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err;
+ struct fb_info_iga *fb = (struct fb_info_iga*) info;
+
+ if (!fb_display[con].cmap.len) { /* no colormap allocated? */
+ err = fb_alloc_cmap(&fb_display[con].cmap,
+ fb->video_cmap_len,0);
+ if (err)
+ return err;
+ }
+ if (con == fb->currcon) /* current console? */
+ return fb_set_cmap(cmap, kspc, iga_setcolreg, info);
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+static int igafb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ /* no panning */
+ return -EINVAL;
+}
+
+static int igafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg, int con, struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+/*
+ * Framebuffer option structure
+ */
+static struct fb_ops igafb_ops = {
+ igafb_open,
+ igafb_release,
+ igafb_get_fix,
+ igafb_get_var,
+ igafb_set_var,
+ igafb_get_cmap,
+ igafb_set_cmap,
+ igafb_pan_display,
+ igafb_ioctl,
+#ifdef __sparc__
+ igafb_mmap
+#else
+ NULL
+#endif
+};
+
+static void igafb_set_disp(int con, struct fb_info_iga *info)
+{
+ struct fb_fix_screeninfo fix;
+ struct display *display;
+ struct display_switch *sw;
+
+ if (con >= 0)
+ display = &fb_display[con];
+ else
+ display = &info->disp; /* used during initialization */
+
+ igafb_get_fix(&fix, con, &info->fb_info);
+
+ memset(display, 0, sizeof(struct display));
+ display->screen_base = (char*)info->frame_buffer;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->next_line = fix.line_length;
+ display->can_soft_blank = 0;
+ display->inverse = 0;
+ igafb_get_var(&display->var, -1, &info->fb_info);
+
+ switch (default_var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ sw = &fbcon_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 15:
+ case 16:
+ sw = &fbcon_cfb16;
+ display->dispsw_data = fbcon_cmap.cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ sw = &fbcon_cfb24;
+ display->dispsw_data = fbcon_cmap.cfb24;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ sw = &fbcon_cfb32;
+ display->dispsw_data = fbcon_cmap.cfb32;
+ break;
+#endif
+ default:
+ return;
+ }
+ memcpy(&info->dispsw, sw, sizeof(*sw));
+ display->dispsw = &info->dispsw;
+
+ display->scrollmode = SCROLL_YREDRAW;
+ info->dispsw.bmove = fbcon_redraw_bmove;
+}
+
+static int igafb_switch(int con, struct fb_info *fb_info)
+{
+ struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
+
+ /* Do we have to save the colormap? */
+ if (fb_display[info->currcon].cmap.len)
+ fb_get_cmap(&fb_display[info->currcon].cmap, 1,
+ iga_getcolreg, fb_info);
+
+ info->currcon = con;
+ /* Install new colormap */
+ do_install_cmap(con, fb_info);
+ igafb_update_var(con, fb_info);
+ 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 */
+}
+
+
+__initfunc(static int iga_init(struct fb_info_iga *info))
+{
+ char vramsz = iga_inb(info, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL)
+ & MEM_SIZE_ALIAS;
+ switch (vramsz) {
+ case MEM_SIZE_1M:
+ info->total_vram = 0x100000;
+ break;
+ case MEM_SIZE_2M:
+ info->total_vram = 0x200000;
+ break;
+ case MEM_SIZE_4M:
+ case MEM_SIZE_RESERVED:
+ info->total_vram = 0x400000;
+ break;
+ }
+
+ if (default_var.bits_per_pixel > 8) {
+ info->video_cmap_len = 16;
+ } else {
+ int i, j;
+ for(i = 0; i < 16; i++) {
+ j = color_table[i];
+ info->palette[i].red = default_red[j];
+ info->palette[i].green = default_grn[j];
+ info->palette[i].blue = default_blu[j];
+ }
+ info->video_cmap_len = 256;
+ }
+
+ strcpy(info->fb_info.modename, igafb_name);
+ info->fb_info.node = -1;
+ 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;
+
+ {
+ int j, k;
+ for (j = 0; j < 16; j++) {
+ k = color_table[j];
+ info->palette[j].red = default_red[k];
+ info->palette[j].green = default_grn[k];
+ info->palette[j].blue = default_blu[k];
+ }
+ }
+
+ igafb_set_disp(-1, info);
+
+ if (register_framebuffer(&info->fb_info) < 0)
+ return 0;
+
+ printk("fb%d: %s frame buffer device at 0x%08lx [%dMB VRAM]\n",
+ GET_FB_IDX(info->fb_info.node), igafb_name,
+ info->frame_buffer_phys, info->total_vram >> 20);
+
+ iga_blank_border(info);
+ return 1;
+}
+
+
+__initfunc(void igafb_init(void))
+{
+ struct pci_dev *pdev;
+ struct fb_info_iga *info;
+ unsigned long addr;
+ extern int con_is_present(void);
+
+ /* Do not attach when we have a serial console. */
+ if (!con_is_present())
+ return;
+
+ pdev = pci_find_device(PCI_VENDOR_ID_INTERG,
+ PCI_DEVICE_ID_INTERG_1682, 0);
+ if(pdev == NULL)
+ return;
+
+ info = kmalloc(sizeof(struct fb_info_iga), GFP_ATOMIC);
+ if (!info) {
+ printk("igafb_init: can't alloc fb_info_iga\n");
+ return;
+ }
+ memset(info, 0, sizeof(struct fb_info_iga));
+
+ info->frame_buffer = pdev->base_address[0];
+ if (!info->frame_buffer)
+ return;
+
+ pcibios_read_config_dword(0, pdev->devfn,
+ PCI_BASE_ADDRESS_0,
+ (unsigned int*)&addr);
+ if (!addr)
+ return;
+ info->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
+
+#ifdef __sparc__
+
+ info->io_base_phys = info->frame_buffer_phys;
+
+ /* Obtain virtual address and correct physical by PCIC shift */
+ info->io_base = pcic_alloc_io(&info->io_base_phys);
+ if (!info->io_base) {
+ return;
+ }
+
+ /*
+ * Figure mmap addresses from PCI config space.
+ * We need two regions: for video memory and for I/O ports.
+ * Later one can add region for video coprocessor registers.
+ * However, mmap routine loops until size != 0, so we put
+ * one additional region with size == 0.
+ */
+
+ info->mmap_map = kmalloc(4 * sizeof(*info->mmap_map), GFP_ATOMIC);
+ if (!info->mmap_map) {
+ printk("igafb_init: can't alloc mmap_map\n");
+ kfree(info);
+ return;
+ }
+
+ memset(info->mmap_map, 0, 4 * sizeof(*info->mmap_map));
+
+ /*
+ * Set default vmode and cmode from PROM properties.
+ */
+ {
+ struct pcidev_cookie *cookie = pdev->sysdata;
+ int node = cookie->prom_node;
+ int width = prom_getintdefault(node, "width", 1024);
+ int height = prom_getintdefault(node, "height", 768);
+ int depth = prom_getintdefault(node, "depth", 8);
+ switch (width) {
+ case 1024:
+ if (height == 768)
+ default_var = default_var_1024x768;
+ break;
+ case 1152:
+ if (height == 900)
+ default_var = default_var_1152x900;
+ break;
+ case 1280:
+ if (height == 1024)
+ default_var = default_var_1280x1024;
+ break;
+ default:
+ break;
+ }
+
+ switch (depth) {
+ case 8:
+ default_var.bits_per_pixel = 8;
+ break;
+ case 16:
+ default_var.bits_per_pixel = 16;
+ break;
+ case 24:
+ default_var.bits_per_pixel = 24;
+ break;
+ case 32:
+ default_var.bits_per_pixel = 32;
+ break;
+ default:
+ break;
+ }
+ }
+
+#endif
+ if (!iga_init(info)) {
+ if (info->mmap_map)
+ kfree(info->mmap_map);
+ kfree(info);
+ }
+
+#ifdef __sparc__
+ /*
+ * Add /dev/fb mmap values.
+ */
+
+ /* First region is for video memory */
+ info->mmap_map[0].voff = 0x0;
+ info->mmap_map[0].poff = info->frame_buffer_phys & PAGE_MASK;
+ info->mmap_map[0].size = info->total_vram & PAGE_MASK;
+ info->mmap_map[0].prot_mask = SRMMU_CACHE;
+ info->mmap_map[0].prot_flag = SRMMU_WRITE;
+
+ /* Second region is for I/O ports */
+ info->mmap_map[1].voff = info->frame_buffer_phys & PAGE_MASK;
+ info->mmap_map[1].poff = info->io_base_phys & PAGE_MASK;
+ info->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */
+ info->mmap_map[1].prot_mask = SRMMU_CACHE;
+ info->mmap_map[1].prot_flag = SRMMU_WRITE;
+#endif /* __sparc__ */
+}
+
+__initfunc(void igafb_setup(char *options, int *ints))
+{
+ char *this_opt;
+
+ if (!options || !*options)
+ return;
+
+ for (this_opt = strtok(options, ","); this_opt;
+ this_opt = strtok(NULL, ",")) {
+ if (!strncmp(this_opt, "font:", 5)) {
+ char *p;
+ int i;
+
+ p = this_opt + 5;
+ for (i = 0; i < sizeof(fontname) - 1; i++)
+ if (!*p || *p == ' ' || *p == ',')
+ break;
+ memcpy(fontname, this_opt + 5, i);
+ fontname[i] = 0;
+ }
+ }
+}
/*
- * drivers/video/imsttfb.c -- frame buffer device for IMS Twin Turbo
+ * drivers/video/imsttfb.c -- frame buffer device for IMS TwinTurbo
*
* This file is derived from the powermac console "imstt" driver:
* Copyright (C) 1997 Sigurdur Asgeirsson
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
+#include <linux/console.h>
#include <linux/selection.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+#if defined(CONFIG_PPC)
#include <linux/nvram.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
TVP = 0x01
};
-/* TwinTurbo registers */
+/* TwinTurbo (Cosmo) registers */
enum {
S1SA = 0, /* 0x00 */
S2SA = 1, /* 0x04 */
#endif
};
-/* IBM ramdac registers */
+/* IBM ramdac direct registers */
enum {
PADDRW = 0x00,
PDATA = 0x04,
PPMASK = 0x08,
- PADDRR = 0x0C,
+ PADDRR = 0x0c,
PIDXLO = 0x10,
PIDXHI = 0x14,
PIDXDATA= 0x18,
- PIDXCTL = 0x1C,
-
- PPIXREP = 0x0A,
- PM0 = 0x20,
- PN0 = 0x21,
- PP0 = 0x22,
- PC0 = 0x23,
- MCTL_3 = 0x72
+ PIDXCTL = 0x1c
+};
+
+/* IBM ramdac indirect registers */
+enum {
+ CLKCTL = 0x02, /* (0x01) Miscellaneous Clock Control */
+ SYNCCTL = 0x03, /* (0x00) Sync Control */
+ HSYNCPOS = 0x04, /* (0x00) Horizontal Sync Position */
+ PWRMNGMT = 0x05, /* (0x00) Power Management [multiples of 4 unblack screen] */
+ DACOP = 0x06, /* (0x02) DAC Operation [0-3 coloured, 4-7 green, odd light, even dark] */
+ PALETCTL = 0x07, /* (0x00) Palette Control */
+ SYSCLKCTL = 0x08, /* (0x01) System Clock Control */
+ PIXFMT = 0x0a, /* () Pixel Format [bpp >> 3 + 2] */
+ BPP8 = 0x0b, /* () 8 Bits/Pixel Control */
+ BPP16 = 0x0c, /* () 16 Bits/Pixel Control [15 or 1 for 555] */
+ BPP24 = 0x0d, /* () 24 Bits/Pixel Control */
+ BPP32 = 0x0e, /* () 32 Bits/Pixel Control */
+ PIXCTL1 = 0x10, /* (0x05) Pixel PLL Control 1 [5-7 ok] */
+ PIXCTL2 = 0x11, /* (0x00) Pixel PLL Control 2 [multiples of 20 ok] */
+ SYSCLKN = 0x15, /* () System Clock N (System PLL Reference Divider) */
+ SYSCLKM = 0x16, /* () System Clock M (System PLL VCO Divider) */
+ SYSCLKP = 0x17, /* () System Clock P */
+ SYSCLKC = 0x18, /* () System Clock C */
+ /*
+ * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
+ * c is charge pump bias which depends on the VCO frequency
+ */
+ PIXCLKM = 0x20, /* () Pixel Clock M */
+ PIXCLKN = 0x21, /* () Pixel Clock N */
+ PIXCLKP = 0x22, /* () Pixel Clock P */
+ PIXCLKC = 0x23, /* () Pixel Clock C */
+ CURSCTL = 0x30, /* (0x00) Cursor Control [1=curs1, 2=curs2, 5=curs3] */
+ CURSXLO = 0x31, /* () Cursor X position, low 8 bits */
+ CURSXHI = 0x32, /* () Cursor X position, high 8 bits */
+ CURSYLO = 0x33, /* () Cursor Y position, low 8 bits */
+ CURSYHI = 0x34, /* () Cursor Y position, high 8 bits */
+ CURSHOTX = 0x35, /* () ??? [position relative to CURSX] */
+ CURSHOTY = 0x36, /* () ??? [position relative to CURSY] */
+ CURSACAEN = 0x37, /* () ??? [even=cursor on, odd=cursor off] */
+ CURS1R = 0x40, /* () Cursor 1 Red */
+ CURS1G = 0x41, /* () Cursor 1 Green */
+ CURS1B = 0x42, /* () Cursor 1 Blue */
+ CURS2R = 0x43, /* () Cursor 2 Red */
+ CURS2G = 0x44, /* () Cursor 2 Green */
+ CURS2B = 0x45, /* () Cursor 2 Blue */
+ CURS3R = 0x46, /* () Cursor 3 Red */
+ CURS3G = 0x47, /* () Cursor 3 Green */
+ CURS3B = 0x48, /* () Cursor 3 Blue */
+ BORDR = 0x60, /* () Border Color Red */
+ BORDG = 0x61, /* () Border Color Green */
+ BORDB = 0x62, /* () Border Color Blue */
+ MISCTL1 = 0x70, /* (0x00) Miscellaneous Control 1 */
+ MISCTL2 = 0x71, /* (0x00) Miscellaneous Control 2 */
+ MISCTL3 = 0x72, /* (0x00) Miscellaneous Control 3 */
+ KEYCTL = 0x78 /* (0x00) Key Control/DB Operation */
};
/* TI TVP 3030 RAMDAC Direct Registers */
};
static struct initvalues ibm_initregs[] = {
- { 0x02, 0x21 }, /* (0x01) Miscellaneous Clock Control */
- { 0x03, 0x00 }, /* (0x00) Sync Control */
- { 0x04, 0x00 }, /* (0x00) Horizontal Sync Position */
- { 0x05, 0x00 }, /* (0x00) Power Management */
- { 0x06, 0x03 }, /* (0x02) DAC Operation */
- { 0x07, 0x00 }, /* (0x00) Palette Control */
- { 0x08, 0x01 }, /* (0x01) System Clock Control */
+ { CLKCTL, 0x21 },
+ { SYNCCTL, 0x00 },
+ { HSYNCPOS, 0x00 },
+ { PWRMNGMT, 0x00 },
+ { DACOP, 0x02 },
+ { PALETCTL, 0x00 },
+ { SYSCLKCTL, 0x01 },
/*
* Note that colors in X are correct only if all video data is
* color" must be configured. This is the case for the IBM DAC
* used in the 2MB and 4MB cards, at least.
*/
- { 0x0b, 0x00 }, /* (U) 8 BPP Control */
- { 0x0c, 0x00 }, /* (U) 16 BPP Control; the "1" means use 555 RGB color encoding */
- { 0x0d, 0x00 }, /* (U) 24 BPP Packed Control */
- { 0x0e, 0x00 }, /* (U) 32 BPP Control */
-
- { 0x10, 0x05 }, /* (0x00) Pixel PLL Control 1 */
- { 0x11, 0x00 }, /* (0x00) Pixel PLL Control 2 */
- { 0x15, 0x08 }, /* (0x08) SYSCLK N (System PLL Reference Divider) */
- { 0x16, 0x4f }, /* (0x41) SYSCLK M (System PLL VCO Divider) */
- { 0x17, 0x00 }, /* (U) SYSCLK P */
- { 0x18, 0x00 }, /* (U) SYSCLK C */
- { 0x30, 0x00 }, /* (0x00) Cursor Control */
- { 0x60, 0xff }, /* (U) Border Color Red */
- { 0x61, 0xff }, /* (U) Border Color Green */
- { 0x62, 0xff }, /* (U) Border Color Blue */
- { 0x70, 0x01 }, /* (0x00) Miscellaneous Control 1 */
- { 0x71, 0x45 }, /* (0x00) Miscellaneous Control 2 */
- { 0x72, 0x00 }, /* (0x00) Miscellaneous Control 3 */
- { 0x78, 0x00 } /* (0x00) Key Control/DB Operation */
+ { BPP8, 0x00 },
+ { BPP16, 0x00 },
+ { BPP24, 0x00 },
+ { BPP32, 0x00 },
+
+ { PIXCTL1, 0x05 },
+ { PIXCTL2, 0x00 },
+ { SYSCLKN, 0x08 },
+ { SYSCLKM, 0x4f },
+ { SYSCLKP, 0x00 },
+ { SYSCLKC, 0x00 },
+ { CURSCTL, 0x00 },
+ { CURS2R, 0xff },
+ { CURS2G, 0xff },
+ { CURS2B, 0xff },
+ { BORDR, 0xff },
+ { BORDG, 0xff },
+ { BORDB, 0xff },
+ { MISCTL1, 0x01 },
+ { MISCTL2, 0x45 },
+ { MISCTL3, 0x00 },
+ { KEYCTL, 0x00 }
};
static struct initvalues tvp_initregs[] = {
- { 0x6, 0x00 },
- { 0x7, 0xe4 },
- { 0xf, 0x06 },
- { 0x18, 0x80 },
- { 0x19, 0x4d },
- { 0x1a, 0x05 },
- { 0x1c, 0x00 },
- { 0x1d, 0x00 },
- { 0x1e, 0x08 },
- { 0x30, 0xff },
- { 0x31, 0xff },
- { 0x32, 0xff },
- { 0x33, 0xff },
- { 0x34, 0xff },
- { 0x35, 0xff },
- { 0x36, 0xff },
- { 0x37, 0xff },
- { 0x38, 0x00 },
- { TVPIRPLA, 0x00 },
- { TVPIRPPD, 0xc0 },
- { TVPIRPPD, 0xd5 },
- { TVPIRPPD, 0xea },
- { TVPIRPLA, 0x00 },
- { TVPIRMPD, 0xb9 },
- { TVPIRMPD, 0x3a },
- { TVPIRMPD, 0xb1 },
- { TVPIRPLA, 0x00 },
- { TVPIRLPD, 0xc1 },
- { TVPIRLPD, 0x3d },
- { TVPIRLPD, 0xf3 },
+ { 0x6, 0x00 },
+ { 0x7, 0xe4 },
+ { 0xf, 0x06 },
+ { 0x18, 0x80 },
+ { 0x19, 0x4d },
+ { 0x1a, 0x05 },
+ { 0x1c, 0x00 },
+ { 0x1d, 0x00 },
+ { 0x1e, 0x08 },
+ { 0x30, 0xff },
+ { 0x31, 0xff },
+ { 0x32, 0xff },
+ { 0x33, 0xff },
+ { 0x34, 0xff },
+ { 0x35, 0xff },
+ { 0x36, 0xff },
+ { 0x37, 0xff },
+ { 0x38, 0x00 },
+ { TVPIRPLA, 0x00 },
+ { TVPIRPPD, 0xc0 },
+ { TVPIRPPD, 0xd5 },
+ { TVPIRPPD, 0xea },
+ { TVPIRPLA, 0x00 },
+ { TVPIRMPD, 0xb9 },
+ { TVPIRMPD, 0x3a },
+ { TVPIRMPD, 0xb1 },
+ { TVPIRPLA, 0x00 },
+ { TVPIRLPD, 0xc1 },
+ { TVPIRLPD, 0x3d },
+ { TVPIRLPD, 0xf3 },
+};
+
+struct imstt_regvals {
+ __u32 pitch;
+ __u16 hes, heb, hsb, ht, ves, veb, vsb, vt, vil;
+ __u8 pclk_m, pclk_n, pclk_p;
+ /* Values of the tvp which change depending on colormode x resolution */
+ __u8 mlc[3]; /* Memory Loop Config 0x39 */
+ __u8 lckl_p[3]; /* P value of LCKL PLL */
+};
+
+struct imstt_cursor {
+ int enable;
+ int on;
+ int vbl_cnt;
+ int blink_rate;
+ __u16 x, y;
+ struct timer_list timer;
};
struct fb_info_imstt {
struct fb_info info;
struct fb_fix_screeninfo fix;
struct display disp;
- struct {
- __u8 red, green, blue;
- } palette[256];
- __u8 *frame_buffer_phys, *frame_buffer;
- __u32 *dc_regs_phys, *dc_regs;
- __u8 *cmap_regs_phys, *cmap_regs;
- __u32 total_vram;
- __u32 ramdac;
+ struct display_switch dispsw;
union {
#ifdef FBCON_HAS_CFB16
__u16 cfb16[16];
__u32 cfb32[16];
#endif
} fbcon_cmap;
+ struct {
+ __u8 red, green, blue;
+ } palette[256];
+ struct imstt_regvals init;
+ struct imstt_cursor cursor;
+ __u8 *frame_buffer_phys, *frame_buffer;
+ __u32 *dc_regs_phys, *dc_regs;
+ __u8 *cmap_regs_phys, *cmap_regs;
+ __u32 total_vram;
+ __u32 ramdac;
};
-#define USE_NV_MODES 1
-#define INIT_BPP 8
-#define INIT_XRES 640
-#define INIT_YRES 480
+#define USE_NV_MODES 1
+#define INIT_BPP 8
+#define INIT_XRES 640
+#define INIT_YRES 480
+#define CURSOR_BLINK_RATE 20
+#define CURSOR_DRAW_DELAY 2
static int currcon = 0;
-/*
- * for the IBM ramdac:
- * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
- * where m = clk[0], n = clk[1], p = clk[2]
- * clk[3] is c, charge pump bias which depends on the VCO frequency
- */
-struct imstt_regvals {
- __u16 hes, heb, hsb, ht, ves, veb, vsb, vt, vil;
- __u8 pclk_m, pclk_n, pclk_p;
- __u32 pitch;
- /* Values of the tvp which change depending on colormode x resolution */
- __u8 mlc[3]; /* Memory Loop Config 0x39 */
- __u8 lckl_p[3]; /* P value of LCKL PLL */
-};
-
-/* 1600x1200, 75Hz */
-static struct imstt_regvals ibm_reg_init_1600x1200x75 = {
- 0x0018, 0x0040, 0x0108, 0x010c, 0x0003, 0x002a, 0x04da, 0x04dd, 0x04da,
- 0x09, 0x00, 0x00,
- 1600
-};
-
-/* 1280x1024, 75Hz (20) */
-static struct imstt_regvals ibm_reg_init_20 = {
- 0x0012, 0x002f, 0x00cf, 0x00d3, 0x0003, 0x0029, 0x0429, 0x042a, 0x0429,
- 0x1a, 0x03, 0x00,
- 1280
-};
-
-/* 1280x960, 75Hz (19) */
-static struct imstt_regvals ibm_reg_init_19 = {
- 0x0012, 0x0030, 0x00d0, 0x00d2, 0x0003, 0x0027, 0x03e7, 0x03e8, 0x03e7,
- 0x3e, 0x09, 0x00,
- 1280
-};
-
-/* 1152x870, 75Hz (18) */
-static struct imstt_regvals ibm_reg_init_18 = {
- 0x0012, 0x0022, 0x00b2, 0x00b6, 0x0003, 0x0031, 0x0397, 0x039a, 0x0397,
- 0x3c, 0x0b, 0x00,
- 1152
-};
-
-/* 1024x768, 75Hz (17) */
-#if 1
-static struct imstt_regvals ibm_reg_init_17 = {
- 0x000a, 0x001c, 0x009c, 0x00a6, 0x0003, 0x0020, 0x0320, 0x0323, 0x0320,
- 0x07, 0x00, 0x01,
- 1024
-};
-#else
-/* this almost works with a 14" apple multiple scan monitor */
-static struct imstt_regvals ibm_reg_init_17 = {
- 0x000a, 0x001d, 0x009c, 0x00ac, 0x0003, 0x0020, 0x0320, 0x0323, 0x0320,
- 0x3e, 0x0a, 0x01,
- 1024
-};
-#endif
-
-/* 832x624, 75Hz (13) */
-static struct imstt_regvals ibm_reg_init_13 = {
- 0x0005, 0x0020, 0x0088, 0x0090, 0x0003, 0x0028, 0x0298, 0x029b, 0x0298,
- 0x3e, 0x0a, 0x01,
- 832
-};
-
-/* 640x480, 67Hz (6) */
-static struct imstt_regvals ibm_reg_init_6 = {
- 0x0008, 0x0012, 0x0062, 0x006c, 0x0003, 0x002a, 0x020a, 0x020c, 0x020a,
- 0x78, 0x13, 0x02,
- 640
-};
-
static struct imstt_regvals tvp_reg_init_2 = {
+ 512,
0x0002, 0x0006, 0x0026, 0x0028, 0x0003, 0x0016, 0x0196, 0x0197, 0x0196,
0xec, 0x2a, 0xf3,
- 512,
{ 0x3c, 0x3b, 0x39 }, { 0xf3, 0xf3, 0xf3 }
};
static struct imstt_regvals tvp_reg_init_6 = {
+ 640,
0x0004, 0x0009, 0x0031, 0x0036, 0x0003, 0x002a, 0x020a, 0x020d, 0x020a,
0xef, 0x2e, 0xb2,
- 640,
{ 0x39, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 }
};
static struct imstt_regvals tvp_reg_init_12 = {
+ 800,
0x0005, 0x000e, 0x0040, 0x0042, 0x0003, 0x018, 0x270, 0x271, 0x270,
0xf6, 0x2e, 0xf2,
- 800,
{ 0x3a, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 }
};
static struct imstt_regvals tvp_reg_init_13 = {
+ 832,
0x0004, 0x0011, 0x0045, 0x0048, 0x0003, 0x002a, 0x029a, 0x029b, 0x0000,
0xfe, 0x3e, 0xf1,
- 832,
{ 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
};
static struct imstt_regvals tvp_reg_init_17 = {
+ 1024,
0x0006, 0x0210, 0x0250, 0x0053, 0x1003, 0x0021, 0x0321, 0x0324, 0x0000,
0xfc, 0x3a, 0xf1,
- 1024,
{ 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
};
static struct imstt_regvals tvp_reg_init_18 = {
+ 1152,
0x0009, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a, 0x0000,
0xfd, 0x3a, 0xf1,
- 1152,
{ 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
};
static struct imstt_regvals tvp_reg_init_19 = {
+ 1280,
0x0009, 0x0016, 0x0066, 0x0069, 0x0003, 0x0027, 0x03e7, 0x03e8, 0x03e7,
0xf7, 0x36, 0xf0,
- 1280,
{ 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
};
static struct imstt_regvals tvp_reg_init_20 = {
+ 1280,
0x0009, 0x0018, 0x0068, 0x006a, 0x0003, 0x0029, 0x0429, 0x042a, 0x0000,
0xf0, 0x2d, 0xf0,
- 1280,
{ 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
};
+static __u32
+getclkMHz (struct fb_info_imstt *p)
+{
+ __u32 clk_m, clk_n, clk_p;
+
+ clk_m = p->init.pclk_m;
+ clk_n = p->init.pclk_n;
+ clk_p = p->init.pclk_p;
+
+ return 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1));
+}
+
+static void
+setclkMHz (struct fb_info_imstt *p, __u32 MHz)
+{
+ __u32 clk_m, clk_n, clk_p, x, stage, spilled;
+
+ clk_m = clk_n = clk_p = 0;
+ stage = spilled = 0;
+ for (;;) {
+ switch (stage) {
+ case 0:
+ clk_m++;
+ break;
+ case 1:
+ clk_n++;
+ break;
+ }
+ x = 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1));
+ if (x == MHz)
+ break;
+ if (x > MHz) {
+ spilled = 1;
+ stage = 1;
+ } else if (spilled && x < MHz) {
+ stage = 0;
+ }
+ }
+
+ p->init.pclk_m = clk_m;
+ p->init.pclk_n = clk_n;
+ p->init.pclk_p = clk_p;
+}
+
static struct imstt_regvals *
-compute_imstt_regvals_ibm (int xres, int yres)
+compute_imstt_regvals_ibm (struct fb_info_imstt *p, int xres, int yres)
{
- struct imstt_regvals *init;
+ struct imstt_regvals *init = &p->init;
+ __u32 MHz, hes, heb, veb, htp, vtp;
switch (xres) {
case 640:
- init = &ibm_reg_init_6;
+ hes = 0x0008; heb = 0x0012; veb = 0x002a; htp = 10; vtp = 2;
+ MHz = 30 /* .25 */ ;
break;
case 832:
- init = &ibm_reg_init_13;
+ hes = 0x0005; heb = 0x0020; veb = 0x0028; htp = 8; vtp = 3;
+ MHz = 57 /* .27_ */ ;
break;
case 1024:
- init = &ibm_reg_init_17;
+ hes = 0x000a; heb = 0x001c; veb = 0x0020; htp = 8; vtp = 3;
+ MHz = 80;
break;
case 1152:
- init = &ibm_reg_init_18;
+ hes = 0x0012; heb = 0x0022; veb = 0x0031; htp = 4; vtp = 3;
+ MHz = 101 /* .6_ */ ;
break;
case 1280:
- init = yres == 960 ? &ibm_reg_init_19 : &ibm_reg_init_20;
+ hes = 0x0012; heb = 0x002f; veb = 0x0029; htp = 4; vtp = 1;
+ MHz = yres == 960 ? 126 : 135;
break;
case 1600:
- init = &ibm_reg_init_1600x1200x75;
+ hes = 0x0018; heb = 0x0040; veb = 0x002a; htp = 4; vtp = 3;
+ MHz = 200;
break;
default:
- init = 0;
- break;
+ return 0;
}
+ setclkMHz(p, MHz);
+
+ init->hes = hes;
+ init->heb = heb;
+ init->hsb = init->heb + xres / 8;
+ init->ht = init->hsb + htp;
+ init->ves = 0x0003;
+ init->veb = veb;
+ init->vsb = init->veb + yres;
+ init->vt = init->vsb + vtp;
+ init->vil = init->vsb;
+
+ init->pitch = xres;
+
return init;
}
static struct imstt_regvals *
-compute_imstt_regvals_tvp (int xres, int yres)
+compute_imstt_regvals_tvp (struct fb_info_imstt *p, int xres, int yres)
{
struct imstt_regvals *init;
init = yres == 960 ? &tvp_reg_init_19 : &tvp_reg_init_20;
break;
default:
- init = 0;
- break;
+ return 0;
}
+ p->init = *init;
return init;
}
static struct imstt_regvals *
-compute_imstt_regvals (struct fb_info_imstt *p, int xres, int yres)
+compute_imstt_regvals (struct fb_info_imstt *p, u_int xres, u_int yres)
{
if (p->ramdac == IBM)
- return compute_imstt_regvals_ibm(xres, yres);
+ return compute_imstt_regvals_ibm(p, xres, yres);
else
- return compute_imstt_regvals_tvp(xres, yres);
+ return compute_imstt_regvals_tvp(p, xres, yres);
}
static void
-set_imstt_regvals_ibm (struct fb_info_imstt *p, struct imstt_regvals *init, int bpp)
+set_imstt_regvals_ibm (struct fb_info_imstt *p, u_int bpp)
{
+ struct imstt_regvals *init = &p->init;
__u8 pformat = (bpp >> 3) + 2;
p->cmap_regs[PIDXHI] = 0; eieio();
- p->cmap_regs[PIDXLO] = PM0; eieio();
+ p->cmap_regs[PIDXLO] = PIXCLKM; eieio();
p->cmap_regs[PIDXDATA] = init->pclk_m; eieio();
- p->cmap_regs[PIDXLO] = PN0; eieio();
+ p->cmap_regs[PIDXLO] = PIXCLKN; eieio();
p->cmap_regs[PIDXDATA] = init->pclk_n; eieio();
- p->cmap_regs[PIDXLO] = PP0; eieio();
+ p->cmap_regs[PIDXLO] = PIXCLKP; eieio();
p->cmap_regs[PIDXDATA] = init->pclk_p; eieio();
- p->cmap_regs[PIDXLO] = PC0; eieio();
+ p->cmap_regs[PIDXLO] = PIXCLKC; eieio();
p->cmap_regs[PIDXDATA] = 0x02; eieio();
p->cmap_regs[PIDXHI] = 0; eieio();
- p->cmap_regs[PIDXLO] = PPIXREP; eieio();
+ p->cmap_regs[PIDXLO] = PIXFMT; eieio();
p->cmap_regs[PIDXDATA] = pformat; eieio();
- p->cmap_regs[PIDXHI] = 0; eieio();
}
static void
-set_imstt_regvals_tvp (struct fb_info_imstt *p, struct imstt_regvals *init, int bpp)
+set_imstt_regvals_tvp (struct fb_info_imstt *p, u_int bpp)
{
+ struct imstt_regvals *init = &p->init;
__u8 tcc, mxc, lckl_n, mic;
__u8 mlc, lckl_p;
}
static void
-set_imstt_regvals (struct fb_info_imstt *p, struct imstt_regvals *init, int bpp)
+set_imstt_regvals (struct fb_info_imstt *p, u_int bpp)
{
+ struct imstt_regvals *init = &p->init;
__u32 ctl, pitch, byteswap, scr;
if (p->ramdac == IBM)
- set_imstt_regvals_ibm(p, init, bpp);
+ set_imstt_regvals_ibm(p, bpp);
else
- set_imstt_regvals_tvp(p, init, bpp);
+ set_imstt_regvals_tvp(p, bpp);
/*
* From what I (jsk) can gather poking around with MacsBug,
break;
case 24:
ctl = 0x17b9;
- pitch = init->pitch - (init->pitch / 4);
+ pitch = init->pitch - (p->init.pitch / 4);
byteswap = 0x2;
break;
case 32:
out_le32(&p->dc_regs[STGCTL], ctl);
}
-void
+static void
set_16 (struct fb_info_imstt *p, __u8 x)
{
if (p->ramdac == IBM) {
p->cmap_regs[PIDXHI] = 0; eieio();
- p->cmap_regs[PIDXLO] = 0x0c; eieio();
+ p->cmap_regs[PIDXLO] = BPP16; eieio();
p->cmap_regs[PIDXDATA] = x; eieio();
} else {
/* ?!? */
}
}
-#define set_555(_p) set_16(_p, 15) /* need 220 or 224 for X */
+#define set_555(_p) set_16(_p, 15)
#define set_565(_p) set_16(_p, 0) /* 220, 224 is darker in X */
-void
+static void
+imstt_set_cursor (struct fb_info_imstt *p, int on)
+{
+ struct imstt_cursor *c = &p->cursor;
+
+ p->cmap_regs[PIDXHI] = 0;
+ if (!on) {
+ p->cmap_regs[PIDXLO] = CURSCTL;
+ p->cmap_regs[PIDXDATA] = 0x00;
+ } else {
+ p->cmap_regs[PIDXLO] = CURSXHI;
+ p->cmap_regs[PIDXDATA] = c->x >> 8;
+ p->cmap_regs[PIDXLO] = CURSXLO;
+ p->cmap_regs[PIDXDATA] = c->x & 0xff;
+ p->cmap_regs[PIDXLO] = CURSYHI;
+ p->cmap_regs[PIDXDATA] = c->y >> 8;
+ p->cmap_regs[PIDXLO] = CURSYLO;
+ p->cmap_regs[PIDXDATA] = c->y & 0xff;
+ p->cmap_regs[PIDXLO] = CURSCTL;
+ p->cmap_regs[PIDXDATA] = 0x02;
+ }
+}
+
+static void
+imsttfb_cursor (struct display *disp, int mode, int x, int y)
+{
+ struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
+ struct imstt_cursor *c = &p->cursor;
+
+ x *= fontwidth(disp);
+ y *= fontheight(disp);
+
+ if (c->x == x && c->y == y && (mode == CM_ERASE) == !c->enable)
+ return;
+
+ c->enable = 0;
+ if (c->on)
+ imstt_set_cursor(p, 0);
+ c->x = x;
+ c->y = y;
+
+ switch (mode) {
+ case CM_ERASE:
+ c->on = 0;
+ break;
+ case CM_DRAW:
+ case CM_MOVE:
+ if (c->on)
+ imstt_set_cursor(p, c->on);
+ else
+ c->vbl_cnt = CURSOR_DRAW_DELAY;
+ c->enable = 1;
+ break;
+ }
+}
+
+static int
+imsttfb_set_font (struct display *disp, int width, int height)
+{
+ return 1;
+}
+
+static void
+imstt_cursor_timer_handler (unsigned long dev_addr)
+{
+ struct fb_info_imstt *p = (struct fb_info_imstt *)dev_addr;
+ struct imstt_cursor *c = &p->cursor;
+
+ if (!c->enable)
+ goto out;
+
+ if (c->vbl_cnt && --c->vbl_cnt == 0) {
+ c->on ^= 1;
+ imstt_set_cursor(p, c->on);
+ c->vbl_cnt = c->blink_rate;
+ }
+
+out:
+ c->timer.expires = jiffies + (HZ / 50);
+ add_timer(&c->timer);
+}
+
+__initfunc(static void
+imstt_cursor_init (struct fb_info_imstt *p))
+{
+ struct imstt_cursor *c = &p->cursor;
+
+ c->enable = 1;
+ c->on = 1;
+ c->blink_rate = CURSOR_BLINK_RATE;
+ c->vbl_cnt = CURSOR_DRAW_DELAY;
+ c->x = c->y = 0;
+
+ init_timer(&c->timer);
+ c->timer.expires = jiffies + (HZ / 50);
+ c->timer.data = (unsigned long)p;
+ c->timer.function = imstt_cursor_timer_handler;
+ add_timer(&c->timer);
+}
+
+static void
imsttfb_rectcopy (struct display *disp, int sy, int sx, int dy, int dx, int height, int width)
{
struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
- __u32 tmp, cnt_reg;
+ __u32 cnt_reg, stat, xxx = 0;
__u32 line_pitch = disp->var.xres * (disp->var.bits_per_pixel >> 3),
rect_height = height,
rect_width = width * (disp->var.bits_per_pixel >> 3),
fb_offset_old = sy * line_pitch + (sx * (disp->var.bits_per_pixel >> 3)),
fb_offset_new = dy * line_pitch + (dx * (disp->var.bits_per_pixel >> 3));
+ stat = in_le32(&p->dc_regs[SSTATUS]) & 0xff;
+
cnt_reg = ((rect_height - 1) << 16) | (rect_width - 1);
+ out_le32(&p->dc_regs[CNT], cnt_reg);
+ out_le32(&p->dc_regs[S1SA], fb_offset_old);
+ out_le32(&p->dc_regs[DSA], fb_offset_old);
+ out_le32(&p->dc_regs[SP], line_pitch);
+ out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
+ out_le32(&p->dc_regs[BLTCTL], 0x5);
- tmp = (line_pitch << 16) | line_pitch;
- out_le32(&p->dc_regs[SP], tmp);
- tmp = line_pitch;
- out_le32(&p->dc_regs[DP_OCTRL], tmp);
-#if 0
- do {
- tmp = in_le32(&p->dc_regs[SSTATUS]);
+ if (++stat == 0x20)
+ stat = 0x10;
+ while ((in_le32(&p->dc_regs[SSTATUS]) & 0xff) != stat && xxx++ < 0xff)
eieio();
- } while (tmp & 0x80);
-#endif
+
+ cnt_reg = ((rect_height - 1) << 16) | (0xffff - (rect_width - 2));
out_le32(&p->dc_regs[CNT], cnt_reg);
- out_le32(&p->dc_regs[S1SA], fb_offset_old);
- out_le32(&p->dc_regs[S2SA], fb_offset_new);
out_le32(&p->dc_regs[DSA], fb_offset_new);
- out_le32(&p->dc_regs[BLTCTL], 0x5);
#if 0
- do {
- tmp = in_le32(&p->dc_regs[SSTATUS]);
- eieio();
- } while (tmp & 0x80);
+ out_le32(&p->dc_regs[S1SA], fb_offset_old);
+ out_le32(&p->dc_regs[SP], line_pitch);
+ out_le32(&p->dc_regs[DP_OCTRL], line_pitch);
+#endif
+ out_le32(&p->dc_regs[BLTCTL], 0x85);
- do {
- tmp = in_le32(&p->dc_regs[SSTATUS]);
+ if (++stat == 0x20)
+ stat = 0x10;
+ while ((in_le32(&p->dc_regs[SSTATUS]) & 0xff) != stat && xxx++ < 0xff)
eieio();
- } while (tmp & 0x40);
-#endif
}
static void
imsttfb_rectcopy(disp, sy, sx, dy, dx, height, width);
}
+#ifdef FBCON_HAS_CFB8
static struct display_switch fbcon_imstt8 = {
fbcon_cfb8_setup, imsttfbcon_bmove, fbcon_cfb8_clear, fbcon_cfb8_putc,
fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
-
+#endif
+#ifdef FBCON_HAS_CFB16
static struct display_switch fbcon_imstt16 = {
fbcon_cfb16_setup, imsttfbcon_bmove, fbcon_cfb16_clear, fbcon_cfb16_putc,
fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins,
FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
-
+#endif
+#ifdef FBCON_HAS_CFB24
static struct display_switch fbcon_imstt24 = {
fbcon_cfb24_setup, imsttfbcon_bmove, fbcon_cfb24_clear, fbcon_cfb24_putc,
fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins,
FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
-
+#endif
+#ifdef FBCON_HAS_CFB32
static struct display_switch fbcon_imstt32 = {
fbcon_cfb32_setup, imsttfbcon_bmove, fbcon_cfb32_clear, fbcon_cfb32_putc,
fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins,
FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
+#endif
#ifdef CONFIG_FB_COMPAT_XPMAC
#include <asm/vc_ioctl.h>
u_int transp, struct fb_info *info)
{
struct fb_info_imstt *p = (struct fb_info_imstt *)info;
- unsigned int bpp = fb_display[currcon].var.bits_per_pixel;
- unsigned int i;
+ u_int bpp = fb_display[currcon].var.bits_per_pixel;
+ u_int i;
if (regno > 255)
return 1;
p->palette[regno].blue = blue;
/* PADDRW/PDATA are the same as TVPPADDRW/TVPPDATA */
- if (fb_display[currcon].var.green.length == 5 /* && bpp == 16 */ && p->ramdac == TVP) {
+ if (p->ramdac == TVP && fb_display[currcon].var.green.length == 5 /* && bpp == 16 */) {
p->cmap_regs[PADDRW] = regno << 3; eieio();
} else {
p->cmap_regs[PADDRW] = regno; eieio();
if (fb_display[con].cmap.len)
fb_set_cmap(&fb_display[con].cmap, 1, imsttfb_setcolreg, info);
else {
- int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ u_int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
fb_set_cmap(fb_default_cmap(size), 1, imsttfb_setcolreg, info);
}
}
return 0;
}
+static void
+set_dispsw (struct display *disp, struct fb_info_imstt *p)
+{
+ u_int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
+
+ disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_DIRECTCOLOR;
+ p->dispsw = fbcon_dummy;
+ disp->dispsw = &p->dispsw;
+ disp->dispsw_data = 0;
+ switch (disp->var.bits_per_pixel) {
+ case 8:
+ disp->var.red.offset = 0;
+ disp->var.red.length = 8;
+ disp->var.green.offset = 0;
+ disp->var.green.length = 8;
+ disp->var.blue.offset = 0;
+ disp->var.blue.length = 8;
+ disp->var.transp.offset = 0;
+ disp->var.transp.length = 0;
+#ifdef FBCON_HAS_CFB8
+ p->dispsw = accel ? fbcon_imstt8 : fbcon_cfb8;
+#endif
+ break;
+ case 16: /* RGB 555 */
+ if (disp->var.red.offset != 11)
+ disp->var.red.offset = 10;
+ disp->var.red.length = 5;
+ disp->var.green.offset = 5;
+ if (disp->var.green.length != 6)
+ disp->var.green.length = 5;
+ disp->var.blue.offset = 0;
+ disp->var.blue.length = 5;
+ disp->var.transp.offset = 0;
+ disp->var.transp.length = 0;
+#ifdef FBCON_HAS_CFB16
+ p->dispsw = accel ? fbcon_imstt16 : fbcon_cfb16;
+ disp->dispsw_data = p->fbcon_cmap.cfb16;
+#endif
+ break;
+ case 24: /* RGB 888 */
+ disp->var.red.offset = 16;
+ disp->var.red.length = 8;
+ disp->var.green.offset = 8;
+ disp->var.green.length = 8;
+ disp->var.blue.offset = 0;
+ disp->var.blue.length = 8;
+ disp->var.transp.offset = 0;
+ disp->var.transp.length = 0;
+#ifdef FBCON_HAS_CFB24
+ p->dispsw = accel ? fbcon_imstt24 : fbcon_cfb24;
+ disp->dispsw_data = p->fbcon_cmap.cfb24;
+#endif
+ break;
+ case 32: /* RGBA 8888 */
+ disp->var.red.offset = 16;
+ disp->var.red.length = 8;
+ disp->var.green.offset = 8;
+ disp->var.green.length = 8;
+ disp->var.blue.offset = 0;
+ disp->var.blue.length = 8;
+ disp->var.transp.offset = 24;
+ disp->var.transp.length = 8;
+#ifdef FBCON_HAS_CFB32
+ p->dispsw = accel ? fbcon_imstt32 : fbcon_cfb32;
+ disp->dispsw_data = p->fbcon_cmap.cfb32;
+#endif
+ break;
+ }
+
+ if (p->ramdac == IBM) {
+ p->dispsw.cursor = imsttfb_cursor;
+ p->dispsw.set_font = imsttfb_set_font;
+ }
+}
+
static int
imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
struct fb_info_imstt *p = (struct fb_info_imstt *)info;
struct display *disp;
- unsigned int oldbpp, oldxres, oldyres, oldgreenlen, oldaccel;
- struct imstt_regvals *init;
+ u_int oldbpp, oldxres, oldyres, oldgreenlen, oldaccel;
disp = &fb_display[con];
if (!((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW))
return 0;
- init = compute_imstt_regvals(p, var->xres, var->yres);
- if (!init)
+ if (!compute_imstt_regvals(p, var->xres, var->yres))
return -EINVAL;
oldbpp = disp->var.bits_per_pixel;
disp->var.height = -1;
disp->var.width = -1;
disp->var.vmode = FB_VMODE_NONINTERLACED;
- disp->var.pixclock = 10000;
disp->var.left_margin = disp->var.right_margin = 16;
disp->var.upper_margin = disp->var.lower_margin = 16;
disp->var.hsync_len = disp->var.vsync_len = 8;
disp->ywrapstep = 0;
disp->scrollmode = SCROLL_YREDRAW;
- if (oldbpp != disp->var.bits_per_pixel || oldaccel != disp->var.accel_flags) {
- unsigned int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
-
- disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
- : FB_VISUAL_DIRECTCOLOR;
- disp->dispsw = &fbcon_dummy;
- disp->dispsw_data = 0;
- switch (disp->var.bits_per_pixel) {
- case 8:
- disp->var.red.offset = 0;
- disp->var.red.length = 8;
- disp->var.green.offset = 0;
- disp->var.green.length = 8;
- disp->var.blue.offset = 0;
- disp->var.blue.length = 8;
- disp->var.transp.offset = 0;
- disp->var.transp.length = 0;
-#ifdef FBCON_HAS_CFB8
- disp->dispsw = accel ? &fbcon_imstt8 : &fbcon_cfb8;
-#endif
- break;
- case 16: /* RGB 565 */
- if (disp->var.red.offset != 10 && disp->var.red.offset != 11)
- disp->var.red.offset = 10;
- disp->var.red.length = 5;
- disp->var.green.offset = 5;
- if (disp->var.green.length != 5 && disp->var.green.length != 6)
- disp->var.green.length = 5;
- disp->var.blue.offset = 0;
- disp->var.blue.length = 5;
- disp->var.transp.offset = 0;
- disp->var.transp.length = 0;
-#ifdef FBCON_HAS_CFB16
- disp->dispsw = accel ? &fbcon_imstt16 : &fbcon_cfb16;
- disp->dispsw_data = p->fbcon_cmap.cfb16;
-#endif
- break;
- case 24: /* RGB 888 */
- disp->var.red.offset = 16;
- disp->var.red.length = 8;
- disp->var.green.offset = 8;
- disp->var.green.length = 8;
- disp->var.blue.offset = 0;
- disp->var.blue.length = 8;
- disp->var.transp.offset = 0;
- disp->var.transp.length = 0;
-#ifdef FBCON_HAS_CFB24
- disp->dispsw = accel ? &fbcon_imstt24 : &fbcon_cfb24;
- disp->dispsw_data = p->fbcon_cmap.cfb24;
-#endif
- break;
- case 32: /* RGBA 8888 */
- disp->var.red.offset = 16;
- disp->var.red.length = 8;
- disp->var.green.offset = 8;
- disp->var.green.length = 8;
- disp->var.blue.offset = 0;
- disp->var.blue.length = 8;
- disp->var.transp.offset = 24;
- disp->var.transp.length = 8;
-#ifdef FBCON_HAS_CFB32
- disp->dispsw = accel ? &fbcon_imstt32 : &fbcon_cfb32;
- disp->dispsw_data = p->fbcon_cmap.cfb32;
-#endif
- break;
- }
- }
+ if (oldbpp != disp->var.bits_per_pixel || oldgreenlen != disp->var.green.length || oldaccel != disp->var.accel_flags)
+ set_dispsw(disp, p);
if (oldxres != disp->var.xres || oldbpp != disp->var.bits_per_pixel)
disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
set_555(p);
}
if (oldxres != disp->var.xres || oldyres != disp->var.yres || oldbpp != disp->var.bits_per_pixel)
- set_imstt_regvals(p, init, disp->var.bits_per_pixel);
+ set_imstt_regvals(p, disp->var.bits_per_pixel);
}
+ disp->var.pixclock = 1000000 / getclkMHz(p);
+
if (oldbpp != disp->var.bits_per_pixel) {
int err = fb_alloc_cmap(&disp->cmap, 0, 0);
if (err)
imsttfb_pan_display (struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
struct fb_info_imstt *p = (struct fb_info_imstt *)info;
- unsigned int off;
+ u_int off;
if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
|| var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
else if (fb_display[con].cmap.len) /* non default colormap? */
fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
else {
- int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ u_int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
}
case FBIMSTT_SETCMAPREG:
if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x17c0000 - sizeof(reg[0])) / sizeof(reg[0]))
return -EFAULT;
- out_le32(&((unsigned int *)p->cmap_regs)[reg[0]], reg[1]);
+ out_le32(&((u_int *)p->cmap_regs)[reg[0]], reg[1]);
break;
case FBIMSTT_GETCMAPREG:
if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x17c0000 - sizeof(reg[0])) / sizeof(reg[0]))
return -EFAULT;
- reg[1] = in_le32(&((unsigned int *)p->cmap_regs)[reg[0]]);
+ reg[1] = in_le32(&((u_int *)p->cmap_regs)[reg[0]]);
if (copy_to_user((void *)(arg + 4), ®[1], 4))
return -EFAULT;
break;
static int
imsttfbcon_switch (int con, struct fb_info *info)
{
+ struct fb_info_imstt *p = (struct fb_info_imstt *)info;
struct display *old = &fb_display[currcon], *new = &fb_display[con];
+ if (old->cmap.len)
+ fb_get_cmap(&old->cmap, 1, imsttfb_getcolreg, info);
+
+ if (p->ramdac == IBM)
+ imsttfb_cursor(old, CM_ERASE, p->cursor.x, p->cursor.y);
+
+ currcon = con;
+
if (old->var.xres != new->var.xres
|| old->var.yres != new->var.yres
- || old->var.bits_per_pixel != new->var.bits_per_pixel) {
- struct fb_info_imstt *p = (struct fb_info_imstt *)info;
- struct imstt_regvals *init = compute_imstt_regvals(p, new->var.xres, new->var.yres);
- if (!init) /* ?!? */ return -1;
+ || old->var.bits_per_pixel != new->var.bits_per_pixel
+ || old->var.green.length != new->var.green.length) {
+ set_dispsw(new, p);
+ if (!compute_imstt_regvals(p, new->var.xres, new->var.yres))
+ return -1;
if (new->var.bits_per_pixel == 16) {
if (new->var.green.length == 6)
set_565(p);
else
set_555(p);
}
- set_imstt_regvals(p, init, new->var.bits_per_pixel);
+ set_imstt_regvals(p, new->var.bits_per_pixel);
#ifdef CONFIG_FB_COMPAT_XPMAC
set_display_info(new);
#endif
}
- if (old->cmap.len)
- fb_get_cmap(&old->cmap, 1, imsttfb_getcolreg, info);
- currcon = con;
+
do_install_cmap(con, info);
return 0;
imsttfbcon_updatevar (int con, struct fb_info *info)
{
struct fb_info_imstt *p = (struct fb_info_imstt *)info;
- unsigned int off;
+ u_int off;
if (con == currcon) {
off = fb_display[con].var.yoffset * (fb_display[con].line_length / 8)
if (blank > 0) {
switch (blank - 1) {
case VESA_NO_BLANKING:
- ctrl &= ~0x000000f0;
+ ctrl &= ~0x00000380;
break;
case VESA_VSYNC_SUSPEND:
ctrl &= ~0x00000020;
ctrl &= ~0x00000010;
break;
case VESA_POWERDOWN:
- ctrl &= ~0x000000f0;
+ ctrl &= ~0x00000380;
break;
}
} else {
- ctrl |= p->ramdac == IBM ? 0x000000b0 : 0x00000080;
+ ctrl |= p->ramdac == IBM ? 0x000017b0 : 0x00001780;
}
out_le32(&p->dc_regs[STGCTL], ctrl);
}
-__initfunc(static void init_imstt(struct fb_info_imstt *p))
+__initfunc(static void
+init_imstt(struct fb_info_imstt *p))
{
__u32 i, tmp;
- struct imstt_regvals *init;
- unsigned int accel;
-
- tmp = in_le32(&p->dc_regs[SSTATUS]);
- /* printk("chip version %ld, ", (tmp & 0x0F00) >> 8); */
tmp = in_le32(&p->dc_regs[PRC]);
if (p->ramdac == IBM)
}
}
-#if USE_NV_MODES && (defined(CONFIG_PMAC) || defined(CONFIG_CHRP))
+#if USE_NV_MODES && defined(CONFIG_PPC)
{
int vmode, cmode;
p->disp.var.height = p->disp.var.width = -1;
p->disp.var.vmode = FB_VMODE_NONINTERLACED;
- p->disp.var.pixclock = 10000;
p->disp.var.left_margin = p->disp.var.right_margin = 16;
p->disp.var.upper_margin = p->disp.var.lower_margin = 16;
p->disp.var.hsync_len = p->disp.var.vsync_len = 8;
p->disp.var.accel_flags = 0; /* FB_ACCELF_TEXT; */
- accel = p->disp.var.accel_flags & FB_ACCELF_TEXT;
-
- p->disp.dispsw = &fbcon_dummy;
- p->disp.dispsw_data = 0;
- switch (p->disp.var.bits_per_pixel) {
- case 8:
- p->disp.var.red.offset = 0;
- p->disp.var.red.length = 8;
- p->disp.var.green.offset = 0;
- p->disp.var.green.length = 8;
- p->disp.var.blue.offset = 0;
- p->disp.var.blue.length = 8;
- p->disp.var.transp.offset = 0;
- p->disp.var.transp.length = 0;
-#ifdef FBCON_HAS_CFB8
- p->disp.dispsw = accel ? &fbcon_imstt8 : &fbcon_cfb8;
-#endif
- break;
- case 16: /* RGB 565 */
- if (p->disp.var.red.offset != 10 && p->disp.var.red.offset != 11)
- p->disp.var.red.offset = 10;
- p->disp.var.red.length = 5;
- p->disp.var.green.offset = 5;
- if (p->disp.var.green.length != 5 && p->disp.var.green.length != 6)
- p->disp.var.green.length = 5;
- p->disp.var.blue.offset = 0;
- p->disp.var.blue.length = 5;
- p->disp.var.transp.offset = 0;
- p->disp.var.transp.length = 0;
-#ifdef FBCON_HAS_CFB16
- p->disp.dispsw = accel ? &fbcon_imstt16 : &fbcon_cfb16;
- p->disp.dispsw_data = p->fbcon_cmap.cfb16;
-#endif
- break;
- case 24: /* RGB 888 */
- p->disp.var.red.offset = 16;
- p->disp.var.red.length = 8;
- p->disp.var.green.offset = 8;
- p->disp.var.green.length = 8;
- p->disp.var.blue.offset = 0;
- p->disp.var.blue.length = 8;
- p->disp.var.transp.offset = 0;
- p->disp.var.transp.length = 0;
-#ifdef FBCON_HAS_CFB24
- p->disp.dispsw = accel ? &fbcon_imstt24 : &fbcon_cfb24;
- p->disp.dispsw_data = p->fbcon_cmap.cfb24;
-#endif
- break;
- case 32: /* RGBA 8888 */
- p->disp.var.red.offset = 16;
- p->disp.var.red.length = 8;
- p->disp.var.green.offset = 8;
- p->disp.var.green.length = 8;
- p->disp.var.blue.offset = 0;
- p->disp.var.blue.length = 8;
- p->disp.var.transp.offset = 24;
- p->disp.var.transp.length = 8;
-#ifdef FBCON_HAS_CFB32
- p->disp.dispsw = accel ? &fbcon_imstt32 : &fbcon_cfb32;
- p->disp.dispsw_data = p->fbcon_cmap.cfb32;
-#endif
- break;
- }
+ set_dispsw(&p->disp, p);
+ if (p->ramdac == IBM)
+ imstt_cursor_init(p);
if (p->disp.var.green.length == 6)
set_565(p);
set_555(p);
if ((p->disp.var.xres * p->disp.var.yres) * (p->disp.var.bits_per_pixel >> 3) > p->total_vram
- || !(init = compute_imstt_regvals(p, p->disp.var.xres, p->disp.var.yres))) {
- printk("imsttfb: %dx%dx%d not supported\n", p->disp.var.xres, p->disp.var.yres, p->disp.var.bits_per_pixel);
+ || !(compute_imstt_regvals(p, p->disp.var.xres, p->disp.var.yres))) {
+ printk("imsttfb: %ux%ux%u not supported\n", p->disp.var.xres, p->disp.var.yres, p->disp.var.bits_per_pixel);
kfree(p);
return;
}
- set_imstt_regvals(p, init, p->disp.var.bits_per_pixel);
+ set_imstt_regvals(p, p->disp.var.bits_per_pixel);
+
+ p->disp.var.pixclock = 1000000 / getclkMHz(p);
sprintf(p->fix.id, "IMS TT (%s)", p->ramdac == IBM ? "IBM" : "TVP");
p->fix.smem_start = (__u8 *)p->frame_buffer_phys;
p->info.flags = FBINFO_FLAG_DEFAULT;
for (i = 0; i < 16; i++) {
- unsigned int j = color_table[i];
+ u_int j = color_table[i];
p->palette[i].red = default_red[j];
p->palette[i].green = default_grn[j];
p->palette[i].blue = default_blu[j];
return;
}
- printk("fb%d: %s frame buffer; %uMB vram\n",
- GET_FB_IDX(p->info.node), p->fix.id, p->total_vram >> 20);
+ tmp = (in_le32(&p->dc_regs[SSTATUS]) & 0x0f00) >> 8;
+ printk("fb%d: %s frame buffer; %uMB vram; chip version %u\n",
+ GET_FB_IDX(p->info.node), p->fix.id, p->total_vram >> 20, tmp);
#ifdef CONFIG_FB_COMPAT_XPMAC
strncpy(display_info.name, p->fix.id, sizeof display_info.name);
display_info.cmap_data_address = (__u32)&p->cmap_regs_phys[PDATA];
display_info.disp_reg_address = 0;
set_display_info(&p->disp);
- console_fb_info = &p->info;
+ if (!console_fb_info)
+ console_fb_info = &p->info;
#endif /* CONFIG_FB_COMPAT_XPMAC */
}
-__initfunc(void imsttfb_of_init(struct device_node *dp))
+#if defined(CONFIG_FB_OF) || defined(CONFIG_PPC)
+__initfunc(void
+imsttfb_of_init(struct device_node *dp))
{
struct fb_info_imstt *p;
int i;
init_imstt(p);
}
+#endif
-__initfunc(void imsttfb_init(void))
+__initfunc(void
+imsttfb_init(void))
{
- unsigned int i;
+#if defined(CONFIG_PPC)
+ u_int i;
struct device_node *dp;
char *names[4] = {"IMS,tt128mb","IMS,tt128mbA","IMS,tt128mb8","IMS,tt128mb8A"};
+#ifdef CONFIG_FB_OF
if (prom_num_displays)
return;
+#endif
for (i = 0; i < 4; i++) {
dp = find_devices(names[i]);
if (dp)
imsttfb_of_init(dp);
}
+#else
+ /* ... */
+#endif
}
needed = bdf_prm.b_un.nrefill * size;
while ((nr_free_pages > freepages.min*2) &&
- (buffermem >> PAGE_SHIFT) * 100 < (buffer_mem.max_percent * num_physpages) &&
+ !buffer_over_max() &&
grow_buffers(GFP_BUFFER, size)) {
obtained += PAGE_SIZE;
if (obtained >= needed)
{
struct ext2_group_desc * gdp;
struct buffer_head * bh = NULL;
- int retval = 0;
+ int retval = -EIO;
gdp = ext2_get_group_desc (sb, block_group, NULL);
if (!gdp)
goto error_out;
+ retval = 0;
bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize);
if (!bh) {
ext2_error (sb, "read_block_bitmap",
ext2_debug ("creating next block\n");
de = (struct ext2_dir_entry_2 *) bh->b_data;
- de->inode = le32_to_cpu(0);
+ de->inode = 0;
de->rec_len = le16_to_cpu(sb->s_blocksize);
dir->i_size = offset + sb->s_blocksize;
dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
de = de1;
}
- de->inode = cpu_to_le32(0);
+ de->inode = 0;
de->name_len = namelen;
de->file_type = 0;
memcpy (de->name, name, namelen);
pde->rec_len =
cpu_to_le16(le16_to_cpu(pde->rec_len) +
le16_to_cpu(dir->rec_len));
- dir->inode = le32_to_cpu(0);
+ else
+ dir->inode = 0;
return 0;
}
i += le16_to_cpu(de->rec_len);
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
+#include <linux/smp_lock.h>
#define NLMDBG_FACILITY NLMDBG_CIENT
/* This one ensures that our parent doesn't terminate while the
* reclaim is in progress */
+ lock_kernel();
lockd_up();
/* First, reclaim all locks that have been granted previously. */
/* Release host handle after use */
nlm_release_host(host);
lockd_down();
+ unlock_kernel();
return 0;
}
break;
if (flags & LOOKUP_SLASHOK)
goto return_base;
- dentry = ERR_PTR(-ENOTDIR);
break;
}
dput(base);
return dir;
}
+/*
+ * Special case: O_CREAT|O_EXCL on a dangling symlink should
+ * give EEXIST for security reasons. While inconsistent, this
+ * is the same scheme used by, for example, Solaris 2.5.1. --KAB
+ *
+ * O_DIRECTORY translates into forcing a directory lookup.
+ */
+#define no_follow(f) (((f) & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
+#define opendir(f) ((f) & O_DIRECTORY)
+#define lookup_flags(f) \
+ (no_follow(f) ? 0 : opendir(f) ? (LOOKUP_FOLLOW | LOOKUP_DIRECTORY) : LOOKUP_FOLLOW)
+
/*
* open_namei()
*
mode &= S_IALLUGO & ~current->fs->umask;
mode |= S_IFREG;
- /*
- * Special case: O_CREAT|O_EXCL on a dangling symlink should
- * give EEXIST for security reasons. While inconsistent, this
- * is the same scheme used by, for example, Solaris 2.5.1. --KAB
- */
- dentry = lookup_dentry(pathname, NULL,
- (flag & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL));
+ dentry = lookup_dentry(pathname, NULL, lookup_flags(flag));
if (IS_ERR(dentry))
return dentry;
#include "struct.h"
#include "attr.h"
-#include <errno.h>
+#include <linux/errno.h>
#include "macros.h"
#include "support.h"
#include "util.h"
#include "struct.h"
#include "dir.h"
-#include <errno.h>
+#include <linux/errno.h>
#include "super.h"
#include "inode.h"
#include "attr.h"
#include "struct.h"
#include "inode.h"
-#include <errno.h>
+#include <linux/errno.h>
#include "macros.h"
#include "attr.h"
#include "super.h"
#include "struct.h"
#include "super.h"
-#include <errno.h>
+#include <linux/errno.h>
#include "macros.h"
#include "inode.h"
#include "support.h"
#include "struct.h"
#include "util.h"
-#include <errno.h>
+#include <linux/errno.h>
/* FreeBSD doesn't seem to have EILSEQ in errno.h */
#ifndef EILSEQ
# define EILSEQ EINVAL
extern struct inode_operations proc_scsi_inode_operations;
extern struct proc_dir_entry proc_sys_root;
+#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(proc_sys_root);
+#endif
EXPORT_SYMBOL(proc_register);
EXPORT_SYMBOL(proc_unregister);
EXPORT_SYMBOL(create_proc_entry);
#include "util.h"
#undef UFS_BALLOC_DEBUG
-#undef UFS_BALLOC_DEBUG_MORE
#ifdef UFS_BALLOC_DEBUG
#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
#define UFSD(x)
#endif
-#ifdef UFS_BALLOC_DEBUG_MORE
-#define UFSDM \
-ufs_print_cylinder_stuff (ucg, swab); \
-printk("inode: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nifree), \
-SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nifree), SWAB32(ucg->cg_cs.cs_nifree)); \
-printk("block: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree), \
-SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree), SWAB32(ucg->cg_cs.cs_nbfree)); \
-printk("fragment: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nffree), \
-SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nffree), SWAB32(ucg->cg_cs.cs_nffree)); \
-printk("ndir: total %u, fs %u, cg %u\n\n", SWAB32(usb1->fs_cstotal.cs_ndir), \
-SWAB32(sb->fs_cs(ucpi->c_cgx).cs_ndir), SWAB32(ucg->cg_cs.cs_ndir));
-#else
-#define UFSDM
-#endif
-
-
unsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *);
unsigned ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, unsigned, unsigned);
static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[];
+void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *, unsigned, int);
/*
* Free 'count' fragments from fragment number 'fragment'
goto failed;
}
- UFSDM
-
end_bit = bit + count;
bbase = ufs_blknum (bit);
blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
SUB_SWAB32(ucg->cg_cs.cs_nffree, uspi->s_fpb);
SUB_SWAB32(usb1->fs_cstotal.cs_nffree, uspi->s_fpb);
SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, uspi->s_fpb);
+ if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
+ ufs_clusteracct (sb, ucpi, blkno, 1);
INC_SWAB32(ucg->cg_cs.cs_nbfree);
INC_SWAB32(usb1->fs_cstotal.cs_nbfree);
INC_SWAB32(sb->fs_cs(cgno).cs_nbfree);
INC_SWAB32(ubh_cg_blktot (ucpi, cylno));
}
- UFSDM
-
ubh_mark_buffer_dirty (USPI_UBH, 1);
ubh_mark_buffer_dirty (UCPI_UBH, 1);
if (sb->s_flags & MS_SYNCHRONOUS) {
UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
- ufs_error (sb, "ufs_free_blocks", "internal error");
+ ufs_error (sb, "ufs_free_blocks", "internal error, "
+ "fragment %u, count %u\n", fragment, count);
goto failed;
}
goto failed;
}
- UFSDM
-
for (i = bit; i < end_bit; i += uspi->s_fpb) {
blkno = ufs_fragstoblks(i);
if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
}
ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno);
+ if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
+ ufs_clusteracct (sb, ucpi, blkno, 1);
DQUOT_FREE_BLOCK(sb, inode, uspi->s_fpb);
INC_SWAB32(ucg->cg_cs.cs_nbfree);
INC_SWAB32(usb1->fs_cstotal.cs_nbfree);
INC_SWAB32(ubh_cg_blktot(ucpi, cylno));
}
- UFSDM
-
ubh_mark_buffer_dirty (USPI_UBH, 1);
ubh_mark_buffer_dirty (UCPI_UBH, 1);
if (sb->s_flags & MS_SYNCHRONOUS) {
}
if (fragment < inode->u.ufs_i.i_lastfrag) {
UFSD(("EXIT (ALREADY ALLOCATED)\n"))
- printk("hlaska 2\n");
unlock_super (sb);
return 0;
}
else {
if (tmp) {
UFSD(("EXIT (ALREADY ALLOCATED)\n"))
- printk("hlaska 3, fragment %u, tmp %u, oldcount %u\n", fragment, tmp, oldcount);
unlock_super(sb);
return 0;
}
return 0;
}
- UFSDM
-
fragno = ufs_dtogd (fragment);
fragoff = ufs_fragnum (fragno);
for (i = oldcount; i < newcount; i++)
SUB_SWAB32(ucg->cg_cs.cs_nffree, count);
SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, count);
SUB_SWAB32(usb1->fs_cstotal.cs_nffree, count);
- usb1->fs_fmod = SWAB32(1);
-
- UFSDM
ubh_mark_buffer_dirty (USPI_UBH, 1);
ubh_mark_buffer_dirty (UCPI_UBH, 1);
"internal error, bad magic number on cg %u", cgno);
ucg->cg_time = SWAB32(CURRENT_TIME);
- UFSDM
-
if (count == uspi->s_fpb) {
result = ufs_alloccg_block (inode, ucpi, goal, err);
if (result == (unsigned)-1)
INC_SWAB32(ucg->cg_frsum[allocsize - count]);
succed:
- usb1->fs_fmod = SWAB32(1);
-
- UFSDM
-
ubh_mark_buffer_dirty (USPI_UBH, 1);
ubh_mark_buffer_dirty (UCPI_UBH, 1);
if (sb->s_flags & MS_SYNCHRONOUS) {
goto gotit;
}
- /*** This function should be optimized later ***/
-
norot:
result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb);
if (result == (unsigned)-1)
ucpi->c_rotor = result;
gotit:
blkno = ufs_fragstoblks(result);
- ubh_clrblock(UCPI_UBH, ucpi->c_freeoff, blkno);
+ ubh_clrblock (UCPI_UBH, ucpi->c_freeoff, blkno);
+ if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
+ ufs_clusteracct (sb, ucpi, blkno, -1);
if(DQUOT_ALLOC_BLOCK(sb, inode, uspi->s_fpb)) {
*err = -EDQUOT;
return (unsigned)-1;
cylno = ufs_cbtocylno(result);
DEC_SWAB16(ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result)));
DEC_SWAB32(ubh_cg_blktot(ucpi, cylno));
- usb1->fs_fmod = 1;
UFSD(("EXIT, result %u\n", result))
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
struct ufs_cylinder_group * ucg;
- unsigned start, length, length2, location, result;
+ unsigned start, length, location, result;
unsigned possition, fragsize, blockmap, mask;
unsigned swab;
(uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
1 << (count - 1 + (uspi->s_fpb & 7)));
if (location == 0) {
- length2 = start + 1;
- location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff, length2,
+ length = start + 1;
+ location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff, length,
(uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
1 << (count - 1 + (uspi->s_fpb & 7)));
if (location == 0) {
return (unsigned)-1;
}
start = 0;
- length = length2;
}
result = (start + length - location) << 3;
ucpi->c_frotor = result;
return (unsigned)-1;
}
+void ufs_clusteracct(struct super_block * sb,
+ struct ufs_cg_private_info * ucpi, unsigned blkno, int cnt)
+{
+ struct ufs_sb_private_info * uspi;
+ int i, start, end, forw, back;
+ unsigned swab;
+
+
+ uspi = sb->u.ufs_sb.s_uspi;
+ swab = sb->u.ufs_sb.s_swab;
+
+ if (uspi->s_contigsumsize <= 0)
+ return;
+
+ if (cnt > 0)
+ ubh_setbit(UCPI_UBH, ucpi->c_clusteroff, blkno);
+ else
+ ubh_clrbit(UCPI_UBH, ucpi->c_clusteroff, blkno);
+
+ /*
+ * Find the size of the cluster going forward.
+ */
+ start = blkno + 1;
+ end = start + uspi->s_contigsumsize;
+ if ( end >= ucpi->c_nclusterblks)
+ end = ucpi->c_nclusterblks;
+ i = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_clusteroff, end, start);
+ if (i > end)
+ i = end;
+ forw = i - start;
+
+ /*
+ * Find the size of the cluster going backward.
+ */
+ start = blkno - 1;
+ end = start - uspi->s_contigsumsize;
+ if (end < 0 )
+ end = -1;
+ i = ubh_find_last_zero_bit (UCPI_UBH, ucpi->c_clusteroff, start, end);
+ if ( i < end)
+ i = end;
+ back = start - i;
+
+ /*
+ * Account for old cluster and the possibly new forward and
+ * back clusters.
+ */
+ i = back + forw + 1;
+ if (i > uspi->s_contigsumsize)
+ i = uspi->s_contigsumsize;
+ ADD_SWAB32(*((u32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (i << 2))), cnt);
+ if (back > 0)
+ SUB_SWAB32(*((u32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (back << 2))), cnt);
+ if (forw > 0)
+ SUB_SWAB32(*((u32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (forw << 2))), cnt);
+}
+
+
static unsigned char ufs_fragtable_8fpb[] = {
0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
#include "util.h"
#undef UFS_CYLINDER_DEBUG
-#undef UFS_CYLINDER_DEBUG_MORE
#ifdef UFS_CYLINDER_DEBUG
#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
ucpi = sb->u.ufs_sb.s_ucpi[bitmap_nr];
ucg = (struct ufs_cylinder_group *)sb->u.ufs_sb.s_ucg[cgno]->b_data;
-#ifdef UFS_CYLINDER_DEBUG_MORE
- ufs_print_cylinder_stuff (ucg, swab);
-#endif
-
UCPI_UBH->fragment = ufs_cgcmin(cgno);
UCPI_UBH->count = uspi->s_cgsize >> sb->s_blocksize_bits;
/*
ucpi->c_iusedoff = SWAB32(ucg->cg_iusedoff);
ucpi->c_freeoff = SWAB32(ucg->cg_freeoff);
ucpi->c_nextfreeoff = SWAB32(ucg->cg_nextfreeoff);
-
+ ucpi->c_clustersumoff = SWAB32(ucg->cg_u.cg_44.cg_clustersumoff);
+ ucpi->c_clusteroff = SWAB32(ucg->cg_u.cg_44.cg_clusteroff);
+ ucpi->c_nclusterblks = SWAB32(ucg->cg_u.cg_44.cg_nclusterblks);
UFSD(("EXIT\n"))
return;
sb->u.ufs_sb.s_cg_loaded++;
else
ufs_put_cylinder (sb, UFS_MAX_GROUP_LOADED-1);
+ ucpi = sb->u.ufs_sb.s_ucpi[sb->u.ufs_sb.s_cg_loaded - 1];
for (j = sb->u.ufs_sb.s_cg_loaded - 1; j > 0; j--) {
sb->u.ufs_sb.s_cgno[j] = sb->u.ufs_sb.s_cgno[j-1];
sb->u.ufs_sb.s_ucpi[j] = sb->u.ufs_sb.s_ucpi[j-1];
}
+ sb->u.ufs_sb.s_ucpi[0] = ucpi;
ufs_read_cylinder (sb, cgno, 0);
}
UFSD(("EXIT\n"))
* 4.4BSD (FreeBSD) support added on February 1st 1998 by
* Niels Kristian Bech Jensen <nkbj@image.dk> partially based
* on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
- *
- * write support by Daniel Pirkl <daniel.pirkl@email.cz> 1998
*/
#include <linux/fs.h>
&& offset < sb->s_blocksize) {
de = (struct ufs_dir_entry *) (bh->b_data + offset);
/* XXX - put in a real ufs_check_dir_entry() */
- if ((de->d_reclen == 0) || (ufs_namlen(de) == 0)) {
+ if ((de->d_reclen == 0) || (ufs_get_de_namlen(de) == 0)) {
/* SWAB16() was unneeded -- compare to 0 */
filp->f_pos = (filp->f_pos &
- (sb->s_blocksize - 1)) +
- sb->s_blocksize;
+ (sb->s_blocksize - 1)) +
+ sb->s_blocksize;
brelse(bh);
return stored;
}
/* On error, skip the f_pos to the
next block. */
filp->f_pos = (filp->f_pos &
- (sb->s_blocksize - 1)) +
+ (sb->s_blocksize - 1)) +
sb->s_blocksize;
brelse (bh);
return stored;
unsigned long version = inode->i_version;
UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)))
- UFSD(("namlen %u\n", ufs_namlen(de)))
- error = filldir(dirent, de->d_name, ufs_namlen(de),
+ UFSD(("namlen %u\n", ufs_get_de_namlen(de)))
+ error = filldir(dirent, de->d_name, ufs_get_de_namlen(de),
filp->f_pos, SWAB32(de->d_ino));
if (error)
break;
error_msg = "reclen is smaller than minimal";
else if (SWAB16(de->d_reclen) % 4 != 0)
error_msg = "reclen % 4 != 0";
- else if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(ufs_namlen(de)))
+ else if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(ufs_get_de_namlen(de)))
error_msg = "reclen is too small for namlen";
else if (dir && ((char *) de - bh->b_data) + SWAB16(de->d_reclen) >
dir->i_sb->s_blocksize)
"offset=%lu, inode=%lu, reclen=%d, namlen=%d",
dir->i_ino, dir->i_size, error_msg, offset,
(unsigned long) SWAB32(de->d_ino),
- SWAB16(de->d_reclen), ufs_namlen(de));
+ SWAB16(de->d_reclen), ufs_get_de_namlen(de));
return (error_msg == NULL ? 1 : 0);
}
#include "util.h"
#undef UFS_IALLOC_DEBUG
-#undef UFS_IALLOC_DEBUG_MORE
#ifdef UFS_IALLOC_DEBUG
#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
#define UFSD(x)
#endif
-#ifdef UFS_IALLOC_DEBUG_MORE
-#define UFSDM \
-ufs_print_cylinder_stuff (ucg, swab); \
-printk("inode: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nifree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nifree), SWAB32(ucg->cg_cs.cs_nifree)); \
-printk("block: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree), SWAB32(ucg->cg_cs.cs_nbfree)); \
-printk("fragment: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nffree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nffree), SWAB32(ucg->cg_cs.cs_nffree)); \
-printk("ndir: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_ndir), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_ndir), SWAB32(ucg->cg_cs.cs_ndir));
-#else
-#define UFSDM
-#endif
-
-
/*
* NOTE! When we get the inode, we're the only people
* that have access to it, and as such there are no
if (!ufs_cg_chkmagic(ucg))
ufs_panic (sb, "ufs_free_fragments", "internal error, bad cg magic number");
- UFSDM
-
ucg->cg_time = SWAB32(CURRENT_TIME);
is_directory = S_ISDIR(inode->i_mode);
ubh_wait_on_buffer (UCPI_UBH);
}
- UFSDM
-
sb->s_dirt = 1;
unlock_super (sb);
UFSD(("EXIT\n"))
if (!ufs_cg_chkmagic(ucg))
ufs_panic (sb, "ufs_new_inode", "internal error, bad cg magic number");
- UFSDM
-
start = ucpi->c_irotor;
bit = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_iusedoff, uspi->s_ipg, start);
if (!(bit < uspi->s_ipg)) {
insert_inode_hash(inode);
mark_inode_dirty(inode);
- UFSDM
-
unlock_super (sb);
if(DQUOT_ALLOC_INODE(sb, inode)) {
* direct fragment
*/
if (fragment < UFS_NDIR_FRAGMENT)
- return ufs_inode_bmap (inode, fragment);
+ return (uspi->s_sbbase + ufs_inode_bmap (inode, fragment));
/*
* indirect fragment
UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift));
if (!tmp)
return 0;
- return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
- fragment & uspi->s_apbmask, uspi, swab);
+ return (uspi->s_sbbase +
+ ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
+ fragment & uspi->s_apbmask, uspi, swab));
}
/*
UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift));
if (!tmp)
return 0;
- tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+ tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
(fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
if (!tmp)
return 0;
- return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
- fragment & uspi->s_apbmask, uspi, swab);
+ return (uspi->s_sbbase +
+ ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
+ fragment & uspi->s_apbmask, uspi, swab));
}
/*
UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift));
if (!tmp)
return 0;
- tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+ tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
(fragment >> uspi->s_2apbshift) & uspi->s_apbmask, uspi, swab);
if (!tmp)
return 0;
- tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+ tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
(fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
if (!tmp)
return 0;
- return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
- fragment & uspi->s_apbmask, uspi, swab);
+ return (uspi->s_sbbase +
+ ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
+ fragment & uspi->s_apbmask, uspi, swab));
}
static struct buffer_head * ufs_inode_getfrag (struct inode * inode,
tmp = SWAB32(*p);
lastfrag = inode->u.ufs_i.i_lastfrag;
if (tmp && fragment < lastfrag) {
- result = getblk (sb->s_dev, tmp + blockoff, sb->s_blocksize);
+ result = getblk (sb->s_dev, uspi->s_sbbase + tmp + blockoff, sb->s_blocksize);
if (tmp == SWAB32(*p)) {
UFSD(("EXIT, result %u\n", tmp + blockoff))
return result;
repeat:
tmp = SWAB32(*p);
if (tmp) {
- result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
+ result = getblk (bh->b_dev, uspi->s_sbbase + tmp + blockoff, sb->s_blocksize);
if (tmp == SWAB32(*p)) {
brelse (bh);
UFSD(("EXIT, result %u\n", tmp + blockoff))
tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err);
if (!tmp) {
if (SWAB32(*p)) {
- printk("REPEAT\n");
goto repeat;
}
else {
return;
}
- bh = bread (sb->s_dev, ufs_inotofsba(inode->i_ino), sb->s_blocksize);
+ bh = bread (sb->s_dev, uspi->s_sbbase + ufs_inotofsba(inode->i_ino), sb->s_blocksize);
if (!bh) {
ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
return;
* Linux has only 16-bit uid and gid, so we can't support EFT.
* Files are dynamically chown()ed to root.
*/
- inode->i_uid = ufs_uid(ufs_inode);
+ inode->i_uid = inode->u.ufs_i.i_uid = ufs_get_inode_uid(ufs_inode);
+ inode->i_gid = inode->u.ufs_i.i_gid = ufs_get_inode_gid(ufs_inode);
if (inode->i_uid == UFS_USEEFT) {
inode->i_uid = 0;
}
inode->u.ufs_i.i_flags = SWAB32(ufs_inode->ui_flags);
inode->u.ufs_i.i_gen = SWAB32(ufs_inode->ui_gen);
inode->u.ufs_i.i_shadow = SWAB32(ufs_inode->ui_u3.ui_sun.ui_shadow);
- inode->u.ufs_i.i_uid = SWAB32(ufs_inode->ui_u3.ui_sun.ui_uid);
- inode->u.ufs_i.i_gid = SWAB32(ufs_inode->ui_u3.ui_sun.ui_gid);
inode->u.ufs_i.i_oeftflag = SWAB32(ufs_inode->ui_u3.ui_sun.ui_oeftflag);
inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize);
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
- else if (S_ISSOCK(inode->i_mode))
- ; /* nothing */
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
struct buffer_head * bh;
struct ufs_inode * ufs_inode;
unsigned i;
- unsigned swab;
+ unsigned flags, swab;
UFSD(("ENTER, ino %lu\n", inode->i_ino))
sb = inode->i_sb;
uspi = sb->u.ufs_sb.s_uspi;
+ flags = sb->u.ufs_sb.s_flags;
swab = sb->u.ufs_sb.s_swab;
if (inode->i_ino < UFS_ROOTINO ||
ufs_inode->ui_mode = SWAB16(inode->i_mode);
ufs_inode->ui_nlink = SWAB16(inode->i_nlink);
- if (inode->i_uid == 0 && inode->u.ufs_i.i_uid >= UFS_USEEFT) {
- ufs_inode->ui_u3.ui_sun.ui_uid = SWAB32(inode->u.ufs_i.i_uid);
- ufs_inode->ui_u1.oldids.ui_suid = (__u16)ufs_inode->ui_u3.ui_sun.ui_uid;
- }
- else {
- ufs_inode->ui_u1.oldids.ui_suid = SWAB16(inode->i_uid);
- ufs_inode->ui_u3.ui_sun.ui_uid = (__u32) ufs_inode->ui_u1.oldids.ui_suid;
- }
- if (inode->i_gid == 0 && inode->u.ufs_i.i_gid >= UFS_USEEFT) {
- ufs_inode->ui_u3.ui_sun.ui_gid = SWAB32(inode->u.ufs_i.i_gid);
- ufs_inode->ui_u1.oldids.ui_sgid = (__u16)ufs_inode->ui_u3.ui_sun.ui_gid;
- }
- else {
- ufs_inode->ui_u1.oldids.ui_sgid = SWAB16(inode->i_gid);
- ufs_inode->ui_u3.ui_sun.ui_gid = (__u32) ufs_inode->ui_u1.oldids.ui_sgid;
- }
+ if (inode->i_uid == 0 && inode->u.ufs_i.i_uid >= UFS_USEEFT)
+ ufs_set_inode_uid (ufs_inode, inode->u.ufs_i.i_uid);
+ else
+ ufs_set_inode_uid (ufs_inode, inode->i_uid);
+
+ if (inode->i_gid == 0 && inode->u.ufs_i.i_gid >= UFS_USEEFT)
+ ufs_set_inode_gid (ufs_inode, inode->u.ufs_i.i_gid);
+ else
+ ufs_set_inode_gid (ufs_inode, inode->i_gid);
ufs_inode->ui_size = SWAB64((u64)inode->i_size);
ufs_inode->ui_atime.tv_sec = SWAB32(inode->i_atime);
/*
* "" means "." ---> so paths like "/usr/lib//libc.a" work
*/
- if (!len && ufs_namlen(de) == 1 && (de->d_name[0] == '.') &&
+ if (!len && ufs_get_de_namlen(de) == 1 && (de->d_name[0] == '.') &&
(de->d_name[1] == '\0'))
return 1;
- if (len != ufs_namlen(de))
+ if (len != ufs_get_de_namlen(de))
return 0;
return !memcmp(name, de->d_name, len);
}
de = (struct ufs_dir_entry *) (bh->b_data + fragoff);
de->d_ino = SWAB32(0);
de->d_reclen = SWAB16(UFS_SECTOR_SIZE);
- de->d_u.d_namlen = SWAB16(0);
+ ufs_set_de_namlen(de,0);
dir->i_size = offset + UFS_SECTOR_SIZE;
mark_inode_dirty(dir);
} else {
return NULL;
}
if ((SWAB32(de->d_ino) == 0 && SWAB16(de->d_reclen) >= rec_len) ||
- (SWAB16(de->d_reclen) >= UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)) + rec_len)) {
+ (SWAB16(de->d_reclen) >= UFS_DIR_REC_LEN(ufs_get_de_namlen(de)) + rec_len)) {
offset += SWAB16(de->d_reclen);
if (SWAB32(de->d_ino)) {
de1 = (struct ufs_dir_entry *) ((char *) de +
- UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)));
+ UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));
de1->d_reclen = SWAB16(SWAB16(de->d_reclen) -
- UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)));
- de->d_reclen = SWAB16(UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)));
+ UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));
+ de->d_reclen = SWAB16(UFS_DIR_REC_LEN(ufs_get_de_namlen(de)));
de = de1;
}
de->d_ino = SWAB32(0);
- de->d_u.d_namlen = SWAB16(namelen);
+ ufs_set_de_namlen(de, namelen);
memcpy (de->d_name, name, namelen + 1);
/*
* XXX shouldn't update any times until successful
de = (struct ufs_dir_entry *) bh->b_data;
UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(de->d_ino),
- SWAB16(de->d_reclen), ufs_namlen(de), de->d_name))
+ SWAB16(de->d_reclen), ufs_get_de_namlen(de), de->d_name))
while (i < bh->b_size) {
if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i))
struct buffer_head * bh;
struct ufs_dir_entry * de;
int err = -EIO;
- unsigned swab;
+ unsigned flags, swab;
sb = dir->i_sb;
swab = sb->u.ufs_sb.s_swab;
-
+ flags = sb->u.ufs_sb.s_flags;
/*
* N.B. Several error exits in ufs_new_inode don't set err.
*/
return err;
}
de->d_ino = SWAB32(inode->i_ino);
+ ufs_set_de_type (de, inode->i_mode);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
struct buffer_head * bh;
struct ufs_dir_entry * de;
int err = -EIO;
- unsigned swab;
+ unsigned flags, swab;
sb = dir->i_sb;
+ flags = sb->u.ufs_sb.s_flags;
swab = sb->u.ufs_sb.s_swab;
err = -ENAMETOOLONG;
if (!bh)
goto out_no_entry;
de->d_ino = SWAB32(inode->i_ino);
+ ufs_set_de_type (de, inode->i_mode);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
struct buffer_head * bh, * dir_block;
struct ufs_dir_entry * de;
int err;
- unsigned swab;
+ unsigned flags, swab;
sb = dir->i_sb;
+ flags = sb->u.ufs_sb.s_flags;
swab = sb->u.ufs_sb.s_swab;
err = -ENAMETOOLONG;
inode->i_blocks = sb->s_blocksize / UFS_SECTOR_SIZE;
de = (struct ufs_dir_entry *) dir_block->b_data;
de->d_ino = SWAB32(inode->i_ino);
- de->d_u.d_namlen = SWAB16(1);
+ ufs_set_de_type (de, inode->i_mode);
+ ufs_set_de_namlen(de,1);
de->d_reclen = SWAB16(UFS_DIR_REC_LEN(1));
strcpy (de->d_name, ".");
de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
de->d_ino = SWAB32(dir->i_ino);
+ ufs_set_de_type (de, dir->i_mode);
de->d_reclen = SWAB16(UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1));
- de->d_u.d_namlen = SWAB16(2);
+ ufs_set_de_namlen(de,2);
strcpy (de->d_name, "..");
inode->i_nlink = 2;
mark_buffer_dirty(dir_block, 1);
if (!bh)
goto out_no_entry;
de->d_ino = SWAB32(inode->i_ino);
+ ufs_set_de_type (de, inode->i_mode);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) ||
!(bh = ufs_bread (inode, 0, 0, &err))) {
- ufs_warning (inode->i_sb, "empty_dir",
+ ufs_warning (inode->i_sb, "empty_dir",
"bad directory (dir #%lu) - no data block",
inode->i_ino);
return 1;
de1 = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
if (SWAB32(de->d_ino) != inode->i_ino || !SWAB32(de1->d_ino) ||
strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) {
- ufs_warning (inode->i_sb, "empty_dir",
+ ufs_warning (inode->i_sb, "empty_dir",
"bad directory (dir #%lu) - no `.' or `..'",
inode->i_ino);
return 1;
if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
brelse (bh);
bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err);
- if (!bh) {
+ if (!bh) {
ufs_error (sb, "empty_dir",
"directory #%lu contains a hole at offset %lu",
inode->i_ino, offset);
retval = -ENOENT;
bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
UFSD(("de: ino %u, reclen %u, namelen %u, name %s\n", SWAB32(de->d_ino),
- SWAB16(de->d_reclen), ufs_namlen(de), de->d_name))
+ SWAB16(de->d_reclen), ufs_get_de_namlen(de), de->d_name))
if (!bh)
goto end_unlink;
UFSD(("name %s, len %u\n", old_dentry->d_name.name, old_dentry->d_name.len))
old_bh = ufs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(old_de->d_ino),
- SWAB16(old_de->d_reclen), ufs_namlen(old_de), old_de->d_name))
+ SWAB16(old_de->d_reclen), ufs_get_de_namlen(old_de), old_de->d_name))
retval = -ENOENT;
if (!old_bh)
/*
+ * linux/fs/ufs/super.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ */
+
+/* Derivated from
+ *
+ * linux/fs/ext2/super.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/inode.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+/*
+ * Inspirated by
+ *
* linux/fs/ufs/super.c
*
* Copyright (C) 1996
*
*/
+
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
+#include <stdarg.h>
+
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ufs_fs.h>
-#include <linux/locks.h>
-#include <asm/uaccess.h>
#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
#include "swab.h"
#include "util.h"
-
#undef UFS_SUPER_DEBUG
#undef UFS_SUPER_DEBUG_MORE
struct ufs_super_block_second * usb2,
struct ufs_super_block_third * usb3, unsigned swab)
{
- printk("\nufs_print_super_stuff\n");
- printk("size of usb: %lu\n", sizeof(struct ufs_super_block));
- printk(" magic: 0x%x\n", SWAB32(usb3->fs_magic));
- printk(" sblkno: %u\n", SWAB32(usb1->fs_sblkno));
- printk(" cblkno: %u\n", SWAB32(usb1->fs_cblkno));
- printk(" iblkno: %u\n", SWAB32(usb1->fs_iblkno));
- printk(" dblkno: %u\n", SWAB32(usb1->fs_dblkno));
- printk(" cgoffset: %u\n", SWAB32(usb1->fs_cgoffset));
- printk(" ~cgmask: 0x%x\n", ~SWAB32(usb1->fs_cgmask));
- printk(" size: %u\n", SWAB32(usb1->fs_size));
- printk(" dsize: %u\n", SWAB32(usb1->fs_dsize));
- printk(" ncg: %u\n", SWAB32(usb1->fs_ncg));
- printk(" bsize: %u\n", SWAB32(usb1->fs_bsize));
- printk(" fsize: %u\n", SWAB32(usb1->fs_fsize));
- printk(" frag: %u\n", SWAB32(usb1->fs_frag));
- printk(" fragshift: %u\n", SWAB32(usb1->fs_fragshift));
- printk(" ~fmask: %u\n", ~SWAB32(usb1->fs_fmask));
- printk(" fshift: %u\n", SWAB32(usb1->fs_fshift));
- printk(" sbsize: %u\n", SWAB32(usb1->fs_sbsize));
- printk(" spc: %u\n", SWAB32(usb1->fs_spc));
- printk(" cpg: %u\n", SWAB32(usb1->fs_cpg));
- printk(" ipg: %u\n", SWAB32(usb1->fs_ipg));
- printk(" fpg: %u\n", SWAB32(usb1->fs_fpg));
- printk(" csaddr: %u\n", SWAB32(usb1->fs_csaddr));
- printk(" cssize: %u\n", SWAB32(usb1->fs_cssize));
- printk(" cgsize: %u\n", SWAB32(usb1->fs_cgsize));
- printk(" fstodb: %u\n", SWAB32(usb1->fs_fsbtodb));
- printk(" postblformat: %u\n", SWAB32(usb3->fs_postblformat));
- printk(" nrpos: %u\n", SWAB32(usb3->fs_nrpos));
- printk(" ndir %u\n", SWAB32(usb1->fs_cstotal.cs_ndir));
- printk(" nifree %u\n", SWAB32(usb1->fs_cstotal.cs_nifree));
- printk(" nbfree %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree));
- printk(" nffree %u\n", SWAB32(usb1->fs_cstotal.cs_nffree));
+ printk("ufs_print_super_stuff\n");
+ printk("size of usb: %u\n", sizeof(struct ufs_super_block));
+ printk(" magic: 0x%x\n", SWAB32(usb3->fs_magic));
+ printk(" sblkno: %u\n", SWAB32(usb1->fs_sblkno));
+ printk(" cblkno: %u\n", SWAB32(usb1->fs_cblkno));
+ printk(" iblkno: %u\n", SWAB32(usb1->fs_iblkno));
+ printk(" dblkno: %u\n", SWAB32(usb1->fs_dblkno));
+ printk(" cgoffset: %u\n", SWAB32(usb1->fs_cgoffset));
+ printk(" ~cgmask: 0x%x\n", ~SWAB32(usb1->fs_cgmask));
+ printk(" size: %u\n", SWAB32(usb1->fs_size));
+ printk(" dsize: %u\n", SWAB32(usb1->fs_dsize));
+ printk(" ncg: %u\n", SWAB32(usb1->fs_ncg));
+ printk(" bsize: %u\n", SWAB32(usb1->fs_bsize));
+ printk(" fsize: %u\n", SWAB32(usb1->fs_fsize));
+ printk(" frag: %u\n", SWAB32(usb1->fs_frag));
+ printk(" fragshift: %u\n", SWAB32(usb1->fs_fragshift));
+ printk(" ~fmask: %u\n", ~SWAB32(usb1->fs_fmask));
+ printk(" fshift: %u\n", SWAB32(usb1->fs_fshift));
+ printk(" sbsize: %u\n", SWAB32(usb1->fs_sbsize));
+ printk(" spc: %u\n", SWAB32(usb1->fs_spc));
+ printk(" cpg: %u\n", SWAB32(usb1->fs_cpg));
+ printk(" ipg: %u\n", SWAB32(usb1->fs_ipg));
+ printk(" fpg: %u\n", SWAB32(usb1->fs_fpg));
+ printk(" csaddr: %u\n", SWAB32(usb1->fs_csaddr));
+ printk(" cssize: %u\n", SWAB32(usb1->fs_cssize));
+ printk(" cgsize: %u\n", SWAB32(usb1->fs_cgsize));
+ printk(" fstodb: %u\n", SWAB32(usb1->fs_fsbtodb));
+ printk(" contigsumsize: %d\n", SWAB32(usb3->fs_u.fs_44.fs_contigsumsize));
+ printk(" postblformat: %u\n", SWAB32(usb3->fs_postblformat));
+ printk(" nrpos: %u\n", SWAB32(usb3->fs_nrpos));
+ printk(" ndir %u\n", SWAB32(usb1->fs_cstotal.cs_ndir));
+ printk(" nifree %u\n", SWAB32(usb1->fs_cstotal.cs_nifree));
+ printk(" nbfree %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree));
+ printk(" nffree %u\n", SWAB32(usb1->fs_cstotal.cs_nffree));
+ printk("\n");
}
void ufs_print_cylinder_stuff(struct ufs_cylinder_group *cg, unsigned swab)
{
printk("\nufs_print_cylinder_stuff\n");
- printk("size of ucg: %lu\n", sizeof(struct ufs_cylinder_group));
- printk(" magic: %x\n", SWAB32(cg->cg_magic));
- printk(" time: %u\n", SWAB32(cg->cg_time));
- printk(" cgx: %u\n", SWAB32(cg->cg_cgx));
- printk(" ncyl: %u\n", SWAB16(cg->cg_ncyl));
- printk(" niblk: %u\n", SWAB16(cg->cg_niblk));
- printk(" ndblk: %u\n", SWAB32(cg->cg_ndblk));
- printk(" cs_ndir: %u\n", SWAB32(cg->cg_cs.cs_ndir));
- printk(" cs_nbfree: %u\n", SWAB32(cg->cg_cs.cs_nbfree));
- printk(" cs_nifree: %u\n", SWAB32(cg->cg_cs.cs_nifree));
- printk(" cs_nffree: %u\n", SWAB32(cg->cg_cs.cs_nffree));
- printk(" rotor: %u\n", SWAB32(cg->cg_rotor));
- printk(" frotor: %u\n", SWAB32(cg->cg_frotor));
- printk(" irotor: %u\n", SWAB32(cg->cg_irotor));
- printk(" frsum: %u, %u, %u, %u, %u, %u, %u, %u\n",
+ printk("size of ucg: %u\n", sizeof(struct ufs_cylinder_group));
+ printk(" magic: %x\n", SWAB32(cg->cg_magic));
+ printk(" time: %u\n", SWAB32(cg->cg_time));
+ printk(" cgx: %u\n", SWAB32(cg->cg_cgx));
+ printk(" ncyl: %u\n", SWAB16(cg->cg_ncyl));
+ printk(" niblk: %u\n", SWAB16(cg->cg_niblk));
+ printk(" ndblk: %u\n", SWAB32(cg->cg_ndblk));
+ printk(" cs_ndir: %u\n", SWAB32(cg->cg_cs.cs_ndir));
+ printk(" cs_nbfree: %u\n", SWAB32(cg->cg_cs.cs_nbfree));
+ printk(" cs_nifree: %u\n", SWAB32(cg->cg_cs.cs_nifree));
+ printk(" cs_nffree: %u\n", SWAB32(cg->cg_cs.cs_nffree));
+ printk(" rotor: %u\n", SWAB32(cg->cg_rotor));
+ printk(" frotor: %u\n", SWAB32(cg->cg_frotor));
+ printk(" irotor: %u\n", SWAB32(cg->cg_irotor));
+ printk(" frsum: %u, %u, %u, %u, %u, %u, %u, %u\n",
SWAB32(cg->cg_frsum[0]), SWAB32(cg->cg_frsum[1]),
SWAB32(cg->cg_frsum[2]), SWAB32(cg->cg_frsum[3]),
SWAB32(cg->cg_frsum[4]), SWAB32(cg->cg_frsum[5]),
SWAB32(cg->cg_frsum[6]), SWAB32(cg->cg_frsum[7]));
- printk(" btotoff: %u\n", SWAB32(cg->cg_btotoff));
- printk(" boff: %u\n", SWAB32(cg->cg_boff));
- printk(" iuseoff: %u\n", SWAB32(cg->cg_iusedoff));
- printk(" freeoff: %u\n", SWAB32(cg->cg_freeoff));
- printk(" nextfreeoff: %u\n", SWAB32(cg->cg_nextfreeoff));
+ printk(" btotoff: %u\n", SWAB32(cg->cg_btotoff));
+ printk(" boff: %u\n", SWAB32(cg->cg_boff));
+ printk(" iuseoff: %u\n", SWAB32(cg->cg_iusedoff));
+ printk(" freeoff: %u\n", SWAB32(cg->cg_freeoff));
+ printk(" nextfreeoff: %u\n", SWAB32(cg->cg_nextfreeoff));
+ printk(" clustersumoff %u\n", SWAB32(cg->cg_u.cg_44.cg_clustersumoff));
+ printk(" clusteroff %u\n", SWAB32(cg->cg_u.cg_44.cg_clusteroff));
+ printk(" nclusterblks %u\n", SWAB32(cg->cg_u.cg_44.cg_nclusterblks));
+ printk("\n");
}
#endif /* UFS_SUPER_DEBUG_MORE */
+static char error_buf[1024];
+
+void ufs_error (struct super_block * sb, const char * function,
+ const char * fmt, ...)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ va_list args;
+
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+
+ if (!(sb->s_flags & MS_RDONLY)) {
+ usb1->fs_clean = UFS_FSBAD;
+ ubh_mark_buffer_dirty(USPI_UBH, 1);
+ sb->s_dirt = 1;
+ sb->s_flags |= MS_RDONLY;
+ }
+ va_start (args, fmt);
+ vsprintf (error_buf, fmt, args);
+ va_end (args);
+ 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);
+
+ 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);
+ }
+}
+
+void ufs_panic (struct super_block * sb, const char * function,
+ const char * fmt, ...)
+{
+ struct ufs_sb_private_info * uspi;
+ struct ufs_super_block_first * usb1;
+ va_list args;
+
+ uspi = sb->u.ufs_sb.s_uspi;
+ usb1 = ubh_get_usb_first(USPI_UBH);
+
+ if (!(sb->s_flags & MS_RDONLY)) {
+ usb1->fs_clean = UFS_FSBAD;
+ ubh_mark_buffer_dirty(USPI_UBH, 1);
+ sb->s_dirt = 1;
+ }
+ va_start (args, fmt);
+ vsprintf (error_buf, fmt, args);
+ va_end (args);
+ /* this is to prevent panic from syncing this filesystem */
+ if (sb->s_lock)
+ sb->s_lock = 0;
+ sb->s_flags |= MS_RDONLY;
+ printk (KERN_CRIT "UFS-fs panic (device %s): %s: %s\n",
+ kdevname(sb->s_dev), function, error_buf);
+/***
+ panic ("UFS-fs panic (device %s): %s: %s\n",
+ kdevname(sb->s_dev), function, error_buf);
+***/
+}
+
+void ufs_warning (struct super_block * sb, const char * function,
+ const char * fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ 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);
+}
+
+static int ufs_parse_options (char * options, unsigned * mount_options)
+{
+ char * this_char;
+ char * value;
+
+ UFSD(("ENTER\n"))
+
+ if (!options)
+ return 1;
+
+ for (this_char = strtok (options, ",");
+ this_char != NULL;
+ this_char = strtok (NULL, ",")) {
+
+ if ((value = strchr (this_char, '=')) != NULL)
+ *value++ = 0;
+ if (!strcmp (this_char, "ufstype")) {
+ ufs_clear_opt (*mount_options, UFSTYPE);
+ if (!strcmp (value, "old"))
+ ufs_set_opt (*mount_options, UFSTYPE_OLD);
+ else if (!strcmp (value, "sun"))
+ ufs_set_opt (*mount_options, UFSTYPE_SUN);
+ else if (!strcmp (value, "44bsd"))
+ ufs_set_opt (*mount_options, UFSTYPE_44BSD);
+ else if (!strcmp (value, "next"))
+ ufs_set_opt (*mount_options, UFSTYPE_NEXT);
+ else {
+ printk ("UFS-fs: Invalid type option: %s\n", value);
+ return 0;
+ }
+ }
+ else if (!strcmp (this_char, "onerror")) {
+ ufs_clear_opt (*mount_options, ONERROR);
+ if (!strcmp (value, "panic"))
+ ufs_set_opt (*mount_options, ONERROR_PANIC);
+ else if (!strcmp (value, "lock"))
+ ufs_set_opt (*mount_options, ONERROR_LOCK);
+ else if (!strcmp (value, "umount"))
+ ufs_set_opt (*mount_options, ONERROR_UMOUNT);
+ else if (!strcmp (value, "repair")) {
+ printk("UFS-fs: Unable to do repair on error, "
+ "will lock lock instead \n");
+ ufs_set_opt (*mount_options, ONERROR_REPAIR);
+ }
+ else {
+ printk ("UFS-fs: Invalid action onerror: %s\n", value);
+ return 0;
+ }
+ }
+ else {
+ printk("UFS-fs: Invalid option: %s\n", this_char);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * Read on-disk structures asscoiated with cylinder groups
+ */
+int ufs_read_cylinder_structures (struct super_block * sb) {
+ struct ufs_sb_private_info * uspi;
+ struct ufs_buffer_head * ubh;
+ unsigned char * base, * space;
+ unsigned size, blks, i;
+ unsigned swab;
+
+ UFSD(("ENTER\n"))
+
+ uspi = sb->u.ufs_sb.s_uspi;
+ swab = sb->u.ufs_sb.s_swab;
+
+ /*
+ * Read cs structures from (usually) first data block
+ * on the device.
+ */
+ size = uspi->s_cssize;
+ blks = howmany(size, uspi->s_fsize);
+ base = space = kmalloc(size, GFP_KERNEL);
+ if (!base)
+ goto failed;
+ for (i = 0; i < blks; i += uspi->s_fpb) {
+ size = uspi->s_bsize;
+ if (i + uspi->s_fpb > blks)
+ size = (blks - i) * uspi->s_fsize;
+ ubh = ubh_bread(sb->s_dev, uspi->s_csaddr + i, size);
+ if (!ubh)
+ goto failed;
+ ubh_ubhcpymem (space, ubh, size);
+ sb->u.ufs_sb.s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space;
+ space += size;
+ ubh_brelse (ubh);
+ ubh = NULL;
+ }
+
+ /*
+ * Read cylinder group (we read only first fragment from block
+ * at this time) and prepare internal data structures for cg caching.
+ */
+ if (!(sb->u.ufs_sb.s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL)))
+ goto failed;
+ for (i = 0; i < uspi->s_ncg; i++)
+ sb->u.ufs_sb.s_ucg[i] = NULL;
+ for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
+ sb->u.ufs_sb.s_ucpi[i] = NULL;
+ sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
+ }
+ for (i = 0; i < uspi->s_ncg; i++) {
+ UFSD(("read cg %u\n", i))
+ if (!(sb->u.ufs_sb.s_ucg[i] = bread (sb->s_dev, ufs_cgcmin(i), sb->s_blocksize)))
+ goto failed;
+ if (!ufs_cg_chkmagic ((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data))
+ goto failed;
+#ifdef UFS_SUPER_DEBUG_MORE
+ ufs_print_cylinder_stuff((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data, swab);
+#endif
+ }
+ for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
+ if (!(sb->u.ufs_sb.s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
+ goto failed;
+ sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
+ }
+ sb->u.ufs_sb.s_cg_loaded = 0;
+ UFSD(("EXIT\n"))
+ return 1;
+
+failed:
+ if (base) kfree (base);
+ if (sb->u.ufs_sb.s_ucg) {
+ for (i = 0; i < uspi->s_ncg; i++)
+ if (sb->u.ufs_sb.s_ucg[i]) brelse (sb->u.ufs_sb.s_ucg[i]);
+ kfree (sb->u.ufs_sb.s_ucg);
+ for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
+ if (sb->u.ufs_sb.s_ucpi[i]) kfree (sb->u.ufs_sb.s_ucpi[i]);
+ }
+ UFSD(("EXIT (FAILED)\n"))
+ return 0;
+}
+
/*
- * Called while file system is mounted, read super block
- * and create important internal structures.
+ * Put on-disk structures associated with cylidner groups and
+ * write them back to disk
*/
-struct super_block * ufs_read_super (
- struct super_block * sb,
- void * data,
+void ufs_put_cylinder_structures (struct super_block * sb) {
+ struct ufs_sb_private_info * uspi;
+ struct ufs_buffer_head * ubh;
+ unsigned char * base, * space;
+ unsigned blks, size, i;
+
+ UFSD(("ENTER\n"))
+
+ uspi = sb->u.ufs_sb.s_uspi;
+
+ size = uspi->s_cssize;
+ blks = howmany(size, uspi->s_fsize);
+ base = space = (char*) sb->u.ufs_sb.s_csp[0];
+ for (i = 0; i < blks; i += uspi->s_fpb) {
+ size = uspi->s_bsize;
+ if (i + uspi->s_fpb > blks)
+ size = (blks - i) * uspi->s_fsize;
+ ubh = ubh_bread (sb->s_dev, uspi->s_csaddr + i, size);
+ ubh_memcpyubh (ubh, space, size);
+ space += size;
+ ubh_mark_buffer_uptodate (ubh, 1);
+ ubh_mark_buffer_dirty (ubh, 0);
+ ubh_brelse (ubh);
+ }
+ for (i = 0; i < sb->u.ufs_sb.s_cg_loaded; i++) {
+ ufs_put_cylinder (sb, i);
+ kfree (sb->u.ufs_sb.s_ucpi[i]);
+ }
+ for (; i < UFS_MAX_GROUP_LOADED; i++)
+ kfree (sb->u.ufs_sb.s_ucpi[i]);
+ for (i = 0; i < uspi->s_ncg; i++)
+ brelse (sb->u.ufs_sb.s_ucg[i]);
+ kfree (sb->u.ufs_sb.s_ucg);
+ kfree (base);
+ UFSD(("EXIT\n"))
+}
+
+struct super_block * ufs_read_super (struct super_block * sb, void * data,
int silent)
{
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
struct ufs_super_block_second * usb2;
struct ufs_super_block_third * usb3;
- struct ufs_buffer_head * ubh;
- unsigned char * base, * space;
- unsigned size, blks, i;
+ struct ufs_buffer_head * ubh;
unsigned block_size, super_block_size;
unsigned flags, swab;
- s64 tmp;
- static unsigned offsets[] = {0, 96, 160}; /* different superblock locations */
-
- UFSD(("ENTER\n"))
-
+
uspi = NULL;
ubh = NULL;
- base = space = NULL;
- sb->u.ufs_sb.s_ucg = NULL;
flags = 0;
+ swab = 0;
- /* sb->s_dev and sb->s_flags are set by our caller
- * data is the mystery argument to sys_mount()
- *
- * Our caller also sets s_dev, s_covered, s_rd_only, s_dirt,
- * and s_type when we return.
- */
-
+ UFSD(("ENTER\n"))
+
MOD_INC_USE_COUNT;
lock_super (sb);
- sb->u.ufs_sb.s_uspi = uspi =
+ /*
+ * Set default mount options
+ * Parse mount options
+ */
+ sb->u.ufs_sb.s_mount_opt = 0;
+ ufs_set_opt (sb->u.ufs_sb.s_mount_opt, ONERROR_LOCK);
+ if (!ufs_parse_options ((char *) data, &sb->u.ufs_sb.s_mount_opt)) {
+ printk("wrong mount options\n");
+ goto failed;
+ }
+ if (!(sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE)) {
+ printk("You didn't specify type of your ufs file system\n\n"
+ " mount -t ufs -o ufstype=sun|44bsd|old|next ....\n\n"
+ "!!! WARNING !!! wrong value may corrupt you file system\n"
+ "default value is ufstype=old\n");
+ ufs_set_opt (sb->u.ufs_sb.s_mount_opt, UFSTYPE_OLD);
+ }
+
+ sb->u.ufs_sb.s_uspi = uspi =
kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL);
if (!uspi)
goto failed;
+
+ switch (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) {
+ case UFS_MOUNT_UFSTYPE_44BSD:
+ UFSD(("44bsd ufstype\n"))
+ uspi->s_fsize = block_size = 512;
+ uspi->s_fmask = ~(512 - 1);
+ uspi->s_fshift = 9;
+ uspi->s_sbsize = super_block_size = 1536;
+ uspi->s_sbbase = 0;
+ flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
+ break;
+
+ case UFS_MOUNT_UFSTYPE_SUN:
+ UFSD(("sun ufstype\n"))
+ uspi->s_fsize = block_size = 1024;
+ uspi->s_fmask = ~(1024 - 1);
+ uspi->s_fshift = 10;
+ uspi->s_sbsize = super_block_size = 2048;
+ uspi->s_sbbase = 0;
+ flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN;
+ break;
+
+ case UFS_MOUNT_UFSTYPE_OLD:
+ UFSD(("old ufstype\n"))
+ uspi->s_fsize = block_size = 1024;
+ uspi->s_fmask = ~(1024 - 1);
+ uspi->s_fshift = 10;
+ uspi->s_sbsize = super_block_size = 2048;
+ uspi->s_sbbase = 0;
+ flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
+ if (!(sb->s_flags & MS_RDONLY)) {
+ printk("old type of ufs is supported read-only\n");
+ goto failed;
+ }
+ break;
- block_size = BLOCK_SIZE;
- super_block_size = BLOCK_SIZE * 2;
+ case UFS_MOUNT_UFSTYPE_NEXT:
+ UFSD(("next ufstype\n"))
+ uspi->s_fsize = block_size = 1024;
+ uspi->s_fmask = ~(1024 - 1);
+ uspi->s_fshift = 10;
+ uspi->s_sbsize = super_block_size = 2048;
+ uspi->s_sbbase = 0;
+ flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
+ if (!(sb->s_flags & MS_RDONLY)) {
+ printk("nextstep type of ufs is supported read-only\n");
+ goto failed;
+ }
+ break;
- uspi->s_fsize = block_size;
- uspi->s_fmask = ~(BLOCK_SIZE - 1);
- uspi->s_fshift = BLOCK_SIZE_BITS;
- uspi->s_sbsize = super_block_size;
- i = 0;
- uspi->s_sbbase = offsets[i];
-again:
+ default:
+ printk("this fs type of ufs is not supported\n");
+ goto failed;
+ }
+
+ if (!(sb->s_flags & MS_RDONLY))
+ printk("!!! warning !!! write support of ufs is still in experimental state\n");
+
+again:
set_blocksize (sb->s_dev, block_size);
/*
* read ufs super block from device
*/
- ubh = ubh_bread2 (sb->s_dev, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
+ ubh = ubh_bread_uspi (uspi, sb->s_dev, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
if (!ubh)
goto failed;
usb1 = ubh_get_usb_first(USPI_UBH);
usb2 = ubh_get_usb_second(USPI_UBH);
usb3 = ubh_get_usb_third(USPI_UBH);
-
+
/*
* Check ufs magic number
- * This code uses goto, because it's a lesser evil than unbalanced
- * structure in conditional code. Brought to you by Fare' as a minimal
- * hack to live with Daniel's (unnecessary, IMNSHO) manual swab
- * optimization -- see swab.h.
*/
#if defined(__LITTLE_ENDIAN) || defined(__BIG_ENDIAN) /* sane bytesex */
switch (usb3->fs_magic) {
goto magic_found;
}
#endif
- /*
- * Magic number not found -- try another super block location
- */
- if (++i < sizeof(offsets)/sizeof(unsigned)) {
- ubh_brelse2(ubh);
+
+ if ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) ==
+ UFS_MOUNT_UFSTYPE_NEXT && uspi->s_sbbase < 256) {
+ ubh_brelse_uspi(uspi);
ubh = NULL;
- uspi->s_sbbase = offsets[i];
+ uspi->s_sbbase += 8;
goto again;
- } else {
- printk("ufs_read_super: "
- "super block location not in "
- "{ 0, 96, 160} "
- "or bad magic number\n");
- goto failed;
}
- magic_found:
+ printk("ufs_read_super: bad magic number\n");
+ goto failed;
+magic_found:
/*
* Check block and fragment sizes
*/
uspi->s_bsize = SWAB32(usb1->fs_bsize);
uspi->s_fsize = SWAB32(usb1->fs_fsize);
uspi->s_sbsize = SWAB32(usb1->fs_sbsize);
+ uspi->s_fmask = SWAB32(usb1->fs_fmask);
+ uspi->s_fshift = SWAB32(usb1->fs_fshift);
if (uspi->s_bsize != 4096 && uspi->s_bsize != 8192) {
- printk("ufs_read_super: fs_bsize %u != {4096, 8192}\n",
- uspi->s_bsize);
+ printk("ufs_read_super: fs_bsize %u != {4096, 8192}\n", uspi->s_bsize);
goto failed;
}
if (uspi->s_fsize != 512 && uspi->s_fsize != 1024) {
- printk("ufs_read_super: fs_fsize %u != {512, 1024}\n",
- uspi->s_fsize);
+ printk("ufs_read_super: fs_fsize %u != {512, 1024}\n", uspi->s_fsize);
goto failed;
}
-
- /*
- * Block size is not 1024. Free buffers, set block_size and
- * super_block_size to superblock-declared values, and try again.
- */
if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) {
- ubh_brelse2(ubh);
+ ubh_brelse_uspi(uspi);
ubh = NULL;
- uspi->s_fmask = SWAB32(usb1->fs_fmask);
- uspi->s_fshift = SWAB32(usb1->fs_fshift);
block_size = uspi->s_fsize;
super_block_size = uspi->s_sbsize;
+ UFSD(("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size))
goto again;
}
#ifdef UFS_SUPER_DEBUG_MORE
ufs_print_super_stuff (usb1, usb2, usb3, swab);
#endif
- /*
- * Check file system flavor
- */
- flags |= UFS_VANILLA;
- /* XXX more consistency check */
- UFSD(("ufs_read_super: maxsymlinklen 0x%8.8x\n", usb3->fs_u.fs_44.fs_maxsymlinklen))
- if (usb3->fs_u.fs_44.fs_maxsymlinklen >= 0) {
- if (usb3->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) {
- UFSD(("Flavor: 44BSD\n"))
- flags |= UFS_44BSD;
- sb->s_flags |= MS_RDONLY;
- } else {
- UFSD(("Flavor: OLD\n"))
- sb->s_flags |= UFS_OLD; /* 4.2BSD */
- }
- } else if (uspi->s_sbbase > 0) {
- UFSD(("Flavor: NEXT\n"))
- flags |= UFS_NEXT;
- sb->s_flags |= MS_RDONLY;
- } else {
- UFSD(("Flavor: SUN\n"))
- flags |= UFS_SUN;
- }
/*
- * Check whether file system was correctly unmounted.
+ * Check, if file system was correctly unmounted.
* If not, make it read only.
*/
if (((flags & UFS_ST_MASK) == UFS_ST_44BSD) ||
((flags & UFS_ST_MASK) == UFS_ST_OLD) ||
- ((flags & UFS_ST_MASK) == UFS_ST_NEXT) ||
- (((flags & UFS_ST_MASK) == UFS_ST_SUN) &&
- ufs_state(usb3) == UFS_FSOK - usb1->fs_time)) {
+ (((flags & UFS_ST_MASK) == UFS_ST_SUN) &&
+ (ufs_get_fs_state(usb3) == (UFS_FSOK - SWAB32(usb1->fs_time))))) {
switch(usb1->fs_clean) {
- case UFS_FSACTIVE: /* 0x00 */
- printk("ufs_read_super: fs is active\n");
- sb->s_flags |= MS_RDONLY;
- break;
- case UFS_FSCLEAN: /* 0x01 */
- UFSD(("ufs_read_super: fs is clean\n"))
+ case UFS_FSCLEAN:
+ UFSD(("fs is clean\n"))
break;
case UFS_FSSTABLE:
- UFSD(("ufs_read_super: fs is stable\n"))
+ UFSD(("fs is stable\n"))
break;
- case UFS_FSOSF1: /* 0x03 */
- /* XXX - is this the correct interpretation under DEC OSF/1? */
- printk("ufs_read_super: "
- "fs is clean and stable (OSF/1)\n");
+ case UFS_FSACTIVE:
+ printk("ufs_read_super: fs is active\n");
+ sb->s_flags |= MS_RDONLY;
break;
- case UFS_FSBAD: /* 0xFF */
+ case UFS_FSBAD:
printk("ufs_read_super: fs is bad\n");
sb->s_flags |= MS_RDONLY;
break;
sb->s_flags |= MS_RDONLY;
break;
}
- } else {
+ }
+ else {
printk("ufs_read_super: fs needs fsck\n");
sb->s_flags |= MS_RDONLY;
}
- sb->s_flags &= ~MS_RDONLY;
/*
* Read ufs_super_block into internal data structures
*/
sb->s_blocksize = SWAB32(usb1->fs_fsize);
sb->s_blocksize_bits = SWAB32(usb1->fs_fshift);
sb->s_op = &ufs_super_ops;
- sb->dq_op = 0; /* XXX */
+ sb->dq_op = NULL; /***/
sb->s_magic = SWAB32(usb3->fs_magic);
uspi->s_sblkno = SWAB32(usb1->fs_sblkno);
uspi->s_ipg = SWAB32(usb1->fs_ipg);
uspi->s_fpg = SWAB32(usb1->fs_fpg);
uspi->s_cpc = SWAB32(usb2->fs_cpc);
- ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qbmask[0];
- ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qbmask[1];
- uspi->s_qbmask = SWAB64(tmp);
- ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qfmask[0];
- ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qfmask[1];
- uspi->s_qfmask = SWAB64(tmp);
+ uspi->s_contigsumsize = SWAB32(usb3->fs_u.fs_44.fs_contigsumsize);
+ uspi->s_qbmask = ufs_get_fs_qbmask(usb3);
+ uspi->s_qfmask = ufs_get_fs_qfmask(usb3);
uspi->s_postblformat = SWAB32(usb3->fs_postblformat);
uspi->s_nrpos = SWAB32(usb3->fs_nrpos);
uspi->s_postbloff = SWAB32(usb3->fs_postbloff);
uspi->s_nspfshift = uspi->s_fshift - UFS_SECTOR_BITS;
uspi->s_nspb = uspi->s_nspf << uspi->s_fpbshift;
uspi->s_inopf = uspi->s_inopb >> uspi->s_fpbshift;
-
- /* we could merge back s_swab and s_flags by having
- foo.s_flags = flags | swab; here, and #defining
- s_swab to s_flags & UFS_BYTESEX in swab.h */
+ uspi->s_bpf = uspi->s_fsize << 3;
+ uspi->s_bpfshift = uspi->s_fshift + 3;
+ uspi->s_bpfmask = uspi->s_bpf - 1;
+
sb->u.ufs_sb.s_flags = flags;
sb->u.ufs_sb.s_swab = swab;
sb->u.ufs_sb.s_rename_lock = 0;
sb->u.ufs_sb.s_rename_wait = NULL;
-
+
sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
- /*
- * Read cs structures from (usually) first data block
- * on the device.
- */
- size = uspi->s_cssize;
- blks = howmany(size, uspi->s_fsize);
- base = space = kmalloc(size, GFP_KERNEL);
- if (!base)
- goto failed;
- for (i = 0; i < blks; i += uspi->s_fpb) {
- size = uspi->s_bsize;
- if (i + uspi->s_fpb > blks)
- size = (blks - i) * uspi->s_fsize;
- ubh = ubh_bread(sb->s_dev, uspi->s_csaddr + i, size);
- if (!ubh)
- goto failed;
- ubh_ubhcpymem (space, ubh, size);
- sb->u.ufs_sb.s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space;
- space += size;
- ubh_brelse (ubh);
- ubh = NULL;
- }
/*
- * Read cylinder group (we read only first fragment from block
- * at this time) and prepare internal data structures for cg caching.
- * XXX - something here fails on CDROMs from DEC!
+ * Read cylinder group structures
*/
- if (!(sb->u.ufs_sb.s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL)))
- goto failed;
- for (i = 0; i < uspi->s_ncg; i++)
- sb->u.ufs_sb.s_ucg[i] = NULL;
- for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
- sb->u.ufs_sb.s_ucpi[i] = NULL;
- sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
- }
- for (i = 0; i < uspi->s_ncg; i++) {
- UFSD(("read cg %u\n", i))
- if (!(sb->u.ufs_sb.s_ucg[i] = bread (sb->s_dev, ufs_cgcmin(i), sb->s_blocksize)))
- goto failed;
- if (!ufs_cg_chkmagic ((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data))
- goto failed;
-#ifdef UFS_SUPER_DEBUG_MORE
- ufs_print_cylinder_stuff((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data, swab);
-#endif
- }
- for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
- if (!(sb->u.ufs_sb.s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
+ if (!(sb->s_flags & MS_RDONLY))
+ if (!ufs_read_cylinder_structures(sb))
goto failed;
- sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
- }
- sb->u.ufs_sb.s_cg_loaded = 0;
unlock_super(sb);
UFSD(("EXIT\n"))
return(sb);
failed:
- if (ubh) ubh_brelse2 (ubh);
+ if (ubh) ubh_brelse_uspi (uspi);
if (uspi) kfree (uspi);
- if (base) kfree (base);
-
- if (sb->u.ufs_sb.s_ucg) {
- for (i = 0; i < uspi->s_ncg; i++)
- if (sb->u.ufs_sb.s_ucg[i]) brelse (sb->u.ufs_sb.s_ucg[i]);
- kfree (sb->u.ufs_sb.s_ucg);
- for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
- if (sb->u.ufs_sb.s_ucpi[i]) kfree (sb->u.ufs_sb.s_ucpi[i]);
- }
sb->s_dev = 0;
unlock_super (sb);
MOD_DEC_USE_COUNT;
return(NULL);
}
-/*
- * Put super block, release internal structures
- */
-void ufs_put_super (struct super_block * sb)
-{
- struct ufs_sb_private_info * uspi;
- struct ufs_buffer_head * ubh;
- unsigned char * base, * space;
- unsigned size, blks, i;
-
- UFSD(("ENTER\n"))
-
- uspi = sb->u.ufs_sb.s_uspi;
- size = uspi->s_cssize;
- blks = howmany(size, uspi->s_fsize);
- base = space = (char*) sb->u.ufs_sb.s_csp[0];
- for (i = 0; i < blks; i += uspi->s_fpb) {
- size = uspi->s_bsize;
- if (i + uspi->s_fpb > blks)
- size = (blks - i) * uspi->s_fsize;
- ubh = ubh_bread (sb->s_dev, uspi->s_csaddr + i, size);
- if (!ubh)
- goto go_on;
- ubh_memcpyubh (ubh, space, size);
- space += size;
- ubh_mark_buffer_uptodate (ubh, 1);
- ubh_mark_buffer_dirty (ubh, 0);
- ubh_brelse (ubh);
- }
-
-go_on:
- for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
- ufs_put_cylinder (sb, i);
- kfree (sb->u.ufs_sb.s_ucpi[i]);
- }
- for (i = 0; i < uspi->s_ncg; i++)
- brelse (sb->u.ufs_sb.s_ucg[i]);
- kfree (sb->u.ufs_sb.s_ucg);
- kfree (base);
- ubh_brelse2 (USPI_UBH);
- kfree (sb->u.ufs_sb.s_uspi);
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return;
-}
-
-/*
- * Write super block to device
- */
void ufs_write_super (struct super_block * sb) {
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
struct ufs_super_block_third * usb3;
- unsigned swab;
-
+ unsigned flags, swab;
+
UFSD(("ENTER\n"))
swab = sb->u.ufs_sb.s_swab;
+ flags = sb->u.ufs_sb.s_flags;
uspi = sb->u.ufs_sb.s_uspi;
usb1 = ubh_get_usb_first(USPI_UBH);
usb3 = ubh_get_usb_third(USPI_UBH);
-
+
if (!(sb->s_flags & MS_RDONLY)) {
- if (SWAB16(usb3->fs_u.fs_sun.fs_state) & UFS_FSOK)
- usb3->fs_u.fs_sun.fs_state = SWAB16(SWAB16(usb3->fs_u.fs_sun.fs_state) & ~UFS_FSOK);
usb1->fs_time = SWAB32(CURRENT_TIME);
- usb3->fs_u.fs_sun.fs_state = SWAB32(UFS_FSOK - SWAB32(usb1->fs_time));
+ if (usb1->fs_clean == UFS_FSCLEAN && (flags&UFS_ST_MASK) == UFS_ST_SUN)
+ ufs_set_fs_state(usb3, UFS_FSOK - SWAB32(usb1->fs_time));
ubh_mark_buffer_dirty (USPI_UBH, 1);
}
sb->s_dirt = 0;
UFSD(("EXIT\n"))
}
-/*
- * Copy some info about file system to user
- */
-int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
+void ufs_put_super (struct super_block * sb)
{
struct ufs_sb_private_info * uspi;
- struct ufs_super_block_first * usb1;
- struct statfs tmp;
- struct statfs *sp = &tmp;
- unsigned long used, avail;
unsigned swab;
-
+
UFSD(("ENTER\n"))
-
- swab = sb->u.ufs_sb.s_swab;
- uspi = sb->u.ufs_sb.s_uspi;
- usb1 = ubh_get_usb_first (USPI_UBH);
- sp->f_type = UFS_MAGIC;
- sp->f_bsize = sb->s_blocksize;
- sp->f_blocks = uspi->s_dsize;
- sp->f_bfree = (SWAB32(usb1->fs_cstotal.cs_nbfree) << uspi->s_fpbshift )+
- SWAB32(usb1->fs_cstotal.cs_nffree);
+ uspi = sb->u.ufs_sb.s_uspi;
+ swab = sb->u.ufs_sb.s_swab;
- avail = sp->f_blocks - (sp->f_blocks / 100) * uspi->s_minfree;
- used = sp->f_blocks - sp->f_bfree;
- if (avail > used)
- sp->f_bavail = avail - used;
- else
- sp->f_bavail = 0;
- sp->f_files = uspi->s_ncg * uspi->s_ipg;
- sp->f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree);
- sp->f_fsid.val[0] = SWAB32(usb1->fs_id[0]);
- sp->f_fsid.val[1] = SWAB32(usb1->fs_id[1]);
- sp->f_namelen = UFS_MAXNAMLEN;
+ if (!(sb->s_flags & MS_RDONLY))
+ ufs_put_cylinder_structures (sb);
- UFSD(("EXIT\n"))
-
- return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0;
+ ubh_brelse_uspi (uspi);
+ kfree (sb->u.ufs_sb.s_uspi);
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+ return;
}
-static char error_buf[1024];
-
-void ufs_warning (struct super_block * sb, const char * function,
- const char * fmt, ...)
-{
- va_list args;
-
- va_start (args, fmt);
- 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);
-}
-
-void ufs_error (struct super_block * sb, const char * function,
- const char * fmt, ...)
+int ufs_remount (struct super_block * sb, int * mount_flags, char * data)
{
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
- va_list args;
-
+ struct ufs_super_block_third * usb3;
+ unsigned new_mount_opt, ufstype;
+ unsigned flags, swab;
+
uspi = sb->u.ufs_sb.s_uspi;
+ flags = sb->u.ufs_sb.s_flags;
+ swab = sb->u.ufs_sb.s_swab;
usb1 = ubh_get_usb_first(USPI_UBH);
+ usb3 = ubh_get_usb_third(USPI_UBH);
- if (!(sb->s_flags & MS_RDONLY)) {
- usb1->fs_clean = UFS_FSBAD;
- ubh_mark_buffer_dirty(USPI_UBH, 1);
- sb->s_dirt = 1;
+ /*
+ * Allow the "check" option to be passed as a remount option.
+ * It is not possible to change ufstype option during remount
+ */
+ ufstype = sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE;
+ new_mount_opt = 0;
+ ufs_set_opt (new_mount_opt, ONERROR_LOCK);
+ if (!ufs_parse_options (data, &new_mount_opt))
+ return -EINVAL;
+ if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) {
+ new_mount_opt |= ufstype;
+ }
+ else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) {
+ printk("ufstype can't be changed during remount\n");
+ return -EINVAL;
+ }
+ sb->u.ufs_sb.s_mount_opt = new_mount_opt;
+
+ if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+ return 0;
+ if (*mount_flags & MS_RDONLY) {
+ ufs_put_cylinder_structures(sb);
+ usb1->fs_time = SWAB32(CURRENT_TIME);
+ if (usb1->fs_clean == UFS_FSCLEAN && (flags&UFS_ST_MASK) == UFS_ST_SUN)
+ ufs_set_fs_state(usb3, UFS_FSOK - SWAB32(usb1->fs_time));
+ ubh_mark_buffer_dirty (USPI_UBH, 1);
+ sb->s_dirt = 0;
sb->s_flags |= MS_RDONLY;
}
- va_start (args, fmt);
- vsprintf (error_buf, fmt, args);
- va_end (args);
- printk (KERN_CRIT "UFS-fs error (device %s): %s: %s\n",
- kdevname(sb->s_dev), function, error_buf);
+ else {
+ if (ufstype != UFS_MOUNT_UFSTYPE_SUN &&
+ ufstype != UFS_MOUNT_UFSTYPE_44BSD) {
+ printk("this ufstype is read-only supported\n");
+ return 0;
+ }
+ if (!ufs_read_cylinder_structures (sb)) {
+ printk("failed during remounting\n");
+ return 0;
+ }
+ sb->s_flags &= ~MS_RDONLY;
+ }
+ return 0;
}
-void ufs_panic (struct super_block * sb, const char * function,
- const char * fmt, ...)
+int ufs_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
{
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
- va_list args;
-
+ struct statfs tmp;
+ unsigned swab;
+
+ swab = sb->u.ufs_sb.s_swab;
uspi = sb->u.ufs_sb.s_uspi;
- usb1 = ubh_get_usb_first(USPI_UBH);
+ usb1 = ubh_get_usb_first (USPI_UBH);
- if (!(sb->s_flags & MS_RDONLY)) {
- usb1->fs_clean = UFS_FSBAD;
- ubh_mark_buffer_dirty(USPI_UBH, 1);
- sb->s_dirt = 1;
- }
- va_start (args, fmt);
- vsprintf (error_buf, fmt, args);
- va_end (args);
- /* this is to prevent panic from syncing this filesystem */
- if (sb->s_lock)
- sb->s_lock = 0;
- sb->s_flags |= MS_RDONLY;
- printk (KERN_CRIT "UFS-fs panic (device %s): %s: %s\n",
- kdevname(sb->s_dev), function, error_buf);
-/* panic ("UFS-fs panic (device %s): %s: %s\n",
- kdevname(sb->s_dev), function, error_buf);
-*/
+ tmp.f_type = UFS_MAGIC;
+ tmp.f_bsize = sb->s_blocksize;
+ tmp.f_blocks = uspi->s_dsize;
+ tmp.f_bfree = ufs_blkstofrags(SWAB32(usb1->fs_cstotal.cs_nbfree)) +
+ SWAB32(usb1->fs_cstotal.cs_nffree);
+ tmp.f_bavail = (tmp.f_bfree > ((tmp.f_blocks / 100) * uspi->s_minfree))
+ ? (tmp.f_bfree - ((tmp.f_blocks / 100) * uspi->s_minfree)) : 0;
+ tmp.f_files = uspi->s_ncg * uspi->s_ipg;
+ tmp.f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree);
+ tmp.f_namelen = UFS_MAXNAMLEN;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
-
static struct super_operations ufs_super_ops = {
ufs_read_inode,
ufs_write_inode,
ufs_put_super,
ufs_write_super,
ufs_statfs,
- NULL, /* XXX - ufs_remount() */
+ ufs_remount
};
static struct file_system_type ufs_fs_type = {
- "ufs",
+ "ufs",
FS_REQUIRES_DEV,
ufs_read_super,
NULL
};
-
__initfunc(int init_ufs_fs(void))
{
- return(register_filesystem(&ufs_fs_type));
+ return register_filesystem(&ufs_fs_type);
}
#ifdef MODULE
{
unregister_filesystem(&ufs_fs_type);
}
-#endif
+#endif
return NULL;
}
-struct ufs_buffer_head * _ubh_bread2_ (struct ufs_sb_private_info * uspi,
+struct ufs_buffer_head * ubh_bread_uspi (struct ufs_sb_private_info * uspi,
kdev_t dev, unsigned fragment, unsigned size)
{
unsigned i, j, count;
kfree (ubh);
}
-void ubh_brelse2 (struct ufs_buffer_head * ubh)
+void ubh_brelse_uspi (struct ufs_sb_private_info * uspi)
{
unsigned i;
- if (!ubh)
+ if (!USPI_UBH)
return;
- for ( i = 0; i < ubh->count; i++ ) {
- brelse (ubh->bh[i]);
- ubh->bh[i] = NULL;
+ for ( i = 0; i < USPI_UBH->count; i++ ) {
+ brelse (USPI_UBH->bh[i]);
+ USPI_UBH->bh[i] = NULL;
}
}
for ( i = 0; i < ubh->count; i++ )
if ( ubh->bh[i]->b_count > max )
max = ubh->bh[i]->b_count;
- if (max == 0)
- printk("Je cosi shnileho v kralovstvi Danskem!\n");
return max;
}
#define max(x,y) ((x)>(y)?(x):(y))
+
/*
- * current filesystem state; method depends on flags
+ * macros used for retyping
*/
-#define ufs_state(usb3) \
- (((flags & UFS_ST_MASK) == UFS_ST_OLD) \
- ? (usb3)->fs_u.fs_sun.fs_state /* old normal way */ \
- : (usb3)->fs_u.fs_44.fs_state /* 4.4BSD way */)
+#define UCPI_UBH ((struct ufs_buffer_head *)ucpi)
+#define USPI_UBH ((struct ufs_buffer_head *)uspi)
+
+
/*
- * namlen, its format depends of flags
+ * macros used for accesing structures
*/
-#define ufs_namlen(de) _ufs_namlen_(de,flags,swab)
-static inline __u16 _ufs_namlen_(struct ufs_dir_entry * de, unsigned flags, unsigned swab) {
- if ((flags & UFS_DE_MASK) == UFS_DE_OLD) {
- return SWAB16(de->d_u.d_namlen);
- } else /* UFS_DE_44BSD */ {
- return de->d_u.d_44.d_namlen;
+#define ufs_get_fs_state(usb3) _ufs_get_fs_state_(usb3,flags,swab)
+static inline __s32 _ufs_get_fs_state_(struct ufs_super_block_third * usb3,
+ unsigned flags, unsigned swab)
+{
+ if ((flags & UFS_ST_MASK) == UFS_ST_SUN)
+ return SWAB32((usb3)->fs_u.fs_sun.fs_state);
+ else
+ return SWAB32((usb3)->fs_u.fs_44.fs_state);
+}
+
+#define ufs_set_fs_state(usb3,value) _ufs_set_fs_state_(usb3,value,flags,swab)
+static inline void _ufs_set_fs_state_(struct ufs_super_block_third * usb3,
+ __s32 value, unsigned flags, unsigned swab)
+{
+ if ((flags & UFS_ST_MASK) == UFS_ST_SUN)
+ (usb3)->fs_u.fs_sun.fs_state = SWAB32(value);
+ else
+ (usb3)->fs_u.fs_44.fs_state = SWAB32(value);
+}
+
+#define ufs_get_fs_qbmask(usb3) _ufs_get_fs_qbmask_(usb3,flags,swab)
+static inline __u64 _ufs_get_fs_qbmask_(struct ufs_super_block_third * usb3,
+ unsigned flags, unsigned swab)
+{
+ __u64 tmp;
+ if ((flags & UFS_ST_MASK) == UFS_ST_SUN) {
+ ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qbmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qbmask[1];
+ }
+ else {
+ ((u32 *)&tmp)[0] = usb3->fs_u.fs_44.fs_qbmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u.fs_44.fs_qbmask[1];
}
+ return SWAB64(tmp);
}
-/*
- * Here is how the uid is computed:
- * if the file system is 4.2BSD, get it from oldids.
- * if it has sun extension and oldids is USEEFT, get it from ui_sun.
- * if it is 4.4 or Hurd, get it from ui_44 (which is the same as from ui_hurd).
- */
-#define ufs_uid(inode) _ufs_uid_(inode,flags,swab)
-static inline __u32 _ufs_uid_(struct ufs_inode * inode, unsigned flags, unsigned swab) {
+#define ufs_get_fs_qfmask(usb3) _ufs_get_fs_qfmask_(usb3,flags,swab)
+static inline __u64 _ufs_get_fs_qfmask_(struct ufs_super_block_third * usb3,
+ unsigned flags, unsigned swab)
+{
+ __u64 tmp;
+ if ((flags & UFS_ST_MASK) == UFS_ST_SUN) {
+ ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qfmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qfmask[1];
+ }
+ else {
+ ((u32 *)&tmp)[0] = usb3->fs_u.fs_44.fs_qfmask[0];
+ ((u32 *)&tmp)[1] = usb3->fs_u.fs_44.fs_qfmask[1];
+ }
+ return SWAB64(tmp);
+}
+
+#define ufs_get_de_namlen(de) \
+ (((flags & UFS_DE_MASK) == UFS_DE_OLD) \
+ ? SWAB16(de->d_u.d_namlen) \
+ : de->d_u.d_44.d_namlen)
+
+#define ufs_set_de_namlen(de,value) \
+ (((flags & UFS_DE_MASK) == UFS_DE_OLD) \
+ ? (de->d_u.d_namlen = SWAB16(value)) \
+ : (de->d_u.d_44.d_namlen = value))
+
+#define ufs_set_de_type(de,mode) _ufs_set_de_type_(de,mode,flags,swab)
+static inline void _ufs_set_de_type_(struct ufs_dir_entry * de, int mode,
+ unsigned flags, unsigned swab)
+{
+ if ((flags & UFS_DE_MASK) == UFS_DE_44BSD) {
+ switch (mode & S_IFMT) {
+ case S_IFSOCK: de->d_u.d_44.d_type = DT_SOCK; break;
+ case S_IFLNK: de->d_u.d_44.d_type = DT_LNK; break;
+ case S_IFREG: de->d_u.d_44.d_type = DT_REG; break;
+ case S_IFBLK: de->d_u.d_44.d_type = DT_BLK; break;
+ case S_IFDIR: de->d_u.d_44.d_type = DT_DIR; break;
+ case S_IFCHR: de->d_u.d_44.d_type = DT_CHR; break;
+ case S_IFIFO: de->d_u.d_44.d_type = DT_FIFO; break;
+ default: de->d_u.d_44.d_type = DT_UNKNOWN;
+ }
+ }
+}
+
+#define ufs_get_inode_uid(inode) _ufs_get_inode_uid_(inode,flags,swab)
+static inline __u32 _ufs_get_inode_uid_(struct ufs_inode * inode,
+ unsigned flags, unsigned swab)
+{
switch (flags & UFS_UID_MASK) {
case UFS_UID_EFT:
return SWAB32(inode->ui_u3.ui_sun.ui_uid);
}
}
-#define ufs_gid(inode) _ufs_gid_(inode,flags,swab)
-static inline __u32 _ufs_gid_(struct ufs_inode * inode, unsigned flags, unsigned swab) {
+#define ufs_set_inode_uid(inode,value) _ufs_set_inode_uid_(inode,value,flags,swab)
+static inline void _ufs_set_inode_uid_(struct ufs_inode * inode, __u32 value,
+ unsigned flags, unsigned swab)
+{
+
+ switch (flags & UFS_UID_MASK) {
+ case UFS_UID_EFT:
+ inode->ui_u1.oldids.ui_suid =
+ inode->ui_u3.ui_sun.ui_uid = SWAB32(value);
+ break;
+ case UFS_UID_44BSD:
+ inode->ui_u1.oldids.ui_suid =
+ inode->ui_u3.ui_44.ui_uid = SWAB32(value);
+ break;
+ case UFS_UID_OLD:
+ default:
+ inode->ui_u1.oldids.ui_suid = SWAB16(value);
+ }
+}
+
+#define ufs_get_inode_gid(inode) _ufs_get_inode_gid_(inode,flags,swab)
+static inline __u32 _ufs_get_inode_gid_(struct ufs_inode * inode,
+ unsigned flags, unsigned swab)
+{
switch (flags & UFS_UID_MASK) {
case UFS_UID_EFT:
return SWAB32(inode->ui_u3.ui_sun.ui_gid);
}
}
-/*
- * macros used to avoid needless retyping
- */
-#define UCPI_UBH ((struct ufs_buffer_head *)ucpi)
-#define USPI_UBH ((struct ufs_buffer_head *)uspi)
+#define ufs_set_inode_gid(inode,value) _ufs_set_inode_gid_(inode,value,flags,swab)
+static inline void _ufs_set_inode_gid_(struct ufs_inode * inode, __u32 value,
+ unsigned flags, unsigned swab)
+{
+ switch (flags & UFS_UID_MASK) {
+ case UFS_UID_EFT:
+ inode->ui_u1.oldids.ui_sgid =
+ inode->ui_u3.ui_sun.ui_gid = SWAB32(value);
+ break;
+ case UFS_UID_44BSD:
+ inode->ui_u1.oldids.ui_sgid =
+ inode->ui_u3.ui_44.ui_gid = SWAB32(value);
+ break;
+ case UFS_UID_OLD:
+ default:
+ inode->ui_u1.oldids.ui_sgid = SWAB16(value);
+ }
+}
+
+
/*
* These functions manipulate ufs buffers
*/
#define ubh_bread(dev,fragment,size) _ubh_bread_(uspi,dev,fragment,size)
extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned);
-#define ubh_bread2(dev,fragment,size) _ubh_bread2_(uspi,dev,fragment,size)
-extern struct ufs_buffer_head * _ubh_bread2_(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned);
+extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned);
extern void ubh_brelse (struct ufs_buffer_head *);
-extern void ubh_brelse2 (struct ufs_buffer_head *);
+extern void ubh_brelse_uspi (struct ufs_sb_private_info *);
extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *, int);
extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int);
extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **);
#define ubh_memcpyubh(ubh,mem,size) _ubh_memcpyubh_(uspi,ubh,mem,size)
extern void _ubh_memcpyubh_(struct ufs_sb_private_info *, struct ufs_buffer_head *, unsigned char *, unsigned);
+
+
/*
* macros to get important structures from ufs_buffer_head
*/
#define ubh_get_ucg(ubh) \
((struct ufs_cylinder_group *)((ubh)->bh[0]->b_data))
+
/*
* Extract byte from ufs_buffer_head
* Extract the bits for a block from a map inside ufs_buffer_head
*/
#define ubh_get_addr8(ubh,begin) \
- ((u8*)(ubh)->bh[(begin) >> uspi->s_fshift]->b_data + ((begin) & ~uspi->s_fmask))
+ ((u8*)(ubh)->bh[(begin) >> uspi->s_fshift]->b_data + \
+ ((begin) & ~uspi->s_fmask))
#define ubh_get_addr16(ubh,begin) \
- (((u16*)((ubh)->bh[(begin) >> (uspi->s_fshift-1)]->b_data)) + ((begin) & (uspi->fsize>>1) - 1)))
+ (((u16*)((ubh)->bh[(begin) >> (uspi->s_fshift-1)]->b_data)) + \
+ ((begin) & (uspi->fsize>>1) - 1)))
#define ubh_get_addr32(ubh,begin) \
- (((u32*)((ubh)->bh[(begin) >> (BLOCK_SIZE_BITS-2)]->b_data)) + \
- ((begin) & ((BLOCK_SIZE>>2) - 1)))
+ (((u32*)((ubh)->bh[(begin) >> (uspi->s_fshift-2)]->b_data)) + \
+ ((begin) & ((uspi->s_fsize>>2) - 1)))
#define ubh_get_addr ubh_get_addr8
#define ubh_blkmap(ubh,begin,bit) \
((*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) >> ((bit) & 7)) & (0xff >> (UFS_MAXFRAG - uspi->s_fpb)))
+
/*
* Macros for access to superblock array structures
*/
#define ubh_isclr(ubh,begin,bit) (!ubh_isset(ubh,begin,bit))
-#define ubh_find_first_zero_bit(ubh,begin,size) \
- _ubh_find_next_zero_bit_(uspi,ubh,begin,size,0)
-#define ubh_find_next_zero_bit(ubh,begin,size,offset) \
- _ubh_find_next_zero_bit_(uspi,ubh,begin,size,offset)
+#define ubh_find_first_zero_bit(ubh,begin,size) _ubh_find_next_zero_bit_(uspi,ubh,begin,size,0)
+#define ubh_find_next_zero_bit(ubh,begin,size,offset) _ubh_find_next_zero_bit_(uspi,ubh,begin,size,offset)
static inline unsigned _ubh_find_next_zero_bit_(
struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh,
unsigned begin, unsigned size, unsigned offset)
{
- unsigned base, rest;
+ unsigned base, count, pos;
+ size -= offset;
begin <<= 3;
- size += begin;
offset += begin;
- base = offset >> (uspi->s_fshift + 3);
- offset &= ((uspi->s_fsize << 3) - 1);
+ base = offset >> uspi->s_bpfshift;
+ offset &= uspi->s_bpfmask;
for (;;) {
- rest = min (size, uspi->s_fsize << 3);
- size -= rest;
- offset = ext2_find_next_zero_bit (ubh->bh[base]->b_data, rest, offset);
- if (offset < rest || !size)
+ count = min (size + offset, uspi->s_bpf);
+ size -= count - offset;
+ pos = ext2_find_next_zero_bit (ubh->bh[base]->b_data, count, offset);
+ if (pos < count + offset || !size)
break;
base++;
offset = 0;
}
- return (base << (uspi->s_fshift + 3)) + offset - begin;
+ return (base << uspi->s_bpfshift) + pos - begin;
}
-#define ubh_isblockclear(ubh,begin,block) \
- (!_ubh_isblockset_(uspi,ubh,begin,block))
-#define ubh_isblockset(ubh,begin,block) \
- _ubh_isblockset_(uspi,ubh,begin,block)
+static inline unsigned find_last_zero_bit (unsigned char * bitmap,
+ unsigned size, unsigned offset)
+{
+ unsigned bit, i;
+ unsigned char * mapp;
+ unsigned char map;
+
+ mapp = bitmap + (size >> 3);
+ map = *mapp--;
+ bit = 1 << (size & 7);
+ for (i = size; i > offset; i--) {
+ if ((map & bit) == 0)
+ break;
+ if ((i & 7) != 0) {
+ bit >>= 1;
+ } else {
+ map = *mapp--;
+ bit = 1 << 7;
+ }
+ }
+ return i;
+}
+#define ubh_find_last_zero_bit(ubh,begin,size,offset) _ubh_find_last_zero_bit_(uspi,ubh,begin,size,offset)
+static inline unsigned _ubh_find_last_zero_bit_(
+ struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh,
+ unsigned begin, unsigned start, unsigned end)
+{
+ unsigned base, count, pos, size;
+
+ size = start - end;
+ begin <<= 3;
+ start += begin;
+ base = start >> uspi->s_bpfshift;
+ start &= uspi->s_bpfmask;
+ for (;;) {
+ count = min (size + (uspi->s_bpf - start), uspi->s_bpf)
+ - (uspi->s_bpf - start);
+ size -= count;
+ pos = find_last_zero_bit (ubh->bh[base]->b_data,
+ start, start - count);
+ if (pos > start - count || !size)
+ break;
+ base--;
+ start = uspi->s_bpf;
+ }
+ return (base << uspi->s_bpfshift) + pos - begin;
+}
+
+#define ubh_isblockclear(ubh,begin,block) (!_ubh_isblockset_(uspi,ubh,begin,block))
+
+#define ubh_isblockset(ubh,begin,block) _ubh_isblockset_(uspi,ubh,begin,block)
static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi,
struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
{
switch (uspi->s_fpb) {
case 8:
- return (*ubh_get_addr (ubh, begin + block) == 0xff);
+ return (*ubh_get_addr (ubh, begin + block) == 0xff);
case 4:
return (*ubh_get_addr (ubh, begin + (block >> 1)) == (0x0f << ((block & 0x01) << 2)));
case 2:
{
switch (uspi->s_fpb) {
case 8:
- *ubh_get_addr (ubh, begin + block) = 0x00;
- return;
+ *ubh_get_addr (ubh, begin + block) = 0x00;
+ return;
case 4:
*ubh_get_addr (ubh, begin + (block >> 1)) &= ~(0x0f << ((block & 0x01) << 2));
return;
{
switch (uspi->s_fpb) {
case 8:
- *ubh_get_addr(ubh, begin + block) = 0xff;
- return;
+ *ubh_get_addr(ubh, begin + block) = 0xff;
+ return;
case 4:
*ubh_get_addr(ubh, begin + (block >> 1)) |= (0x0f << ((block & 0x01) << 2));
return;
ADD_SWAB32(fraglist[fragsize], cnt);
}
-#define ubh_scanc(ubh,begin,size,table,mask) \
- _ubh_scanc_(uspi,ubh,begin,size,table,mask)
+#define ubh_scanc(ubh,begin,size,table,mask) _ubh_scanc_(uspi,ubh,begin,size,table,mask)
static inline unsigned _ubh_scanc_(struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh,
unsigned begin, unsigned size, unsigned char * table, unsigned char mask)
{
#define TASK_ADDR_LIMIT 24
#define TASK_EXEC_DOMAIN 32
#define TASK_NEED_RESCHED 40
-#define TASK_SIZE 1120
+#define TASK_SIZE 1096
#define STACK_SIZE 16384
#define HAE_CACHE 0
#define HAE_REG 8
#define ENV_LANGUAGE 0x0E
#define ENV_TTY_DEV 0x0F
-#endif
+#ifdef __KERNEL__
+extern long srm_dispatch(long code, ...);
+extern void srm_puts(const char *);
+extern long srm_printk(const char *, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+struct crb_struct;
+struct hwrpb_struct;
+extern long srm_fixup(struct crb_struct *, struct hwrpb_struct *);
+#endif /* __KERNEL__ */
+
+#endif /* __AXP_CONSOLE_H */
#define O_SYNC 040000
#define FASYNC 020000 /* fcntl, for BSD compatibility */
#define O_DIRECT 040000 /* direct disk access - should check with OSF/1 */
+#define O_DIRECTORY 0100000 /* must be a directory */
#define F_DUPFD 0 /* dup */
#define F_GETFD 1 /* get f_flags */
#include <linux/tasks.h>
extern unsigned int local_irq_count[NR_CPUS];
+extern unsigned long hardirq_no[NR_CPUS];
/*
* Are we in an interrupt context? Either doing bottom half
#include <asm/atomic.h>
#include <asm/spinlock.h>
+#include <asm/smp.h>
extern int global_irq_holder;
extern spinlock_t global_irq_lock;
{
++local_irq_count[cpu];
atomic_inc(&global_irq_count);
+ hardirq_no[cpu] |= 1L << irq; /* debugging only */
}
static inline void hardirq_exit(int cpu, int irq)
{
+ hardirq_no[cpu] &= ~(1L << irq); /* debugging only */
atomic_dec(&global_irq_count);
--local_irq_count[cpu];
}
unsigned long dsr_offset; /* "Dynamic System Recognition Data Block Table" */
};
+#ifdef __KERNEL__
+
extern struct hwrpb_struct *hwrpb;
+static inline void
+hwrpb_update_checksum(struct hwrpb_struct *h)
+{
+ unsigned long sum = 0, *l;
+ for (l = (unsigned long *) h; l < (unsigned long *) &h->chksum; ++l)
+ sum += *l;
+ h->chksum = sum;
+}
+
+#endif /* __KERNEL__ */
+
#endif /* __ALPHA_HWRPB_H */
#ifdef CONFIG_ALPHA_GENERIC
# define RTC_PORT(x) ((x) + alpha_mv.rtc_port)
-# define RTC_ADDR(x) ((x) | alpha_mv.rtc_addr)
-# define RTC_ALWAYS_BCD (alpha_mv.rtc_bcd)
#else
# ifdef CONFIG_ALPHA_JENSEN
# define RTC_PORT(x) (0x170+(x))
-# define RTC_ADDR(x) (x)
# else
# define RTC_PORT(x) (0x70 + (x))
-# define RTC_ADDR(x) (0x80 | (x))
-# endif
-# ifdef CONFIG_ALPHA_RUFFIAN
-# define RTC_ALWAYS_BCD 1
-# else
-# define RTC_ALWAYS_BCD 0
# endif
#endif
-
+#define RTC_ALWAYS_BCD 0
#endif /* __KERNEL__ */
unsigned long hae_cache;
unsigned long *hae_register;
- unsigned int nr_irqs : 16;
- unsigned int rtc_port : 16;
- unsigned int rtc_addr : 15;
- unsigned int rtc_bcd : 1;
- unsigned int max_asn : 16;
+ int nr_irqs;
+ int rtc_port;
+ int max_asn;
unsigned long max_dma_address;
unsigned long mmu_context_mask;
unsigned long irq_probe_mask;
mm_segment_t fs;
/* Breakpoint handling for ptrace. */
- long debugreg[8];
+ unsigned long bpt_addr[2];
+ unsigned int bpt_insn[2];
+ int bpt_nsaved;
};
#define INIT_MMAP { &init_mm, PAGE_OFFSET, PAGE_OFFSET+0x10000000, \
*/
typedef struct {
- volatile unsigned long lock;
+ volatile unsigned int lock;
+#if DEBUG_SPINLOCK
+ char debug_state, target_ipl, saved_ipl, on_cpu;
void *previous;
struct task_struct * task;
+#endif
} spinlock_t;
-#define SPIN_LOCK_UNLOCKED { 0, 0, 0 }
+#if DEBUG_SPINLOCK
+#define SPIN_LOCK_UNLOCKED {0, 1, 0, 0, 0, 0}
+#define spin_lock_init(x) \
+ ((x)->lock = 0, (x)->target_ipl = 0, (x)->debug_state = 1, \
+ (x)->previous = 0, (x)->task = 0)
+#else
+#define SPIN_LOCK_UNLOCKED { 0 }
+#define spin_lock_init(x) ((x)->lock = 0)
+#endif
-#define spin_lock_init(x) \
- ((x)->lock = 0, (x)->previous = 0, (x)->task = 0)
#define spin_unlock_wait(x) \
({ do { barrier(); } while(((volatile spinlock_t *)x)->lock); })
#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock))
#if DEBUG_SPINLOCK
+extern void spin_unlock(spinlock_t * lock);
extern void spin_lock(spinlock_t * lock);
+extern int spin_trylock(spinlock_t * lock);
+
+#define spin_lock_own(LOCK, LOCATION) \
+do { \
+ if (!((LOCK)->lock && (LOCK)->on_cpu == smp_processor_id())) \
+ printk("%s: called on %d from %p but lock %s on %d\n", \
+ LOCATION, smp_processor_id(), \
+ __builtin_return_address(0), \
+ (LOCK)->lock ? "taken" : "freed", (LOCK)->on_cpu); \
+} while (0)
#else
+static inline void spin_unlock(spinlock_t * lock)
+{
+ mb();
+ lock->lock = 0;
+}
+
static inline void spin_lock(spinlock_t * lock)
{
long tmp;
of this object file's text section so as to perfect
branch prediction. */
__asm__ __volatile__(
- "1: ldq_l %0,%1\n"
+ "1: ldl_l %0,%1\n"
" blbs %0,2f\n"
" or %0,1,%0\n"
- " stq_c %0,%1\n"
+ " stl_c %0,%1\n"
" beq %0,2f\n"
" mb\n"
".section .text2,\"ax\"\n"
- "2: ldq %0,%1\n"
+ "2: ldl %0,%1\n"
" blbs %0,2b\n"
" br 1b\n"
".previous"
: "=r" (tmp), "=m" (__dummy_lock(lock))
: "m"(__dummy_lock(lock)));
}
-#endif /* DEBUG_SPINLOCK */
-
-static inline void spin_unlock(spinlock_t * lock)
-{
- mb();
- lock->lock = 0;
-}
#define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
+#define spin_lock_own(LOCK, LOCATION) ((void)0)
+#endif /* DEBUG_SPINLOCK */
#define spin_lock_irq(lock) \
(__cli(), spin_lock(lock))
extern unsigned long whami(void);
extern void wripir(unsigned long);
-#define halt() \
-__asm__ __volatile__ ("call_pal %0 #halt" : : "i" (PAL_halt) : "memory")
+extern void halt(void) __attribute__((noreturn));
#define switch_to(prev,next) do { \
current = next; \
#define O_NDELAY O_NONBLOCK
#define O_SYNC 010000
#define FASYNC 020000 /* fcntl, for BSD compatibility */
+#define O_DIRECTORY 040000 /* must be a directory */
#define F_DUPFD 0 /* dup */
#define F_GETFD 1 /* get f_flags */
#define FASYNC 020000 /* fcntl, for BSD compatibility */
#define O_DIRECT 040000 /* direct disk access hint - currently ignored */
#define O_LARGEFILE 0100000
+#define O_DIRECTORY 0200000 /* must be a directory */
#define F_DUPFD 0 /* dup */
#define F_GETFD 1 /* get f_flags */
#define O_NDELAY O_NONBLOCK
#define O_SYNC 010000
#define FASYNC 020000 /* fcntl, for BSD compatibility */
+#define O_DIRECTORY 040000 /* must be a directory */
#define F_DUPFD 0 /* dup */
#define F_GETFD 1 /* get f_flags */
#define O_EXCL 0x0400 /* not fcntl */
#define O_NOCTTY 0x0800 /* not fcntl */
#define FASYNC 0x1000 /* fcntl, for BSD compatibility */
+#define O_DIRECTORY 0x2000 /* must be a directory */
#define O_NDELAY O_NONBLOCK
#define O_NDELAY O_NONBLOCK
#define O_SYNC 010000
#define FASYNC 020000 /* fcntl, for BSD compatibility */
+#define O_DIRECTORY 040000 /* must be a directory */
#define F_DUPFD 0 /* dup */
#define F_GETFD 1 /* get f_flags */
#define O_NONBLOCK 0x4000
#define O_NDELAY (0x0004 | O_NONBLOCK)
#define O_NOCTTY 0x8000 /* not fcntl */
+#define O_DIRECTORY 0x10000 /* must be a directory */
#define F_DUPFD 0 /* dup */
#define F_GETFD 1 /* get f_flags */
#define O_SYNC 0x2000
#define O_NONBLOCK 0x4000
#define O_NOCTTY 0x8000 /* not fcntl */
+#define O_DIRECTORY 0x10000 /* must be a directory */
#define F_DUPFD 0 /* dup */
#define F_GETFD 1 /* get f_flags */
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
-#elif (MAJOR_NR == SCSI_DISK_MAJOR)
+#elif (SCSI_DISK_MAJOR(MAJOR_NR))
#define DEVICE_NAME "scsidisk"
#define DEVICE_INTR do_sd
#define TIMEOUT_VALUE (2*HZ)
#define DEVICE_REQUEST do_sd_request
-#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4))
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
* Loop filter types
*/
-#define LO_CRYPT_NONE 0
-#define LO_CRYPT_XOR 1
-#define LO_CRYPT_DES 2
-#define LO_CRYPT_DUMMY 9
+#define LO_CRYPT_NONE 0
+#define LO_CRYPT_XOR 1
+#define LO_CRYPT_DES 2
+#define LO_CRYPT_FISH2 3 /* Brand new Twofish encryption */
+#define LO_CRYPT_BLOW 4
+#define LO_CRYPT_CAST128 5
+#define LO_CRYPT_IDEA 6
+#define LO_CRYPT_DUMMY 9
#define LO_CRYPT_SKIPJACK 10
#define MAX_LO_CRYPT 20
/* The parallel port specs apparently say that there needs to be
* a .5usec wait before and after the strobe. Since there are wildly
* different computers running linux, I can't come up with a perfect
- * value, but since it worked well on most printers before without,
- * I'll initialize it to 0.
+ * value so if 20 is not good for you use `tunelp /dev/lp? -w ?`.
+ * You can also set it to 0 if your printer handle that.
*/
-#define LP_INIT_WAIT 0
+#define LP_INIT_WAIT 20
/* This is the amount of time that the driver waits for the printer to
* catch up when the printer's buffer appears to be filled. If you
#define LP_MAJOR 6
#define VCS_MAJOR 7
#define LOOP_MAJOR 7
-#define SCSI_DISK_MAJOR 8
+#define SCSI_DISK0_MAJOR 8
#define SCSI_TAPE_MAJOR 9
#define MD_MAJOR 9
#define MISC_MAJOR 10
#define IDE4_MAJOR 56
#define IDE5_MAJOR 57
+#define SCSI_DISK1_MAJOR 65
+#define SCSI_DISK2_MAJOR 66
+#define SCSI_DISK3_MAJOR 67
+#define SCSI_DISK4_MAJOR 68
+#define SCSI_DISK5_MAJOR 69
+#define SCSI_DISK6_MAJOR 70
+#define SCSI_DISK7_MAJOR 71
+
#define SPECIALIX_NORMAL_MAJOR 75
#define SPECIALIX_CALLOUT_MAJOR 76
* Tests for SCSI devices.
*/
+#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
+ ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
+
#define SCSI_BLK_MAJOR(M) \
- ((M) == SCSI_DISK_MAJOR \
+ (SCSI_DISK_MAJOR(M) \
|| (M) == SCSI_CDROM_MAJOR)
static __inline__ int scsi_blk_major(int m) {
return vma;
}
+extern __inline__ void kswapd_wakeup(void)
+{
+ wake_up(&kswapd_wait);
+}
+
+#define buffer_under_min() ((buffermem >> PAGE_SHIFT) * 100 < \
+ buffer_mem.min_percent * num_physpages)
+#define buffer_under_borrow() ((buffermem >> PAGE_SHIFT) * 100 < \
+ buffer_mem.borrow_percent * num_physpages)
+#define buffer_under_max() ((buffermem >> PAGE_SHIFT) * 100 < \
+ buffer_mem.max_percent * num_physpages)
+#define buffer_over_min() ((buffermem >> PAGE_SHIFT) * 100 > \
+ buffer_mem.min_percent * num_physpages)
+#define buffer_over_borrow() ((buffermem >> PAGE_SHIFT) * 100 > \
+ buffer_mem.borrow_percent * num_physpages)
+#define buffer_over_max() ((buffermem >> PAGE_SHIFT) * 100 > \
+ buffer_mem.max_percent * num_physpages)
+#define pgcache_under_min() (page_cache_size * 100 < \
+ page_cache.min_percent * num_physpages)
+#define pgcache_under_borrow() (page_cache_size * 100 < \
+ page_cache.borrow_percent * num_physpages)
+#define pgcache_under_max() (page_cache_size * 100 < \
+ page_cache.max_percent * num_physpages)
+#define pgcache_over_min() (page_cache_size * 100 > \
+ page_cache.min_percent * num_physpages)
+#define pgcache_over_borrow() (page_cache_size * 100 > \
+ page_cache.borrow_percent * num_physpages)
+#define pgcache_over_max() (page_cache_size * 100 > \
+ page_cache.max_percent * num_physpages)
+
#endif /* __KERNEL__ */
#endif
void (*enable_irq)(struct parport *);
void (*disable_irq)(struct parport *);
- int (*examine_irq)(struct parport *);
+ void (*interrupt)(int, void *, struct pt_regs *);
void (*inc_use_count)(void);
void (*dec_use_count)(void);
void *private_data; /* for lowlevel driver */
int number; /* port index - the `n' in `parportn' */
- spinlock_t lock;
+ spinlock_t pardevice_lock;
+ spinlock_t waitlist_lock;
+ spinlock_t cad_lock;
};
/* parport_register_port registers a new parallel port at the given address (if
/* parport_register_device declares that a device is connected to a port, and
* tells the kernel all it needs to know.
- * pf is the preemption function (may be NULL for a transient driver)
- * kf is the wake-up function (may be NULL for a transient driver)
+ * pf is the preemption function (may be NULL for no callback)
+ * kf is the wake-up function (may be NULL for no callback)
* irq_func is the interrupt handler (may be NULL for no interrupts)
- * Only one lurking driver can be used on a given port.
* handle is a user pointer that gets handed to callback functions.
*/
struct pardevice *parport_register_device(struct parport *port,
return parport_claim_or_block(dev);
}
+/*
+ * Lowlevel drivers _can_ call this support function to handle irqs.
+ */
+extern __inline__ void parport_generic_irq(int irq, struct parport *port,
+ struct pt_regs *regs)
+{
+ read_lock(&port->cad_lock);
+ if (!port->cad)
+ goto out_unlock;
+ if (port->cad->irq_func)
+ port->cad->irq_func(irq, port->cad->private, regs);
+ else
+ printk(KERN_ERR "%s: irq%d happened with irq_func NULL "
+ "with %s as cad!\n", port->name, irq, port->cad->name);
+ out_unlock:
+ read_unlock(&port->cad_lock);
+}
+
/* Flags used to identify what a device does. */
-#define PARPORT_DEV_TRAN 0x0000 /* We're transient. */
-#define PARPORT_DEV_LURK 0x0001 /* We lurk. */
+#define PARPORT_DEV_TRAN 0 /* WARNING !! DEPRECATED !! */
+#define PARPORT_DEV_LURK (1<<0) /* WARNING !! DEPRECATED !! */
+#define PARPORT_DEV_EXCL (1<<1) /* Need exclusive access. */
-#define PARPORT_FLAG_COMA 1
+#define PARPORT_FLAG_COMA (1<<0)
+#define PARPORT_FLAG_EXCL (1<<1) /* EXCL driver registered. */
extern void parport_parse_irqs(int, const char *[], int irqval[]);
extern int parport_ieee1284_nibble_mode_ok(struct parport *, unsigned char);
extern int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle);
-extern int parport_pc_examine_irq(struct parport *p);
-
extern void parport_pc_inc_use_count(void);
extern void parport_pc_dec_use_count(void);
/*
- * $Id: pci.h,v 1.84 1998/08/17 23:06:43 cort Exp $
+ * $Id: pci.h,v 1.87 1998/10/11 15:13:12 mj Exp $
*
* PCI defines and function prototypes
* Copyright 1994, Drew Eckhardt
#define PCI_DEVICE_ID_ADAPTEC_7884 0x8478
#define PCI_DEVICE_ID_ADAPTEC_1030 0x8b78
-#define PCI_VENDOR_ID_ADAPTEC2 0x9005
-#define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010
-#define PCI_DEVICE_ID_ADAPTEC2_7890 0x001f
-#define PCI_DEVICE_ID_ADAPTEC2_3940U2 0x0050
-#define PCI_DEVICE_ID_ADAPTEC2_7896 0x005f
-
+#define PCI_VENDOR_ID_ADAPTEC2 0x9005
+#define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010
+#define PCI_DEVICE_ID_ADAPTEC2_7890 0x001f
+#define PCI_DEVICE_ID_ADAPTEC2_3940U2 0x0050
+#define PCI_DEVICE_ID_ADAPTEC2_7896 0x005f
#define PCI_VENDOR_ID_ATRONICS 0x907f
#define PCI_DEVICE_ID_ATRONICS_2015 0x2015
unsigned fwid; /* firmware ID */
unsigned port; /* adapter I/O port base */
int irq; /* interrupt request level */
- unsigned long dpmbase; /* dual-port memory base */
+ void * dpmbase; /* dual-port memory base */
unsigned dpmsize; /* dual-port memory size */
unsigned pclk; /* CPU clock rate, kHz */
unsigned long memory; /* memory size */
*
* NeXTstep support added on February 5th 1998 by
* Niels Kristian Bech Jensen <nkbj@image.dk>.
+ *
+ * Write support by Daniel Pirkl <daniel.pirkl@email.cz>
*/
#ifndef __LINUX_UFS_FS_H
/* From here to next blank line, s_flags for ufs_sb_info */
/* endianness */
-#define UFS_BYTESEX 0x00000001 /* mask; leave room to 0xF */
+#define UFS_BYTESEX 0x00000001 /* mask; leave room to 0xF */
#if defined(__LITTLE_ENDIAN) || defined(__BIG_ENDIAN)
/* these are for sane architectures */
#define UFS_NATIVE_ENDIAN 0x00000000
#define UFS_ST_OLD 0x00000000
#define UFS_ST_44BSD 0x00000100
#define UFS_ST_SUN 0x00000200
-#define UFS_ST_NEXT 0x00000400
-/* filesystem flavors (combo of features) */
-#define UFS_FEATURES 0x00FFFFF0 /* room for extension */
-#define UFS_VANILLA 0x00000000
-#define UFS_OLD 0x00000000 /* 4.2BSD */
-#define UFS_44BSD 0x00000130
-#define UFS_HURD 0x00000130
-#define UFS_SUN 0x00000200
-#define UFS_NEXT 0x00000400
+/*cylinder group encoding */
+#define UFS_CG_MASK 0x00003000 /* mask for the following */
+#define UFS_CG_OLD 0x00000000
+#define UFS_CG_44BSD 0x00002000
+#define UFS_CG_SUN 0x00001000
/* fs_inodefmt options */
#define UFS_42INODEFMT -1
#define UFS_44INODEFMT 2
+/* mount options */
+#define UFS_MOUNT_ONERROR 0x0000000F
+#define UFS_MOUNT_ONERROR_PANIC 0x00000001
+#define UFS_MOUNT_ONERROR_LOCK 0x00000002
+#define UFS_MOUNT_ONERROR_UMOUNT 0x00000004
+#define UFS_MOUNT_ONERROR_REPAIR 0x00000008
+
+#define UFS_MOUNT_UFSTYPE 0x000000F0
+#define UFS_MOUNT_UFSTYPE_OLD 0x00000010
+#define UFS_MOUNT_UFSTYPE_44BSD 0x00000020
+#define UFS_MOUNT_UFSTYPE_SUN 0x00000040
+#define UFS_MOUNT_UFSTYPE_NEXT 0x00000080
+
+
+#define ufs_clear_opt(o,opt) o &= ~UFS_MOUNT_##opt
+#define ufs_set_opt(o,opt) o |= UFS_MOUNT_##opt
+#define ufs_test_opt(o,opt) ((o) & UFS_MOUNT_##opt)
+
/*
* MINFREE gives the minimum acceptable percentage of file system
* blocks which may be free. If the freelist drops below this level
__s32 tv_usec;
};
+/*
+ * File types
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
struct ufs_dir_entry {
__u32 d_ino; /* inode number of this entry */
__u16 d_reclen; /* length of this entry */
__u32 cg_iusedoff; /* (char) used inode map */
__u32 cg_freeoff; /* (u_char) free block map */
__u32 cg_nextfreeoff; /* (u_char) next available space */
- __u32 cg_sparecon[16]; /* reserved for future use */
+ union {
+ struct {
+ __u32 cg_clustersumoff; /* (u_int32) counts of avail clusters */
+ __u32 cg_clusteroff; /* (u_int8) free cluster map */
+ __u32 cg_nclusterblks; /* number of clusters this cg */
+ __u32 cg_sparecon[13]; /* reserved for future use */
+ } cg_44;
+ __u32 cg_sparecon[16]; /* reserved for future use */
+ } cg_u;
__u8 cg_space[1]; /* space for cylinder group maps */
/* actually longer */
};
__u16 ui_suid; /* 0x4 */
__u16 ui_sgid; /* 0x6 */
} oldids;
- __u32 ui_inumber; /* 0x4 lsf: inode number */
+ __u32 ui_inumber; /* 0x4 lsf: inode number */
__u32 ui_author; /* 0x4 GNU HURD: author */
} ui_u1;
__u64 ui_size; /* 0x8 */
__u32 ui_gen; /* 0x6c like ext2 i_version, for NFS support */
union {
struct {
- __u32 ui_shadow;/* 0x70 shadow inode with security data */
- __u32 ui_uid; /* 0x74 long EFT version of uid */
- __u32 ui_gid; /* 0x78 long EFT version of gid */
- __u32 ui_oeftflag;/* 0x7c reserved */
+ __u32 ui_shadow; /* 0x70 shadow inode with security data */
+ __u32 ui_uid; /* 0x74 long EFT version of uid */
+ __u32 ui_gid; /* 0x78 long EFT version of gid */
+ __u32 ui_oeftflag; /* 0x7c reserved */
} ui_sun;
struct {
- __u32 ui_uid; /* 0x70 File owner */
- __u32 ui_gid; /* 0x74 File group */
- __s32 ui_spare[2];/* 0x78 reserved */
+ __u32 ui_uid; /* 0x70 File owner */
+ __u32 ui_gid; /* 0x74 File group */
+ __s32 ui_spare[2]; /* 0x78 reserved */
} ui_44;
struct {
- __u32 ui_uid; /* 0x70 */
- __u32 ui_gid; /* 0x74 */
- __u16 ui_modeh;/* 0x78 mode high bits */
- __u16 ui_spare;/* 0x7A unused */
- __u32 ui_trans;/* 0x7c filesystem translator */
+ __u32 ui_uid; /* 0x70 */
+ __u32 ui_gid; /* 0x74 */
+ __u16 ui_modeh; /* 0x78 mode high bits */
+ __u16 ui_spare; /* 0x7A unused */
+ __u32 ui_trans; /* 0x7c filesystem translator */
} ui_hurd;
} ui_u3;
};
extern void ufs_put_inode (struct inode *);
extern void ufs_write_inode (struct inode *);
extern int ufs_sync_inode (struct inode *);
-extern void ufs_print_inode (struct inode *);
extern void ufs_write_inode (struct inode *);
extern void ufs_delete_inode (struct inode *);
extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
extern void ufs_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
extern void ufs_panic (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
-
extern int init_ufs_fs(void);
extern void ufs_write_super (struct super_block *);
-extern void ufs_print_cylinder_stuff(struct ufs_cylinder_group *, __u32);
/* symlink.c */
extern struct inode_operations ufs_symlink_inode_operations;
*
* NeXTstep support added on February 5th 1998 by
* Niels Kristian Bech Jensen <nkbj@image.dk>.
- *
- * write support by Daniel Pirkl <daniel.pirkl@email.cz>
*/
#ifndef _LINUX_UFS_FS_I_H
*
* $Id: ufs_fs_sb.h,v 1.8 1998/05/06 12:04:40 jj Exp $
*
- * Write support by Daniel Pirkl (daniel.pirkl@email.cz)
- * Charles University (Prague), Faculty of Mathematics and Physics
+ * Write support by Daniel Pirkl <daniel.pirkl@email.cz>
*/
#ifndef __LINUX_UFS_FS_SB_H
__u32 c_iusedoff; /* (char) used inode map */
__u32 c_freeoff; /* (u_char) free block map */
__u32 c_nextfreeoff; /* (u_char) next available space */
+ __u32 c_clustersumoff;/* (u_int32) counts of avail clusters */
+ __u32 c_clusteroff; /* (u_int8) free cluster map */
+ __u32 c_nclusterblks; /* number of clusters this cg */
};
-
struct ufs_sb_private_info {
struct ufs_buffer_head s_ubh; /* buffer containing super block */
__u32 s_ipg; /* inodes per group */
__u32 s_fpg; /* fragments per group */
__u32 s_cpc; /* cyl per cycle in postbl */
+ __s32 s_contigsumsize;/* size of cluster summary array, 44bsd */
__s64 s_qbmask; /* ~usb_bmask */
__s64 s_qfmask; /* ~usb_fmask */
__s32 s_postblformat; /* format of positional layout tables */
__u32 s_nspb; /* number of sector per block */
__u32 s_inopf; /* inodes per fragment */
__u32 s_sbbase; /* offset of NeXTstep superblock */
+ __u32 s_bpf; /* bits per fragment */
+ __u32 s_bpfshift; /* bits per fragment shift*/
+ __u32 s_bpfmask; /* bits per fragment mask */
};
-#define UFS_MAX_GROUP_LOADED 1
-#define UFS_CGNO_EMPTY uspi->s_ncg
+#define UFS_MAX_GROUP_LOADED 8
+#define UFS_CGNO_EMPTY ((unsigned)-1)
struct ufs_sb_info {
struct ufs_sb_private_info * s_uspi;
struct ufs_cg_private_info * s_ucpi[UFS_MAX_GROUP_LOADED];
unsigned s_cgno[UFS_MAX_GROUP_LOADED];
unsigned short s_cg_loaded;
+ unsigned s_mount_opt;
};
/*
struct video_clip *clips; /* Set only */
int clipcount;
#define VIDEO_WINDOW_INTERLACE 1
+#define VIDEO_CLIP_BITMAP -1
+/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
+#define VIDEO_CLIPMAP_SIZE (128 * 625)
};
struct video_capture
void* private; /* -> driver private data */
/****** hardware configuration ******/
unsigned ioport; /* adapter I/O port base #1 */
- unsigned long maddr; /* dual-port memory address */
+ void * maddr; /* dual-port memory address */
unsigned msize; /* dual-port memory size */
int irq; /* interrupt request level */
int dma; /* DMA request level */
fast_memmove(dst, src, size);
return dst;
}
+
#else
+
+#ifdef CONFIG_SUN4
+/* To be honest, this is slow_memmove :). But sun4 is crappy, so what we can do. */
+static __inline__ void fast_memmove(void *d, const void *s, size_t count)
+{
+ int i;
+ if (d<s) {
+ for (i=0; i<count; i++)
+ ((char *) d)[i] = ((char *) s)[i];
+ } else
+ for (i=0; i<count; i++)
+ ((char *) d)[count-i-1] = ((char *) s)[count-i-1];
+}
+
+static __inline__ void *mymemmove(char *dst, const char *src, size_t size)
+{
+ fast_memmove(dst, src, size);
+ return dst;
+}
+
+#else
+
static __inline__ void *mymemmove(void *d, const void *s, size_t count)
{
return(memmove(d, s, count));
{
memmove(dst, src, size);
}
-#endif /* !i386 */
+
+#endif /* !sun4 */
+
+#endif /* !i386 */
#endif /* !m68k */
#ifdef CONFIG_SOUNDMODEM
extern void sm_setup(char *str, int *ints);
#endif
-#ifdef CONFIG_PMAC_CONSOLE
-extern void pmac_cons_setup(char *str, int *ints);
-extern void pmac_vmode_setup(char *str, int *ints);
+#ifdef CONFIG_ADBMOUSE
+extern void adb_mouse_setup(char *str, int *ints);
#endif
#ifdef CONFIG_WDT
extern void wdt_setup(char *str, int *ints);
#include <linux/errno.h>
#include <asm/dma.h>
#include <asm/system.h>
+#include <asm/spinlock.h>
/* A note on resource allocation:
#include <linux/console.h>
#include <linux/time.h>
+#include <asm/spinlock.h>
+
extern unsigned char aux_device_present, pckbd_read_mask;
#if defined(CONFIG_PROC_FS)
extern int sys_tz;
extern int request_dma(unsigned int dmanr, char * deviceID);
extern void free_dma(unsigned int dmanr);
+extern spinlock_t dma_spin_lock;
#ifdef MODVERSIONS
const struct module_symbol __export_Using_Versions
/* dma handling */
EXPORT_SYMBOL(request_dma);
EXPORT_SYMBOL(free_dma);
+EXPORT_SYMBOL(dma_spin_lock);
#ifdef HAVE_DISABLE_HLT
EXPORT_SYMBOL(disable_hlt);
EXPORT_SYMBOL(enable_hlt);
} while (tmp != bh);
/* Refuse to swap out all buffer pages */
- if ((buffermem >> PAGE_SHIFT) * 100 < (buffer_mem.min_percent * num_physpages))
+ if (buffer_under_min())
goto next;
}
age_page(page);
if (page->age)
break;
- if (page_cache_size * 100 < (page_cache.min_percent * num_physpages))
+ if (pgcache_under_min())
break;
if (PageSwapCache(page)) {
delete_from_swap_cache(page);
if (gfp_mask & __GFP_WAIT)
stop = 0;
- if (((buffermem >> PAGE_SHIFT) * 100 > buffer_mem.borrow_percent * num_physpages)
- || (page_cache_size * 100 > page_cache.borrow_percent * num_physpages))
+ if (buffer_over_borrow() || pgcache_over_borrow())
shrink_mmap(i, gfp_mask);
switch (state) {
}
if ((long) (now - want) >= 0) {
- if (want_wakeup || (num_physpages * buffer_mem.max_percent) < (buffermem >> PAGE_SHIFT) * 100
- || (num_physpages * page_cache.max_percent < page_cache_size * 100)) {
+ if (want_wakeup || buffer_over_max() || pgcache_over_max()) {
/* Set the next wake-up time */
next_swap_jiffies = now + swapout_interval;
- wake_up(&kswapd_wait);
+ kswapd_wakeup();
}
}
timer_active |= (1<<SWAP_TIMER);
/*
* Find a connected NET/ROM socket given their circuit IDs.
*/
-static struct sock *nr_find_peer(unsigned char index, unsigned char id)
+static struct sock *nr_find_peer(unsigned char index, unsigned char id, ax25_address *dest)
{
struct sock *s;
unsigned long flags;
cli();
for (s = nr_list; s != NULL; s = s->next) {
- if (s->protinfo.nr->your_index == index && s->protinfo.nr->your_id == id) {
+ if (s->protinfo.nr->your_index == index && s->protinfo.nr->your_id == id && ax25cmp(&s->protinfo.nr->dest_addr, dest) == 0) {
restore_flags(flags);
return s;
}
sk->state_change(sk);
sk->dead = 1;
sk->destroy = 1;
+ sk->socket = NULL;
break;
default:
+ sk->socket = NULL;
break;
}
sock->sk = NULL;
- sk->socket = NULL; /* Not used, but we should do this */
return 0;
}
if (sk->zapped == 0)
return -EINVAL;
- if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
+ if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct
+full_sockaddr_ax25))
+ return -EINVAL;
+
+ if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25)))
return -EINVAL;
if (addr->fsa_ax25.sax25_family != AF_NETROM)
if (circuit_index == 0 && circuit_id == 0) {
if (frametype == NR_CONNACK && flags == NR_CHOKE_FLAG)
- sk = nr_find_peer(peer_circuit_index, peer_circuit_id);
+ sk = nr_find_peer(peer_circuit_index, peer_circuit_id, src);
} else {
if (frametype == NR_CONNREQ)
- sk = nr_find_peer(circuit_index, circuit_id);
+ sk = nr_find_peer(circuit_index, circuit_id, src);
else
sk = nr_find_socket(circuit_index, circuit_id);
}
ax25_address *nr_dest;
struct device *dev;
- while ((skb = skb_dequeue(&loopback_queue)) != NULL) {
+ if ((skb = skb_dequeue(&loopback_queue)) != NULL) {
nr_dest = (ax25_address *)(skb->data + 7);
- if ((dev = nr_dev_get(nr_dest)) == NULL) {
- kfree_skb(skb);
- continue;
- }
+ dev = nr_dev_get(nr_dest);
- if (nr_rx_frame(skb, dev) == 0)
+ if (dev == NULL || nr_rx_frame(skb, dev) == 0)
kfree_skb(skb);
+
+ if (!skb_queue_empty(&loopback_queue) && !nr_loopback_running())
+ nr_set_loopback_timer();
}
}
if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
break;
+ /*
+ * The L2 link to a neighbour has failed in the past
+ * and now a frame comes from this neighbour. We assume
+ * it was a temporary trouble with the link and reset the
+ * routes now (and not wait for a node broadcast).
+ */
+ if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) {
+ struct nr_node *node;
+
+ for (node = nr_node_list; node != NULL; node = node->next)
+ for (i = 0; i < node->count; i++)
+ if (node->routes[i].neighbour == nr_neigh)
+ if (i < node->which)
+ node->which = i;
+ }
+
if (nr_neigh != NULL)
nr_neigh->failed = 0;
static void
print_item (WINDOW * win, const char *item, int choice, int selected, int hotkey)
{
- int i, j;
+ int j;
char menu_item[menu_width+1];
+#if OLD_NCURSES
+ int i;
+#endif
strncpy(menu_item, item, menu_width);
menu_item[menu_width] = 0;
static void
print_line (WINDOW * win, int row, int width)
{
- int i, y, x;
+ int y, x;
char *line;
+#if OLD_NCURSES
+ int i;
+#endif
line = get_line ();
line += MIN (strlen (line), hscroll); /* Scroll horizontally */